diff options
Diffstat (limited to 'telephony')
105 files changed, 7569 insertions, 2949 deletions
diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java index bb5f126..7d600f0 100644 --- a/telephony/java/android/telephony/CellLocation.java +++ b/telephony/java/android/telephony/CellLocation.java @@ -62,13 +62,10 @@ public abstract class CellLocation { * @hide */ public static CellLocation newFromBundle(Bundle bundle) { - // TODO: My need to be use: Settings.Secure.getInt(mContext, Settings.Secure.CURRENT_ACTIVE_PHONE, 0)) - // instead of SystemProperties??? - - // NOTE here TelephonyManager.getDefault().getPhoneType() cannot be used since at startup - // ITelephony have not been created - if (RILConstants.CDMA_PHONE == - SystemProperties.getInt(Settings.Secure.CURRENT_ACTIVE_PHONE, RILConstants.GSM_PHONE)) { + // TelephonyManager.getDefault().getPhoneType() handles the case when + // ITelephony interface is not up yet. + int type = TelephonyManager.getDefault().getPhoneType(); + if (type == RILConstants.CDMA_PHONE) { return new CdmaCellLocation(bundle); } else { return new GsmCellLocation(bundle); @@ -85,17 +82,13 @@ public abstract class CellLocation { * */ public static CellLocation getEmpty() { - // TODO: My need to be use: Settings.Secure.getInt(mContext, Settings.Secure.CURRENT_ACTIVE_PHONE, 0)) - // instead of SystemProperties??? - - // NOTE here TelephonyManager.getDefault().getPhoneType() cannot be used since at startup - // ITelephony have not been created - if (RILConstants.CDMA_PHONE == - SystemProperties.getInt(Settings.Secure.CURRENT_ACTIVE_PHONE, RILConstants.GSM_PHONE)) { + // TelephonyManager.getDefault().getPhoneType() handles the case when + // ITelephony interface is not up yet. + int type = TelephonyManager.getDefault().getPhoneType(); + if (type == RILConstants.CDMA_PHONE) { return new CdmaCellLocation(); } else { return new GsmCellLocation(); } } - } diff --git a/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java b/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java index 8a82966..6390d8e 100644 --- a/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java +++ b/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java @@ -21,11 +21,11 @@ import android.text.Editable; /* * Japanese Phone number formatting rule is a bit complicated. * Here are some valid examples: - * + * * 022-229-1234 0223-23-1234 022-301-9876 015-482-7849 0154-91-3478 * 01547-5-4534 090-1234-1234 080-0123-6789 * 0800-000-9999 0570-000-000 0276-00-0000 - * + * * As you can see, there is no straight-forward rule here. * In order to handle this, a big array is prepared. */ @@ -151,14 +151,14 @@ import android.text.Editable; -100, -100, -45, -45, -100, -100, -100, -100, -100, -100, -25, -35, -35, -35, -35, -35, -35, -25, -25, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -45}; - + public static void format(Editable text) { // Here, "root" means the position of "'": // 0'3, 0'90, and +81'-90 // (dash will be deleted soon, so it is actually +81'90). int rootIndex = 1; int length = text.length(); - if (length > 3 + if (length > 3 && text.subSequence(0, 3).toString().equals("+81")) { rootIndex = 3; } else if (length < 1 || text.charAt(0) != '0') { @@ -176,10 +176,10 @@ import android.text.Editable; i++; } } - + length = text.length(); int dashposition; - + i = rootIndex; int base = 0; while (i < length) { @@ -208,7 +208,7 @@ import android.text.Editable; i++; } } - + if (length > 3 && rootIndex == 3) { text.insert(rootIndex, "-"); } diff --git a/telephony/java/android/telephony/NeighboringCellInfo.aidl b/telephony/java/android/telephony/NeighboringCellInfo.aidl index a7e709e..c464332 100644 --- a/telephony/java/android/telephony/NeighboringCellInfo.aidl +++ b/telephony/java/android/telephony/NeighboringCellInfo.aidl @@ -2,16 +2,16 @@ ** ** Copyright 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 +** 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 +** 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 +** 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. */ diff --git a/telephony/java/android/telephony/NeighboringCellInfo.java b/telephony/java/android/telephony/NeighboringCellInfo.java index 326401a..f492abd 100644 --- a/telephony/java/android/telephony/NeighboringCellInfo.java +++ b/telephony/java/android/telephony/NeighboringCellInfo.java @@ -20,7 +20,7 @@ import android.os.Parcel; import android.os.Parcelable; /** - * Represents the neighboring cell information, including + * Represents the neighboring cell information, including * Received Signal Strength and Cell ID location. */ public class NeighboringCellInfo implements Parcelable @@ -52,7 +52,7 @@ public class NeighboringCellInfo implements Parcelable mRssi = rssi; mCid = cid; } - + /** * Initialize the object from a parcel. */ @@ -60,12 +60,12 @@ public class NeighboringCellInfo implements Parcelable mRssi = in.readInt(); mCid = in.readInt(); } - + /** - * @return received signal strength in "asu", ranging from 0 - 31, + * @return received signal strength in "asu", ranging from 0 - 31, * or UNKNOWN_RSSI if unknown * - * For GSM, dBm = -113 + 2*asu, + * For GSM, dBm = -113 + 2*asu, * 0 means "-113 dBm or less" and 31 means "-51 dBm or greater" */ public int getRssi() { @@ -95,7 +95,7 @@ public class NeighboringCellInfo implements Parcelable @Override public String toString() { - return "["+ ((mCid == UNKNOWN_CID) ? "/" : Integer.toHexString(mCid)) + return "["+ ((mCid == UNKNOWN_CID) ? "/" : Integer.toHexString(mCid)) + " at " + ((mRssi == UNKNOWN_RSSI)? "/" : mRssi) + "]"; } @@ -105,7 +105,7 @@ public class NeighboringCellInfo implements Parcelable public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mRssi); - dest.writeInt(mCid); + dest.writeInt(mCid); } public static final Parcelable.Creator<NeighboringCellInfo> CREATOR diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index d3942fc..dbe8431 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -701,17 +701,6 @@ public class PhoneNumberUtils } /** - * Note: calls extractNetworkPortion(), so do not use for - * SIM EF[ADN] style records - * - * Exceptions thrown if extractNetworkPortion(s).length() == 0 - */ - public static byte[] - networkPortionToCalledPartyBCD(String s) { - return numberToCalledPartyBCD(extractNetworkPortion(s)); - } - - /** * Return true iff the network portion of <code>address</code> is, * as far as we can tell on the device, suitable for use as an SMS * destination address. @@ -744,12 +733,25 @@ public class PhoneNumberUtils } /** + * Note: calls extractNetworkPortion(), so do not use for + * SIM EF[ADN] style records + * + * Returns null if network portion is empty. + */ + public static byte[] + networkPortionToCalledPartyBCD(String s) { + String networkPortion = extractNetworkPortion(s); + return numberToCalledPartyBCDHelper(networkPortion, false); + } + + /** * Same as {@link #networkPortionToCalledPartyBCD}, but includes a * one-byte length prefix. */ public static byte[] networkPortionToCalledPartyBCDWithLength(String s) { - return numberToCalledPartyBCDWithLength(extractNetworkPortion(s)); + String networkPortion = extractNetworkPortion(s); + return numberToCalledPartyBCDHelper(networkPortion, true); } /** @@ -761,61 +763,46 @@ public class PhoneNumberUtils */ public static byte[] numberToCalledPartyBCD(String number) { - // The extra byte required for '+' is taken into consideration while calculating - // length of ret. - int size = (hasPlus(number) ? number.length() - 1 : number.length()); - byte[] ret = new byte[(size + 1) / 2 + 1]; - - return numberToCalledPartyBCDHelper(ret, 0, number); + return numberToCalledPartyBCDHelper(number, false); } /** - * Same as {@link #numberToCalledPartyBCD}, but includes a - * one-byte length prefix. + * If includeLength is true, prepend a one-byte length value to + * the return array. */ private static byte[] - numberToCalledPartyBCDWithLength(String number) { - // The extra byte required for '+' is taken into consideration while calculating - // length of ret. - int size = (hasPlus(number) ? number.length() - 1 : number.length()); - int length = (size + 1) / 2 + 1; - byte[] ret = new byte[length + 1]; - - ret[0] = (byte) (length & 0xff); - return numberToCalledPartyBCDHelper(ret, 1, number); - } - - private static boolean - hasPlus(String s) { - return s.indexOf('+') >= 0; - } - - private static byte[] - numberToCalledPartyBCDHelper(byte[] ret, int offset, String number) { - if (hasPlus(number)) { - number = number.replaceAll("\\+", ""); - ret[offset] = (byte) TOA_International; - } else { - ret[offset] = (byte) TOA_Unknown; + numberToCalledPartyBCDHelper(String number, boolean includeLength) { + int numberLenReal = number.length(); + int numberLenEffective = numberLenReal; + boolean hasPlus = number.indexOf('+') != -1; + if (hasPlus) numberLenEffective--; + + if (numberLenEffective == 0) return null; + + int resultLen = (numberLenEffective + 1) / 2; // Encoded numbers require only 4 bits each. + int extraBytes = 1; // Prepended TOA byte. + if (includeLength) extraBytes++; // Optional prepended length byte. + resultLen += extraBytes; + + byte[] result = new byte[resultLen]; + + int digitCount = 0; + for (int i = 0; i < numberLenReal; i++) { + char c = number.charAt(i); + if (c == '+') continue; + int shift = ((digitCount & 0x01) == 1) ? 4 : 0; + result[extraBytes + (digitCount >> 1)] |= (byte)((charToBCD(c) & 0x0F) << shift); + digitCount++; } - int size = number.length(); - int curChar = 0; - int countFullBytes = ret.length - offset - 1 - ((size - curChar) & 1); - for (int i = 1; i < 1 + countFullBytes; i++) { - ret[offset + i] - = (byte) ((charToBCD(number.charAt(curChar++))) - | (charToBCD(number.charAt(curChar++))) << 4); - } + // 1-fill any trailing odd nibble/quartet. + if ((digitCount & 0x01) == 1) result[extraBytes + (digitCount >> 1)] |= 0xF0; - // The left-over octet for odd-length phone numbers should be - // filled with 0xf. - if (countFullBytes + offset < ret.length - 1) { - ret[ret.length - 1] - = (byte) (charToBCD(number.charAt(curChar)) - | (0xf << 4)); - } - return ret; + int offset = 0; + if (includeLength) result[offset++] = (byte)(resultLen - 1); + result[offset] = (byte)(hasPlus ? TOA_International : TOA_Unknown); + + return result; } /** all of 'a' up to len must match non-US trunk prefix ('0') */ diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index df6860b..e113680 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -4,6 +4,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.telephony.ServiceState; +import android.telephony.SignalStrength; import android.telephony.CellLocation; import android.util.Log; @@ -41,16 +42,22 @@ public class PhoneStateListener { /** * Listen for changes to the network signal strength (cellular). + * {@more} + * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE + * READ_PHONE_STATE} * <p> - * Example: The status bar uses this to control the signal-strength - * icon. * * @see #onSignalStrengthChanged + * + * TODO: @deprecated to be deprecated by LISTEN_SIGNAL_STRENGTHS, @see #onSignalStrengthsChanged */ public static final int LISTEN_SIGNAL_STRENGTH = 0x00000002; /** * Listen for changes to the message-waiting indicator. + * {@more} + * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE + * READ_PHONE_STATE} * <p> * Example: The status bar uses this to determine when to display the * voicemail icon. @@ -61,7 +68,9 @@ public class PhoneStateListener { /** * Listen for changes to the call-forwarding indicator. - * + * {@more} + * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE + * READ_PHONE_STATE} * @see #onCallForwardingIndicatorChanged */ public static final int LISTEN_CALL_FORWARDING_INDICATOR = 0x00000008; @@ -84,7 +93,9 @@ public class PhoneStateListener { /** * Listen for changes to the device call state. - * + * {@more} + * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE + * READ_PHONE_STATE} * @see #onCallStateChanged */ public static final int LISTEN_CALL_STATE = 0x00000020; @@ -99,7 +110,9 @@ public class PhoneStateListener { /** * Listen for changes to the direction of data traffic on the data * connection (cellular). - * + * {@more} + * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE + * READ_PHONE_STATE} * Example: The status bar uses this to display the appropriate * data-traffic icon. * @@ -107,6 +120,18 @@ public class PhoneStateListener { */ public static final int LISTEN_DATA_ACTIVITY = 0x00000080; + /** + * Listen for changes to the network signal strengths (cellular). + * <p> + * Example: The status bar uses this to control the signal-strength + * icon. + * + * @see #onSignalStrengthsChanged + * + * @hide + */ + public static final int LISTEN_SIGNAL_STRENGTHS = 0x00000100; + public PhoneStateListener() { } @@ -129,6 +154,7 @@ public class PhoneStateListener { * @see ServiceState#STATE_IN_SERVICE * @see ServiceState#STATE_OUT_OF_SERVICE * @see ServiceState#STATE_POWER_OFF + * @deprecated, @see #onSignalStrengthsChanged */ public void onSignalStrengthChanged(int asu) { // default implementation empty @@ -185,12 +211,27 @@ public class PhoneStateListener { * @see TelephonyManager#DATA_ACTIVITY_IN * @see TelephonyManager#DATA_ACTIVITY_OUT * @see TelephonyManager#DATA_ACTIVITY_INOUT + * @see TelephonyManager#DATA_ACTIVITY_DORMANT */ public void onDataActivity(int direction) { // default implementation empty } /** + * Callback invoked when network signal strengths changes. + * + * @see ServiceState#STATE_EMERGENCY_ONLY + * @see ServiceState#STATE_IN_SERVICE + * @see ServiceState#STATE_OUT_OF_SERVICE + * @see ServiceState#STATE_POWER_OFF + * + * @hide + */ + public void onSignalStrengthsChanged(SignalStrength signalStrength) { + // default implementation empty + } + + /** * The callback methods need to be called on the handler thread where * this object was created. If the binder did that for us it'd be nice. */ @@ -229,6 +270,9 @@ public class PhoneStateListener { public void onDataActivity(int direction) { Message.obtain(mHandler, LISTEN_DATA_ACTIVITY, direction, 0, null).sendToTarget(); } + public void onSignalStrengthsChanged(SignalStrength signalStrength) { + Message.obtain(mHandler, LISTEN_SIGNAL_STRENGTHS, 0, 0, signalStrength).sendToTarget(); + } }; Handler mHandler = new Handler() { @@ -259,6 +303,9 @@ public class PhoneStateListener { case LISTEN_DATA_ACTIVITY: PhoneStateListener.this.onDataActivity(msg.arg1); break; + case LISTEN_SIGNAL_STRENGTHS: + PhoneStateListener.this.onSignalStrengthsChanged((SignalStrength)msg.obj); + break; } } }; diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 4de0954..50c4d41 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -99,12 +99,9 @@ public class ServiceState implements Parcelable { public static final int REGISTRATION_STATE_UNKNOWN = 4; /** @hide */ public static final int REGISTRATION_STATE_ROAMING = 5; - /** @hide */ - public static final int REGISTRATION_STATE_ROAMING_AFFILIATE = 6; private int mState = STATE_OUT_OF_SERVICE; private boolean mRoaming; - private int mExtendedCdmaRoaming; private String mOperatorAlphaLong; private String mOperatorAlphaShort; private String mOperatorNumeric; @@ -115,6 +112,8 @@ public class ServiceState implements Parcelable { private boolean mCssIndicator; private int mNetworkId; private int mSystemId; + private int mCdmaRoamingIndicator; + private int mCdmaDefaultRoamingIndicator; /** * Create a new ServiceState from a intent notifier Bundle @@ -159,7 +158,8 @@ public class ServiceState implements Parcelable { mCssIndicator = s.mCssIndicator; mNetworkId = s.mNetworkId; mSystemId = s.mSystemId; - mExtendedCdmaRoaming = s.mExtendedCdmaRoaming; + mCdmaRoamingIndicator = s.mCdmaRoamingIndicator; + mCdmaDefaultRoamingIndicator = s.mCdmaDefaultRoamingIndicator; } /** @@ -176,7 +176,8 @@ public class ServiceState implements Parcelable { mCssIndicator = (in.readInt() != 0); mNetworkId = in.readInt(); mSystemId = in.readInt(); - mExtendedCdmaRoaming = in.readInt(); + mCdmaRoamingIndicator = in.readInt(); + mCdmaDefaultRoamingIndicator = in.readInt(); } public void writeToParcel(Parcel out, int flags) { @@ -190,7 +191,8 @@ public class ServiceState implements Parcelable { out.writeInt(mCssIndicator ? 1 : 0); out.writeInt(mNetworkId); out.writeInt(mSystemId); - out.writeInt(mExtendedCdmaRoaming); + out.writeInt(mCdmaRoamingIndicator); + out.writeInt(mCdmaDefaultRoamingIndicator); } public int describeContents() { @@ -231,15 +233,25 @@ public class ServiceState implements Parcelable { return mRoaming; } - /** @hide */ - public int getExtendedCdmaRoaming(){ - return this.mExtendedCdmaRoaming; + /** + * @hide + */ + public int getCdmaRoamingIndicator(){ + return this.mCdmaRoamingIndicator; + } + + /** + * @hide + */ + public int getCdmaDefaultRoamingIndicator(){ + return this.mCdmaDefaultRoamingIndicator; } /** * Get current registered operator name in long alphanumeric format * * In GSM/UMTS, long format can be upto 16 characters long + * In CDMA, returns the ERI text, if set, otherwise the ONS * * @return long name of operator, null if unregistered or unknown */ @@ -289,7 +301,8 @@ public class ServiceState implements Parcelable { + ((null == mOperatorAlphaLong) ? 0 : mOperatorAlphaLong.hashCode()) + ((null == mOperatorAlphaShort) ? 0 : mOperatorAlphaShort.hashCode()) + ((null == mOperatorNumeric) ? 0 : mOperatorNumeric.hashCode()) - + (mExtendedCdmaRoaming)); + + mCdmaRoamingIndicator + + mCdmaDefaultRoamingIndicator); } @Override @@ -316,7 +329,9 @@ public class ServiceState implements Parcelable { && equalsHandlesNulls(mCssIndicator, s.mCssIndicator) && equalsHandlesNulls(mNetworkId, s.mNetworkId) && equalsHandlesNulls(mSystemId, s.mSystemId) - && equalsHandlesNulls(mExtendedCdmaRoaming, s.mExtendedCdmaRoaming)); + && equalsHandlesNulls(mCdmaRoamingIndicator, s.mCdmaRoamingIndicator) + && equalsHandlesNulls(mCdmaDefaultRoamingIndicator, + s.mCdmaDefaultRoamingIndicator)); } @Override @@ -363,9 +378,10 @@ public class ServiceState implements Parcelable { + " " + (mIsManualNetworkSelection ? "(manual)" : "") + " " + radioTechnology + " " + (mCssIndicator ? "CSS supported" : "CSS not supported") - + "NetworkId: " + mNetworkId - + "SystemId: " + mSystemId - + "ExtendedCdmaRoaming: " + mExtendedCdmaRoaming); + + " " + mNetworkId + + " " + mSystemId + + "RoamInd: " + mCdmaRoamingIndicator + + "DefRoamInd: " + mCdmaDefaultRoamingIndicator); } public void setStateOutOfService() { @@ -379,7 +395,8 @@ public class ServiceState implements Parcelable { mCssIndicator = false; mNetworkId = -1; mSystemId = -1; - mExtendedCdmaRoaming = -1; + mCdmaRoamingIndicator = -1; + mCdmaDefaultRoamingIndicator = -1; } public void setStateOff() { @@ -393,7 +410,8 @@ public class ServiceState implements Parcelable { mCssIndicator = false; mNetworkId = -1; mSystemId = -1; - mExtendedCdmaRoaming = -1; + mCdmaRoamingIndicator = -1; + mCdmaDefaultRoamingIndicator = -1; } public void setState(int state) { @@ -404,9 +422,18 @@ public class ServiceState implements Parcelable { mRoaming = roaming; } - /** @hide */ - public void setExtendedCdmaRoaming (int roaming) { - this.mExtendedCdmaRoaming = roaming; + /** + * @hide + */ + public void setCdmaRoamingIndicator(int roaming) { + this.mCdmaRoamingIndicator = roaming; + } + + /** + * @hide + */ + public void setCdmaDefaultRoamingIndicator (int roaming) { + this.mCdmaDefaultRoamingIndicator = roaming; } public void setOperatorName(String longName, String shortName, String numeric) { @@ -415,6 +442,16 @@ public class ServiceState implements Parcelable { mOperatorNumeric = numeric; } + /** + * In CDMA mOperatorAlphaLong can be set from the ERI + * text, this is done from the CDMAPhone and not from the CdmaServiceStateTracker + * + * @hide + */ + public void setCdmaEriText(String longName) { + mOperatorAlphaLong = longName; + } + public void setIsManualSelection(boolean isManual) { mIsManualNetworkSelection = isManual; } @@ -447,7 +484,8 @@ public class ServiceState implements Parcelable { mCssIndicator = m.getBoolean("cssIndicator"); mNetworkId = m.getInt("networkId"); mSystemId = m.getInt("systemId"); - mExtendedCdmaRoaming = m.getInt("extendedCdmaRoaming"); + mCdmaRoamingIndicator = m.getInt("cdmaRoamingIndicator"); + mCdmaDefaultRoamingIndicator = m.getInt("cdmaDefaultRoamingIndicator"); } /** @@ -467,7 +505,8 @@ public class ServiceState implements Parcelable { m.putBoolean("cssIndicator", mCssIndicator); m.putInt("networkId", mNetworkId); m.putInt("systemId", mSystemId); - m.putInt("extendedCdmaRoaming", mExtendedCdmaRoaming); + m.putInt("cdmaRoamingIndicator", mCdmaRoamingIndicator); + m.putInt("cdmaDefaultRoamingIndicator", mCdmaDefaultRoamingIndicator); } //***** CDMA diff --git a/telephony/java/android/telephony/SignalStrength.aidl b/telephony/java/android/telephony/SignalStrength.aidl new file mode 100644 index 0000000..c25411e --- /dev/null +++ b/telephony/java/android/telephony/SignalStrength.aidl @@ -0,0 +1,22 @@ +/* //device/java/android/android/content/Intent.aidl +** +** Copyright (C) 2009 Qualcomm Innovation Center, Inc. All Rights Reserved. +** 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 android.telephony; + +parcelable SignalStrength; + diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java new file mode 100644 index 0000000..8ed0065 --- /dev/null +++ b/telephony/java/android/telephony/SignalStrength.java @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2009 Qualcomm Innovation Center, Inc. All Rights Reserved. + * 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 android.telephony; + +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; + +/** + * Contains phone signal strength related information. + * + * @hide + */ +public class SignalStrength implements Parcelable { + + static final String LOG_TAG = "PHONE"; + + private int mGsmSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5 + private int mGsmBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5 + private int mCdmaDbm; // This value is the RSSI value + private int mCdmaEcio; // This value is the Ec/Io + private int mEvdoDbm; // This value is the EVDO RSSI value + private int mEvdoEcio; // This value is the EVDO Ec/Io + private int mEvdoSnr; // Valid values are 0-8. 8 is the highest signal to noise ratio + + private boolean isGsm; // This value is set by the ServiceStateTracker onSignalStrengthResult + + /** + * Create a new SignalStrength from a intent notifier Bundle + * + * This method is used by PhoneStateIntentReceiver and maybe by + * external applications. + * + * @param m Bundle from intent notifier + * @return newly created SignalStrength + * + */ + public static SignalStrength newFromBundle(Bundle m) { + SignalStrength ret; + ret = new SignalStrength(); + ret.setFromNotifierBundle(m); + return ret; + } + + /** + * Empty constructor + * + */ + public SignalStrength() { + mGsmSignalStrength = 99; + mGsmBitErrorRate = -1; + mCdmaDbm = -1; + mCdmaEcio = -1; + mEvdoDbm = -1; + mEvdoEcio = -1; + mEvdoSnr = -1; + isGsm = true; + } + + /** + * Constructor + * + */ + public SignalStrength(int gsmSignalStrength, int gsmBitErrorRate, + int cdmaDbm, int cdmaEcio, + int evdoDbm, int evdoEcio, int evdoSnr, boolean gsm) { + mGsmSignalStrength = gsmSignalStrength; + mGsmBitErrorRate = gsmBitErrorRate; + mCdmaDbm = cdmaDbm; + mCdmaEcio = cdmaEcio; + mEvdoDbm = evdoDbm; + mEvdoEcio = evdoEcio; + mEvdoSnr = evdoSnr; + isGsm = gsm; + } + + /** + * Copy constructors + * + * @param s Source SignalStrength + */ + public SignalStrength(SignalStrength s) { + copyFrom(s); + } + + /** + * @hide + */ + protected void copyFrom(SignalStrength s) { + mGsmSignalStrength = s.mGsmSignalStrength; + mGsmBitErrorRate = s.mGsmBitErrorRate; + mCdmaDbm = s.mCdmaDbm; + mCdmaEcio = s.mCdmaEcio; + mEvdoDbm = s.mEvdoDbm; + mEvdoEcio = s.mEvdoEcio; + mEvdoSnr = s.mEvdoSnr; + isGsm = s.isGsm; + } + + /** + * Construct a SignalStrength object from the given parcel. + */ + public SignalStrength(Parcel in) { + mGsmSignalStrength = in.readInt(); + mGsmBitErrorRate = in.readInt(); + mCdmaDbm = in.readInt(); + mCdmaEcio = in.readInt(); + mEvdoDbm = in.readInt(); + mEvdoEcio = in.readInt(); + mEvdoSnr = in.readInt(); + isGsm = (in.readInt() != 0); + } + + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mGsmSignalStrength); + out.writeInt(mGsmBitErrorRate); + out.writeInt(mCdmaDbm); + out.writeInt(mCdmaEcio); + out.writeInt(mEvdoDbm); + out.writeInt(mEvdoEcio); + out.writeInt(mEvdoSnr); + out.writeInt(isGsm ? 1 : 0); + } + + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<SignalStrength> CREATOR = new Parcelable.Creator() { + public SignalStrength createFromParcel(Parcel in) { + return new SignalStrength(in); + } + + public SignalStrength[] newArray(int size) { + return new SignalStrength[size]; + } + }; + + /** + * Get the GSM Signal Strength, valid values are (0-31, 99) as defined in TS 27.007 8.5 + */ + public int getGsmSignalStrength() { + return this.mGsmSignalStrength; + } + + /** + * Get the GSM bit error rate (0-7, 99) as defined in TS 27.007 8.5 + */ + public int getGsmBitErrorRate() { + return this.mGsmBitErrorRate; + } + + /** + * Get the CDMA RSSI value in dBm + */ + public int getCdmaDbm() { + return this.mCdmaDbm; + } + + /** + * Get the CDMA Ec/Io value in dB*10 + */ + public int getCdmaEcio() { + return this.mCdmaEcio; + } + + /** + * Get the EVDO RSSI value in dBm + */ + public int getEvdoDbm() { + return this.mEvdoDbm; + } + + /** + * Get the EVDO Ec/Io value in dB*10 + */ + public int getEvdoEcio() { + return this.mEvdoEcio; + } + + /** + * Get the signal to noise ratio. Valid values are 0-8. 8 is the highest. + */ + public int getEvdoSnr() { + return this.mEvdoSnr; + } + + /** + * @hide + */ + public boolean isGsm() { + return this.isGsm; + } + + /** + * @hide + */ + @Override + public int hashCode() { + return ((mGsmSignalStrength * 0x1234) + + mGsmBitErrorRate + + mCdmaDbm + mCdmaEcio + + mEvdoDbm + mEvdoEcio + mEvdoSnr + + (isGsm ? 1 : 0)); + } + + /** + * @hide + */ + @Override + public boolean equals (Object o) { + SignalStrength s; + + try { + s = (SignalStrength) o; + } catch (ClassCastException ex) { + return false; + } + + if (o == null) { + return false; + } + + return (mGsmSignalStrength == s.mGsmSignalStrength + && mGsmBitErrorRate == s.mGsmBitErrorRate + && mCdmaDbm == s.mCdmaDbm + && mCdmaEcio == s.mCdmaEcio + && mEvdoDbm == s.mEvdoDbm + && mEvdoEcio == s.mEvdoEcio + && mEvdoSnr == s.mEvdoSnr + && isGsm == s.isGsm); + } + + /** + * @hide + */ + @Override + public String toString() { + return ("SignalStrength:" + + " " + mGsmSignalStrength + + " " + mGsmBitErrorRate + + " " + mCdmaDbm + + " " + mCdmaEcio + + " " + mEvdoDbm + + " " + mEvdoEcio + + " " + mEvdoSnr + + " " + (isGsm ? "gsm" : "cdma")); + } + + /** + * Test whether two objects hold the same data values or both are null + * + * @param a first obj + * @param b second obj + * @return true if two objects equal or both are null + * @hide + */ + private static boolean equalsHandlesNulls (Object a, Object b) { + return (a == null) ? (b == null) : a.equals (b); + } + + /** + * Set SignalStrength based on intent notifier map + * + * @param m intent notifier map + * @hide + */ + private void setFromNotifierBundle(Bundle m) { + mGsmSignalStrength = m.getInt("GsmSignalStrength"); + mGsmBitErrorRate = m.getInt("GsmBitErrorRate"); + mCdmaDbm = m.getInt("CdmaDbm"); + mCdmaEcio = m.getInt("CdmaEcio"); + mEvdoDbm = m.getInt("EvdoDbm"); + mEvdoEcio = m.getInt("EvdoEcio"); + mEvdoSnr = m.getInt("EvdoSnr"); + isGsm = m.getBoolean("isGsm"); + } + + /** + * Set intent notifier Bundle based on SignalStrength + * + * @param m intent notifier Bundle + * @hide + */ + public void fillInNotifierBundle(Bundle m) { + m.putInt("GsmSignalStrength", mGsmSignalStrength); + m.putInt("GsmBitErrorRate", mGsmBitErrorRate); + m.putInt("CdmaDbm", mCdmaDbm); + m.putInt("CdmaEcio", mCdmaEcio); + m.putInt("EvdoDbm", mEvdoDbm); + m.putInt("EvdoEcio", mEvdoEcio); + m.putInt("EvdoSnr", mEvdoSnr); + m.putBoolean("isGsm", Boolean.valueOf(isGsm)); + } +} diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 9395d66..890f930 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -22,7 +22,6 @@ import android.os.ServiceManager; import android.text.TextUtils; import com.android.internal.telephony.EncodeException; -import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.ISms; import com.android.internal.telephony.IccConstants; import com.android.internal.telephony.SmsRawData; @@ -31,14 +30,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static android.telephony.SmsMessage.ENCODING_7BIT; -import static android.telephony.SmsMessage.ENCODING_8BIT; -import static android.telephony.SmsMessage.ENCODING_16BIT; -import static android.telephony.SmsMessage.ENCODING_UNKNOWN; -import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES; -import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER; -import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS; -import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER; +/* + * TODO(code review): Curious question... Why are a lot of these + * methods not declared as static, since they do not seem to require + * any local object state? Assumedly this cannot be changed without + * interfering with the API... + */ /** * Manages SMS operations such as sending data, text, and pdu SMS messages. @@ -88,7 +85,7 @@ public final class SmsManager { } /** - * Divide a text message into several messages, none bigger than + * Divide a message text into several fragments, none bigger than * the maximum SMS message size. * * @param text the original message. Must not be null. @@ -96,40 +93,7 @@ public final class SmsManager { * comprise the original message */ public ArrayList<String> divideMessage(String text) { - int size = text.length(); - int[] params = SmsMessage.calculateLength(text, false); - /* SmsMessage.calculateLength returns an int[4] with: - * int[0] being the number of SMS's required, - * int[1] the number of code units used, - * int[2] is the number of code units remaining until the next message. - * int[3] is the encoding type that should be used for the message. - */ - int messageCount = params[0]; - int encodingType = params[3]; - ArrayList<String> result = new ArrayList<String>(messageCount); - - int start = 0; - int limit; - - if (messageCount > 1) { - limit = (encodingType == ENCODING_7BIT)? - MAX_USER_DATA_SEPTETS_WITH_HEADER: MAX_USER_DATA_BYTES_WITH_HEADER; - } else { - limit = (encodingType == ENCODING_7BIT)? - MAX_USER_DATA_SEPTETS: MAX_USER_DATA_BYTES; - } - - try { - while (start < size) { - int end = GsmAlphabet.findLimitIndex(text, start, limit, encodingType); - result.add(text.substring(start, end)); - start = end; - } - } - catch (EncodeException e) { - // ignore it. - } - return result; + return SmsMessage.fragmentText(text); } /** diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java index 3b7f4b5..775b034 100644 --- a/telephony/java/android/telephony/SmsMessage.java +++ b/telephony/java/android/telephony/SmsMessage.java @@ -17,11 +17,17 @@ package android.telephony; import android.os.Parcel; +import android.util.Log; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; import com.android.internal.telephony.SmsMessageBase.SubmitPduBase; +import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails; + +import java.lang.Math; +import java.util.ArrayList; import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; @@ -43,19 +49,41 @@ public class SmsMessage { UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3; } - /** Unknown encoding scheme (see TS 23.038) */ + /** + * TODO(cleanup): given that we now have more than one possible + * 7bit encoding, this result starts to look rather vague and + * maybe confusing... If this is just an indication of code unit + * size, maybe that is no problem. Otherwise, should we try to + * create an aggregate collection of GSM and CDMA encodings? CDMA + * contains a superset of the encodings we use (it does not + * support 8-bit GSM, but we also do not use that encoding + * currently)... We could get rid of these and directly reference + * the CDMA encoding definitions... + */ + + /** User data text encoding code unit size */ public static final int ENCODING_UNKNOWN = 0; - /** 7-bit encoding scheme (see TS 23.038) */ public static final int ENCODING_7BIT = 1; - /** 8-bit encoding scheme (see TS 23.038) */ public static final int ENCODING_8BIT = 2; - /** 16-bit encoding scheme (see TS 23.038) */ public static final int ENCODING_16BIT = 3; /** The maximum number of payload bytes per message */ public static final int MAX_USER_DATA_BYTES = 140; /** + * TODO(cleanup): It would be more flexible and less fragile to + * rewrite this (meaning get rid of the following constant) such + * that an actual UDH is taken into consideration (meaning its + * length is measured), allowing for messages that actually + * contain other UDH fields... Hence it is actually a shame to + * extend the API with this constant. If necessary, maybe define + * the size of such a header and let the math for calculating + * max_octets/septets be done elsewhere. And, while I am griping, + * if we use the word septet, we should use the word octet in + * corresponding places, not byte... + */ + + /** * The maximum number of payload bytes per message if a user data header * is present. This assumes the header only contains the * CONCATENATED_8_BIT_REFERENCE element. @@ -221,54 +249,95 @@ 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 + * passed as an argument to the actual final encoding function. + * This would better ensure that the logic behind size calculation + * actually matched the encoding. + */ + /** * Calculates the number of SMS's required to encode the message body and - * the number of characters remaining until the next message, given the - * current encoding. + * the number of characters remaining until the next message. * - * @param messageBody the message to encode - * @param use7bitOnly if true, characters that are not part of the GSM - * alphabet are counted as a single space char. If false, a - * messageBody containing non-GSM alphabet characters is calculated - * for 16-bit encoding. - * @return an int[4] with int[0] being the number of SMS's required, int[1] - * the number of code units used, and int[2] is the number of code - * units remaining until the next message. int[3] is the encoding - * type that should be used for the message. - */ - public static int[] calculateLength(CharSequence messageBody, boolean use7bitOnly) { + * @param msgBody the message to encode + * @param use7bitOnly if true, characters that are not part of the + * radio-specific 7-bit encoding are counted as single + * space chars. If false, and if the messageBody contains + * non-7-bit encodable characters, length is calculated + * using a 16-bit encoding. + * @return an int[4] with int[0] being the number of SMS's + * required, int[1] the number of code units used, and + * int[2] is the number of code units remaining until the + * next message. int[3] is an indicator of the encoding + * code unit size (see the ENCODING_* definitions in this + * class). + */ + public static int[] calculateLength(CharSequence msgBody, boolean use7bitOnly) { + int activePhone = TelephonyManager.getDefault().getPhoneType(); + TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ? + com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly) : + com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly); int ret[] = new int[4]; + ret[0] = ted.msgCount; + ret[1] = ted.codeUnitCount; + ret[2] = ted.codeUnitsRemaining; + ret[3] = ted.codeUnitSize; + return ret; + } + + /** + * Divide a message text into several fragments, none bigger than + * the maximum SMS message text size. + * + * @param text text, must not be null. + * @return an <code>ArrayList</code> of strings that, in order, + * comprise the original msg text + */ + public static ArrayList<String> fragmentText(String text) { + int activePhone = TelephonyManager.getDefault().getPhoneType(); + TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ? + com.android.internal.telephony.gsm.SmsMessage.calculateLength(text, false) : + com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false); + + // TODO(cleanup): The code here could be rolled into the logic + // below cleanly if these MAX_* constants were defined more + // flexibly... + + int limit; + if (ted.msgCount > 1) { + limit = (ted.codeUnitSize == ENCODING_7BIT) ? + MAX_USER_DATA_SEPTETS_WITH_HEADER : MAX_USER_DATA_BYTES_WITH_HEADER; + } else { + limit = (ted.codeUnitSize == ENCODING_7BIT) ? + MAX_USER_DATA_SEPTETS : MAX_USER_DATA_BYTES; + } - try { - // Try GSM alphabet - int septets = GsmAlphabet.countGsmSeptets(messageBody, !use7bitOnly); - ret[1] = septets; - if (septets > MAX_USER_DATA_SEPTETS) { - ret[0] = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1; - ret[2] = MAX_USER_DATA_SEPTETS_WITH_HEADER - - (septets % MAX_USER_DATA_SEPTETS_WITH_HEADER); - } else { - ret[0] = 1; - ret[2] = MAX_USER_DATA_SEPTETS - septets; + int pos = 0; // Index in code units. + int textLen = text.length(); + ArrayList<String> result = new ArrayList<String>(ted.msgCount); + while (pos < textLen) { + int nextPos = 0; // Counts code units. + if (ted.codeUnitSize == ENCODING_7BIT) { + if (PHONE_TYPE_CDMA == activePhone) { + nextPos = pos + Math.min(limit, textLen - pos); + } else { + nextPos = GsmAlphabet.findGsmSeptetLimitIndex(text, pos, limit); + } + } else { // Assume unicode. + nextPos = pos + Math.min(limit / 2, textLen - pos); } - ret[3] = ENCODING_7BIT; - } catch (EncodeException ex) { - // fall back to UCS-2 - int octets = messageBody.length() * 2; - ret[1] = messageBody.length(); - if (octets > MAX_USER_DATA_BYTES) { - // 6 is the size of the user data header - ret[0] = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1; - ret[2] = (MAX_USER_DATA_BYTES_WITH_HEADER - - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2; - } else { - ret[0] = 1; - ret[2] = (MAX_USER_DATA_BYTES - octets)/2; + if ((nextPos <= pos) || (nextPos > textLen)) { + Log.e(LOG_TAG, "fragmentText failed (" + pos + " >= " + nextPos + " or " + + nextPos + " >= " + textLen + ")"); + break; } - ret[3] = ENCODING_16BIT; + result.add(text.substring(pos, nextPos)); + pos = nextPos; } - - return ret; + return result; } /** @@ -307,7 +376,8 @@ public class SmsMessage { if (PHONE_TYPE_CDMA == activePhone) { spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, - destinationAddress, message, statusReportRequested, header); + destinationAddress, message, statusReportRequested, + SmsHeader.fromByteArray(header)); } else { spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, header); @@ -331,7 +401,7 @@ public class SmsMessage { if (PHONE_TYPE_CDMA == activePhone) { spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, - destinationAddress, message, statusReportRequested); + destinationAddress, message, statusReportRequested, null); } else { spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested); @@ -515,9 +585,14 @@ public class SmsMessage { return mWrappedSmsMessage.getUserData(); } - /* Not part of the SDK interface and only needed by specific classes: - protected SmsHeader getUserDataHeader() - */ + /** + * Return the user data header (UDH). + * + * @hide + */ + public SmsHeader getUserDataHeader() { + return mWrappedSmsMessage.getUserDataHeader(); + } /** * Returns the raw PDU for the message. diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 559542a..c9dcd8b 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -16,26 +16,24 @@ package android.telephony; -import com.android.internal.telephony.*; - -import java.util.ArrayList; -import java.util.List; - -import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; -import android.telephony.CellLocation; import com.android.internal.telephony.IPhoneSubInfo; import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.ITelephonyRegistry; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.TelephonyProperties; +import java.util.List; + /** * Provides access to information about the telephony services on * the device. Applications can use the methods in this class to @@ -192,8 +190,9 @@ public class TelephonyManager { /** * Returns the current location of the device. * - * <p>Requires Permission: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION - * ACCESS_COARSE_LOCATION}. + * <p>Requires Permission: + * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or + * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_FINE_LOCATION}. */ public CellLocation getCellLocation() { try { @@ -238,10 +237,10 @@ public class TelephonyManager { /** * Returns the neighboring cell information of the device. - * + * * @return List of NeighboringCellInfo or null if info unavailable. - * - * <p>Requires Permission: + * + * <p>Requires Permission: * (@link android.Manifest.permission#ACCESS_COARSE_UPDATES} */ public List<NeighboringCellInfo> getNeighboringCellInfo() { @@ -250,24 +249,25 @@ public class TelephonyManager { } catch (RemoteException ex) { } return null; - + } - + /** * No phone module + * */ public static final int PHONE_TYPE_NONE = 0; /** * GSM phone */ - public static final int PHONE_TYPE_GSM = 1; + public static final int PHONE_TYPE_GSM = RILConstants.GSM_PHONE; /** * CDMA phone * @hide */ - public static final int PHONE_TYPE_CDMA = 2; + public static final int PHONE_TYPE_CDMA = RILConstants.CDMA_PHONE; /** * Returns a constant indicating the device phone type. @@ -278,16 +278,41 @@ public class TelephonyManager { */ public int getPhoneType() { try{ - if(getITelephony().getActivePhoneType() == RILConstants.CDMA_PHONE) { - return PHONE_TYPE_CDMA; + ITelephony telephony = getITelephony(); + if (telephony != null) { + if(telephony.getActivePhoneType() == RILConstants.CDMA_PHONE) { + return PHONE_TYPE_CDMA; + } else { + return PHONE_TYPE_GSM; + } } else { - return PHONE_TYPE_GSM; + // This can happen when the ITelephony interface is not up yet. + return getPhoneTypeFromProperty(); } - }catch(RemoteException ex){ - return PHONE_TYPE_NONE; + } catch(RemoteException ex){ + // This shouldn't happen in the normal case, as a backup we + // read from the system property. + return getPhoneTypeFromProperty(); } } + + private int getPhoneTypeFromProperty() { + int type = + SystemProperties.getInt(TelephonyProperties.CURRENT_ACTIVE_PHONE, + getPhoneTypeFromNetworkType()); + return type; + } + + private int getPhoneTypeFromNetworkType() { + // When the system property CURRENT_ACTIVE_PHONE, has not been set, + // use the system property for default network type. + // This is a fail safe, and can only happen at first boot. + int mode = SystemProperties.getInt("ro.telephony.default_network", -1); + if (mode == -1) + return PHONE_TYPE_NONE; + return PhoneFactory.getPhoneType(mode); + } // // // Current Network @@ -587,6 +612,21 @@ public class TelephonyManager { } /** + * Returns the voice mail count. + * <p> + * Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * @hide + */ + public int getVoiceMessageCount() { + try { + return getITelephony().getVoiceMessageCount(); + } catch (RemoteException ex) { + } + return 0; + } + + /** * Retrieves the alphabetic identifier associated with the voice * mail number. * <p> @@ -627,7 +667,10 @@ public class TelephonyManager { } catch (RemoteException ex) { // the phone process is restarting. return CALL_STATE_IDLE; - } + } catch (NullPointerException ex) { + // the phone process is restarting. + return CALL_STATE_IDLE; + } } /** Data connection activity: No traffic. */ @@ -639,6 +682,11 @@ public class TelephonyManager { /** Data connection activity: Currently both sending and receiving * IP PPP traffic. */ public static final int DATA_ACTIVITY_INOUT = DATA_ACTIVITY_IN | DATA_ACTIVITY_OUT; + /** + * Data connection is active, but physical link is down + * @hide + */ + public static final int DATA_ACTIVITY_DORMANT = 0x00000004; /** * Returns a constant indicating the type of activity on a data connection @@ -648,6 +696,7 @@ public class TelephonyManager { * @see #DATA_ACTIVITY_IN * @see #DATA_ACTIVITY_OUT * @see #DATA_ACTIVITY_INOUT + * @see #DATA_ACTIVITY_DORMANT */ public int getDataActivity() { try { @@ -655,7 +704,10 @@ public class TelephonyManager { } catch (RemoteException ex) { // the phone process is restarting. return DATA_ACTIVITY_NONE; - } + } catch (NullPointerException ex) { + // the phone process is restarting. + return DATA_ACTIVITY_NONE; + } } /** Data connection state: Disconnected. IP traffic not available. */ @@ -729,4 +781,48 @@ public class TelephonyManager { // system process dead } } + + /** + * Returns the CDMA ERI icon index to display + * + * @hide + */ + public int getCdmaEriIconIndex() { + try { + return getITelephony().getCdmaEriIconIndex(); + } catch (RemoteException ex) { + // the phone process is restarting. + return -1; + } + } + + /** + * Returns the CDMA ERI icon mode, + * 0 - ON + * 1 - FLASHING + * + * @hide + */ + public int getCdmaEriIconMode() { + try { + return getITelephony().getCdmaEriIconMode(); + } catch (RemoteException ex) { + // the phone process is restarting. + return -1; + } + } + + /** + * Returns the CDMA ERI text, + * + * @hide + */ + public String getCdmaEriText() { + try { + return getITelephony().getCdmaEriText(); + } catch (RemoteException ex) { + // the phone process is restarting. + return null; + } + } } diff --git a/telephony/java/android/telephony/gsm/SmsMessage.java b/telephony/java/android/telephony/gsm/SmsMessage.java index 0928ddf..84dfca0 100644 --- a/telephony/java/android/telephony/gsm/SmsMessage.java +++ b/telephony/java/android/telephony/gsm/SmsMessage.java @@ -21,6 +21,7 @@ import android.telephony.TelephonyManager; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; import com.android.internal.telephony.SmsMessageBase.SubmitPduBase; @@ -369,7 +370,8 @@ public class SmsMessage { if (PHONE_TYPE_CDMA == activePhone) { spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, - destinationAddress, message, statusReportRequested, header); + destinationAddress, message, statusReportRequested, + SmsHeader.fromByteArray(header)); } else { spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, header); @@ -395,7 +397,7 @@ public class SmsMessage { if (PHONE_TYPE_CDMA == activePhone) { spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, - destinationAddress, message, statusReportRequested); + destinationAddress, message, statusReportRequested, null); } else { spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested); @@ -744,4 +746,3 @@ public class SmsMessage { } } } - diff --git a/telephony/java/android/telephony/package.html b/telephony/java/android/telephony/package.html index aee4a6f..cb2fb49 100644 --- a/telephony/java/android/telephony/package.html +++ b/telephony/java/android/telephony/package.html @@ -1,6 +1,6 @@ <HTML> <BODY> -Provides APIs for monitoring the basic phone information, such as +Provides APIs for monitoring the basic phone information, such as the network type and connection state, plus utilities for manipulating phone number strings. </BODY> diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java index fbc596c..3edca66 100644 --- a/telephony/java/com/android/internal/telephony/BaseCommands.java +++ b/telephony/java/com/android/internal/telephony/BaseCommands.java @@ -55,33 +55,39 @@ public abstract class BaseCommands implements CommandsInterface { protected RegistrantList mVoicePrivacyOnRegistrants = new RegistrantList(); protected RegistrantList mVoicePrivacyOffRegistrants = new RegistrantList(); protected Registrant mUnsolOemHookRawRegistrant; + protected RegistrantList mOtaProvisionRegistrants = new RegistrantList(); + protected RegistrantList mCallWaitingInfoRegistrants = new RegistrantList(); + protected RegistrantList mDisplayInfoRegistrants = new RegistrantList(); + protected RegistrantList mSignalInfoRegistrants = new RegistrantList(); + protected RegistrantList mNumberInfoRegistrants = new RegistrantList(); + protected RegistrantList mRedirNumInfoRegistrants = new RegistrantList(); + protected RegistrantList mLineControlInfoRegistrants = new RegistrantList(); + protected RegistrantList mT53ClirInfoRegistrants = new RegistrantList(); + protected RegistrantList mT53AudCntrlInfoRegistrants = new RegistrantList(); + protected Registrant mSMSRegistrant; protected Registrant mNITZTimeRegistrant; protected Registrant mSignalStrengthRegistrant; protected Registrant mUSSDRegistrant; protected Registrant mSmsOnSimRegistrant; - /** Registrant for handling SMS Status Reports */ protected Registrant mSmsStatusRegistrant; - /** Registrant for handling Supplementary Service Notifications */ protected Registrant mSsnRegistrant; protected Registrant mStkSessionEndRegistrant; protected Registrant mStkProCmdRegistrant; protected Registrant mStkEventRegistrant; protected Registrant mStkCallSetUpRegistrant; - /** Registrant for handling SIM/RUIM SMS storage full messages */ protected Registrant mIccSmsFullRegistrant; - /** Registrant for handling Icc Refresh notifications */ + protected Registrant mEmergencyCallbackModeRegistrant; protected Registrant mIccRefreshRegistrant; - /** Registrant for handling RING notifications */ protected Registrant mRingRegistrant; - /** Registrant for handling RESTRICTED STATE changed notification */ protected Registrant mRestrictedStateRegistrant; + protected Registrant mGsmBroadcastSmsRegistrant; - //Network Mode received from PhoneFactory + // Network Mode received from PhoneFactory protected int mNetworkMode; - //CDMA subscription received from PhoneFactory + // CDMA subscription received from PhoneFactory protected int mCdmaSubscription; - //Type of Phone, GSM or CDMA. Set by CDMAPhone or GSMPhone. + // Type of Phone, GSM or CDMA. Set by CDMAPhone or GSMPhone. protected int mPhoneType; @@ -332,6 +338,14 @@ public abstract class BaseCommands implements CommandsInterface { mSMSRegistrant.clear(); } + public void setOnNewGsmBroadcastSms(Handler h, int what, Object obj) { + mGsmBroadcastSmsRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnNewGsmBroadcastSms(Handler h) { + mGsmBroadcastSmsRegistrant.clear(); + } + public void setOnSmsOnSim(Handler h, int what, Object obj) { mSmsOnSimRegistrant = new Registrant (h, what, obj); } @@ -424,6 +438,10 @@ public abstract class BaseCommands implements CommandsInterface { mIccRefreshRegistrant = new Registrant (h, what, obj); } + public void setEmergencyCallbackMode(Handler h, int what, Object obj) { + mEmergencyCallbackModeRegistrant = new Registrant (h, what, obj); + } + public void unSetOnIccRefresh(Handler h) { mIccRefreshRegistrant.clear(); } @@ -462,6 +480,29 @@ public abstract class BaseCommands implements CommandsInterface { mRestrictedStateRegistrant.clear(); } + public void registerForDisplayInfo(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mDisplayInfoRegistrants.add(r); + } + + public void unregisterForDisplayInfo(Handler h) { + mDisplayInfoRegistrants.remove(h); + } + + public void registerForCallWaitingInfo(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mCallWaitingInfoRegistrants.add(r); + } + + public void unregisterForCallWaitingInfo(Handler h) { + mCallWaitingInfoRegistrants.remove(h); + } + + public void registerForSignalInfo(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mSignalInfoRegistrants.add(r); + } + public void setOnUnsolOemHookRaw(Handler h, int what, Object obj) { mUnsolOemHookRawRegistrant = new Registrant (h, what, obj); } @@ -470,6 +511,64 @@ public abstract class BaseCommands implements CommandsInterface { mUnsolOemHookRawRegistrant.clear(); } + public void unregisterForSignalInfo(Handler h) { + mSignalInfoRegistrants.remove(h); + } + + public void registerForCdmaOtaProvision(Handler h,int what, Object obj){ + Registrant r = new Registrant (h, what, obj); + mOtaProvisionRegistrants.add(r); + } + + public void unregisterForCdmaOtaProvision(Handler h){ + mOtaProvisionRegistrants.remove(h); + } + + public void registerForNumberInfo(Handler h,int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mNumberInfoRegistrants.add(r); + } + + public void unregisterForNumberInfo(Handler h){ + mNumberInfoRegistrants.remove(h); + } + + public void registerForRedirectedNumberInfo(Handler h,int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mRedirNumInfoRegistrants.add(r); + } + + public void unregisterForRedirectedNumberInfo(Handler h) { + mRedirNumInfoRegistrants.remove(h); + } + + public void registerForLineControlInfo(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mLineControlInfoRegistrants.add(r); + } + + public void unregisterForLineControlInfo(Handler h) { + mLineControlInfoRegistrants.remove(h); + } + + public void registerFoT53ClirlInfo(Handler h,int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mT53ClirInfoRegistrants.add(r); + } + + public void unregisterForT53ClirInfo(Handler h) { + mT53ClirInfoRegistrants.remove(h); + } + + public void registerForT53AudioControlInfo(Handler h,int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mT53AudCntrlInfoRegistrants.add(r); + } + + public void unregisterForT53AudioControlInfo(Handler h) { + mT53AudCntrlInfoRegistrants.remove(h); + } + //***** Protected Methods /** * Store new RadioState and send notification based on the changes diff --git a/telephony/java/com/android/internal/telephony/Call.java b/telephony/java/com/android/internal/telephony/Call.java index 70471b6..7eb9d85 100644 --- a/telephony/java/com/android/internal/telephony/Call.java +++ b/telephony/java/com/android/internal/telephony/Call.java @@ -46,6 +46,13 @@ public abstract class Call { public State state = State.IDLE; + // Flag to indicate if the current calling/caller information + // is accurate. If false the information is known to be accurate. + // + // For CDMA, during call waiting/3 way, there is no network response + // if call waiting is answered, network timed out, dropped, 3 way + // merged, etc. + protected boolean isGeneric = false; /* Instance Methods */ @@ -126,6 +133,7 @@ public abstract class Call { if (t < time) { earliest = c; + time = t; } } @@ -157,10 +165,8 @@ public abstract class Call { public long getEarliestConnectTime() { - List l; long time = Long.MAX_VALUE; - - l = getConnections(); + List l = getConnections(); if (l.size() == 0) { return 0; @@ -189,4 +195,44 @@ public abstract class Call { return getState().isRinging(); } + /** + * Returns the Connection associated with this Call that was created + * last, or null if there are no Connections in this Call + */ + public Connection + getLatestConnection() { + List l = getConnections(); + if (l.size() == 0) { + return null; + } + + long time = 0; + Connection latest = null; + for (int i = 0, s = l.size() ; i < s ; i++) { + Connection c = (Connection) l.get(i); + long t = c.getCreateTime(); + + if (t > time) { + latest = c; + time = t; + } + } + + return latest; + } + + /** + * To indicate if the connection information is accurate + * or not. false means accurate. Only used for CDMA. + */ + public boolean isGeneric() { + return isGeneric; + } + + /** + * Set the generic instance variable + */ + public void setGeneric(boolean generic) { + isGeneric = generic; + } } diff --git a/telephony/java/com/android/internal/telephony/CallTracker.java b/telephony/java/com/android/internal/telephony/CallTracker.java index eb339f8..9619a66 100644 --- a/telephony/java/com/android/internal/telephony/CallTracker.java +++ b/telephony/java/com/android/internal/telephony/CallTracker.java @@ -44,19 +44,21 @@ public abstract class CallTracker extends Handler { //***** Events - protected static final int EVENT_POLL_CALLS_RESULT = 1; - protected static final int EVENT_CALL_STATE_CHANGE = 2; - protected static final int EVENT_REPOLL_AFTER_DELAY = 3; - protected static final int EVENT_OPERATION_COMPLETE = 4; - protected static final int EVENT_GET_LAST_CALL_FAIL_CAUSE = 5; - - protected static final int EVENT_SWITCH_RESULT = 8; - protected static final int EVENT_RADIO_AVAILABLE = 9; - protected static final int EVENT_RADIO_NOT_AVAILABLE = 10; - protected static final int EVENT_CONFERENCE_RESULT = 11; - protected static final int EVENT_SEPARATE_RESULT = 12; - protected static final int EVENT_ECT_RESULT = 13; - + protected static final int EVENT_POLL_CALLS_RESULT = 1; + protected static final int EVENT_CALL_STATE_CHANGE = 2; + protected static final int EVENT_REPOLL_AFTER_DELAY = 3; + protected static final int EVENT_OPERATION_COMPLETE = 4; + protected static final int EVENT_GET_LAST_CALL_FAIL_CAUSE = 5; + + protected static final int EVENT_SWITCH_RESULT = 8; + protected static final int EVENT_RADIO_AVAILABLE = 9; + protected static final int EVENT_RADIO_NOT_AVAILABLE = 10; + protected static final int EVENT_CONFERENCE_RESULT = 11; + protected static final int EVENT_SEPARATE_RESULT = 12; + protected static final int EVENT_ECT_RESULT = 13; + protected static final int EVENT_EXIT_ECM_RESPONSE_CDMA = 14; + protected static final int EVENT_CALL_WAITING_INFO_CDMA = 15; + protected static final int EVENT_THREE_WAY_DIAL_L2_RESULT_CDMA = 16; protected void pollCallsWhenSafe() { needsPoll = true; diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java index da53e15..afc8b62 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfo.java +++ b/telephony/java/com/android/internal/telephony/CallerInfo.java @@ -70,17 +70,23 @@ public class CallerInfo { */ public String name; public String phoneNumber; + + public String cnapName; + public int numberPresentation; + public int namePresentation; + public boolean contactExists; + public String phoneLabel; /* Split up the phoneLabel into number type and label name */ public int numberType; public String numberLabel; - + public int photoResource; public long person_id; public boolean needUpdate; public Uri contactRefUri; - - // fields to hold individual contact preference data, + + // fields to hold individual contact preference data, // including the send to voicemail flag and the ringtone // uri reference. public Uri contactRingtoneUri; @@ -110,7 +116,7 @@ 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; @@ -118,9 +124,10 @@ public class CallerInfo { info.numberLabel = null; info.cachedPhoto = null; info.isCachedPhotoCurrent = false; - + info.contactExists = false; + if (Config.LOGV) Log.v(TAG, "construct callerInfo from cursor"); - + if (cursor != null) { if (cursor.moveToFirst()) { @@ -137,7 +144,7 @@ public class CallerInfo { if (columnIndex != -1) { info.phoneNumber = cursor.getString(columnIndex); } - + // Look for the label/type combo columnIndex = cursor.getColumnIndex(Phones.LABEL); if (columnIndex != -1) { @@ -161,7 +168,7 @@ public class CallerInfo { info.person_id = cursor.getLong(columnIndex); } } - + // look for the custom ringtone, create from the string stored // in the database. columnIndex = cursor.getColumnIndex(People.CUSTOM_RINGTONE); @@ -174,8 +181,9 @@ public class CallerInfo { // look for the send to voicemail flag, set it to true only // under certain circumstances. columnIndex = cursor.getColumnIndex(People.SEND_TO_VOICEMAIL); - info.shouldSendToVoicemail = (columnIndex != -1) && + info.shouldSendToVoicemail = (columnIndex != -1) && ((cursor.getInt(columnIndex)) == 1); + info.contactExists = true; } cursor.close(); } @@ -186,7 +194,7 @@ public class CallerInfo { return info; } - + /** * getCallerInfo given a URI, look up in the call-log database * for the uri unique key. @@ -196,11 +204,11 @@ public class CallerInfo { * number. The returned CallerInfo is null if no number is supplied. */ public static CallerInfo getCallerInfo(Context context, Uri contactRef) { - - return getCallerInfo(context, contactRef, + + return getCallerInfo(context, contactRef, context.getContentResolver().query(contactRef, null, null, null, null)); } - + /** * getCallerInfo given a phone number, look up in the call-log database * for the matching caller id info. @@ -216,13 +224,13 @@ public class CallerInfo { return null; } else { // Change the callerInfo number ONLY if it is an emergency number - // or if it is the voicemail number. If it is either, take a + // or if it is the voicemail number. If it is either, take a // shortcut and skip the query. if (PhoneNumberUtils.isEmergencyNumber(number)) { CallerInfo ci = new CallerInfo(); // Note we're setting the phone number here (refer to javadoc - // comments at the top of CallerInfo class). + // comments at the top of CallerInfo class). ci.phoneNumber = context.getString( com.android.internal.R.string.emergency_call_dialog_number_for_display); return ci; @@ -233,14 +241,14 @@ public class CallerInfo { CallerInfo ci = new CallerInfo(); // Note we're setting the phone number here (refer to javadoc - // comments at the top of CallerInfo class). + // comments at the top of CallerInfo class). ci.phoneNumber = TelephonyManager.getDefault().getVoiceMailAlphaTag(); // TODO: FIND ANOTHER ICON //info.photoResource = android.R.drawable.badge_voicemail; return ci; } } catch (SecurityException ex) { - // Don't crash if this process doesn't have permission to + // Don't crash if this process doesn't have permission to // retrieve VM number. It's still allowed to look up caller info. // But don't try it again. sSkipVmCheck = true; @@ -249,16 +257,16 @@ public class CallerInfo { } Uri contactUri = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, - Uri.encode(number)); - + Uri.encode(number)); + CallerInfo info = getCallerInfo(context, contactUri); - // if no query results were returned with a viable number, - // fill in the original number value we used to query with. + // if no query results were returned with a viable number, + // fill in the original number value we used to query with. if (TextUtils.isEmpty(info.phoneNumber)) { info.phoneNumber = number; } - + return info; } @@ -270,9 +278,9 @@ public class CallerInfo { * @param number a phone number. * @return if the number belongs to a contact, the contact's name is * returned; otherwise, the number itself is returned. - * - * TODO NOTE: This MAY need to refer to the Asynchronous Query API - * [startQuery()], instead of getCallerInfo, but since it looks like + * + * TODO NOTE: This MAY need to refer to the Asynchronous Query API + * [startQuery()], instead of getCallerInfo, but since it looks like * it is only being used by the provider calls in the messaging app: * 1. android.provider.Telephony.Mms.getDisplayAddress() * 2. android.provider.Telephony.Sms.getDisplayAddress() @@ -302,5 +310,4 @@ public class CallerInfo { return null; } } -} - +} diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java index 04da9f7..f81f42a 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java +++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java @@ -35,10 +35,10 @@ import android.util.Log; */ public class CallerInfoAsyncQuery { - + private static final boolean DBG = false; private static final String LOG_TAG = "PHONE"; - + private static final int EVENT_NEW_QUERY = 1; private static final int EVENT_ADD_LISTENER = 2; private static final int EVENT_END_OF_QUEUE = 3; @@ -55,24 +55,24 @@ public class CallerInfoAsyncQuery { */ public interface OnQueryCompleteListener { /** - * Called when the query is complete. - */ + * Called when the query is complete. + */ public void onQueryComplete(int token, Object cookie, CallerInfo ci); } - - + + /** * Wrap the cookie from the WorkerArgs with additional information needed by our - * classes. + * classes. */ private static final class CookieWrapper { public OnQueryCompleteListener listener; public Object cookie; public int event; public String number; - } - - + } + + /** * Simple exception used to communicate problems with the query pool. */ @@ -81,12 +81,12 @@ public class CallerInfoAsyncQuery { super(error); } } - + /** * Our own implementation of the AsyncQueryHandler. */ private class CallerInfoAsyncQueryHandler extends AsyncQueryHandler { - + /** * The information relevant to each CallerInfo query. Each query may have multiple * listeners, so each AsyncCursorInfo is associated with 2 or more CookieWrapper @@ -96,20 +96,20 @@ public class CallerInfoAsyncQuery { private Context mQueryContext; private Uri mQueryUri; private CallerInfo mCallerInfo; - + /** * Our own query worker thread. - * + * * This thread handles the messages enqueued in the looper. The normal sequence * of events is that a new query shows up in the looper queue, followed by 0 or * more add listener requests, and then an end request. Of course, these requests * can be interlaced with requests from other tokens, but is irrelevant to this * handler since the handler has no state. - * + * * Note that we depend on the queue to keep things in order; in other words, the - * looper queue must be FIFO with respect to input from the synchronous startQuery + * looper queue must be FIFO with respect to input from the synchronous startQuery * calls and output to this handleMessage call. - * + * * This use of the queue is required because CallerInfo objects may be accessed * multiple times before the query is complete. All accesses (listeners) must be * queued up and informed in order when the query is complete. @@ -123,22 +123,22 @@ public class CallerInfoAsyncQuery { public void handleMessage(Message msg) { WorkerArgs args = (WorkerArgs) msg.obj; CookieWrapper cw = (CookieWrapper) args.cookie; - + if (cw == null) { // Normally, this should never be the case for calls originating // from within this code. - // However, if there is any code that this Handler calls (such as in + // However, if there is any code that this Handler calls (such as in // super.handleMessage) that DOES place unexpected messages on the // queue, then we need pass these messages on. - if (DBG) log("Unexpected command (CookieWrapper is null): " + msg.what + + if (DBG) log("Unexpected command (CookieWrapper is null): " + msg.what + " ignored by CallerInfoWorkerHandler, passing onto parent."); - + super.handleMessage(msg); } else { - - if (DBG) log("Processing event: " + cw.event + " token (arg1): " + msg.arg1 + + + if (DBG) log("Processing event: " + cw.event + " token (arg1): " + msg.arg1 + " command: " + msg.what + " query URI: " + args.uri); - + switch (cw.event) { case EVENT_NEW_QUERY: //start the sql command. @@ -148,7 +148,7 @@ public class CallerInfoAsyncQuery { // shortcuts to avoid query for recognized numbers. case EVENT_EMERGENCY_NUMBER: case EVENT_VOICEMAIL_NUMBER: - + case EVENT_ADD_LISTENER: case EVENT_END_OF_QUEUE: // query was already completed, so just send the reply. @@ -157,17 +157,17 @@ public class CallerInfoAsyncQuery { Message reply = args.handler.obtainMessage(msg.what); reply.obj = args; reply.arg1 = msg.arg1; - + reply.sendToTarget(); - + break; default: } } } } - - + + /** * Asynchronous query handler class for the contact / callerinfo object. */ @@ -182,29 +182,29 @@ public class CallerInfoAsyncQuery { /** * Overrides onQueryComplete from AsyncQueryHandler. - * + * * This method takes into account the state of this class; we construct the CallerInfo * object only once for each set of listeners. When the query thread has done its work - * and calls this method, we inform the remaining listeners in the queue, until we're - * out of listeners. Once we get the message indicating that we should expect no new - * listeners for this CallerInfo object, we release the AsyncCursorInfo back into the + * and calls this method, we inform the remaining listeners in the queue, until we're + * out of listeners. Once we get the message indicating that we should expect no new + * listeners for this CallerInfo object, we release the AsyncCursorInfo back into the * pool. */ @Override protected void onQueryComplete(int token, Object cookie, Cursor cursor) { if (DBG) log("query complete for token: " + token); - + //get the cookie and notify the listener. CookieWrapper cw = (CookieWrapper) cookie; if (cw == null) { // Normally, this should never be the case for calls originating // from within this code. - // However, if there is any code that calls this method, we should + // However, if there is any code that calls this method, we should // check the parameters to make sure they're viable. if (DBG) log("Cookie is null, ignoring onQueryComplete() request."); return; } - + if (cw.event == EVENT_END_OF_QUEUE) { release(); return; @@ -216,16 +216,16 @@ public class CallerInfoAsyncQuery { throw new QueryPoolException ("Bad context or query uri, or CallerInfoAsyncQuery already released."); } - + // adjust the callerInfo data as needed, and only if it was set from the // initial query request. // Change the callerInfo number ONLY if it is an emergency number or the - // voicemail number, and adjust other data (including photoResource) + // voicemail number, and adjust other data (including photoResource) // accordingly. if (cw.event == EVENT_EMERGENCY_NUMBER) { mCallerInfo = new CallerInfo(); // Note we're setting the phone number here (refer to javadoc - // comments at the top of CallerInfo class). + // comments at the top of CallerInfo class). mCallerInfo.phoneNumber = mQueryContext.getString(com.android.internal .R.string.emergency_call_dialog_number_for_display); mCallerInfo.photoResource = com.android.internal.R.drawable.picture_emergency; @@ -234,8 +234,8 @@ public class CallerInfoAsyncQuery { mCallerInfo = new CallerInfo(); try { // Note we're setting the phone number here (refer to javadoc - // comments at the top of CallerInfo class). - mCallerInfo.phoneNumber = + // comments at the top of CallerInfo class). + mCallerInfo.phoneNumber = TelephonyManager.getDefault().getVoiceMailAlphaTag(); } catch (SecurityException ex) { // Should never happen: if this process does not have @@ -243,80 +243,80 @@ public class CallerInfoAsyncQuery { // permission to retrieve VM number and would not generate // an EVENT_VOICEMAIL_NUMBER. But if it happens, don't crash. } - } else { + } else { mCallerInfo = CallerInfo.getCallerInfo(mQueryContext, mQueryUri, cursor); // Use the number entered by the user for display. if (!TextUtils.isEmpty(cw.number)) { mCallerInfo.phoneNumber = PhoneNumberUtils.formatNumber(cw.number); } } - + if (DBG) log("constructing CallerInfo object for token: " + token); - + //notify that we can clean up the queue after this. CookieWrapper endMarker = new CookieWrapper(); endMarker.event = EVENT_END_OF_QUEUE; startQuery (token, endMarker, null, null, null, null, null); } - + //notify the listener that the query is complete. if (cw.listener != null) { - if (DBG) log("notifying listener: " + cw.listener.getClass().toString() + + if (DBG) log("notifying listener: " + cw.listener.getClass().toString() + " for token: " + token); cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo); } } } - + /** * Private constructor for factory methods. */ private CallerInfoAsyncQuery() { } - + /** * Factory method to start query with a Uri query spec */ - public static CallerInfoAsyncQuery startQuery(int token, Context context, Uri contactRef, + public static CallerInfoAsyncQuery startQuery(int token, Context context, Uri contactRef, OnQueryCompleteListener listener, Object cookie) { - + CallerInfoAsyncQuery c = new CallerInfoAsyncQuery(); c.allocate(context, contactRef); if (DBG) log("starting query for URI: " + contactRef + " handler: " + c.toString()); - + //create cookieWrapper, start query CookieWrapper cw = new CookieWrapper(); cw.listener = listener; cw.cookie = cookie; cw.event = EVENT_NEW_QUERY; - + c.mHandler.startQuery (token, cw, contactRef, null, null, null, null); - + return c; } - + /** * Factory method to start query with a number */ - public static CallerInfoAsyncQuery startQuery(int token, Context context, String number, + public static CallerInfoAsyncQuery startQuery(int token, Context context, String number, OnQueryCompleteListener listener, Object cookie) { //contruct the URI object and start Query. Uri contactRef = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, number); - + CallerInfoAsyncQuery c = new CallerInfoAsyncQuery(); c.allocate(context, contactRef); if (DBG) log("starting query for number: " + number + " handler: " + c.toString()); - + //create cookieWrapper, start query CookieWrapper cw = new CookieWrapper(); cw.listener = listener; cw.cookie = cookie; cw.number = number; - // check to see if these are recognized numbers, and use shortcuts if we can. + // check to see if these are recognized numbers, and use shortcuts if we can. if (PhoneNumberUtils.isEmergencyNumber(number)) { cw.event = EVENT_EMERGENCY_NUMBER; } else { @@ -325,13 +325,13 @@ public class CallerInfoAsyncQuery { try { vmNumber = TelephonyManager.getDefault().getVoiceMailNumber(); } catch (SecurityException ex) { - // Don't crash if this process doesn't have permission to + // Don't crash if this process doesn't have permission to // retrieve VM number. It's still allowed to look up caller info. // But don't try it again. sSkipVmCheck = true; } } - if (PhoneNumberUtils.compare(number, vmNumber)) { + if (PhoneNumberUtils.compare(number, vmNumber)) { cw.event = EVENT_VOICEMAIL_NUMBER; } else { cw.event = EVENT_NEW_QUERY; @@ -339,24 +339,24 @@ public class CallerInfoAsyncQuery { } c.mHandler.startQuery (token, cw, contactRef, null, null, null, null); - + return c; } - + /** * Method to add listeners to a currently running query */ public void addQueryListener(int token, OnQueryCompleteListener listener, Object cookie) { - if (DBG) log("adding listener to query: " + mHandler.mQueryUri + " handler: " + + if (DBG) log("adding listener to query: " + mHandler.mQueryUri + " handler: " + mHandler.toString()); - + //create cookieWrapper, add query request to end of queue. CookieWrapper cw = new CookieWrapper(); cw.listener = listener; cw.cookie = cookie; cw.event = EVENT_ADD_LISTENER; - + mHandler.startQuery (token, cw, null, null, null, null, null); } @@ -382,12 +382,12 @@ public class CallerInfoAsyncQuery { mHandler.mCallerInfo = null; mHandler = null; } - + /** * static logging method */ private static void log(String msg) { Log.d(LOG_TAG, msg); - } + } } diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java index 5a1bb7e..25c512e 100644 --- a/telephony/java/com/android/internal/telephony/CommandsInterface.java +++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; + import android.os.Message; import android.os.Handler; @@ -147,6 +149,14 @@ public interface CommandsInterface { static final int SIM_REFRESH_INIT = 1; // SIM initialized; reload all static final int SIM_REFRESH_RESET = 2; // SIM reset; may be locked + // GSM SMS fail cause for acknowledgeLastIncomingSMS. From TS 23.040, 9.2.3.22. + static final int GSM_SMS_FAIL_CAUSE_MEMORY_CAPACITY_EXCEEDED = 0xD3; + static final int GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR = 0xFF; + + // CDMA SMS fail cause for acknowledgeLastIncomingCdmaSms. From TS N.S00005, 6.5.2.125. + static final int CDMA_SMS_FAIL_CAUSE_RESOURCE_SHORTAGE = 35; + static final int CDMA_SMS_FAIL_CAUSE_OTHER_TERMINAL_PROBLEM = 39; + //***** Methods RadioState getRadioState(); @@ -348,12 +358,12 @@ public interface CommandsInterface { void unSetOnCallRing(Handler h); /** - * Sets the handler for RESTRICTED_STATE changed notification, + * Sets the handler for RESTRICTED_STATE changed notification, * eg, for Domain Specific Access Control * unlike the register* methods, there's only one signal strength handler - * - * AsyncResult.result is an int[1] - * response.obj.result[0] is a bitmask of RIL_RESTRICTED_STATE_* values + * + * AsyncResult.result is an int[1] + * response.obj.result[0] is a bitmask of RIL_RESTRICTED_STATE_* values */ void setOnRestrictedStateChanged(Handler h, int what, Object obj); @@ -424,6 +434,104 @@ public interface CommandsInterface { void setSuppServiceNotifications(boolean enable, Message result); //void unSetSuppServiceNotifications(Handler h); + /** + * Sets the handler for Event Notifications for CDMA Display Info. + * Unlike the register* methods, there's only one notification handler + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForDisplayInfo(Handler h, int what, Object obj); + void unregisterForDisplayInfo(Handler h); + + /** + * Sets the handler for Event Notifications for CallWaiting Info. + * Unlike the register* methods, there's only one notification handler + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForCallWaitingInfo(Handler h, int what, Object obj); + void unregisterForCallWaitingInfo(Handler h); + + /** + * Sets the handler for Event Notifications for Signal Info. + * Unlike the register* methods, there's only one notification handler + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForSignalInfo(Handler h, int what, Object obj); + void unregisterForSignalInfo(Handler h); + + /** + * Registers the handler for CDMA number information record + * Unlike the register* methods, there's only one notification handler + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForNumberInfo(Handler h, int what, Object obj); + void unregisterForNumberInfo(Handler h); + + /** + * Registers the handler for CDMA redirected number Information record + * Unlike the register* methods, there's only one notification handler + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForRedirectedNumberInfo(Handler h, int what, Object obj); + void unregisterForRedirectedNumberInfo(Handler h); + + /** + * Registers the handler for CDMA line control information record + * Unlike the register* methods, there's only one notification handler + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForLineControlInfo(Handler h, int what, Object obj); + void unregisterForLineControlInfo(Handler h); + + /** + * Registers the handler for CDMA T53 CLIR information record + * Unlike the register* methods, there's only one notification handler + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerFoT53ClirlInfo(Handler h, int what, Object obj); + void unregisterForT53ClirInfo(Handler h); + + /** + * Registers the handler for CDMA T53 audio control information record + * Unlike the register* methods, there's only one notification handler + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForT53AudioControlInfo(Handler h, int what, Object obj); + void unregisterForT53AudioControlInfo(Handler h); + + /** + * Fires on if Modem enters Emergency Callback mode + */ + void setEmergencyCallbackMode(Handler h, int what, Object obj); + + /** + * Fires on any CDMA OTA provision status change + */ + void registerForCdmaOtaProvision(Handler h,int what, Object obj); + void unregisterForCdmaOtaProvision(Handler h); /** * Returns current ICC status. @@ -516,7 +624,7 @@ public interface CommandsInterface { * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj - * ar.result contains a List of PDPContextState + * ar.result contains a List of DataCallState * @deprecated */ void getPDPContextList(Message result); @@ -526,7 +634,7 @@ public interface CommandsInterface { * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj - * ar.result contains a List of PDPContextState + * ar.result contains a List of DataCallState */ void getDataCallList(Message result); @@ -767,6 +875,12 @@ public interface CommandsInterface { */ void stopDtmf(Message result); + /** + * ar.exception carries exception on failure + * ar.userObject contains the orignal value of result.obj + * ar.result is null on success and failure + */ + void sendBurstDtmf(String dtmfString, Message result); /** * smscPDU is smsc address in PDU form GSM BCD format prefixed @@ -833,9 +947,9 @@ public interface CommandsInterface { void setRadioPower(boolean on, Message response); - void acknowledgeLastIncomingSMS(boolean success, Message response); + void acknowledgeLastIncomingGsmSms(boolean success, int cause, Message response); - void acknowledgeLastIncomingCdmaSms(boolean success, Message response); + void acknowledgeLastIncomingCdmaSms(boolean success, int cause, Message response); /** * parameters equivilient to 27.007 AT+CRSM command @@ -1038,6 +1152,20 @@ public interface CommandsInterface { */ void setSmscAddress(String address, Message result); + /** + * Indicates whether there is storage available for new SMS messages. + * @param available true if storage is available + * @param result callback message + */ + void reportSmsMemoryStatus(boolean available, Message result); + + /** + * Indicates to the vendor ril that StkService is running + * rand is eady to receive RIL_UNSOL_STK_XXXX commands. + * + * @param result callback message + */ + void reportStkServiceIsRunning(Message result); void invokeOemRilRequestRaw(byte[] data, Message response); @@ -1074,6 +1202,31 @@ public interface CommandsInterface { */ public void handleCallSetupRequestFromSim(boolean accept, Message response); + /** + * Activate or deactivate cell broadcast SMS for GSM. + * + * @param activate + * true = activate, false = deactivate + * @param result Callback message is empty on completion + */ + public void setGsmBroadcastActivation(boolean activate, Message result); + + /** + * Configure cell broadcast SMS for GSM. + * + * @param response Callback message is empty on completion + */ + public void setGsmBroadcastConfig(SmsBroadcastConfigInfo[] config, Message response); + + /** + * Query the current configuration of cell broadcast SMS of GSM. + * + * @param response + * Callback message contains the configuration from the modem + * on completion + */ + public void getGsmBroadcastConfig(Message response); + //***** new Methods for CDMA support /** @@ -1087,13 +1240,12 @@ public interface CommandsInterface { public void getDeviceIdentity(Message response); /** - * Request the device IMSI_M / MDN / AH_SID / H_SID / H_NID. + * Request the device MDN / H_SID / H_NID / MIN. * "response" is const char ** - * [0] is IMSI_M if CDMA subscription is available - * [1] is MDN if CDMA subscription is available - * [2] is AH_SID (Analog Home SID) if CDMA subscription - * [3] is H_SID (Home SID) if CDMA subscription is available - * [4] is H_NID (Home SID) if CDMA subscription is available + * [0] is MDN if CDMA subscription is available + * [1] is H_SID (Home SID) if CDMA subscription is available + * [2] is H_NID (Home NID) if CDMA subscription is available + * [3] is MIN (10 digits, MIN2+MIN1) if CDMA subscription is available */ public void getCDMASubscription(Message response); @@ -1133,7 +1285,7 @@ public interface CommandsInterface { * @param enable is true to enable, false to disable * @param response is callback message */ - void setTTYModeEnabled(boolean enable, Message response); + void setTTYMode(int ttyMode, Message response); /** * Query the TTY mode for the CDMA phone @@ -1142,7 +1294,7 @@ public interface CommandsInterface { * * @param response is callback message */ - void queryTTYModeEnabled(Message response); + void queryTTYMode(Message response); /** * Setup a packet data connection On successful completion, the result @@ -1181,14 +1333,14 @@ public interface CommandsInterface { public void deactivateDataCall(int cid, Message result); /** - * Activate or deactivate cell broadcast SMS. + * Activate or deactivate cell broadcast SMS for CDMA. * * @param activate - * 0 = activate, 1 = deactivate + * true = activate, false = deactivate * @param result * Callback message is empty on completion */ - public void activateCdmaBroadcastSms(int activate, Message result); + public void setCdmaBroadcastActivation(boolean activate, Message result); /** * Configure cdma cell broadcast SMS. @@ -1196,6 +1348,7 @@ public interface CommandsInterface { * @param result * Callback message is empty on completion */ + // TODO: Change the configValuesArray to a RIL_BroadcastSMSConfig public void setCdmaBroadcastConfig(int[] configValuesArray, Message result); /** @@ -1205,4 +1358,12 @@ public interface CommandsInterface { * Callback message contains the configuration from the modem on completion */ public void getCdmaBroadcastConfig(Message result); + + /** + * Requests the radio's system selection module to exit emergency callback mode. + * This function should only be called from CDMAPHone.java. + * + * @param response callback message + */ + public void exitEmergencyCallbackMode(Message response); } diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java index 86ceb89..92f6cb8 100644 --- a/telephony/java/com/android/internal/telephony/Connection.java +++ b/telephony/java/com/android/internal/telephony/Connection.java @@ -27,27 +27,36 @@ public abstract class Connection { public static int PRESENTATION_UNKNOWN = 3; // no specified or unknown by network public static int PRESENTATION_PAYPHONE = 4; // show pay phone info - + public enum DisconnectCause { - NOT_DISCONNECTED, /* has not yet disconnected */ - INCOMING_MISSED, /* an incoming call that was missed and never answered */ - NORMAL, /* normal; remote */ - LOCAL, /* normal; local hangup */ - BUSY, /* outgoing call to busy line */ - CONGESTION, /* outgoing call to congested network */ - MMI, /* not presently used; dial() returns null */ - INVALID_NUMBER, /* invalid dial string */ + NOT_DISCONNECTED, /* has not yet disconnected */ + INCOMING_MISSED, /* an incoming call that was missed and never answered */ + NORMAL, /* normal; remote */ + LOCAL, /* normal; local hangup */ + BUSY, /* outgoing call to busy line */ + CONGESTION, /* outgoing call to congested network */ + MMI, /* not presently used; dial() returns null */ + INVALID_NUMBER, /* invalid dial string */ LOST_SIGNAL, - LIMIT_EXCEEDED, /* eg GSM ACM limit exceeded */ - INCOMING_REJECTED, /* an incoming call that was rejected */ - POWER_OFF, /* radio is turned off explicitly */ - OUT_OF_SERVICE, /* out of service */ - ICC_ERROR, /* No ICC, ICC locked, or other ICC error */ - CALL_BARRED, /* call was blocked by call barrring */ - FDN_BLOCKED, /* call was blocked by fixed dial number */ - CS_RESTRICTED, /* call was blocked by restricted all voice access */ - CS_RESTRICTED_NORMAL,/* call was blocked by restricted normal voice access */ - CS_RESTRICTED_EMERGENCY/* call was blocked by restricted emergency voice access */ + LIMIT_EXCEEDED, /* eg GSM ACM limit exceeded */ + INCOMING_REJECTED, /* an incoming call that was rejected */ + POWER_OFF, /* radio is turned off explicitly */ + OUT_OF_SERVICE, /* out of service */ + ICC_ERROR, /* No ICC, ICC locked, or other ICC error */ + CALL_BARRED, /* call was blocked by call barrring */ + FDN_BLOCKED, /* call was blocked by fixed dial number */ + CS_RESTRICTED, /* call was blocked by restricted all voice access */ + CS_RESTRICTED_NORMAL, /* call was blocked by restricted normal voice access */ + CS_RESTRICTED_EMERGENCY, /* call was blocked by restricted emergency voice access */ + CDMA_LOCKED_UNTIL_POWER_CYCLE, /* MS is locked until next power cycle */ + CDMA_DROP, + CDMA_INTERCEPT, /* INTERCEPT order received, MS state idle entered */ + CDMA_REORDER, /* MS has been redirected, call is cancelled */ + CDMA_SO_REJECT, /* service option rejection */ + CDMA_RETRY_ORDER, /* requeseted service is rejected, retry delay is set */ + CDMA_ACCESS_FAILURE, + CDMA_PREEMPTED, + CDMA_NOT_EMERGENCY /* not an emergency call */ } Object userData; @@ -64,6 +73,31 @@ public abstract class Connection { public abstract String getAddress(); /** + * Gets cdma CNAP name associated with connection + * @return cnap name or null if unavailable + */ + public String getCnapName() { + return null; + } + + /** + * Get orignal dial string + * @return orignal dial string or null if unavailable + */ + public String getOrigDialString(){ + return null; + } + + /** + * Gets cdma CNAP presentation associated with connection + * @return cnap name or null if unavailable + */ + + public int getCnapNamePresentation() { + return 0; + }; + + /** * @return Call that owns this Connection, or null if none */ public abstract Call getCall(); @@ -195,8 +229,14 @@ public abstract class Connection { WILD, /* The post dial string playback is waiting for a call to proceedAfterWildChar() */ COMPLETE, /* The post dial string playback is complete */ - CANCELLED /* The post dial string playback was cancelled + CANCELLED, /* The post dial string playback was cancelled with cancelPostDial() */ + PAUSE /* The post dial string playback is pausing for a + call to processNextPostDialChar*/ + } + + public void clearUserData(){ + userData = null; } public abstract PostDialState getPostDialState(); @@ -220,8 +260,8 @@ public abstract class Connection { /** * Cancel any post */ - public abstract void cancelPostDial(); - + public abstract void cancelPostDial(); + /** * Returns the caller id presentation type for incoming and waiting calls * @return one of PRESENTATION_* diff --git a/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java b/telephony/java/com/android/internal/telephony/DataCallState.java index 31cdacf..d0f3d24 100644 --- a/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java +++ b/telephony/java/com/android/internal/telephony/DataCallState.java @@ -1,5 +1,6 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2009 Qualcomm Innovation Center, Inc. All Rights Reserved. + * 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. @@ -14,25 +15,18 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; -/** - * {@hide} - */ -public class PDPContextState { +public class DataCallState { public int cid; public int active; public String type; public String apn; public String address; + @Override public String toString() { - return "com.android.internal.telephony.gsm.PDPContextState: {" + - " cid: " + cid + - ", active: " + active + - ", type: " + type + - ", apn: " + apn + - ", address: " + address + - " }"; + return "DataCallState: {" + " cid: " + cid + ", active: " + active + ", type: " + type + + ", apn: " + apn + ", address: " + address + " }"; } } diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java index 6e9d1ab..7809fed 100644 --- a/telephony/java/com/android/internal/telephony/DataConnection.java +++ b/telephony/java/com/android/internal/telephony/DataConnection.java @@ -55,57 +55,83 @@ public abstract class DataConnection extends Handler { public enum FailCause { NONE, - BAD_APN, - BAD_PAP_SECRET, - BARRED, + OPERATOR_BARRED, + INSUFFICIENT_RESOURCES, + MISSING_UKNOWN_APN, + UNKNOWN_PDP_ADDRESS, USER_AUTHENTICATION, + ACTIVATION_REJECT_GGSN, + ACTIVATION_REJECT_UNSPECIFIED, SERVICE_OPTION_NOT_SUPPORTED, SERVICE_OPTION_NOT_SUBSCRIBED, - SIM_LOCKED, - RADIO_OFF, - NO_SIGNAL, - NO_DATA_PLAN, + SERVICE_OPTION_OUT_OF_ORDER, + NSAPI_IN_USE, + PROTOCOL_ERRORS, + REGISTRATION_FAIL, + GPRS_REGISTRATION_FAIL, + UNKNOWN, + RADIO_NOT_AVAILABLE, - SUSPENED_TEMPORARY, - RADIO_ERROR_RETRY, - UNKNOWN; + RADIO_ERROR_RETRY; public boolean isPermanentFail() { - return (this == RADIO_OFF); + return (this == OPERATOR_BARRED) || (this == MISSING_UKNOWN_APN) || + (this == UNKNOWN_PDP_ADDRESS) || (this == USER_AUTHENTICATION) || + (this == ACTIVATION_REJECT_GGSN) || (this == ACTIVATION_REJECT_UNSPECIFIED) || + (this == SERVICE_OPTION_NOT_SUPPORTED) || + (this == SERVICE_OPTION_NOT_SUBSCRIBED) || (this == NSAPI_IN_USE) || + (this == PROTOCOL_ERRORS); + } + + public boolean isEventLoggable() { + return (this == OPERATOR_BARRED) || (this == INSUFFICIENT_RESOURCES) || + (this == UNKNOWN_PDP_ADDRESS) || (this == USER_AUTHENTICATION) || + (this == ACTIVATION_REJECT_GGSN) || (this == ACTIVATION_REJECT_UNSPECIFIED) || + (this == SERVICE_OPTION_NOT_SUBSCRIBED) || + (this == SERVICE_OPTION_NOT_SUPPORTED) || + (this == SERVICE_OPTION_OUT_OF_ORDER) || (this == NSAPI_IN_USE) || + (this == PROTOCOL_ERRORS); } + @Override public String toString() { switch (this) { case NONE: - return "no error"; - case BAD_APN: - return "bad apn"; - case BAD_PAP_SECRET: - return "bad pap secret"; - case BARRED: - return "barred"; + return "No Error"; + case OPERATOR_BARRED: + return "Operator Barred"; + case INSUFFICIENT_RESOURCES: + return "Insufficient Resources"; + case MISSING_UKNOWN_APN: + return "Missing / Unknown APN"; + case UNKNOWN_PDP_ADDRESS: + return "Unknown PDP Address"; case USER_AUTHENTICATION: - return "error user autentication"; + return "Error User Autentication"; + case ACTIVATION_REJECT_GGSN: + return "Activation Reject GGSN"; + case ACTIVATION_REJECT_UNSPECIFIED: + return "Activation Reject unspecified"; case SERVICE_OPTION_NOT_SUPPORTED: - return "data not supported"; + return "Data Not Supported"; case SERVICE_OPTION_NOT_SUBSCRIBED: - return "datt not subcribed"; - case SIM_LOCKED: - return "sim locked"; - case RADIO_OFF: - return "radio is off"; - case NO_SIGNAL: - return "no signal"; - case NO_DATA_PLAN: - return "no data plan"; + return "Data Not subscribed"; + case SERVICE_OPTION_OUT_OF_ORDER: + return "Data Services Out of Order"; + case NSAPI_IN_USE: + return "NSAPI in use"; + case PROTOCOL_ERRORS: + return "Protocol Errors"; + case REGISTRATION_FAIL: + return "Network Registration Failure"; + case GPRS_REGISTRATION_FAIL: + return "Data Network Registration Failure"; case RADIO_NOT_AVAILABLE: - return "radio not available"; - case SUSPENED_TEMPORARY: - return "suspend temporary"; + return "Radio Not Available"; case RADIO_ERROR_RETRY: - return "transient radio error"; + return "Transient Radio Rrror"; default: - return "unknown data error"; + return "Unknown Data Error"; } } } diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java index 5b826b2..c074cb8 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -63,7 +63,8 @@ public abstract class DataConnectionTracker extends Handler { NONE, DATAIN, DATAOUT, - DATAINANDOUT + DATAINANDOUT, + DORMANT } //***** Event Codes @@ -92,19 +93,20 @@ public abstract class DataConnectionTracker extends Handler { protected static final int EVENT_NV_READY = 31; protected static final int EVENT_PS_RESTRICT_ENABLED = 32; protected static final int EVENT_PS_RESTRICT_DISABLED = 33; + public static final int EVENT_CLEAN_UP_CONNECTION = 34; //***** Constants protected static final int RECONNECT_DELAY_INITIAL_MILLIS = 5 * 1000; - /** Cap out with 1 hour retry interval. */ - protected static final int RECONNECT_DELAY_MAX_MILLIS = 60 * 60 * 1000; + /** Cap out with 30 min retry interval. */ + protected static final int RECONNECT_DELAY_MAX_MILLIS = 30 * 60 * 1000; /** Slow poll when attempting connection recovery. */ protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000; /** Default ping deadline, in seconds. */ - protected final int DEFAULT_PING_DEADLINE = 5; + protected static final int DEFAULT_PING_DEADLINE = 5; /** Default max failure count before attempting to network re-registration. */ - protected final int DEFAULT_MAX_PDP_RESET_FAIL = 3; + protected static final int DEFAULT_MAX_PDP_RESET_FAIL = 3; /** * After detecting a potential connection problem, this is the max number @@ -148,7 +150,7 @@ public abstract class DataConnectionTracker extends Handler { /** Intent sent when the reconnect alarm fires. */ protected PendingIntent mReconnectIntent = null; - + /** CID of active data connection */ protected int cidActive; @@ -216,7 +218,7 @@ public abstract class DataConnectionTracker extends Handler { } // abstract handler methods - protected abstract void onTrySetupData(); + protected abstract void onTrySetupData(String reason); protected abstract void onRoamingOff(); protected abstract void onRoamingOn(); protected abstract void onRadioAvailable(); @@ -225,13 +227,18 @@ public abstract class DataConnectionTracker extends Handler { protected abstract void onDisconnectDone(AsyncResult ar); protected abstract void onVoiceCallStarted(); protected abstract void onVoiceCallEnded(); + protected abstract void onCleanUpConnection(boolean tearDown, String reason); //***** Overridden from Handler public void handleMessage (Message msg) { switch (msg.what) { case EVENT_TRY_SETUP_DATA: - onTrySetupData(); + String reason = null; + if (msg.obj instanceof String) { + reason = (String)msg.obj; + } + onTrySetupData(reason); break; case EVENT_ROAMING_OFF: @@ -267,6 +274,11 @@ public abstract class DataConnectionTracker extends Handler { onVoiceCallEnded(); break; + case EVENT_CLEAN_UP_CONNECTION: + boolean tearDown = (msg.arg1 == 0) ? false : true; + onCleanUpConnection(tearDown, (String)msg.obj); + break; + default: Log.e("DATA", "Unidentified event = " + msg.what); break; @@ -274,12 +286,6 @@ public abstract class DataConnectionTracker extends Handler { } /** - * Simply tear down data connections due to radio off - * and don't setup again. - */ - public abstract void cleanConnectionBeforeRadioOff(); - - /** * Report the current state of data connectivity (enabled or disabled) * @return {@code false} if data connectivity has been explicitly disabled, * {@code true} otherwise. diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java index 79b4afe..d6151c6 100644 --- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -62,7 +62,7 @@ public class DefaultPhoneNotifier implements PhoneNotifier { public void notifySignalStrength(Phone sender) { try { - mRegistry.notifySignalStrength(sender.getSignalStrengthASU()); + mRegistry.notifySignalStrength(sender.getSignalStrength()); } catch (RemoteException ex) { // system process is dead } @@ -200,6 +200,8 @@ public class DefaultPhoneNotifier implements PhoneNotifier { return TelephonyManager.DATA_ACTIVITY_OUT; case DATAINANDOUT: return TelephonyManager.DATA_ACTIVITY_INOUT; + case DORMANT: + return TelephonyManager.DATA_ACTIVITY_DORMANT; default: return TelephonyManager.DATA_ACTIVITY_NONE; } @@ -217,6 +219,8 @@ public class DefaultPhoneNotifier implements PhoneNotifier { return Phone.DataActivityState.DATAOUT; case TelephonyManager.DATA_ACTIVITY_INOUT: return Phone.DataActivityState.DATAINANDOUT; + case TelephonyManager.DATA_ACTIVITY_DORMANT: + return Phone.DataActivityState.DORMANT; default: return Phone.DataActivityState.NONE; } diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java index 8f4c69c..e8095e1 100644 --- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java +++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java @@ -182,7 +182,7 @@ public class GsmAlphabet { return stringToGsm7BitPacked(data); } - int headerBits = header.length * 8; + int headerBits = (header.length + 1) * 8; int headerSeptets = headerBits / 7; headerSeptets += (headerBits % 7) > 0 ? 1 : 0; @@ -194,7 +194,8 @@ public class GsmAlphabet { (headerSeptets*7), true); // Paste in the header - System.arraycopy(header, 0, ret, 1, header.length); + ret[1] = (byte)header.length; + System.arraycopy(header, 0, ret, 2, header.length); return ret; } @@ -575,52 +576,6 @@ public class GsmAlphabet { return size; } - /** - * Returns the index into <code>s</code> of the first character - * after <code>limit</code> octets have been reached, starting at - * index <code>start</code>. This is used when dividing messages - * in UCS2 encoding into units within the SMS message size limit. - * - * @param s source string - * @param start index of where to start counting septets - * @param limit maximum septets to include, - * e.g. <code>MAX_USER_DATA_BYTES</code> - * @return index of first character that won't fit, or the length - * of the entire string if everything fits - */ - public static int - findUCS2LimitIndex(String s, int start, int limit) { - int numCharToBeEncoded = s.length() - start; - return ((numCharToBeEncoded*2 > limit)? limit/2: numCharToBeEncoded) + start; - } - - /** - * Returns the index into <code>s</code> of the first character - * after <code>limit</code> septets/octets have been reached - * according to the <code>encodingType</code>, starting at - * index <code>start</code>. This is used when dividing messages - * units within the SMS message size limit. - * - * @param s source string - * @param start index of where to start counting septets - * @param limit maximum septets to include, - * e.g. <code>MAX_USER_DATA_BYTES</code> - * @return index of first character that won't fit, or the length - * of the entire string if everything fits - */ - public static int - findLimitIndex(String s, int start, int limit, int encodingType) throws EncodeException { - if (encodingType == SmsMessage.ENCODING_7BIT) { - return findGsmSeptetLimitIndex(s, start, limit); - } - else if (encodingType == SmsMessage.ENCODING_16BIT) { - return findUCS2LimitIndex(s, start, limit); - } - else { - throw new EncodeException("Unsupported encoding type: " + encodingType); - } - } - // Set in the static initializer private static int sGsmSpaceChar; diff --git a/telephony/java/com/android/internal/telephony/IExtendedNetworkService.aidl b/telephony/java/com/android/internal/telephony/IExtendedNetworkService.aidl index 6c1f4bb..facdc49 100644 --- a/telephony/java/com/android/internal/telephony/IExtendedNetworkService.aidl +++ b/telephony/java/com/android/internal/telephony/IExtendedNetworkService.aidl @@ -1,11 +1,11 @@ package com.android.internal.telephony; /** - * Interface used to interact with extended MMI/USSD network service. + * Interface used to interact with extended MMI/USSD network service. */ interface IExtendedNetworkService { /** - * Set a MMI/USSD command to ExtendedNetworkService for further process. + * Set a MMI/USSD command to ExtendedNetworkService for further process. * This should be called when a MMI command is placed from panel. * @param number the dialed MMI/USSD number. */ diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl index e0884b3..0202ec8 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -18,6 +18,7 @@ package com.android.internal.telephony; import android.os.Bundle; import android.telephony.ServiceState; +import android.telephony.SignalStrength; oneway interface IPhoneStateListener { void onServiceStateChanged(in ServiceState serviceState); @@ -30,5 +31,6 @@ oneway interface IPhoneStateListener { void onCallStateChanged(int state, String incomingNumber); void onDataConnectionStateChanged(int state); void onDataActivity(int direction); + void onSignalStrengthsChanged(in SignalStrength signalStrength); } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index bab0603..d83b135 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -221,5 +221,27 @@ interface ITelephony { */ int getActivePhoneType(); + /** + * Returns the CDMA ERI icon index to display + */ + int getCdmaEriIconIndex(); + + /** + * Returns the CDMA ERI icon mode, + * 0 - ON + * 1 - FLASHING + */ + int getCdmaEriIconMode(); + + /** + * Returns the CDMA ERI text, + */ + String getCdmaEriText(); + + /** + * Returns the unread count of voicemails + */ + int getVoiceMessageCount(); + } diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 1b011fe..865c6ca 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -19,6 +19,7 @@ package com.android.internal.telephony; import android.content.Intent; import android.os.Bundle; import android.telephony.ServiceState; +import android.telephony.SignalStrength; import com.android.internal.telephony.IPhoneStateListener; interface ITelephonyRegistry { @@ -26,7 +27,7 @@ interface ITelephonyRegistry { void notifyCallState(int state, String incomingNumber); void notifyServiceState(in ServiceState state); - void notifySignalStrength(int signalStrengthASU); + void notifySignalStrength(in SignalStrength signalStrength); void notifyMessageWaitingChanged(boolean mwi); void notifyCallForwardingChanged(boolean cfi); void notifyDataActivity(int state); diff --git a/telephony/java/com/android/internal/telephony/IccConstants.java b/telephony/java/com/android/internal/telephony/IccConstants.java index 014fbb6..7eafafd 100644 --- a/telephony/java/com/android/internal/telephony/IccConstants.java +++ b/telephony/java/com/android/internal/telephony/IccConstants.java @@ -61,4 +61,5 @@ public interface IccConstants { static final String DF_TELECOM = "7F10"; static final String DF_GRAPHICS = "5F50"; static final String DF_GSM = "7F20"; + static final String DF_CDMA = "7F25"; } diff --git a/telephony/java/com/android/internal/telephony/IccRecords.java b/telephony/java/com/android/internal/telephony/IccRecords.java index 114094b..ea24c25 100644 --- a/telephony/java/com/android/internal/telephony/IccRecords.java +++ b/telephony/java/com/android/internal/telephony/IccRecords.java @@ -196,7 +196,7 @@ public abstract class IccRecords extends Handler implements IccConstants { * If not available (eg, on an older CPHS SIM) -1 is returned if * getVoiceMessageWaiting() is true */ - public int getCountVoiceMessages() { + public int getVoiceMessageCount() { return countVoiceMessages; } diff --git a/telephony/java/com/android/internal/telephony/IccVmFixedException.java b/telephony/java/com/android/internal/telephony/IccVmFixedException.java index 45679c1..a75496f 100644 --- a/telephony/java/com/android/internal/telephony/IccVmFixedException.java +++ b/telephony/java/com/android/internal/telephony/IccVmFixedException.java @@ -28,5 +28,5 @@ public final class IccVmFixedException extends IccException { public IccVmFixedException(String s) { super(s); - } + } }
\ No newline at end of file diff --git a/telephony/java/com/android/internal/telephony/IccVmNotSupportedException.java b/telephony/java/com/android/internal/telephony/IccVmNotSupportedException.java index 7e90d24..3c9d126 100644 --- a/telephony/java/com/android/internal/telephony/IccVmNotSupportedException.java +++ b/telephony/java/com/android/internal/telephony/IccVmNotSupportedException.java @@ -28,5 +28,5 @@ public final class IccVmNotSupportedException extends IccException { public IccVmNotSupportedException(String s) { super(s); - } + } } diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java index 03c1c56..c8d384d 100644 --- a/telephony/java/com/android/internal/telephony/Phone.java +++ b/telephony/java/com/android/internal/telephony/Phone.java @@ -23,6 +23,7 @@ import android.os.Message; import android.preference.PreferenceManager; import android.telephony.CellLocation; import android.telephony.ServiceState; +import android.telephony.SignalStrength; import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.gsm.NetworkInfo; @@ -82,9 +83,11 @@ public interface Phone { * <li>DATAIN = Receiving IP ppp traffic</li> * <li>DATAOUT = Sending IP ppp traffic</li> * <li>DATAINANDOUT = Both receiving and sending IP ppp traffic</li> + * <li>DORMANT = The data connection is still active, + but physical link is down</li> * </ul> */ - NONE, DATAIN, DATAOUT, DATAINANDOUT; + NONE, DATAIN, DATAOUT, DATAINANDOUT, DORMANT; }; enum SuppService { @@ -99,6 +102,7 @@ public interface Phone { static final String DATA_APN_KEY = "apn"; static final String DATA_IFACE_NAME_KEY = "iface"; static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable"; + static final String PHONE_IN_ECM_STATE = "phoneinECMState"; /** * APN types for data connections. These are usage categories for an APN @@ -150,7 +154,7 @@ public interface Phone { static final String REASON_PS_RESTRICT_ENABLED = "psRestrictEnabled"; static final String REASON_PS_RESTRICT_DISABLED = "psRestrictDisabled"; static final String REASON_SIM_LOADED = "simLoaded"; - + // Used for band mode selection methods static final int BM_UNSPECIFIED = 0; // selected by baseband automatically static final int BM_EURO_BAND = 1; // GSM-900 / DCS-1800 / WCDMA-IMT-2000 @@ -162,28 +166,53 @@ public interface Phone { // Used for preferred network type // Note NT_* substitute RILConstants.NETWORK_MODE_* above the Phone - int NT_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */ - int NT_MODE_GSM_ONLY = 1; /* GSM only */ - int NT_MODE_WCDMA_ONLY = 2; /* WCDMA only */ - int NT_MODE_GSM_UMTS = 3; /* GSM/WCDMA (auto mode, according to PRL) - AVAILABLE Application Settings menu*/ - int NT_MODE_CDMA = 4; /* CDMA and EvDo (auto mode, according to PRL) - AVAILABLE Application Settings menu*/ - int NT_MODE_CDMA_NO_EVDO = 5; /* CDMA only */ - int NT_MODE_EVDO_NO_CDMA = 6; /* EvDo only */ - int NT_MODE_GLOBAL = 7; /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL) - AVAILABLE Application Settings menu*/ - int PREFERRED_NT_MODE = NT_MODE_GSM_ONLY; + int NT_MODE_WCDMA_PREF = RILConstants.NETWORK_MODE_WCDMA_PREF; + int NT_MODE_GSM_ONLY = RILConstants.NETWORK_MODE_GSM_ONLY; + int NT_MODE_WCDMA_ONLY = RILConstants.NETWORK_MODE_WCDMA_ONLY; + int NT_MODE_GSM_UMTS = RILConstants.NETWORK_MODE_GSM_UMTS; + + int NT_MODE_CDMA = RILConstants.NETWORK_MODE_CDMA; + + int NT_MODE_CDMA_NO_EVDO = RILConstants.NETWORK_MODE_CDMA_NO_EVDO; + int NT_MODE_EVDO_NO_CDMA = RILConstants.NETWORK_MODE_EVDO_NO_CDMA; + int NT_MODE_GLOBAL = RILConstants.NETWORK_MODE_GLOBAL; + + int PREFERRED_NT_MODE = RILConstants.PREFERRED_NETWORK_MODE; // Used for CDMA roaming mode - static final int CDMA_RM_HOME = 0; //Home Networks only, as defined in PRL - static final int CDMA_RM_AFFILIATED = 1; //Roaming an Affiliated networks, as defined in PRL - static final int CDMA_RM_ANY = 2; //Roaming on Any Network, as defined in PRL + static final int CDMA_RM_HOME = 0; // Home Networks only, as defined in PRL + static final int CDMA_RM_AFFILIATED = 1; // Roaming an Affiliated networks, as defined in PRL + static final int CDMA_RM_ANY = 2; // Roaming on Any Network, as defined in PRL // Used for CDMA subscription mode - static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; //RUIM/SIM (default) - static final int CDMA_SUBSCRIPTION_NV = 1; //NV -> non-volatile memory + static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; // RUIM/SIM (default) + static final int CDMA_SUBSCRIPTION_NV = 1; // NV -> non-volatile memory + + static final int PREFERRED_CDMA_SUBSCRIPTION = CDMA_SUBSCRIPTION_NV; + + static final int TTY_MODE_OFF = 0; + static final int TTY_MODE_FULL = 1; + static final int TTY_MODE_HCO = 2; + static final int TTY_MODE_VCO = 3; + + /** + * CDMA OTA PROVISION STATUS, the same as RIL_CDMA_OTA_Status in ril.h + */ + + public static final int CDMA_OTA_PROVISION_STATUS_SPL_UNLOCKED = 0; + public static final int CDMA_OTA_PROVISION_STATUS_SPC_RETRIES_EXCEEDED = 1; + public static final int CDMA_OTA_PROVISION_STATUS_A_KEY_EXCHANGED = 2; + public static final int CDMA_OTA_PROVISION_STATUS_SSD_UPDATED = 3; + public static final int CDMA_OTA_PROVISION_STATUS_NAM_DOWNLOADED = 4; + public static final int CDMA_OTA_PROVISION_STATUS_MDN_DOWNLOADED = 5; + public static final int CDMA_OTA_PROVISION_STATUS_IMSI_DOWNLOADED = 6; + public static final int CDMA_OTA_PROVISION_STATUS_PRL_DOWNLOADED = 7; + public static final int CDMA_OTA_PROVISION_STATUS_COMMITTED = 8; + public static final int CDMA_OTA_PROVISION_STATUS_OTAPA_STARTED = 9; + public static final int CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED = 10; + public static final int CDMA_OTA_PROVISION_STATUS_OTAPA_ABORTED = 11; + /** * Get the current ServiceState. Use @@ -200,7 +229,7 @@ public interface Phone { /** * Get the current DataState. No change notification exists at this * interface -- use - * {@link com.android.internal.telephony.PhoneStateIntentReceiver PhoneStateIntentReceiver} + * {@link com.android.telephony.PhoneStateListener PhoneStateListener} * instead. */ DataState getDataConnectionState(); @@ -270,9 +299,9 @@ public interface Phone { * <ul><li>0 means "-113 dBm or less".</li> * <li>31 means "-51 dBm or greater".</li></ul> * - * @return Current signal strength in ASU's. + * @return Current signal strength as SignalStrength */ - int getSignalStrengthASU(); + SignalStrength getSignalStrength(); /** * Notifies when a previously untracked non-ringing/waiting connection has appeared. @@ -494,6 +523,21 @@ public interface Phone { void unregisterForInCallVoicePrivacyOff(Handler h); /** + * Register for notifications when CDMA OTA Provision status change + * + * @param h Handler that receives the notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForCdmaOtaStatusChange(Handler h, int what, Object obj); + + /** + * Unegister for notifications when CDMA OTA Provision status change + * @param h Handler to be removed from the registrant list. + */ + void unregisterForCdmaOtaStatusChange(Handler h); + + /** * Returns SIM record load state. Use * <code>getSimCard().registerForReady()</code> for change notification. * @@ -707,6 +751,19 @@ public interface Phone { */ void stopDtmf(); + /** + * send burst DTMF tone, it can send the string as single character or multiple character + * ignore if there is no active call or not valid digits string. + * Valid digit means only includes characters ISO-LATIN characters 0-9, *, # + * The difference between sendDtmf and sendBurstDtmf is sendDtmf only sends one character, + * this api can send single character and multiple character, also, this api has response + * back to caller. + * + * @param dtmfString is string representing the dialing digit(s) in the active call + * @param onCompelte is the callback message when the action is processed by BP + * + */ + void sendBurstDtmf(String dtmfString, Message onComplete); /** * Sets the radio power on/off state (off is sometimes @@ -771,6 +828,12 @@ public interface Phone { String getVoiceMailNumber(); /** + * Returns unread voicemail count. This count is shown when the voicemail + * notification is expanded.<p> + */ + int getVoiceMessageCount(); + + /** * Returns the alpha tag associated with the voice mail number. * If there is no alpha tag associated or the record is not yet available, * returns a default localized string. <p> @@ -803,7 +866,7 @@ public interface Phone { * * @param commandInterfaceCFReason is one of the valid call forwarding * CF_REASONS, as defined in - * <code>com.android.internal.telephony.CommandsInterface./code> + * <code>com.android.internal.telephony.CommandsInterface.</code> * @param onComplete a callback message when the action is completed. * @see com.android.internal.telephony.CallForwardInfo for details. */ @@ -816,10 +879,10 @@ public interface Phone { * * @param commandInterfaceCFReason is one of the valid call forwarding * CF_REASONS, as defined in - * <code>com.android.internal.telephony.CommandsInterface./code> + * <code>com.android.internal.telephony.CommandsInterface.</code> * @param commandInterfaceCFAction is one of the valid call forwarding * CF_ACTIONS, as defined in - * <code>com.android.internal.telephony.CommandsInterface./code> + * <code>com.android.internal.telephony.CommandsInterface.</code> * @param dialingNumber is the target phone number to forward calls to * @param timerSeconds is used by CFNRy to indicate the timeout before * forwarding is attempted. @@ -1279,6 +1342,20 @@ 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. + */ + String getCdmaMin(); + + /** + * Retrieves PRL Version for CDMA phones + */ + String getCdmaPrlVersion(); /** * Retrieves the ESN for CDMA phones. @@ -1306,22 +1383,22 @@ public interface Phone { public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(); /** - * setTTYModeEnabled + * setTTYMode * sets a TTY mode option. * * @param enable is a boolean representing the state that you are * requesting, true for enabled, false for disabled. * @param onComplete a callback message when the action is completed */ - void setTTYModeEnabled(boolean enable, Message onComplete); + void setTTYMode(int ttyMode, Message onComplete); /** - * queryTTYModeEnabled + * queryTTYMode * query the status of the TTY mode * * @param onComplete a callback message when the action is completed. */ - void queryTTYModeEnabled(Message onComplete); + void queryTTYMode(Message onComplete); /** * Activate or deactivate cell broadcast SMS. @@ -1344,10 +1421,220 @@ public interface Phone { /** * Configure cell broadcast SMS. * + * TODO: Change the configValuesArray to a RIL_BroadcastSMSConfig + * * @param response * Callback message is empty on completion */ public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response); public void notifyDataActivity(); + + /** + * Returns the CDMA ERI icon index to display + */ + public int getCdmaEriIconIndex(); + + /** + * Returns the CDMA ERI icon mode, + * 0 - ON + * 1 - FLASHING + */ + public int getCdmaEriIconMode(); + + /** + * Returns the CDMA ERI text, + */ + public String getCdmaEriText(); + + /** + * request to exit emergency call back mode + * the caller should use setOnECMModeExitResponse + * to receive the emergency callback mode exit response + */ + void exitEmergencyCallbackMode(); + + /** + * this decides if the dial number is OTA(Over the air provision) number or not + * @param dialStr is string representing the dialing digit(s) + * @return true means the dialStr is OTA number, and false means the dialStr is not OTA number + */ + boolean isOtaSpNumber(String dialStr); + + /** + * Register for notifications when CDMA call waiting comes + * + * @param h Handler that receives the notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForCallWaiting(Handler h, int what, Object obj); + + /** + * Unegister for notifications when CDMA Call waiting comes + * @param h Handler to be removed from the registrant list. + */ + void unregisterForCallWaiting(Handler h); + + + /** + * Register for signal information notifications from the network. + * Message.obj will contain an AsyncResult. + * AsyncResult.result will be a SuppServiceNotification instance. + * + * @param h Handler that receives the notification message. + * @param what User-defined message code. + * @param obj User object. + */ + + void registerForSignalInfo(Handler h, int what, Object obj) ; + /** + * Unregisters for signal information notifications. + * Extraneous calls are tolerated silently + * + * @param h Handler to be removed from the registrant list. + */ + void unregisterForSignalInfo(Handler h); + + /** + * Register for display information notifications from the network. + * Message.obj will contain an AsyncResult. + * AsyncResult.result will be a SuppServiceNotification instance. + * + * @param h Handler that receives the notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForDisplayInfo(Handler h, int what, Object obj); + + /** + * Unregisters for display information notifications. + * Extraneous calls are tolerated silently + * + * @param h Handler to be removed from the registrant list. + */ + void unregisterForDisplayInfo(Handler h) ; + + /** + * Register for CDMA number information record notification from the network. + * Message.obj will contain an AsyncResult. + * AsyncResult.result will be a CdmaInformationRecords.CdmaNumberInfoRec + * instance. + * + * @param h Handler that receives the notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForNumberInfo(Handler h, int what, Object obj); + + /** + * Unregisters for number information record notifications. + * Extraneous calls are tolerated silently + * + * @param h Handler to be removed from the registrant list. + */ + void unregisterForNumberInfo(Handler h); + + /** + * Register for CDMA redirected number information record notification + * from the network. + * Message.obj will contain an AsyncResult. + * AsyncResult.result will be a CdmaInformationRecords.CdmaRedirectingNumberInfoRec + * instance. + * + * @param h Handler that receives the notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForRedirectedNumberInfo(Handler h, int what, Object obj); + + /** + * Unregisters for redirected number information record notification. + * Extraneous calls are tolerated silently + * + * @param h Handler to be removed from the registrant list. + */ + void unregisterForRedirectedNumberInfo(Handler h); + + /** + * Register for CDMA line control information record notification + * from the network. + * Message.obj will contain an AsyncResult. + * AsyncResult.result will be a CdmaInformationRecords.CdmaLineControlInfoRec + * instance. + * + * @param h Handler that receives the notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForLineControlInfo(Handler h, int what, Object obj); + + /** + * Unregisters for line control information notifications. + * Extraneous calls are tolerated silently + * + * @param h Handler to be removed from the registrant list. + */ + void unregisterForLineControlInfo(Handler h); + + /** + * Register for CDMA T53 CLIR information record notifications + * from the network. + * Message.obj will contain an AsyncResult. + * AsyncResult.result will be a CdmaInformationRecords.CdmaT53ClirInfoRec + * instance. + * + * @param h Handler that receives the notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerFoT53ClirlInfo(Handler h, int what, Object obj); + + /** + * Unregisters for T53 CLIR information record notification + * Extraneous calls are tolerated silently + * + * @param h Handler to be removed from the registrant list. + */ + void unregisterForT53ClirInfo(Handler h); + + /** + * Register for CDMA T53 audio control information record notifications + * from the network. + * Message.obj will contain an AsyncResult. + * AsyncResult.result will be a CdmaInformationRecords.CdmaT53AudioControlInfoRec + * instance. + * + * @param h Handler that receives the notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForT53AudioControlInfo(Handler h, int what, Object obj); + + /** + * Unregisters for T53 audio control information record notifications. + * Extraneous calls are tolerated silently + * + * @param h Handler to be removed from the registrant list. + */ + void unregisterForT53AudioControlInfo(Handler h); + + /** + * registers for exit emergency call back mode request response + * + * @param h Handler that receives the notification message. + * @param what User-defined message code. + * @param obj User object. + */ + + void setOnEcbModeExitResponse(Handler h, int what, Object obj); + + /** + * Unregisters for exit emergency call back mode request response + * + * @param h Handler to be removed from the registrant list. + */ + void unsetOnEcbModeExitResponse(Handler h); + + } diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index 0314034..a26e729 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -29,6 +29,7 @@ import android.os.RegistrantList; import android.os.SystemProperties; import android.preference.PreferenceManager; import android.telephony.ServiceState; +import android.telephony.SignalStrength; import android.text.TextUtils; import android.util.Log; @@ -90,6 +91,8 @@ public abstract class PhoneBase implements Phone { protected static final int EVENT_RUIM_RECORDS_LOADED = 21; protected static final int EVENT_NV_READY = 22; protected static final int EVENT_SET_ENHANCED_VP = 23; + protected static final int EVENT_EMERGENCY_CALLBACK_MODE_ENTER = 24; + protected static final int EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE = 25; // Key used to read/write current CLIR setting public static final String CLIR_KEY = "clir_key"; @@ -187,7 +190,7 @@ public abstract class PhoneBase implements Phone { setUnitTestMode(unitTestMode); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false); + mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false); } // Inherited documentation suffices. @@ -204,7 +207,7 @@ public abstract class PhoneBase implements Phone { mDnsCheckDisabled = b; SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); SharedPreferences.Editor editor = sp.edit(); - editor.putBoolean(DNS_SERVER_CHECK_DISABLED_KEY, b); + editor.putBoolean(DNS_SERVER_CHECK_DISABLED_KEY, b); editor.commit(); } @@ -282,7 +285,6 @@ public abstract class PhoneBase implements Phone { mCM.unregisterForInCallVoicePrivacyOff(h); } - /** * Notifiy registrants of a new ringing Connection. * Subclasses of Phone probably want to replace this with a @@ -567,9 +569,6 @@ public abstract class PhoneBase implements Phone { mCM.setPreferredNetworkType(networkType, response); } - /** - * Set the status of the preferred Network Type: Global, CDMA only or GSM/UMTS only - */ public void getPreferredNetworkType(Message response) { mCM.getPreferredNetworkType(response); } @@ -582,12 +581,12 @@ public abstract class PhoneBase implements Phone { mCM.setSmscAddress(address, result); } - public void setTTYModeEnabled(boolean enable, Message onComplete) { + 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."); } - public void queryTTYModeEnabled(Message onComplete) { + 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."); } @@ -632,10 +631,159 @@ public abstract class PhoneBase implements Phone { mNotifier.notifyDataActivity(this); } + public void notifyMessageWaitingIndicator() { + // This function is added to send the notification to DefaultPhoneNotifier. + mNotifier.notifyMessageWaitingChanged(this); + } + public void notifyDataConnection(String reason) { mNotifier.notifyDataConnection(this, reason); } public abstract String getPhoneName(); + /** @hide */ + public int getVoiceMessageCount(){ + return 0; + } + + /** + * Returns the CDMA ERI icon index to display + */ + public int getCdmaEriIconIndex() { + Log.e(LOG_TAG, "Error! getCdmaEriIconIndex should never be executed in GSM mode"); + return -1; + } + + /** + * Returns the CDMA ERI icon mode, + * 0 - ON + * 1 - FLASHING + */ + public int getCdmaEriIconMode() { + Log.e(LOG_TAG, "Error! getCdmaEriIconMode should never be executed in GSM mode"); + return -1; + } + + /** + * Returns the CDMA ERI text, + */ + public String getCdmaEriText() { + Log.e(LOG_TAG, "Error! getCdmaEriText should never be executed in GSM mode"); + 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."); + return null; + } + + 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."); + return null; + } + + public void sendBurstDtmf(String dtmfString, 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."); + } + + 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."); + } + + 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."); + } + + 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."); + } + + 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."); + 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."); + } + + 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."); + } + + public void registerForSignalInfo(Handler h, int what, Object obj) { + mCM.registerForSignalInfo(h, what, obj); + } + + public void unregisterForSignalInfo(Handler h) { + mCM.unregisterForSignalInfo(h); + } + + public void registerForDisplayInfo(Handler h, int what, Object obj) { + mCM.registerForDisplayInfo(h, what, obj); + } + + public void unregisterForDisplayInfo(Handler h) { + mCM.unregisterForDisplayInfo(h); + } + + public void registerForNumberInfo(Handler h, int what, Object obj) { + mCM.registerForNumberInfo(h, what, obj); + } + + public void unregisterForNumberInfo(Handler h) { + mCM.unregisterForNumberInfo(h); + } + + public void registerForRedirectedNumberInfo(Handler h, int what, Object obj) { + mCM.registerForRedirectedNumberInfo(h, what, obj); + } + + public void unregisterForRedirectedNumberInfo(Handler h) { + mCM.unregisterForRedirectedNumberInfo(h); + } + + public void registerForLineControlInfo(Handler h, int what, Object obj) { + mCM.registerForLineControlInfo( h, what, obj); + } + + public void unregisterForLineControlInfo(Handler h) { + mCM.unregisterForLineControlInfo(h); + } + + public void registerFoT53ClirlInfo(Handler h, int what, Object obj) { + mCM.registerFoT53ClirlInfo(h, what, obj); + } + + public void unregisterForT53ClirInfo(Handler h) { + mCM.unregisterForT53ClirInfo(h); + } + + public void registerForT53AudioControlInfo(Handler h, int what, Object obj) { + mCM.registerForT53AudioControlInfo( h, what, obj); + } + + public void unregisterForT53AudioControlInfo(Handler h) { + mCM.unregisterForT53AudioControlInfo(h); + } + + 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."); + } + + 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."); + } } diff --git a/telephony/java/com/android/internal/telephony/PhoneFactory.java b/telephony/java/com/android/internal/telephony/PhoneFactory.java index 86e2f04..a84f74e 100644 --- a/telephony/java/com/android/internal/telephony/PhoneFactory.java +++ b/telephony/java/com/android/internal/telephony/PhoneFactory.java @@ -107,30 +107,49 @@ public class PhoneFactory { //reads the system properties and makes commandsinterface sCommandsInterface = new RIL(context, networkMode, cdmaSubscription); - switch(networkMode) { - case RILConstants.NETWORK_MODE_CDMA: - case RILConstants.NETWORK_MODE_CDMA_NO_EVDO: - case RILConstants.NETWORK_MODE_EVDO_NO_CDMA: - case RILConstants.NETWORK_MODE_GLOBAL: - sProxyPhone = new PhoneProxy(new CDMAPhone(context, - sCommandsInterface, sPhoneNotifier)); - Log.i(LOG_TAG, "Creating CDMAPhone"); - break; - case RILConstants.NETWORK_MODE_WCDMA_PREF: - case RILConstants.NETWORK_MODE_GSM_ONLY: - case RILConstants.NETWORK_MODE_WCDMA_ONLY: - case RILConstants.NETWORK_MODE_GSM_UMTS: - default: - sProxyPhone = new PhoneProxy(new GSMPhone(context, - sCommandsInterface, sPhoneNotifier)); - Log.i(LOG_TAG, "Creating GSMPhone"); - break; + int phoneType = getPhoneType(networkMode); + if (phoneType == RILConstants.GSM_PHONE) { + sProxyPhone = new PhoneProxy(new GSMPhone(context, + sCommandsInterface, sPhoneNotifier)); + Log.i(LOG_TAG, "Creating GSMPhone"); + } else if (phoneType == RILConstants.CDMA_PHONE) { + sProxyPhone = new PhoneProxy(new CDMAPhone(context, + sCommandsInterface, sPhoneNotifier)); + Log.i(LOG_TAG, "Creating CDMAPhone"); } + sMadeDefaults = true; } } } + /* + * This function returns the type of the phone, depending + * on the network mode. + * + * @param network mode + * @return Phone Type + */ + public static int getPhoneType(int networkMode) { + switch(networkMode) { + case RILConstants.NETWORK_MODE_CDMA: + case RILConstants.NETWORK_MODE_CDMA_NO_EVDO: + case RILConstants.NETWORK_MODE_EVDO_NO_CDMA: + return RILConstants.CDMA_PHONE; + + case RILConstants.NETWORK_MODE_WCDMA_PREF: + case RILConstants.NETWORK_MODE_GSM_ONLY: + case RILConstants.NETWORK_MODE_WCDMA_ONLY: + case RILConstants.NETWORK_MODE_GSM_UMTS: + return RILConstants.GSM_PHONE; + + case RILConstants.NETWORK_MODE_GLOBAL: + return RILConstants.CDMA_PHONE; + default: + return RILConstants.GSM_PHONE; + } + } + public static Phone getDefaultPhone() { if (sLooper != Looper.myLooper()) { throw new RuntimeException( diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java index b76d801..5b3c8dd 100644 --- a/telephony/java/com/android/internal/telephony/PhoneProxy.java +++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java @@ -26,6 +26,7 @@ import android.os.Message; import android.preference.PreferenceManager; import android.telephony.CellLocation; import android.telephony.ServiceState; +import android.telephony.SignalStrength; import android.util.Log; import com.android.internal.telephony.cdma.CDMAPhone; @@ -127,10 +128,9 @@ public class PhoneProxy extends Handler implements Phone { Intent intent = new Intent(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED); intent.putExtra(Phone.PHONE_NAME_KEY, mActivePhone.getPhoneName()); ActivityManagerNative.broadcastStickyIntent(intent, null); - break; default: - Log.e(LOG_TAG, "Error! This handler was not registered for this message type. Message: " + Log.e(LOG_TAG,"Error! This handler was not registered for this message type. Message: " + msg.what); break; } @@ -198,8 +198,8 @@ public class PhoneProxy extends Handler implements Phone { return mActivePhone.getActiveApn(); } - public int getSignalStrengthASU() { - return mActivePhone.getSignalStrengthASU(); + public SignalStrength getSignalStrength() { + return mActivePhone.getSignalStrength(); } public void registerForUnknownConnection(Handler h, int what, Object obj) { @@ -306,6 +306,14 @@ public class PhoneProxy extends Handler implements Phone { mActivePhone.unregisterForInCallVoicePrivacyOff(h); } + public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) { + mActivePhone.registerForCdmaOtaStatusChange(h,what,obj); + } + + public void unregisterForCdmaOtaStatusChange(Handler h) { + mActivePhone.unregisterForCdmaOtaStatusChange(h); + } + public boolean getIccRecordsLoaded() { return mActivePhone.getIccRecordsLoaded(); } @@ -406,6 +414,14 @@ public class PhoneProxy extends Handler implements Phone { return mActivePhone.getLine1Number(); } + public String getCdmaMin() { + return mActivePhone.getCdmaMin(); + } + + public String getCdmaPrlVersion() { + return mActivePhone.getCdmaPrlVersion(); + } + public String getLine1AlphaTag() { return mActivePhone.getLine1AlphaTag(); } @@ -418,6 +434,11 @@ public class PhoneProxy extends Handler implements Phone { return mActivePhone.getVoiceMailNumber(); } + /** @hide */ + public int getVoiceMessageCount(){ + return mActivePhone.getVoiceMessageCount(); + } + public String getVoiceMailAlphaTag() { return mActivePhone.getVoiceMailAlphaTag(); } @@ -648,12 +669,12 @@ public class PhoneProxy extends Handler implements Phone { return mActivePhone.getIccPhoneBookInterfaceManager(); } - public void setTTYModeEnabled(boolean enable, Message onComplete) { - mActivePhone.setTTYModeEnabled(enable, onComplete); + public void setTTYMode(int ttyMode, Message onComplete) { + mActivePhone.setTTYMode(ttyMode, onComplete); } - public void queryTTYModeEnabled(Message onComplete) { - mActivePhone.queryTTYModeEnabled(onComplete); + public void queryTTYMode(Message onComplete) { + mActivePhone.queryTTYMode(onComplete); } public void activateCellBroadcastSms(int activate, Message response) { @@ -679,5 +700,100 @@ public class PhoneProxy extends Handler implements Phone { public void setSmscAddress(String address, Message result) { mActivePhone.setSmscAddress(address, result); } -} + public int getCdmaEriIconIndex() { + return mActivePhone.getCdmaEriIconIndex(); + } + + public String getCdmaEriText() { + return mActivePhone.getCdmaEriText(); + } + + public int getCdmaEriIconMode() { + return mActivePhone.getCdmaEriIconMode(); + } + + public void sendBurstDtmf(String dtmfString, Message onComplete){ + mActivePhone.sendBurstDtmf(dtmfString,onComplete); + } + + public void exitEmergencyCallbackMode(){ + mActivePhone.exitEmergencyCallbackMode(); + } + + public boolean isOtaSpNumber(String dialStr){ + return mActivePhone.isOtaSpNumber(dialStr); + } + + public void registerForCallWaiting(Handler h, int what, Object obj){ + mActivePhone.registerForCallWaiting(h,what,obj); + } + + public void unregisterForCallWaiting(Handler h){ + mActivePhone.unregisterForCallWaiting(h); + } + + public void registerForSignalInfo(Handler h, int what, Object obj) { + mActivePhone.registerForSignalInfo(h,what,obj); + } + + public void unregisterForSignalInfo(Handler h) { + mActivePhone.unregisterForSignalInfo(h); + } + + public void registerForDisplayInfo(Handler h, int what, Object obj) { + mActivePhone.registerForDisplayInfo(h,what,obj); + } + + public void unregisterForDisplayInfo(Handler h) { + mActivePhone.unregisterForDisplayInfo(h); + } + + public void registerForNumberInfo(Handler h, int what, Object obj) { + mActivePhone.registerForNumberInfo(h, what, obj); + } + + public void unregisterForNumberInfo(Handler h) { + mActivePhone.unregisterForNumberInfo(h); + } + + public void registerForRedirectedNumberInfo(Handler h, int what, Object obj) { + mActivePhone.registerForRedirectedNumberInfo(h, what, obj); + } + + public void unregisterForRedirectedNumberInfo(Handler h) { + mActivePhone.unregisterForRedirectedNumberInfo(h); + } + + public void registerForLineControlInfo(Handler h, int what, Object obj) { + mActivePhone.registerForLineControlInfo( h, what, obj); + } + + public void unregisterForLineControlInfo(Handler h) { + mActivePhone.unregisterForLineControlInfo(h); + } + + public void registerFoT53ClirlInfo(Handler h, int what, Object obj) { + mActivePhone.registerFoT53ClirlInfo(h, what, obj); + } + + public void unregisterForT53ClirInfo(Handler h) { + mActivePhone.unregisterForT53ClirInfo(h); + } + + public void registerForT53AudioControlInfo(Handler h, int what, Object obj) { + mActivePhone.registerForT53AudioControlInfo( h, what, obj); + } + + public void unregisterForT53AudioControlInfo(Handler h) { + mActivePhone.unregisterForT53AudioControlInfo(h); + } + + public void setOnEcbModeExitResponse(Handler h, int what, Object obj){ + mActivePhone.setOnEcbModeExitResponse(h,what,obj); + } + + public void unsetOnEcbModeExitResponse(Handler h){ + mActivePhone.unsetOnEcbModeExitResponse(h); + } +} diff --git a/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java b/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java index fd822cd..b31161c 100644 --- a/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java +++ b/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java @@ -23,6 +23,7 @@ import android.content.IntentFilter; import android.os.Handler; import android.os.Message; import android.telephony.ServiceState; +import android.telephony.SignalStrength; import android.telephony.TelephonyManager; import android.util.Log; @@ -39,8 +40,6 @@ public final class PhoneStateIntentReceiver extends BroadcastReceiver { private static final String LOG_TAG = "PHONE"; private static final boolean DBG = false; - public static final String INTENT_KEY_ASU = "asu"; - private static final int NOTIF_PHONE = 1 << 0; private static final int NOTIF_SERVICE = 1 << 1; private static final int NOTIF_SIGNAL = 1 << 2; @@ -49,7 +48,8 @@ public final class PhoneStateIntentReceiver extends BroadcastReceiver { Phone.State mPhoneState = Phone.State.IDLE; ServiceState mServiceState = new ServiceState(); - int mAsu = -1; + SignalStrength mSignalStrength = new SignalStrength(); + private Context mContext; private Handler mTarget; private IntentFilter mFilter; @@ -106,12 +106,14 @@ public final class PhoneStateIntentReceiver extends BroadcastReceiver { * Throws RuntimeException if client has not called notifySignalStrength() */ public int getSignalStrength() { + // TODO: use new SignalStrength instead of asu if ((mWants & NOTIF_SIGNAL) == 0) { throw new RuntimeException ("client must call notifySignalStrength(int)"); } + int gsmSignalStrength = mSignalStrength.getGsmSignalStrength(); - return mAsu; + return (gsmSignalStrength == 99 ? -1 : gsmSignalStrength); } /** @@ -129,10 +131,15 @@ public final class PhoneStateIntentReceiver extends BroadcastReceiver { int dBm = -1; - if (mAsu != -1) { - dBm = -113 + 2*mAsu; + if(!mSignalStrength.isGsm()) { + dBm = mSignalStrength.getCdmaDbm(); + } else { + int gsmSignalStrength = mSignalStrength.getGsmSignalStrength(); + int asu = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength); + if (asu != -1) { + dBm = -113 + 2*asu; + } } - return dBm; } @@ -180,8 +187,7 @@ public final class PhoneStateIntentReceiver extends BroadcastReceiver { try { if (TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED.equals(action)) { - mAsu = intent.getIntExtra(INTENT_KEY_ASU, mAsu); - if (DBG) Log.d(LOG_TAG, "onReceiveIntent: set asu=" + mAsu); + mSignalStrength = SignalStrength.newFromBundle(intent.getExtras()); if (mTarget != null && getNotifySignalStrength()) { Message message = Message.obtain(mTarget, mAsuEventWhat); diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java index be18a39..4db3e5b 100644 --- a/telephony/java/com/android/internal/telephony/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -38,9 +38,19 @@ import android.telephony.SmsMessage; import android.util.Config; import android.util.Log; +import com.android.internal.telephony.CallForwardInfo; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.DataCallState; import com.android.internal.telephony.gsm.NetworkInfo; -import com.android.internal.telephony.gsm.PDPContextState; +import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; import com.android.internal.telephony.gsm.SuppServiceNotification; +import com.android.internal.telephony.IccCardApplication; +import com.android.internal.telephony.IccCardStatus; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.SmsResponse; +import com.android.internal.telephony.cdma.CdmaCallWaitingNotification; +import com.android.internal.telephony.cdma.CdmaInformationRecords; import java.io.ByteArrayInputStream; import java.io.DataInputStream; @@ -156,7 +166,7 @@ class RILRequest { } void - onError(int error) { + onError(int error, Object ret) { CommandException ex; ex = CommandException.fromRilErrno(error); @@ -166,7 +176,7 @@ class RILRequest { + " error: " + ex); if (mResult != null) { - AsyncResult.forMessage(mResult, null, ex); + AsyncResult.forMessage(mResult, ret, ex); mResult.sendToTarget(); } @@ -233,6 +243,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { private static final int CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES = 31; BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { sendScreenState(true); @@ -280,7 +291,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { s = mSocket; if (s == null) { - rr.onError(RADIO_NOT_AVAILABLE); + rr.onError(RADIO_NOT_AVAILABLE, null); rr.release(); mRequestMessagesPending--; alreadySubtracted = true; @@ -321,7 +332,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { // make sure this request has not already been handled, // eg, if RILReceiver cleared the list. if (req != null || !alreadySubtracted) { - rr.onError(RADIO_NOT_AVAILABLE); + rr.onError(RADIO_NOT_AVAILABLE, null); rr.release(); } } catch (RuntimeException exc) { @@ -330,7 +341,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { // make sure this request has not already been handled, // eg, if RILReceiver cleared the list. if (req != null || !alreadySubtracted) { - rr.onError(GENERIC_FAILURE); + rr.onError(GENERIC_FAILURE, null); rr.release(); } } @@ -535,7 +546,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { synchronized (mRequestsList) { for (int i = 0, sz = mRequestsList.size() ; i < sz ; i++) { RILRequest rr = mRequestsList.get(i); - rr.onError(RADIO_NOT_AVAILABLE); + rr.onError(RADIO_NOT_AVAILABLE, null); rr.release(); } @@ -562,18 +573,22 @@ public final class RIL extends BaseCommands implements CommandsInterface { mNetworkMode = networkMode; //At startup mPhoneType is first set from networkMode switch(networkMode) { + case RILConstants.NETWORK_MODE_WCDMA_PREF: + case RILConstants.NETWORK_MODE_GSM_ONLY: + case RILConstants.NETWORK_MODE_WCDMA_ONLY: + case RILConstants.NETWORK_MODE_GSM_UMTS: + mPhoneType = RILConstants.GSM_PHONE; + break; case RILConstants.NETWORK_MODE_CDMA: case RILConstants.NETWORK_MODE_CDMA_NO_EVDO: case RILConstants.NETWORK_MODE_EVDO_NO_CDMA: + mPhoneType = RILConstants.CDMA_PHONE; + break; case RILConstants.NETWORK_MODE_GLOBAL: mPhoneType = RILConstants.CDMA_PHONE; break; - case RILConstants.NETWORK_MODE_WCDMA_PREF: - case RILConstants.NETWORK_MODE_GSM_ONLY: - case RILConstants.NETWORK_MODE_WCDMA_ONLY: - case RILConstants.NETWORK_MODE_GSM_UMTS: default: - mPhoneType = RILConstants.GSM_PHONE; + mPhoneType = RILConstants.CDMA_PHONE; } PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); @@ -1052,6 +1067,17 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } + public void + sendBurstDtmf(String dtmfString, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_BURST_DTMF, result); + + rr.mp.writeString(dtmfString); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " : " + dtmfString); + + send(rr); + } public void sendSMS (String smscPDU, String pdu, Message result) { @@ -1234,13 +1260,19 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result); - rr.mp.writeInt(5); + rr.mp.writeInt(6); rr.mp.writeString(radioTechnology); rr.mp.writeString(profile); rr.mp.writeString(apn); rr.mp.writeString(user); rr.mp.writeString(password); + //TODO(): Add to the APN database, AuthType is set to CHAP/PAP + // 0 => Neither PAP nor CHAP will be performed, 3 => PAP / CHAP will be performed. + if (user != null) + rr.mp.writeString("3"); + else + rr.mp.writeString("0"); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + apn); @@ -1314,28 +1346,31 @@ public final class RIL extends BaseCommands implements CommandsInterface { } public void - acknowledgeLastIncomingSMS(boolean success, Message result) { + acknowledgeLastIncomingGsmSms(boolean success, int cause, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_SMS_ACKNOWLEDGE, result); - rr.mp.writeInt(1); + rr.mp.writeInt(2); rr.mp.writeInt(success ? 1 : 0); + rr.mp.writeInt(cause); - if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " " + success + " " + cause); send(rr); } public void - acknowledgeLastIncomingCdmaSms(boolean success, Message result) { + acknowledgeLastIncomingCdmaSms(boolean success, int cause, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, result); rr.mp.writeInt(success ? 0 : 1); //RIL_CDMA_SMS_ErrorClass // cause code according to X.S004-550E - rr.mp.writeInt(39); //39 means other terminal problem; is not interpreted for success. + rr.mp.writeInt(cause); - if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " " + success + " " + cause); send(rr); } @@ -1361,6 +1396,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { if (RILJ_LOGD) riljLog(rr.serialString() + "> iccIO: " + requestToString(rr.mRequest) + " 0x" + Integer.toHexString(command) + " 0x" + Integer.toHexString(fileid) + " " + + " path: " + path + "," + p1 + "," + p2 + "," + p3); send(rr); @@ -1777,7 +1813,6 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void setSmscAddress(String address, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_SMSC_ADDRESS, result); - rr.mp.writeInt(1); rr.mp.writeString(address); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) @@ -1786,6 +1821,84 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } + /** + * {@inheritDoc} + */ + public void reportSmsMemoryStatus(boolean available, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_REPORT_SMS_MEMORY_STATUS, result); + rr.mp.writeInt(1); + rr.mp.writeInt(available ? 1 : 0); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + + requestToString(rr.mRequest) + ": " + available); + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void reportStkServiceIsRunning(Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING, result); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void getGsmBroadcastConfig(Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_GSM_GET_BROADCAST_CONFIG, response); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void setGsmBroadcastConfig(SmsBroadcastConfigInfo[] config, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_GSM_SET_BROADCAST_CONFIG, response); + + int numOfConfig = config.length; + rr.mp.writeInt(numOfConfig); + + for(int i = 0; i < numOfConfig; i++) { + rr.mp.writeInt(config[i].getFromServiceId()); + rr.mp.writeInt(config[i].getToServiceId()); + rr.mp.writeInt(config[i].getFromCodeScheme()); + rr.mp.writeInt(config[i].getToCodeScheme()); + rr.mp.writeInt(config[i].isSelected() ? 1 : 0); + } + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " with " + numOfConfig + "configs : "); + for (int i = 0; i < numOfConfig; i++) { + riljLog(config[i].toString()); + } + } + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void setGsmBroadcastActivation(boolean activate, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_GSM_BROADCAST_ACTIVATION, response); + + rr.mp.writeInt(1); + rr.mp.writeInt(activate ? 0 : 1); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + //***** Private Methods private void sendScreenState(boolean on) { @@ -1793,7 +1906,8 @@ public final class RIL extends BaseCommands implements CommandsInterface { rr.mp.writeInt(1); rr.mp.writeInt(on ? 1 : 0); - if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + ": " + on); + if (RILJ_LOGD) riljLog(rr.serialString() + + "> " + requestToString(rr.mRequest) + ": " + on); send(rr); } @@ -1838,7 +1952,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { * and/or radio knowing. */ if (RILJ_LOGD) Log.d(LOG_TAG, "Radio ON @ init; reset to OFF"); - setRadioPower(false, null); + setRadioPower(false, null); } else { if (DBG) Log.d(LOG_TAG, "Radio OFF @ init"); setRadioState(newState); @@ -1941,28 +2055,24 @@ public final class RIL extends BaseCommands implements CommandsInterface { return; } - if (error != 0) { - rr.onError(error); - rr.release(); - return; - } + Object ret = null; - Object ret; - - try {switch (rr.mRequest) { -/* + if (error == 0 || p.dataAvail() > 0) { + // either command succeeds or command fails but with data payload + try {switch (rr.mRequest) { + /* cat libs/telephony/ril_commands.h \ | egrep "^ *{RIL_" \ | sed -re 's/\{([^,]+),[^,]+,([^}]+).+/case \1: ret = \2(p); break;/' -*/ + */ case RIL_REQUEST_GET_SIM_STATUS: ret = responseIccCardStatus(p); break; - case RIL_REQUEST_ENTER_SIM_PIN: ret = responseVoid(p); break; - case RIL_REQUEST_ENTER_SIM_PUK: ret = responseVoid(p); break; - case RIL_REQUEST_ENTER_SIM_PIN2: ret = responseVoid(p); break; - case RIL_REQUEST_ENTER_SIM_PUK2: ret = responseVoid(p); break; - case RIL_REQUEST_CHANGE_SIM_PIN: ret = responseVoid(p); break; - case RIL_REQUEST_CHANGE_SIM_PIN2: ret = responseVoid(p); break; - case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: ret = responseVoid(p); break; + case RIL_REQUEST_ENTER_SIM_PIN: ret = responseInts(p); break; + case RIL_REQUEST_ENTER_SIM_PUK: ret = responseInts(p); break; + case RIL_REQUEST_ENTER_SIM_PIN2: ret = responseInts(p); break; + case RIL_REQUEST_ENTER_SIM_PUK2: ret = responseInts(p); break; + case RIL_REQUEST_CHANGE_SIM_PIN: ret = responseInts(p); break; + case RIL_REQUEST_CHANGE_SIM_PIN2: ret = responseInts(p); break; + case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: ret = responseInts(p); break; case RIL_REQUEST_GET_CURRENT_CALLS: ret = responseCallList(p); break; case RIL_REQUEST_DIAL: ret = responseVoid(p); break; case RIL_REQUEST_GET_IMSI: ret = responseString(p); break; @@ -1973,7 +2083,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_CONFERENCE: ret = responseVoid(p); break; case RIL_REQUEST_UDUB: ret = responseVoid(p); break; case RIL_REQUEST_LAST_CALL_FAIL_CAUSE: ret = responseInts(p); break; - case RIL_REQUEST_SIGNAL_STRENGTH: ret = responseInts(p); break; + case RIL_REQUEST_SIGNAL_STRENGTH: ret = responseSignalStrength(p); break; case RIL_REQUEST_REGISTRATION_STATE: ret = responseStrings(p); break; case RIL_REQUEST_GPRS_REGISTRATION_STATE: ret = responseStrings(p); break; case RIL_REQUEST_OPERATOR: ret = responseStrings(p); break; @@ -1997,7 +2107,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_ANSWER: ret = responseVoid(p); break; case RIL_REQUEST_DEACTIVATE_DATA_CALL: ret = responseVoid(p); break; case RIL_REQUEST_QUERY_FACILITY_LOCK: ret = responseInts(p); break; - case RIL_REQUEST_SET_FACILITY_LOCK: ret = responseVoid(p); break; + case RIL_REQUEST_SET_FACILITY_LOCK: ret = responseInts(p); break; case RIL_REQUEST_CHANGE_BARRING_PASSWORD: ret = responseVoid(p); break; case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: ret = responseInts(p); break; case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: ret = responseVoid(p); break; @@ -2042,33 +2152,42 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_CDMA_BURST_DTMF: ret = responseVoid(p); break; case RIL_REQUEST_CDMA_SEND_SMS: ret = responseSMS(p); break; case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE: ret = responseVoid(p); break; - case RIL_REQUEST_GET_BROADCAST_CONFIG: ret = responseBR_SMS_CNF(p); break; - case RIL_REQUEST_SET_BROADCAST_CONFIG: ret = responseVoid(p); break; - case RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG: ret = responseCDMA_BR_CNF(p); break; + case RIL_REQUEST_GSM_GET_BROADCAST_CONFIG: ret = responseGmsBroadcastConfig(p); break; + case RIL_REQUEST_GSM_SET_BROADCAST_CONFIG: ret = responseVoid(p); break; + case RIL_REQUEST_GSM_BROADCAST_ACTIVATION: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG: ret = responseCdmaBroadcastConfig(p); break; case RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG: ret = responseVoid(p); break; - case RIL_REQUEST_BROADCAST_ACTIVATION: ret = responseVoid(p); break; - case RIL_REQUEST_CDMA_VALIDATE_AKEY: ret = responseVoid(p); break; case RIL_REQUEST_CDMA_BROADCAST_ACTIVATION: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_VALIDATE_AKEY: ret = responseVoid(p); break; case RIL_REQUEST_CDMA_SUBSCRIPTION: ret = responseStrings(p); break; case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: ret = responseInts(p); break; case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: ret = responseVoid(p); break; case RIL_REQUEST_DEVICE_IDENTITY: ret = responseStrings(p); break; case RIL_REQUEST_GET_SMSC_ADDRESS: ret = responseString(p); break; 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; default: throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest); //break; - }} catch (Throwable tr) { - // Exceptions here usually mean invalid RIL responses + }} catch (Throwable tr) { + // Exceptions here usually mean invalid RIL responses - Log.w(LOG_TAG, rr.serialString() + "< " - + requestToString(rr.mRequest) - + " exception, possible invalid RIL response", tr); + Log.w(LOG_TAG, rr.serialString() + "< " + + requestToString(rr.mRequest) + + " exception, possible invalid RIL response", tr); - if (rr.mResult != null) { - AsyncResult.forMessage(rr.mResult, null, tr); - rr.mResult.sendToTarget(); + if (rr.mResult != null) { + AsyncResult.forMessage(rr.mResult, null, tr); + rr.mResult.sendToTarget(); + } + rr.release(); + return; } + } + + if (error != 0) { + rr.onError(error, ret); rr.release(); return; } @@ -2167,7 +2286,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM: ret = responseInts(p); break; case RIL_UNSOL_ON_USSD: ret = responseStrings(p); break; case RIL_UNSOL_NITZ_TIME_RECEIVED: ret = responseString(p); break; - case RIL_UNSOL_SIGNAL_STRENGTH: ret = responseInts(p); break; + case RIL_UNSOL_SIGNAL_STRENGTH: ret = responseSignalStrength(p); break; case RIL_UNSOL_DATA_CALL_LIST_CHANGED: ret = responseDataCallList(p);break; case RIL_UNSOL_SUPP_SVC_NOTIFICATION: ret = responseSuppServiceNotification(p); break; case RIL_UNSOL_STK_SESSION_END: ret = responseVoid(p); break; @@ -2176,13 +2295,18 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_UNSOL_STK_CALL_SETUP: ret = responseInts(p); break; case RIL_UNSOL_SIM_SMS_STORAGE_FULL: ret = responseVoid(p); break; case RIL_UNSOL_SIM_REFRESH: ret = responseInts(p); break; - case RIL_UNSOL_CALL_RING: ret = responseVoid(p); break; + case RIL_UNSOL_CALL_RING: ret = responseCallRing(p); break; case RIL_UNSOL_RESTRICTED_STATE_CHANGED: ret = responseInts(p); break; case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: ret = responseVoid(p); break; case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS: ret = responseCdmaSms(p); break; case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: ret = responseString(p); break; case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL: ret = responseVoid(p); break; + case RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE: ret = responseVoid(p); break; + case RIL_UNSOL_CDMA_CALL_WAITING: ret = responseCdmaCallWaiting(p); break; + case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS: ret = responseInts(p); break; + case RIL_UNSOL_CDMA_INFO_REC: ret = responseCdmaInformationRecord(p); break; case RIL_UNSOL_OEM_HOOK_RAW: ret = responseRaw(p); break; + default: throw new RuntimeException("Unrecognized unsol response: " + response); //break; (implied) @@ -2366,10 +2490,11 @@ public final class RIL extends BaseCommands implements CommandsInterface { break; case RIL_UNSOL_CALL_RING: - if (RILJ_LOGD) unsljLog(response); + if (RILJ_LOGD) unsljLogRet(response, ret); if (mRingRegistrant != null) { - mRingRegistrant.notifyRegistrant(); + mRingRegistrant.notifyRegistrant( + new AsyncResult (null, ret, null)); } break; @@ -2381,12 +2506,16 @@ public final class RIL extends BaseCommands implements CommandsInterface { } case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: + if (RILJ_LOGD) unsljLog(response); + if (mIccStatusChangedRegistrants != null) { mIccStatusChangedRegistrants.notifyRegistrants(); } break; case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS: + if (RILJ_LOGD) unsljLog(response); + SmsMessage sms = (SmsMessage) ret; if (mSMSRegistrant != null) { @@ -2396,19 +2525,64 @@ public final class RIL extends BaseCommands implements CommandsInterface { break; case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: - // TODO T: waiting for SMS BC feature + if (RILJ_LOGD) unsljLog(response); + + if (mGsmBroadcastSmsRegistrant != null) { + mGsmBroadcastSmsRegistrant + .notifyRegistrant(new AsyncResult(null, ret, null)); + } break; case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL: - if (Config.LOGD) { - if (RILJ_LOGD) riljLog("[UNSL]< RUIM_SMS_STORAGE_FULL"); - } + if (RILJ_LOGD) unsljLog(response); if (mIccSmsFullRegistrant != null) { mIccSmsFullRegistrant.notifyRegistrant(); } break; + case RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE: + if (RILJ_LOGD) unsljLog(response); + + if (mEmergencyCallbackModeRegistrant != null) { + mEmergencyCallbackModeRegistrant.notifyRegistrant(); + } + break; + + case RIL_UNSOL_CDMA_CALL_WAITING: + if (RILJ_LOGD) unsljLog(response); + + if (mCallWaitingInfoRegistrants != null) { + mCallWaitingInfoRegistrants.notifyRegistrants( + new AsyncResult (null, ret, null)); + } + break; + + case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS: + if (RILJ_LOGD) unsljLogRet(response, ret); + + if (mOtaProvisionRegistrants != null) { + mOtaProvisionRegistrants.notifyRegistrants( + new AsyncResult (null, ret, null)); + } + break; + + case RIL_UNSOL_CDMA_INFO_REC: + ArrayList<CdmaInformationRecords> listInfoRecs; + + try { + listInfoRecs = (ArrayList<CdmaInformationRecords>)ret; + } catch (ClassCastException e) { + Log.e(LOG_TAG, "Unexpected exception casting to listInfoRecs", e); + break; + } + + for (CdmaInformationRecords rec : listInfoRecs) { + if (RILJ_LOGD) unsljLogRet(response, rec); + notifyRegistrantsCdmaInfoRec(rec); + } + break; + case RIL_UNSOL_OEM_HOOK_RAW: if (RILJ_LOGD) unsljLogvRet(response, IccUtils.bytesToHexString((byte[])ret)); if (mUnsolOemHookRawRegistrant != null) { @@ -2524,13 +2698,14 @@ public final class RIL extends BaseCommands implements CommandsInterface { private Object responseSMS(Parcel p) { - int messageRef; + int messageRef, errorCode; String ackPDU; messageRef = p.readInt(); ackPDU = p.readString(); + errorCode = p.readInt(); - SmsResponse response = new SmsResponse(messageRef, ackPDU); + SmsResponse response = new SmsResponse(messageRef, ackPDU, errorCode); return response; } @@ -2547,6 +2722,11 @@ public final class RIL extends BaseCommands implements CommandsInterface { String s = p.readString(); + if (RILJ_LOGD) riljLog("< iccIO: " + + " 0x" + Integer.toHexString(sw1) + + " 0x" + Integer.toHexString(sw2) + " " + + s); + return new IccIoResult(sw1, sw2, s); } @@ -2658,33 +2838,24 @@ public final class RIL extends BaseCommands implements CommandsInterface { dc.als = p.readInt(); voiceSettings = p.readInt(); dc.isVoice = (0 == voiceSettings) ? false : true; - - //dc.isVoicePrivacy = (0 != p.readInt()); - int voicePrivacy = p.readInt(); - dc.isVoicePrivacy = (0 != voicePrivacy); - + dc.isVoicePrivacy = (0 != p.readInt()); dc.number = p.readString(); int np = p.readInt(); dc.numberPresentation = DriverCall.presentationFromCLIP(np); dc.name = p.readString(); dc.namePresentation = p.readInt(); - // Make sure there's a leading + on addresses with a TOA - // of 145 - - dc.number = PhoneNumberUtils.stringFromStringAndTOA( - dc.number, dc.TOA); + // Make sure there's a leading + on addresses with a TOA of 145 + dc.number = PhoneNumberUtils.stringFromStringAndTOA(dc.number, dc.TOA); response.add(dc); - if ( RILConstants.CDMA_VOICE_PRIVACY == voiceSettings ) { + if (dc.isVoicePrivacy) { mVoicePrivacyOnRegistrants.notifyRegistrants(); - Log.d(LOG_TAG, "InCall VoicePrivacy is enabled: " + - Integer.toString(voiceSettings)); + Log.d(LOG_TAG, "InCall VoicePrivacy is enabled"); } else { mVoicePrivacyOffRegistrants.notifyRegistrants(); - Log.d(LOG_TAG, "InCall VoicePrivacy is disabled: " + - Integer.toString(voiceSettings)); + Log.d(LOG_TAG, "InCall VoicePrivacy is disabled"); } } @@ -2696,21 +2867,21 @@ public final class RIL extends BaseCommands implements CommandsInterface { private Object responseDataCallList(Parcel p) { int num; - ArrayList<PDPContextState> response; + ArrayList<DataCallState> response; num = p.readInt(); - response = new ArrayList<PDPContextState>(num); + response = new ArrayList<DataCallState>(num); for (int i = 0; i < num; i++) { - PDPContextState pdp = new PDPContextState(); + DataCallState dataCall = new DataCallState(); - pdp.cid = p.readInt(); - pdp.active = p.readInt(); - pdp.type = p.readString(); - pdp.apn = p.readString(); - pdp.address = p.readString(); + dataCall.cid = p.readInt(); + dataCall.active = p.readInt(); + dataCall.type = p.readString(); + dataCall.apn = p.readString(); + dataCall.address = p.readString(); - response.add(pdp); + response.add(dataCall); } return response; @@ -2751,51 +2922,66 @@ public final class RIL extends BaseCommands implements CommandsInterface { response = new ArrayList<NeighboringCellInfo>(num); for (int i = 0 ; i < num ; i++) { - try { - int rssi = p.readInt(); - int cid = Integer.valueOf(p.readString(), 16); - cell = new NeighboringCellInfo(rssi, cid); - response.add(cell); - } catch ( Exception e) { - } + int rssi = p.readInt(); + int cid = Integer.valueOf(p.readString(), 16); + cell = new NeighboringCellInfo(rssi, cid); + response.add(cell); } return response; } - private Object - responseBR_SMS_CNF(Parcel p) { - // TODO - return null; + private Object responseGmsBroadcastConfig(Parcel p) { + int num; + ArrayList<SmsBroadcastConfigInfo> response; + SmsBroadcastConfigInfo info; + + num = p.readInt(); + response = new ArrayList<SmsBroadcastConfigInfo>(num); + + for (int i = 0; i < num; i++) { + int fromId = p.readInt(); + int toId = p.readInt(); + int fromScheme = p.readInt(); + int toScheme = p.readInt(); + boolean selected = (p.readInt() == 1); + + info = new SmsBroadcastConfigInfo(fromId, toId, fromScheme, + toScheme, selected); + response.add(info); + } + return response; } private Object - responseCDMA_BR_CNF(Parcel p) { + responseCdmaBroadcastConfig(Parcel p) { int numServiceCategories; int response[]; 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 int numInts; numInts = CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES * CDMA_BSI_NO_OF_INTS_STRUCT + 1; response = new int[numInts]; - // indicate that a zero length table was received - response[0] = 0; - //for all supported service categories set 'english' as default language - //and selection status to false - for (int i = 1, j = 1 - ; i <= (CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES - * CDMA_BSI_NO_OF_INTS_STRUCT) - ; i += CDMA_BSI_NO_OF_INTS_STRUCT, j++ ) { - response[i] = j; - response[i+1] = 1; - response[i+2] = 0; + // Faking a default record for all possible records. + response[0] = CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES; + + // Loop over CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES set 'english' as + // default language and selection status to false for all. + for (int i = 1; i < numInts; i += CDMA_BSI_NO_OF_INTS_STRUCT ) { + response[i + 0] = i / CDMA_BSI_NO_OF_INTS_STRUCT; + response[i + 1] = 1; + response[i + 2] = 0; } } else { int numInts; - numInts = numServiceCategories * CDMA_BSI_NO_OF_INTS_STRUCT + 1; + numInts = (numServiceCategories * CDMA_BSI_NO_OF_INTS_STRUCT) + 1; response = new int[numInts]; response[0] = numServiceCategories; @@ -2807,6 +2993,116 @@ public final class RIL extends BaseCommands implements CommandsInterface { return response; } + private Object + responseSignalStrength(Parcel p) { + int numInts = 7; + int response[]; + + /* TODO: Add SignalStrength class to match RIL_SignalStrength */ + response = new int[numInts]; + for (int i = 0 ; i < numInts ; i++) { + response[i] = p.readInt(); + } + + return response; + } + + private ArrayList<CdmaInformationRecords> + responseCdmaInformationRecord(Parcel p) { + int numberOfInfoRecs; + ArrayList<CdmaInformationRecords> response; + + /** + * Loop through all of the information records unmarshalling them + * and converting them to Java Objects. + */ + numberOfInfoRecs = p.readInt(); + response = new ArrayList<CdmaInformationRecords>(numberOfInfoRecs); + + for (int i = 0; i < numberOfInfoRecs; i++) { + CdmaInformationRecords InfoRec = new CdmaInformationRecords(p); + response.add(InfoRec); + } + + return response; + } + + private Object + responseCdmaCallWaiting(Parcel p) { + CdmaCallWaitingNotification notification = new CdmaCallWaitingNotification(); + + notification.number = p.readString(); + notification.numberPresentation = p.readInt(); + notification.name = p.readString(); + notification.namePresentation = notification.numberPresentation; + notification.isPresent = p.readInt(); + notification.signalType = p.readInt(); + notification.alertPitch = p.readInt(); + notification.signal = p.readInt(); + + return notification; + } + + private Object + responseCallRing(Parcel p){ + char response[] = new char[4]; + + response[0] = (char) p.readInt(); // isPresent + response[1] = (char) p.readInt(); // signalType + response[2] = (char) p.readInt(); // alertPitch + response[3] = (char) p.readInt(); // signal + + return response; + } + + private void + notifyRegistrantsCdmaInfoRec(CdmaInformationRecords infoRec) { + int response = RIL_UNSOL_CDMA_INFO_REC; + if (infoRec.record instanceof CdmaInformationRecords.CdmaDisplayInfoRec) { + if (mDisplayInfoRegistrants != null) { + if (RILJ_LOGD) unsljLogRet(response, infoRec.record); + mDisplayInfoRegistrants.notifyRegistrants( + new AsyncResult (null, infoRec.record, null)); + } + } else if (infoRec.record instanceof CdmaInformationRecords.CdmaSignalInfoRec) { + if (mSignalInfoRegistrants != null) { + if (RILJ_LOGD) unsljLogRet(response, infoRec.record); + mSignalInfoRegistrants.notifyRegistrants( + new AsyncResult (null, infoRec.record, null)); + } + } else if (infoRec.record instanceof CdmaInformationRecords.CdmaNumberInfoRec) { + if (mNumberInfoRegistrants != null) { + if (RILJ_LOGD) unsljLogRet(response, infoRec.record); + mNumberInfoRegistrants.notifyRegistrants( + new AsyncResult (null, infoRec.record, null)); + } + } else if (infoRec.record instanceof CdmaInformationRecords.CdmaRedirectingNumberInfoRec) { + if (mRedirNumInfoRegistrants != null) { + if (RILJ_LOGD) unsljLogRet(response, infoRec.record); + mRedirNumInfoRegistrants.notifyRegistrants( + new AsyncResult (null, infoRec.record, null)); + } + } else if (infoRec.record instanceof CdmaInformationRecords.CdmaLineControlInfoRec) { + if (mLineControlInfoRegistrants != null) { + if (RILJ_LOGD) unsljLogRet(response, infoRec.record); + mLineControlInfoRegistrants.notifyRegistrants( + new AsyncResult (null, infoRec.record, null)); + } + } else if (infoRec.record instanceof CdmaInformationRecords.CdmaT53ClirInfoRec) { + if (mT53ClirInfoRegistrants != null) { + if (RILJ_LOGD) unsljLogRet(response, infoRec.record); + mT53ClirInfoRegistrants.notifyRegistrants( + new AsyncResult (null, infoRec.record, null)); + } + } else if (infoRec.record instanceof CdmaInformationRecords.CdmaT53AudioControlInfoRec) { + if (mT53AudCntrlInfoRegistrants != null) { + if (RILJ_LOGD) unsljLogRet(response, infoRec.record); + mT53AudCntrlInfoRegistrants.notifyRegistrants( + new AsyncResult (null, infoRec.record, null)); + } + } + } + static String requestToString(int request) { /* @@ -2902,11 +3198,11 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_CDMA_BURST_DTMF: return "RIL_REQUEST_CDMA_BURST_DTMF"; case RIL_REQUEST_CDMA_SEND_SMS: return "RIL_REQUEST_CDMA_SEND_SMS"; case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE: return "RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE"; - case RIL_REQUEST_GET_BROADCAST_CONFIG: return "RIL_REQUEST_GET_BROADCAST_CONFIG"; - case RIL_REQUEST_SET_BROADCAST_CONFIG: return "RIL_REQUEST_SET_BROADCAST_CONFIG"; + case RIL_REQUEST_GSM_GET_BROADCAST_CONFIG: return "RIL_REQUEST_GSM_GET_BROADCAST_CONFIG"; + case RIL_REQUEST_GSM_SET_BROADCAST_CONFIG: return "RIL_REQUEST_GSM_SET_BROADCAST_CONFIG"; case RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG: return "RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG"; case RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG: return "RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG"; - case RIL_REQUEST_BROADCAST_ACTIVATION: return "RIL_REQUEST_BROADCAST_ACTIVATION"; + case RIL_REQUEST_GSM_BROADCAST_ACTIVATION: return "RIL_REQUEST_GSM_BROADCAST_ACTIVATION"; case RIL_REQUEST_CDMA_VALIDATE_AKEY: return "RIL_REQUEST_CDMA_VALIDATE_AKEY"; case RIL_REQUEST_CDMA_BROADCAST_ACTIVATION: return "RIL_REQUEST_CDMA_BROADCAST_ACTIVATION"; case RIL_REQUEST_CDMA_SUBSCRIPTION: return "RIL_REQUEST_CDMA_SUBSCRIPTION"; @@ -2915,6 +3211,9 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_DEVICE_IDENTITY: return "RIL_REQUEST_DEVICE_IDENTITY"; case RIL_REQUEST_GET_SMSC_ADDRESS: return "RIL_REQUEST_GET_SMSC_ADDRESS"; case RIL_REQUEST_SET_SMSC_ADDRESS: return "RIL_REQUEST_SET_SMSC_ADDRESS"; + case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE: return "REQUEST_EXIT_EMERGENCY_CALLBACK_MODE"; + case RIL_REQUEST_REPORT_SMS_MEMORY_STATUS: return "RIL_REQUEST_REPORT_SMS_MEMORY_STATUS"; + case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING: return "RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING"; default: return "<unknown request>"; } } @@ -2947,8 +3246,16 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_UNSOL_SIM_SMS_STORAGE_FULL: return "UNSOL_SIM_SMS_STORAGE_FULL"; case RIL_UNSOL_SIM_REFRESH: return "UNSOL_SIM_REFRESH"; case RIL_UNSOL_CALL_RING: return "UNSOL_CALL_RING"; - case RIL_UNSOL_RESTRICTED_STATE_CHANGED: return "RIL_UNSOL_RESTRICTED_STATE_CHANGED"; - case RIL_UNSOL_OEM_HOOK_RAW: return "RIL_UNSOL_OEM_HOOK_RAW"; + case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: return "UNSOL_RESPONSE_SIM_STATUS_CHANGED"; + case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS: return "UNSOL_RESPONSE_CDMA_NEW_SMS"; + case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: return "UNSOL_RESPONSE_NEW_BROADCAST_SMS"; + case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL: return "UNSOL_CDMA_RUIM_SMS_STORAGE_FULL"; + case RIL_UNSOL_RESTRICTED_STATE_CHANGED: return "UNSOL_RESTRICTED_STATE_CHANGED"; + case RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE: return "UNSOL_ENTER_EMERGENCY_CALLBACK_MODE"; + case RIL_UNSOL_CDMA_CALL_WAITING: return "UNSOL_CDMA_CALL_WAITING"; + case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS: return "UNSOL_CDMA_OTA_PROVISION_STATUS"; + case RIL_UNSOL_CDMA_INFO_REC: return "UNSOL_CDMA_INFO_REC"; + case RIL_UNSOL_OEM_HOOK_RAW: return "UNSOL_OEM_HOOK_RAW"; default: return "<unknown reponse>"; } } @@ -3048,7 +3355,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { /** * {@inheritDoc} */ - public void queryTTYModeEnabled(Message response) { + public void queryTTYMode(Message response) { RILRequest rr = RILRequest.obtain( RILConstants.RIL_REQUEST_QUERY_TTY_MODE, response); @@ -3058,12 +3365,12 @@ public final class RIL extends BaseCommands implements CommandsInterface { /** * {@inheritDoc} */ - public void setTTYModeEnabled(boolean enable, Message response) { + public void setTTYMode(int ttyMode, Message response) { RILRequest rr = RILRequest.obtain( RILConstants.RIL_REQUEST_SET_TTY_MODE, response); rr.mp.writeInt(1); - rr.mp.writeInt(enable ? 1 : 0); + rr.mp.writeInt(ttyMode); send(rr); } @@ -3075,7 +3382,6 @@ public final class RIL extends BaseCommands implements CommandsInterface { sendCDMAFeatureCode(String FeatureCode, Message response) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_FLASH, response); - rr.mp.writeInt(1); rr.mp.writeString(FeatureCode); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) @@ -3090,11 +3396,11 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } + // TODO: Change the configValuesArray to a RIL_BroadcastSMSConfig public void setCdmaBroadcastConfig(int[] configValuesArray, Message response) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG, response); - rr.mp.writeInt(configValuesArray[0]); - for(int i = 1; i <= (configValuesArray[0] * 3); i++) { + for(int i = 0; i < configValuesArray.length; i++) { rr.mp.writeInt(configValuesArray[i]); } @@ -3103,11 +3409,22 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void activateCdmaBroadcastSms(int activate, Message response) { + public void setCdmaBroadcastActivation(boolean activate, Message response) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_BROADCAST_ACTIVATION, response); rr.mp.writeInt(1); - rr.mp.writeInt(activate); + rr.mp.writeInt(activate ? 0 :1); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void exitEmergencyCallbackMode(Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, response); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index bcf5141..b2e16c7 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -16,6 +16,13 @@ package com.android.internal.telephony; +/** + * TODO: This should probably not be an interface see + * http://www.javaworld.com/javaworld/javaqa/2001-06/01-qa-0608-constants.html and google with + * http://www.google.com/search?q=interface+constants&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:en-US:unofficial&client=firefox-a + * + * Also they should all probably be static final. + */ /** * {@hide} @@ -51,7 +58,7 @@ public interface RILConstants { int NETWORK_MODE_EVDO_NO_CDMA = 6; /* EvDo only */ int NETWORK_MODE_GLOBAL = 7; /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL) AVAILABLE Application Settings menu*/ - int PREFERRED_NETWORK_MODE = NETWORK_MODE_GSM_ONLY; + int PREFERRED_NETWORK_MODE = NETWORK_MODE_WCDMA_PREF; /* CDMA subscription source. See ril.h RIL_REQUEST_CDMA_SET_SUBSCRIPTION */ int SUBSCRIPTION_FROM_RUIM = 0; /* CDMA subscription from RUIM when available */ @@ -67,8 +74,9 @@ public interface RILConstants { int CDM_TTY_MODE_DISABLED = 0; int CDM_TTY_MODE_ENABLED = 1; - byte CDMA_VOICE_PRIVACY = 0x70; /* "p" value used in Ril_Call.isVoice if Privacy - is active */ + int CDM_TTY_FULL_MODE = 1; + int CDM_TTY_HCO_MODE = 2; + int CDM_TTY_VCO_MODE = 3; /* cat include/telephony/ril.h | \ @@ -198,9 +206,9 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_CDMA_VALIDATE_AKEY = 86; int RIL_REQUEST_CDMA_SEND_SMS = 87; int RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE = 88; - int RIL_REQUEST_GET_BROADCAST_CONFIG = 89; - int RIL_REQUEST_SET_BROADCAST_CONFIG = 90; - int RIL_REQUEST_BROADCAST_ACTIVATION = 91; + int RIL_REQUEST_GSM_GET_BROADCAST_CONFIG = 89; + int RIL_REQUEST_GSM_SET_BROADCAST_CONFIG = 90; + int RIL_REQUEST_GSM_BROADCAST_ACTIVATION = 91; int RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG = 92; int RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG = 93; int RIL_REQUEST_CDMA_BROADCAST_ACTIVATION = 94; @@ -208,8 +216,11 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM = 96; int RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM = 97; int RIL_REQUEST_DEVICE_IDENTITY = 98; + int RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE = 99; int RIL_REQUEST_GET_SMSC_ADDRESS = 100; int RIL_REQUEST_SET_SMSC_ADDRESS = 101; + int RIL_REQUEST_REPORT_SMS_MEMORY_STATUS = 102; + int RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING = 103; int RIL_UNSOL_RESPONSE_BASE = 1000; int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000; int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001; diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java index f2bd361..890ea63 100644 --- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java @@ -20,11 +20,13 @@ import android.app.Activity; import android.app.PendingIntent; import android.app.AlertDialog; import android.app.PendingIntent.CanceledException; +import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.DialogInterface; +import android.content.IntentFilter; import android.content.res.Resources; import android.database.Cursor; import android.database.SQLException; @@ -32,6 +34,7 @@ import android.net.Uri; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; +import android.os.PowerManager; import android.provider.Telephony; import android.provider.Telephony.Sms.Intents; import android.provider.Settings; @@ -75,6 +78,7 @@ public abstract class SMSDispatcher extends Handler { protected static final String[] RAW_PROJECTION = new String[] { "pdu", "sequence", + "destination_port", }; static final int MAIL_SEND_SMS = 1; @@ -113,7 +117,7 @@ public abstract class SMSDispatcher extends Handler { /** Maximum number of times to retry sending a failed SMS. */ private static final int MAX_SEND_RETRIES = 3; /** Delay before next send attempt on a failed SMS, in milliseconds. */ - private static final int SEND_RETRY_DELAY = 2000; + private static final int SEND_RETRY_DELAY = 2000; /** single part SMS */ private static final int SINGLE_PART_SMS = 1; @@ -122,15 +126,30 @@ public abstract class SMSDispatcher extends Handler { * CONCATENATED_16_BIT_REFERENCE message set. Should be * incremented for each set of concatenated messages. */ - protected static int sConcatenatedRef; + private static int sConcatenatedRef; private SmsCounter mCounter; private SmsTracker mSTracker; + /** Wake lock to ensure device stays awake while dispatching the SMS intent. */ + private PowerManager.WakeLock mWakeLock; + + /** + * Hold the wake lock for 5 seconds, which should be enough time for + * any receiver(s) to grab its own wake lock. + */ + private final int WAKE_LOCK_TIMEOUT = 5000; + private static SmsMessage mSmsMessage; private static SmsMessageBase mSmsMessageBase; private SmsMessageBase.SubmitPduBase mSubmitPduBase; + private boolean mStorageAvailable = true; + + protected static int getNextConcatenatedRef() { + sConcatenatedRef += 1; + return sConcatenatedRef; + } /** * Implement the per-application based SMS control, which only allows @@ -155,11 +174,11 @@ public abstract class SMSDispatcher extends Handler { /** * Check to see if an application allow to send new SMS messages - * + * * @param appName is the application sending sms * @param smsWaiting is the number of new sms wants to be sent - * @return true if application is allowed to send the requested number - * of new sms messages + * @return true if application is allowed to send the requested number + * of new sms messages */ boolean check(String appName, int smsWaiting) { if (!mSmsStamp.containsKey(appName)) { @@ -178,7 +197,7 @@ public abstract class SMSDispatcher extends Handler { sent.remove(0); } - + if ( (sent.size() + smsWaiting) <= mMaxAllowed) { for (int i = 0; i < smsWaiting; i++ ) { sent.add(ct); @@ -191,14 +210,16 @@ public abstract class SMSDispatcher extends Handler { protected SMSDispatcher(PhoneBase phone) { mPhone = phone; - mWapPush = new WapPushOverSms(phone); + mWapPush = new WapPushOverSms(phone, this); mContext = phone.getContext(); mResolver = mContext.getContentResolver(); mCm = phone.mCM; mSTracker = null; + createWakelock(); + int check_period = Settings.Gservices.getInt(mResolver, - Settings.Gservices.SMS_OUTGOING_CEHCK_INTERVAL_MS, + Settings.Gservices.SMS_OUTGOING_CHECK_INTERVAL_MS, DEFAULT_SMS_CHECK_PERIOD); int max_count = Settings.Gservices.getInt(mResolver, Settings.Gservices.SMS_OUTGOING_CEHCK_MAX_COUNT, @@ -211,6 +232,15 @@ public abstract class SMSDispatcher extends Handler { // Don't always start message ref at 0. sConcatenatedRef = new Random().nextInt(256); + + // Register for device storage intents. Use these to notify the RIL + // that storage for SMS is or is not available. + // TODO: Revisit this for a later release. Storage reporting should + // rely more on application indication. + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW); + filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK); + mContext.registerReceiver(mResultReceiver, filter); } public void dispose() { @@ -252,16 +282,27 @@ public abstract class SMSDispatcher extends Handler { ar = (AsyncResult) msg.obj; - // FIXME only acknowledge on store - acknowledgeLastIncomingSms(true, null); - if (ar.exception != null) { Log.e(TAG, "Exception processing incoming SMS. Exception:" + ar.exception); return; } sms = (SmsMessage) ar.result; - dispatchMessage(sms.mWrappedSmsMessage); + try { + if (mStorageAvailable) { + int result = dispatchMessage(sms.mWrappedSmsMessage); + if (result != Activity.RESULT_OK) { + // RESULT_OK means that message was broadcast for app(s) to handle. + // Any other result, we should ack here. + boolean handled = (result == Intents.RESULT_SMS_HANDLED); + acknowledgeLastIncomingSms(handled, result, null); + } + } else { + acknowledgeLastIncomingSms(false, Intents.RESULT_SMS_OUT_OF_MEMORY, null); + } + } catch (RuntimeException ex) { + acknowledgeLastIncomingSms(false, Intents.RESULT_SMS_GENERIC_ERROR, null); + } break; @@ -298,13 +339,35 @@ public abstract class SMSDispatcher extends Handler { sendMultipartSms(mSTracker); } else { sendSms(mSTracker); - } + } mSTracker = null; } break; } } + private void createWakelock() { + PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SMSDispatcher"); + mWakeLock.setReferenceCounted(true); + } + + /** + * Grabs a wake lock and sends intent as an ordered broadcast. + * The resultReceiver will check for errors and ACK/NACK back + * to the RIL. + * + * @param intent intent to broadcast + * @param permission Receivers are required to have this permission + */ + void dispatch(Intent intent, String permission) { + // Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any + // receivers time to take their own wake locks. + mWakeLock.acquire(WAKE_LOCK_TIMEOUT); + mContext.sendOrderedBroadcast(intent, permission, mResultReceiver, + this, Activity.RESULT_OK, null, null); + } + /** * Called when SIM_FULL message is received from the RIL. Notifies interested * parties that SIM storage for SMS messages is full. @@ -312,7 +375,8 @@ public abstract class SMSDispatcher extends Handler { private void handleIccFull(){ // broadcast SIM_FULL intent Intent intent = new Intent(Intents.SIM_FULL_ACTION); - mPhone.getContext().sendBroadcast(intent, "android.permission.RECEIVE_SMS"); + mWakeLock.acquire(WAKE_LOCK_TIMEOUT); + mContext.sendBroadcast(intent, "android.permission.RECEIVE_SMS"); } /** @@ -412,19 +476,28 @@ public abstract class SMSDispatcher extends Handler { * Dispatches an incoming SMS messages. * * @param sms the incoming message from the phone + * @return a result code from {@link Telephony.Sms.Intents}, or + * {@link Activity#RESULT_OK} if the message has been broadcast + * to applications */ - protected abstract void dispatchMessage(SmsMessageBase sms); + protected abstract int dispatchMessage(SmsMessageBase sms); /** * If this is the last part send the parts out to the application, otherwise * the part is stored for later processing. + * + * NOTE: concatRef (naturally) needs to be non-null, but portAddrs can be null. + * @return a result code from {@link Telephony.Sms.Intents}, or + * {@link Activity#RESULT_OK} if the message has been broadcast + * to applications */ - protected void processMessagePart(SmsMessageBase sms, int referenceNumber, - int sequence, int count, int destinationPort) { + protected int processMessagePart(SmsMessageBase sms, + SmsHeader.ConcatRef concatRef, SmsHeader.PortAddrs portAddrs) { + // Lookup all other related parts StringBuilder where = new StringBuilder("reference_number ="); - where.append(referenceNumber); + where.append(concatRef.refNumber); where.append(" AND address = ?"); String[] whereArgs = new String[] {sms.getOriginatingAddress()}; @@ -433,28 +506,27 @@ public abstract class SMSDispatcher extends Handler { try { cursor = mResolver.query(mRawUri, RAW_PROJECTION, where.toString(), whereArgs, null); int cursorCount = cursor.getCount(); - if (cursorCount != count - 1) { + if (cursorCount != concatRef.msgCount - 1) { // We don't have all the parts yet, store this one away ContentValues values = new ContentValues(); values.put("date", new Long(sms.getTimestampMillis())); values.put("pdu", HexDump.toHexString(sms.getPdu())); values.put("address", sms.getOriginatingAddress()); - values.put("reference_number", referenceNumber); - values.put("count", count); - values.put("sequence", sequence); - if (destinationPort != -1) { - values.put("destination_port", destinationPort); + values.put("reference_number", concatRef.refNumber); + values.put("count", concatRef.msgCount); + values.put("sequence", concatRef.seqNumber); + if (portAddrs != null) { + values.put("destination_port", portAddrs.destPort); } mResolver.insert(mRawUri, values); - - return; + return Intents.RESULT_SMS_HANDLED; } // All the parts are in place, deal with them int pduColumn = cursor.getColumnIndex("pdu"); int sequenceColumn = cursor.getColumnIndex("sequence"); - pdus = new byte[count][]; + pdus = new byte[concatRef.msgCount][]; for (int i = 0; i < cursorCount; i++) { cursor.moveToNext(); int cursorSequence = (int)cursor.getLong(sequenceColumn); @@ -462,43 +534,48 @@ public abstract class SMSDispatcher extends Handler { cursor.getString(pduColumn)); } // This one isn't in the DB, so add it - pdus[sequence - 1] = sms.getPdu(); + pdus[concatRef.seqNumber - 1] = sms.getPdu(); // Remove the parts from the database mResolver.delete(mRawUri, where.toString(), whereArgs); } catch (SQLException e) { Log.e(TAG, "Can't access multipart SMS database", e); - return; // TODO: NACK the message or something, don't just discard. + // TODO: Would OUT_OF_MEMORY be more appropriate? + return Intents.RESULT_SMS_GENERIC_ERROR; } finally { if (cursor != null) cursor.close(); } + /** + * TODO(cleanup): The following code has duplicated logic with + * the radio-specific dispatchMessage code, which is fragile, + * in addition to being redundant. Instead, if this method + * maybe returned the reassembled message (or just contents), + * the following code (which is not really related to + * reconstruction) could be better consolidated. + */ + // Dispatch the PDUs to applications - switch (destinationPort) { - case SmsHeader.PORT_WAP_PUSH: { - // Build up the data stream - ByteArrayOutputStream output = new ByteArrayOutputStream(); - for (int i = 0; i < count; i++) { - SmsMessage msg = SmsMessage.createFromPdu(pdus[i]); - byte[] data = msg.getUserData(); - output.write(data, 0, data.length); + if (portAddrs != null) { + if (portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) { + // Build up the data stream + ByteArrayOutputStream output = new ByteArrayOutputStream(); + for (int i = 0; i < concatRef.msgCount; i++) { + SmsMessage msg = SmsMessage.createFromPdu(pdus[i]); + byte[] data = msg.getUserData(); + output.write(data, 0, data.length); + } + // Handle the PUSH + return mWapPush.dispatchWapPdu(output.toByteArray()); + } else { + // The messages were sent to a port, so concoct a URI for it + dispatchPortAddressedPdus(pdus, portAddrs.destPort); } - - // Handle the PUSH - mWapPush.dispatchWapPdu(output.toByteArray()); - break; - } - - case -1: + } else { // The messages were not sent to a port dispatchPdus(pdus); - break; - - default: - // The messages were sent to a port, so concoct a URI for it - dispatchPortAddressedPdus(pdus, destinationPort); - break; } + return Activity.RESULT_OK; } /** @@ -509,8 +586,7 @@ public abstract class SMSDispatcher extends Handler { protected void dispatchPdus(byte[][] pdus) { Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION); intent.putExtra("pdus", pdus); - mPhone.getContext().sendBroadcast( - intent, "android.permission.RECEIVE_SMS"); + dispatch(intent, "android.permission.RECEIVE_SMS"); } /** @@ -523,8 +599,7 @@ public abstract class SMSDispatcher extends Handler { Uri uri = Uri.parse("sms://localhost:" + port); Intent intent = new Intent(Intents.DATA_SMS_RECEIVED_ACTION, uri); intent.putExtra("pdus", pdus); - mPhone.getContext().sendBroadcast( - intent, "android.permission.RECEIVE_SMS"); + dispatch(intent, "android.permission.RECEIVE_SMS"); } @@ -649,7 +724,7 @@ public abstract class SMSDispatcher extends Handler { /** * Send the multi-part SMS based on multipart Sms tracker - * + * * @param tracker holds the multipart Sms tracker ready to be sent */ protected abstract void sendMultipartSms (SmsTracker tracker); @@ -688,13 +763,15 @@ public abstract class SMSDispatcher extends Handler { /** * Send an acknowledge message. * @param success indicates that last message was successfully received. + * @param result result code indicating any error * @param response callback message sent when operation completes. */ - protected abstract void acknowledgeLastIncomingSms(boolean success, Message response); + protected abstract void acknowledgeLastIncomingSms(boolean success, + int result, Message response); /** * Check if a SmsTracker holds multi-part Sms - * + * * @param tracker a SmsTracker could hold a multi-part Sms * @return true for tracker holds Multi-parts Sms */ @@ -725,7 +802,7 @@ public abstract class SMSDispatcher extends Handler { mRetryCount = 0; } } - + protected SmsTracker SmsTrackerFactory(HashMap data, PendingIntent sentIntent, PendingIntent deliveryIntent) { return new SmsTracker(data, sentIntent, deliveryIntent); @@ -741,4 +818,28 @@ public abstract class SMSDispatcher extends Handler { } } }; + + private BroadcastReceiver mResultReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Intent.ACTION_DEVICE_STORAGE_LOW)) { + mStorageAvailable = false; + mCm.reportSmsMemoryStatus(false, null); + } else if (intent.getAction().equals(Intent.ACTION_DEVICE_STORAGE_OK)) { + mStorageAvailable = true; + mCm.reportSmsMemoryStatus(true, null); + } else { + // Assume the intent is one of the SMS receive intents that + // was sent as an ordered broadcast. Check result and ACK. + int rc = getResultCode(); + boolean success = (rc == Activity.RESULT_OK) + || (rc == Intents.RESULT_SMS_HANDLED); + + // For a multi-part message, this only ACKs the last part. + // Previous parts were ACK'd as they were received. + acknowledgeLastIncomingSms(success, rc, null); + } + } + + }; } diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java index 7274e99..bdcf3f7 100644 --- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java @@ -22,6 +22,7 @@ import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; import android.telephony.ServiceState; +import android.telephony.SignalStrength; /** * {@hide} @@ -50,6 +51,8 @@ public abstract class ServiceStateTracker extends Handler { public ServiceState ss; protected ServiceState newSS; + public SignalStrength mSignalStrength; + // Used as a unique identifier to track requests associated with a poll // and ignore stale responses.The value is a count-down of expected responses // in this pollingContext @@ -104,13 +107,15 @@ public abstract class ServiceStateTracker extends Handler { protected static final int EVENT_POLL_STATE_OPERATOR_CDMA = 25; protected static final int EVENT_RUIM_READY = 26; protected static final int EVENT_RUIM_RECORDS_LOADED = 27; - protected static final int EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA = 28; - protected static final int EVENT_POLL_SIGNAL_STRENGTH_CDMA = 29; - protected static final int EVENT_GET_SIGNAL_STRENGTH_CDMA = 30; - protected static final int EVENT_NETWORK_STATE_CHANGED_CDMA = 31; - protected static final int EVENT_GET_LOC_DONE_CDMA = 32; - protected static final int EVENT_SIGNAL_STRENGTH_UPDATE_CDMA = 33; - protected static final int EVENT_NV_LOADED = 34; + protected static final int EVENT_POLL_SIGNAL_STRENGTH_CDMA = 28; + protected static final int EVENT_GET_SIGNAL_STRENGTH_CDMA = 29; + protected static final int EVENT_NETWORK_STATE_CHANGED_CDMA = 30; + protected static final int EVENT_GET_LOC_DONE_CDMA = 31; + protected static final int EVENT_SIGNAL_STRENGTH_UPDATE_CDMA = 32; + protected static final int EVENT_NV_LOADED = 33; + protected static final int EVENT_POLL_STATE_CDMA_SUBSCRIPTION = 34; + protected static final int EVENT_NV_READY = 35; + protected static final int EVENT_ERI_FILE_LOADED = 36; //***** Time Zones protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; @@ -142,12 +147,18 @@ public abstract class ServiceStateTracker extends Handler { "uk", // U.K }; + //***** Registration denied reason + protected static final String REGISTRATION_DENIED_GEN = "General"; + protected static final String REGISTRATION_DENIED_AUTH = "Authentication Failure"; //***** Constructors public ServiceStateTracker() { } + public boolean getDesiredPowerState() { + return mDesiredPowerState; + } /** * Registration point for combined roaming on diff --git a/telephony/java/com/android/internal/telephony/SmsHeader.java b/telephony/java/com/android/internal/telephony/SmsHeader.java index 64b884e..7872eec 100644 --- a/telephony/java/com/android/internal/telephony/SmsHeader.java +++ b/telephony/java/com/android/internal/telephony/SmsHeader.java @@ -16,227 +16,242 @@ package com.android.internal.telephony; +import android.telephony.SmsMessage; + import com.android.internal.util.HexDump; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + import java.util.ArrayList; /** - * This class represents a SMS user data header. - * + * SMS user data header, as specified in TS 23.040 9.2.3.24. */ public class SmsHeader { - /** See TS 23.040 9.2.3.24 for description of this element ID. */ - public static final int CONCATENATED_8_BIT_REFERENCE = 0x00; - /** See TS 23.040 9.2.3.24 for description of this element ID. */ - public static final int SPECIAL_SMS_MESSAGE_INDICATION = 0x01; - /** See TS 23.040 9.2.3.24 for description of this element ID. */ - public static final int APPLICATION_PORT_ADDRESSING_8_BIT = 0x04; - /** See TS 23.040 9.2.3.24 for description of this element ID. */ - public static final int APPLICATION_PORT_ADDRESSING_16_BIT= 0x05; - /** See TS 23.040 9.2.3.24 for description of this element ID. */ - public static final int CONCATENATED_16_BIT_REFERENCE = 0x08; - public static final int PORT_WAP_PUSH = 2948; - public static final int PORT_WAP_WSP = 9200; + // TODO(cleanup): this datastructure is generally referred to as + // the 'user data header' or UDH, and so the class name should + // change to reflect this... - private byte[] m_data; - private ArrayList<Element> m_elements = new ArrayList<Element>(); - public int nbrOfHeaders; - - /** - * Creates an SmsHeader object from raw user data header bytes. - * - * @param data is user data header bytes - * @return an SmsHeader object + /** SMS user data header information element identifiers. + * (see TS 23.040 9.2.3.24) */ - public static SmsHeader parse(byte[] data) { - SmsHeader header = new SmsHeader(); - header.m_data = data; - - int index = 0; - header.nbrOfHeaders = 0; - while (index < data.length) { - int id = data[index++] & 0xff; - int length = data[index++] & 0xff; - byte[] elementData = new byte[length]; - System.arraycopy(data, index, elementData, 0, length); - header.add(new Element(id, elementData)); - index += length; - header.nbrOfHeaders++; - } + public static final int ELT_ID_CONCATENATED_8_BIT_REFERENCE = 0x00; + public static final int ELT_ID_SPECIAL_SMS_MESSAGE_INDICATION = 0x01; + public static final int ELT_ID_APPLICATION_PORT_ADDRESSING_8_BIT = 0x04; + public static final int ELT_ID_APPLICATION_PORT_ADDRESSING_16_BIT = 0x05; + public static final int ELT_ID_SMSC_CONTROL_PARAMS = 0x06; + public static final int ELT_ID_UDH_SOURCE_INDICATION = 0x07; + public static final int ELT_ID_CONCATENATED_16_BIT_REFERENCE = 0x08; + public static final int ELT_ID_WIRELESS_CTRL_MSG_PROTOCOL = 0x09; + public static final int ELT_ID_TEXT_FORMATTING = 0x0A; + public static final int ELT_ID_PREDEFINED_SOUND = 0x0B; + public static final int ELT_ID_USER_DEFINED_SOUND = 0x0C; + public static final int ELT_ID_PREDEFINED_ANIMATION = 0x0D; + public static final int ELT_ID_LARGE_ANIMATION = 0x0E; + public static final int ELT_ID_SMALL_ANIMATION = 0x0F; + public static final int ELT_ID_LARGE_PICTURE = 0x10; + public static final int ELT_ID_SMALL_PICTURE = 0x11; + public static final int ELT_ID_VARIABLE_PICTURE = 0x12; + public static final int ELT_ID_USER_PROMPT_INDICATOR = 0x13; + public static final int ELT_ID_EXTENDED_OBJECT = 0x14; + public static final int ELT_ID_REUSED_EXTENDED_OBJECT = 0x15; + public static final int ELT_ID_COMPRESSION_CONTROL = 0x16; + public static final int ELT_ID_OBJECT_DISTR_INDICATOR = 0x17; + public static final int ELT_ID_STANDARD_WVG_OBJECT = 0x18; + public static final int ELT_ID_CHARACTER_SIZE_WVG_OBJECT = 0x19; + public static final int ELT_ID_EXTENDED_OBJECT_DATA_REQUEST_CMD = 0x1A; + public static final int ELT_ID_RFC_822_EMAIL_HEADER = 0x20; + public static final int ELT_ID_HYPERLINK_FORMAT_ELEMENT = 0x21; + public static final int ELT_ID_REPLY_ADDRESS_ELEMENT = 0x22; + public static final int ELT_ID_ENHANCED_VOICE_MAIL_INFORMATION = 0x23; - return header; - } + public static final int PORT_WAP_PUSH = 2948; + public static final int PORT_WAP_WSP = 9200; - public SmsHeader() { } + public static class PortAddrs { + public int destPort; + public int origPort; + public boolean areEightBits; + } - /** - * Returns the list of SmsHeader Elements that make up the header. - * - * @return the list of SmsHeader Elements. - */ - public ArrayList<Element> getElements() { - return m_elements; + public static class ConcatRef { + public int refNumber; + public int seqNumber; + public int msgCount; + public boolean isEightBits; } /** - * Add an element to the SmsHeader. - * - * @param element to add. + * A header element that is not explicitly parsed, meaning not + * PortAddrs or ConcatRef. */ - public void add(Element element) { - m_elements.add(element); + public static class MiscElt { + public int id; + public byte[] data; } - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - - builder.append("UDH LENGTH: " + m_data.length + " octets"); - builder.append("UDH: "); - builder.append(HexDump.toHexString(m_data)); - builder.append("\n"); - - for (Element e : getElements()) { - builder.append(" 0x" + HexDump.toHexString((byte)e.getID()) + " - "); - switch (e.getID()) { - case CONCATENATED_8_BIT_REFERENCE: { - builder.append("Concatenated Short Message 8bit ref\n"); - byte[] data = e.getData(); - builder.append(" " + data.length + " (0x"); - builder.append(HexDump.toHexString((byte)data.length) - + ") Bytes - Information Element\n"); - builder.append(" " + data[0] + " : SM reference number\n"); - builder.append(" " + data[1] + " : number of messages\n"); - builder.append(" " + data[2] + " : this SM sequence number\n"); - break; - } - - case CONCATENATED_16_BIT_REFERENCE: { - builder.append("Concatenated Short Message 16bit ref\n"); - byte[] data = e.getData(); - builder.append(" " + data.length + " (0x"); - builder.append(HexDump.toHexString((byte)data.length) - + ") Bytes - Information Element\n"); - builder.append(" " + (data[0] & 0xff) * 256 + (data[1] & 0xff) - + " : SM reference number\n"); - builder.append(" " + data[2] + " : number of messages\n"); - builder.append(" " + data[3] + " : this SM sequence number\n"); - break; - } - - case APPLICATION_PORT_ADDRESSING_8_BIT: - { - builder.append("Application port addressing 8bit\n"); - byte[] data = e.getData(); - - builder.append(" " + data.length + " (0x"); - builder.append(HexDump.toHexString( - (byte)data.length) + ") Bytes - Information Element\n"); - - int source = (data[0] & 0xff); - builder.append(" " + source + " : DESTINATION port\n"); - - int dest = (data[1] & 0xff); - builder.append(" " + dest + " : SOURCE port\n"); - break; - } - - case APPLICATION_PORT_ADDRESSING_16_BIT: { - builder.append("Application port addressing 16bit\n"); - byte[] data = e.getData(); - - builder.append(" " + data.length + " (0x"); - builder.append(HexDump.toHexString((byte)data.length) - + ") Bytes - Information Element\n"); + public PortAddrs portAddrs; + public ConcatRef concatRef; + public ArrayList<MiscElt> miscEltList = new ArrayList<MiscElt>(); - int source = (data[0] & 0xff) << 8; - source |= (data[1] & 0xff); - builder.append(" " + source + " : DESTINATION port\n"); + public SmsHeader() {} - int dest = (data[2] & 0xff) << 8; - dest |= (data[3] & 0xff); - builder.append(" " + dest + " : SOURCE port\n"); - break; + /** + * Create structured SmsHeader object from serialized byte array representation. + * (see TS 23.040 9.2.3.24) + * @param data is user data header bytes + * @return SmsHeader object + */ + public static SmsHeader fromByteArray(byte[] data) { + ByteArrayInputStream inStream = new ByteArrayInputStream(data); + SmsHeader smsHeader = new SmsHeader(); + while (inStream.available() > 0) { + /** + * NOTE: as defined in the spec, ConcatRef and PortAddr + * fields should not reoccur, but if they do the last + * occurrence is to be used. Also, for ConcatRef + * elements, if the count is zero, sequence is zero, or + * sequence is larger than count, the entire element is to + * be ignored. + */ + int id = inStream.read(); + int length = inStream.read(); + ConcatRef concatRef; + PortAddrs portAddrs; + switch (id) { + case ELT_ID_CONCATENATED_8_BIT_REFERENCE: + concatRef = new ConcatRef(); + concatRef.refNumber = inStream.read(); + concatRef.msgCount = inStream.read(); + concatRef.seqNumber = inStream.read(); + concatRef.isEightBits = true; + if (concatRef.msgCount != 0 && concatRef.seqNumber != 0 && + concatRef.seqNumber <= concatRef.msgCount) { + smsHeader.concatRef = concatRef; } - - default: { - builder.append("Unknown element\n"); - break; + break; + case ELT_ID_CONCATENATED_16_BIT_REFERENCE: + concatRef = new ConcatRef(); + concatRef.refNumber = (inStream.read() << 8) | inStream.read(); + concatRef.msgCount = inStream.read(); + concatRef.seqNumber = inStream.read(); + concatRef.isEightBits = false; + if (concatRef.msgCount != 0 && concatRef.seqNumber != 0 && + concatRef.seqNumber <= concatRef.msgCount) { + smsHeader.concatRef = concatRef; } + break; + case ELT_ID_APPLICATION_PORT_ADDRESSING_8_BIT: + portAddrs = new PortAddrs(); + portAddrs.destPort = inStream.read(); + portAddrs.origPort = inStream.read(); + portAddrs.areEightBits = true; + smsHeader.portAddrs = portAddrs; + break; + case ELT_ID_APPLICATION_PORT_ADDRESSING_16_BIT: + portAddrs = new PortAddrs(); + portAddrs.destPort = (inStream.read() << 8) | inStream.read(); + portAddrs.origPort = (inStream.read() << 8) | inStream.read(); + portAddrs.areEightBits = false; + smsHeader.portAddrs = portAddrs; + break; + default: + MiscElt miscElt = new MiscElt(); + miscElt.id = id; + miscElt.data = new byte[length]; + inStream.read(miscElt.data, 0, length); + smsHeader.miscEltList.add(miscElt); } } - - return builder.toString(); - } - - private int calcSize() { - int size = 1; // +1 for the UDHL field - for (Element e : m_elements) { - size += e.getData().length; - size += 2; // 1 byte ID, 1 byte length - } - - return size; + return smsHeader; } /** - * Converts SmsHeader object to a byte array as specified in TS 23.040 9.2.3.24. + * Create serialized byte array representation from structured SmsHeader object. + * (see TS 23.040 9.2.3.24) * @return Byte array representing the SmsHeader */ - public byte[] toByteArray() { - if (m_elements.size() == 0) return null; - - if (m_data == null) { - int size = calcSize(); - int cur = 1; - m_data = new byte[size]; - - m_data[0] = (byte) (size-1); // UDHL does not include itself - - for (Element e : m_elements) { - int length = e.getData().length; - m_data[cur++] = (byte) e.getID(); - m_data[cur++] = (byte) length; - System.arraycopy(e.getData(), 0, m_data, cur, length); - cur += length; - } + public static byte[] toByteArray(SmsHeader smsHeader) { + if ((smsHeader.portAddrs == null) && + (smsHeader.concatRef == null) && + (smsHeader.miscEltList.size() == 0)) { + return null; } - return m_data; + ByteArrayOutputStream outStream = new ByteArrayOutputStream(SmsMessage.MAX_USER_DATA_BYTES); + ConcatRef concatRef = smsHeader.concatRef; + if (concatRef != null) { + if (concatRef.isEightBits) { + outStream.write(ELT_ID_CONCATENATED_8_BIT_REFERENCE); + outStream.write(3); + outStream.write(concatRef.refNumber); + } else { + outStream.write(ELT_ID_CONCATENATED_16_BIT_REFERENCE); + outStream.write(4); + outStream.write(concatRef.refNumber >>> 8); + outStream.write(concatRef.refNumber & 0x00FF); + } + outStream.write(concatRef.msgCount); + outStream.write(concatRef.seqNumber); + } + PortAddrs portAddrs = smsHeader.portAddrs; + if (portAddrs != null) { + if (portAddrs.areEightBits) { + outStream.write(ELT_ID_APPLICATION_PORT_ADDRESSING_8_BIT); + outStream.write(2); + outStream.write(portAddrs.destPort); + outStream.write(portAddrs.origPort); + } else { + outStream.write(ELT_ID_APPLICATION_PORT_ADDRESSING_16_BIT); + outStream.write(4); + outStream.write(portAddrs.destPort >>> 8); + outStream.write(portAddrs.destPort & 0x00FF); + outStream.write(portAddrs.origPort >>> 8); + outStream.write(portAddrs.origPort & 0x00FF); + } + } + for (MiscElt miscElt : smsHeader.miscEltList) { + outStream.write(miscElt.id); + outStream.write(miscElt.data.length); + outStream.write(miscElt.data, 0, miscElt.data.length); + } + return outStream.toByteArray(); } - /** - * A single Element in the SMS User Data Header. - * - * See TS 23.040 9.2.3.24. - * - */ - public static class Element { - private byte[] m_data; - private int m_id; - - public Element(int id, byte[] data) { - m_id = id; - m_data = data; + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("UserDataHeader "); + builder.append("{ ConcatRef "); + if (concatRef == null) { + builder.append("unset"); + } else { + builder.append("{ refNumber=" + concatRef.refNumber); + builder.append(", msgCount=" + concatRef.msgCount); + builder.append(", seqNumber=" + concatRef.seqNumber); + builder.append(", isEightBits=" + concatRef.isEightBits); + builder.append(" }"); } - - /** - * Returns the Information Element Identifier for this element. - * - * @return the IE identifier. - */ - public int getID() { - return m_id; + builder.append(", PortAddrs "); + if (portAddrs == null) { + builder.append("unset"); + } else { + builder.append("{ destPort=" + portAddrs.destPort); + builder.append(", origPort=" + portAddrs.origPort); + builder.append(", areEightBits=" + portAddrs.areEightBits); + builder.append(" }"); } - - /** - * Returns the data portion of this element. - * - * @return element data. - */ - public byte[] getData() { - return m_data; + for (MiscElt miscElt : miscEltList) { + builder.append(", MiscElt "); + builder.append("{ id=" + miscElt.id); + builder.append(", length=" + miscElt.data.length); + builder.append(", data=" + HexDump.toHexString(miscElt.data)); + builder.append(" }"); } + builder.append(" }"); + return builder.toString(); } + } diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java index 1aad38d..3c7dd45 100644 --- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java +++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java @@ -86,6 +86,38 @@ public abstract class SmsMessageBase { /** TP-Message-Reference - Message Reference of sent message. @hide */ public int messageRef; + /** + * For a specific text string, this object describes protocol + * properties of encoding it for transmission as message user + * data. + */ + public static class TextEncodingDetails { + /** + *The number of SMS's required to encode the text. + */ + public int msgCount; + + /** + * The number of code units consumed so far, where code units + * are basically characters in the encoding -- for example, + * septets for the standard ASCII and GSM encodings, and 16 + * bits for Unicode. + */ + public int codeUnitCount; + + /** + * How many code units are still available without spilling + * into an additional message. + */ + public int codeUnitsRemaining; + + /** + * The encoding code unit size (specified using + * android.telephony.SmsMessage ENCODING_*). + */ + public int codeUnitSize; + } + public static abstract class SubmitPduBase { public byte[] encodedScAddress; // Null if not applicable. public byte[] encodedMessage; @@ -245,8 +277,6 @@ public abstract class SmsMessageBase { /** * Returns an object representing the user data header * - * @return an object representing the user data header - * * {@hide} */ public SmsHeader getUserDataHeader() { @@ -254,9 +284,14 @@ public abstract class SmsMessageBase { } /** + * TODO(cleanup): The term PDU is used in a seemingly non-unique + * manner -- for example, what is the difference between this byte + * array and the contents of SubmitPdu objects. Maybe a more + * illustrative term would be appropriate. + */ + + /** * Returns the raw PDU for the message. - * - * @return the raw PDU for the message. */ public byte[] getPdu() { return mPdu; @@ -309,7 +344,9 @@ public abstract class SmsMessageBase { } protected void parseMessageBody() { - if (originatingAddress.couldBeEmailGateway()) { + // originatingAddress could be null if this message is from a status + // report. + if (originatingAddress != null && originatingAddress.couldBeEmailGateway()) { extractEmailAddressFromMessageBody(); } } diff --git a/telephony/java/com/android/internal/telephony/SmsResponse.java b/telephony/java/com/android/internal/telephony/SmsResponse.java index 3c4df56..bd79e02 100644 --- a/telephony/java/com/android/internal/telephony/SmsResponse.java +++ b/telephony/java/com/android/internal/telephony/SmsResponse.java @@ -26,9 +26,15 @@ public class SmsResponse { int messageRef; /** ackPdu for the just-sent SMS. */ String ackPdu; + /** + * errorCode: See 3GPP 27.005, 3.2.5 for GSM/UMTS, + * 3GPP2 N.S0005 (IS-41C) Table 171 for CDMA, -1 if unknown or not applicable. + */ + int errorCode; - public SmsResponse(int messageRef, String ackPdu) { + public SmsResponse(int messageRef, String ackPdu, int errorCode) { this.messageRef = messageRef; this.ackPdu = ackPdu; + this.errorCode = errorCode; } } diff --git a/telephony/java/com/android/internal/telephony/TelephonyEventLog.java b/telephony/java/com/android/internal/telephony/TelephonyEventLog.java index 97f9d7d..cdce488 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyEventLog.java +++ b/telephony/java/com/android/internal/telephony/TelephonyEventLog.java @@ -30,4 +30,6 @@ public final class TelephonyEventLog { 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; } diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index c342233..9152211 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -51,9 +51,24 @@ public class TelephonyIntents { * <p class="note"> * Requires no permission. */ - public static final String ACTION_RADIO_TECHNOLOGY_CHANGED + public static final String ACTION_RADIO_TECHNOLOGY_CHANGED = "android.intent.action.RADIO_TECHNOLOGY"; - + /** + * <p>Broadcast Action: The emergency callback mode is changed. + * <ul> + * <li><em>phoneinECMState</em> - A boolean value,true=phone in ECM, false=ECM off</li> + * </ul> + * <p class="note"> + * You can <em>not</em> receive this through components declared + * in manifests, only by explicitly registering for it with + * {@link android.content.Context#registerReceiver(android.content.BroadcastReceiver, + * android.content.IntentFilter) Context.registerReceiver()}. + * + * <p class="note"> + * Requires no permission. + */ + public static final String ACTION_EMERGENCY_CALLBACK_MODE_CHANGED + = "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED"; /** * Broadcast Action: The phone's signal strength has changed. The intent will have the * following extra values:</p> @@ -166,4 +181,34 @@ public class TelephonyIntents { */ public static final String ACTION_NETWORK_SET_TIMEZONE = "android.intent.action.NETWORK_SET_TIMEZONE"; + + /** + * <p>Broadcast Action: It indicates the Emergency callback mode blocks datacall/sms + * <p class="note">. + * This is to pop up a notice to show user that the phone is in emergency callback mode + * and atacalls and outgoing sms are blocked. + */ + public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS + = "android.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS"; + + /** + * Broadcast Action: The MDN changed during the CDMA OTA Process + * The intent will have the following extra values:</p> + * <ul> + * <li><em>mdn</em> - An Integer of the updated MDN number.</li> + * </ul> + * + * <p class="note"> + */ + // TODO(Moto): Generally broadcast intents are for use to allow entities which + // may not know about each other to "communicate". This seems quite specific + // and maybe using the registrant style would be better. + + // Moto: Since this is used for apps not in the same process of phone, can the + // registrant style be used? (Ling Li says: Maybe the "app" can request rather + // than save the MDN each time and this intent would not be necessary?) + // Moto response: Moto internal discussion is on-going. + public static final String ACTION_CDMA_OTA_MDN_CHANGED + = "android.intent.action.ACTION_MDN_STATE_CHANGED"; + } diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java index 396b42d..290e1fc 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java +++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java @@ -44,6 +44,7 @@ public interface TelephonyProperties * Availability: when registered to a network */ static final String PROPERTY_OPERATOR_ALPHA = "gsm.operator.alpha"; + //TODO: most of these proprieties are generic, substitute gsm. with phone. bug 1856959 /** Numeric name (MCC+MNC) of current registered operator. * Availability: when registered to a network @@ -68,6 +69,8 @@ public interface TelephonyProperties */ static final String PROPERTY_OPERATOR_ISO_COUNTRY = "gsm.operator.iso-country"; + static final String CURRENT_ACTIVE_PHONE = "gsm.current.phone-type"; + //****** SIM Card /** * One of <code>"UNKNOWN"</code> <code>"ABSENT"</code> <code>"PIN_REQUIRED"</code> @@ -95,4 +98,12 @@ public interface TelephonyProperties */ static String PROPERTY_DATA_NETWORK_TYPE = "gsm.network.type"; + /** Indicate if phone is in emergency callback mode */ + static final String PROPERTY_INECM_MODE = "ril.cdma.inecmmode"; + + /** Indicate the timer value for exiting emergency callback mode */ + static final String PROPERTY_ECM_EXIT_TIMER = "ro.cdma.ecmexittimer"; + + /** The international dialing prefix conversion string */ + static final String PROPERTY_IDP_STRING = "ro.cdma.idpstring"; } diff --git a/telephony/java/com/android/internal/telephony/WapPushOverSms.java b/telephony/java/com/android/internal/telephony/WapPushOverSms.java index 98899c9..9970940 100644 --- a/telephony/java/com/android/internal/telephony/WapPushOverSms.java +++ b/telephony/java/com/android/internal/telephony/WapPushOverSms.java @@ -16,9 +16,10 @@ package com.android.internal.telephony; +import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.os.PowerManager; +import android.provider.Telephony; import android.provider.Telephony.Sms.Intents; import android.util.Config; import android.util.Log; @@ -34,18 +35,17 @@ public class WapPushOverSms { private final Context mContext; private WspTypeDecoder pduDecoder; - private PowerManager.WakeLock mWakeLock; + private SMSDispatcher mSmsDispatcher; /** - * Hold the wake lock for 5 seconds, which should be enough time for + * Hold the wake lock for 5 seconds, which should be enough time for * any receiver(s) to grab its own wake lock. */ private final int WAKE_LOCK_TIMEOUT = 5000; - public WapPushOverSms(Phone phone) { - + public WapPushOverSms(Phone phone, SMSDispatcher smsDispatcher) { + mSmsDispatcher = smsDispatcher; mContext = phone.getContext(); - createWakelock(); } /** @@ -53,8 +53,11 @@ public class WapPushOverSms { * wap-230-wsp-20010705-a section 8 for details on the WAP PDU format. * * @param pdu The WAP PDU, made up of one or more SMS PDUs + * @return a result code from {@link Telephony.Sms.Intents}, or + * {@link Activity#RESULT_OK} if the message has been broadcast + * to applications */ - public void dispatchWapPdu(byte[] pdu) { + public int dispatchWapPdu(byte[] pdu) { if (Config.LOGD) Log.d(LOG_TAG, "Rx: " + IccUtils.bytesToHexString(pdu)); @@ -66,7 +69,7 @@ public class WapPushOverSms { if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH) && (pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) { if (Config.LOGD) Log.w(LOG_TAG, "Received non-PUSH WAP PDU. Type = " + pduType); - return; + return Intents.RESULT_SMS_HANDLED; } pduDecoder = new WspTypeDecoder(pdu); @@ -79,7 +82,7 @@ public class WapPushOverSms { */ if (pduDecoder.decodeUintvarInteger(index) == false) { if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Header Length error."); - return; + return Intents.RESULT_SMS_GENERIC_ERROR; } headerLength = (int)pduDecoder.getValue32(); index += pduDecoder.getDecodedDataLength(); @@ -100,7 +103,7 @@ public class WapPushOverSms { */ if (pduDecoder.decodeContentType(index) == false) { if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Header Content-Type error."); - return; + return Intents.RESULT_SMS_GENERIC_ERROR; } int binaryContentType; String mimeType = pduDecoder.getValueString(); @@ -130,7 +133,7 @@ public class WapPushOverSms { Log.w(LOG_TAG, "Received PDU. Unsupported Content-Type = " + binaryContentType); } - return; + return Intents.RESULT_SMS_HANDLED; } } else { if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML)) { @@ -147,7 +150,7 @@ public class WapPushOverSms { binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_MMS; } else { if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Unknown Content-Type = " + mimeType); - return; + return Intents.RESULT_SMS_HANDLED; } } index += pduDecoder.getDecodedDataLength(); @@ -169,6 +172,7 @@ public class WapPushOverSms { if (dispatchedByApplication == false) { dispatchWapPdu_default(pdu, transactionId, pduType, mimeType, dataIndex); } + return Activity.RESULT_OK; } private void dispatchWapPdu_default( @@ -184,7 +188,7 @@ public class WapPushOverSms { intent.putExtra("pduType", pduType); intent.putExtra("data", data); - sendBroadcast(intent, "android.permission.RECEIVE_WAP_PUSH"); + mSmsDispatcher.dispatch(intent, "android.permission.RECEIVE_WAP_PUSH"); } private void dispatchWapPdu_PushCO(byte[] pdu, int transactionId, int pduType) { @@ -194,7 +198,7 @@ public class WapPushOverSms { intent.putExtra("pduType", pduType); intent.putExtra("data", pdu); - sendBroadcast(intent, "android.permission.RECEIVE_WAP_PUSH"); + mSmsDispatcher.dispatch(intent, "android.permission.RECEIVE_WAP_PUSH"); } private void dispatchWapPdu_MMS(byte[] pdu, int transactionId, int pduType, int dataIndex) { @@ -209,20 +213,7 @@ public class WapPushOverSms { intent.putExtra("pduType", pduType); intent.putExtra("data", data); - sendBroadcast(intent, "android.permission.RECEIVE_MMS"); - } - - private void createWakelock() { - PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WapPushOverSms"); - mWakeLock.setReferenceCounted(true); - } - - private void sendBroadcast(Intent intent, String permission) { - // Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any - // receivers time to take their own wake locks. - mWakeLock.acquire(WAKE_LOCK_TIMEOUT); - mContext.sendBroadcast(intent, permission); + mSmsDispatcher.dispatch(intent, "android.permission.RECEIVE_MMS"); } } diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java index 8ffb7ec..3362de8 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java +++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java @@ -16,7 +16,10 @@ package com.android.internal.telephony.cdma; +import android.app.ActivityManagerNative; import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; @@ -24,20 +27,22 @@ import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; import android.os.SystemProperties; +import android.preference.PreferenceManager; import android.provider.Settings; import android.telephony.CellLocation; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; +import android.telephony.SignalStrength; import android.text.TextUtils; import android.util.Log; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION; - import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Connection; import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.IccException; import com.android.internal.telephony.IccFileHandler; import com.android.internal.telephony.IccPhoneBookInterfaceManager; import com.android.internal.telephony.IccSmsInterfaceManager; @@ -48,10 +53,12 @@ import com.android.internal.telephony.PhoneNotifier; import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.PhoneSubInfo; import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.TelephonyProperties; -import java.util.ArrayList; import java.util.List; - +import java.util.Timer; +import java.util.TimerTask; /** * {@hide} */ @@ -59,6 +66,12 @@ public class CDMAPhone extends PhoneBase { static final String LOG_TAG = "CDMA"; private static final boolean LOCAL_DEBUG = true; + // Default Emergency Callback Mode exit timer + private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 30000; + static final String VM_COUNT_CDMA = "vm_count_key_cdma"; + private static final String VM_NUMBER_CDMA = "vm_number_key_cdma"; + private String mVmNumber = null; + //***** Instance Variables CdmaCallTracker mCT; CdmaSMSDispatcher mSMS; @@ -71,11 +84,29 @@ public class CDMAPhone extends PhoneBase { RuimPhoneBookInterfaceManager mRuimPhoneBookInterfaceManager; RuimSmsInterfaceManager mRuimSmsInterfaceManager; PhoneSubInfo mSubInfo; + EriManager mEriManager; - protected RegistrantList mNvLoadedRegistrants = new RegistrantList(); + // mNvLoadedRegistrants are informed after the EVENT_NV_READY + private RegistrantList mNvLoadedRegistrants = new RegistrantList(); + + // mEriFileLoadedRegistrants are informed after the ERI text has been loaded + private RegistrantList mEriFileLoadedRegistrants = new RegistrantList(); + + // mECMExitRespRegistrant is informed after the phone has been exited + //the emergency callback mode + //keep track of if phone is in emergency callback mode + private boolean mIsPhoneInECMState; + private Registrant mECMExitRespRegistrant; private String mEsn; private String mMeid; + // A runnable which is used to automatically exit from ECM after a period of time. + private Runnable mExitEcmRunnable = new Runnable() { + public void run() { + exitEmergencyCallbackMode(); + } + }; + Registrant mPostDialHandler; @@ -102,6 +133,7 @@ public class CDMAPhone extends PhoneBase { mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this); mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this); mSubInfo = new PhoneSubInfo(this); + mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML); mCM.registerForAvailable(h, EVENT_RADIO_AVAILABLE, null); mRuimRecords.registerForRecordsLoaded(h, EVENT_RUIM_RECORDS_LOADED, null); @@ -111,10 +143,19 @@ public class CDMAPhone extends PhoneBase { mCM.setOnCallRing(h, EVENT_CALL_RING, null); mSST.registerForNetworkAttach(h, EVENT_REGISTERED_TO_NETWORK, null); mCM.registerForNVReady(h, EVENT_NV_READY, null); + mCM.setEmergencyCallbackMode(h, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null); + //Change the system setting - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.CURRENT_ACTIVE_PHONE, RILConstants.CDMA_PHONE); + SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE, + new Integer(RILConstants.CDMA_PHONE).toString()); + + // This is needed to handle phone process crashes + String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); + mIsPhoneInECMState = inEcm.equals("true"); + + // Notify voicemails. + notifier.notifyMessageWaitingChanged(this); } public void dispose() { @@ -130,6 +171,7 @@ public class CDMAPhone extends PhoneBase { mCM.unSetOnSuppServiceNotification(h); mCM.unSetOnCallRing(h); + //Force all referenced classes to unregister their former registered events mCT.dispose(); mDataConnection.dispose(); @@ -141,6 +183,7 @@ public class CDMAPhone extends PhoneBase { mRuimPhoneBookInterfaceManager.dispose(); mRuimSmsInterfaceManager.dispose(); mSubInfo.dispose(); + mEriManager.dispose(); } } @@ -155,6 +198,7 @@ public class CDMAPhone extends PhoneBase { this.mDataConnection = null; this.mCT = null; this.mSST = null; + this.mEriManager = null; } protected void finalize() { @@ -215,7 +259,7 @@ public class CDMAPhone extends PhoneBase { public DataActivityState getDataActivityState() { DataActivityState ret = DataActivityState.NONE; - if (mSST.getCurrentCdmaDataConnectionState() != ServiceState.RADIO_TECHNOLOGY_UNKNOWN) { + if (mSST.getCurrentCdmaDataConnectionState() == ServiceState.STATE_IN_SERVICE) { switch (mDataConnection.getActivity()) { case DATAIN: @@ -229,6 +273,10 @@ public class CDMAPhone extends PhoneBase { case DATAINANDOUT: ret = DataActivityState.DATAINANDOUT; break; + + case DORMANT: + ret = DataActivityState.DORMANT; + break; } } return ret; @@ -249,26 +297,19 @@ public class CDMAPhone extends PhoneBase { if (fc != null) { //mMmiRegistrants.notifyRegistrants(new AsyncResult(null, fc, null)); fc.processCode(); - } else { - FeatureCode digits = new FeatureCode(this); - // use dial number as poundString - digits.poundString = newDialString; - digits.processCode(); + return null; } - return null; - } else { - return mCT.dial(newDialString); } + return mCT.dial(newDialString); } - - public int getSignalStrengthASU() { - return mSST.rssi == 99 ? -1 : mSST.rssi; + public SignalStrength getSignalStrength() { + return mSST.mSignalStrength; } public boolean getMessageWaitingIndicator() { - return mRuimRecords.getVoiceMessageWaiting(); + return (getVoiceMessageCount() > 0); } public List<? extends MmiCode> @@ -347,7 +388,15 @@ public class CDMAPhone extends PhoneBase { } public String getLine1Number() { - return mRuimRecords.getMdnNumber(); + return mSST.getMdnNumber(); + } + + public String getCdmaPrlVersion(){ + return mRuimRecords.getPrlVersion(); + } + + public String getCdmaMIN() { + return mSST.getCdmaMin(); } public void getCallWaiting(Message onComplete) { @@ -378,8 +427,13 @@ public class CDMAPhone extends PhoneBase { } public String getSubscriberId() { - Log.e(LOG_TAG, "method getSubscriberId for IMSI is NOT supported in CDMA!"); - return null; + // Subscriber ID is the combination of MCC+MNC+MIN as CDMA IMSI + // TODO(Moto): Replace with call to mRuimRecords.getIMSI_M() when implemented. + if ((getServiceState().getOperatorNumeric() != null) && (getCdmaMIN() != null)) { + return (getServiceState().getOperatorNumeric() + getCdmaMIN()); + } else { + return null; + } } public boolean canConference() { @@ -410,7 +464,7 @@ public class CDMAPhone extends PhoneBase { } public void setOnPostDialCharacter(Handler h, int what, Object obj) { - Log.e(LOG_TAG, "setOnPostDialCharacter: not possible in CDMA"); + mPostDialHandler = new Registrant(h, what, obj); } public boolean handlePinMmi(String dialString) { @@ -454,14 +508,50 @@ public class CDMAPhone extends PhoneBase { mDataConnection.setDataOnRoamingEnabled(enable); } + public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) { + mCM.registerForCdmaOtaProvision(h, what, obj); + } + + public void unregisterForCdmaOtaStatusChange(Handler h) { + mCM.unregisterForCdmaOtaProvision(h); + } + + public void setOnEcbModeExitResponse(Handler h, int what, Object obj) { + mECMExitRespRegistrant = new Registrant (h, what, obj); + } + + public void unsetOnEcbModeExitResponse(Handler h) { + mECMExitRespRegistrant.clear(); + } + + public void registerForCallWaiting(Handler h, int what, Object obj) { + mCT.registerForCallWaiting(h, what, obj); + } + + public void unregisterForCallWaiting(Handler h) { + mCT.unregisterForCallWaiting(h); + } + public String getIpAddress(String apnType) { return mDataConnection.getIpAddress(); } public void getNeighboringCids(Message response) { - // WINK:TODO: implement after Cupcake merge - mCM.getNeighboringCids(response); // workaround. + /* + * This is currently not implemented. At least as of June + * 2009, there is no neighbor cell information available for + * CDMA because some party is resisting making this + * information readily available. Consequently, calling this + * function can have no useful effect. This situation may + * (and hopefully will) change in the future. + */ + if (response != null) { + CommandException ce = new CommandException( + CommandException.Error.REQUEST_NOT_SUPPORTED); + AsyncResult.forMessage(response).exception = ce; + response.sendToTarget(); + } } public DataState getDataConnectionState() { @@ -476,12 +566,11 @@ public class CDMAPhone extends PhoneBase { ret = DataState.CONNECTED; } else if (mSST == null) { - // Radio Technology Change is ongoning, dispose() and removeReferences() have - // already been called + // Radio Technology Change is ongoning, dispose() and removeReferences() have + // already been called - ret = DataState.DISCONNECTED; - } else if (mSST.getCurrentCdmaDataConnectionState() - == ServiceState.RADIO_TECHNOLOGY_UNKNOWN) { + ret = DataState.DISCONNECTED; + } else if (mSST.getCurrentCdmaDataConnectionState() != ServiceState.STATE_IN_SERVICE) { // If we're out of service, open TCP sockets may still work // but no data will flow ret = DataState.DISCONNECTED; @@ -541,6 +630,21 @@ public class CDMAPhone extends PhoneBase { mCM.stopDtmf(null); } + public void sendBurstDtmf(String dtmfString, Message onComplete) { + boolean check = true; + for (int itr = 0;itr < dtmfString.length(); itr++) { + if (!PhoneNumberUtils.is12Key(dtmfString.charAt(itr))) { + Log.e(LOG_TAG, + "sendDtmf called with invalid character '" + dtmfString.charAt(itr)+ "'"); + check = false; + break; + } + } + if ((mCT.state == Phone.State.OFFHOOK)&&(check)) { + mCM.sendBurstDtmf(dtmfString, onComplete); + } + } + public void getAvailableNetworks(Message response) { Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA"); } @@ -554,7 +658,7 @@ public class CDMAPhone extends PhoneBase { } public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) { - Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA"); + Log.e(LOG_TAG, "setOutgoingCallerIdDisplay: not possible in CDMA"); } public void enableLocationUpdates() { @@ -583,15 +687,33 @@ public class CDMAPhone extends PhoneBase { public void setVoiceMailNumber(String alphaTag, String voiceMailNumber, Message onComplete) { - //mSIMRecords.setVoiceMailNumber(alphaTag, voiceMailNumber, onComplete); - //TODO: Where do we have to store this value has to be clarified with QC + Message resp; + mVmNumber = voiceMailNumber; + resp = h.obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete); + mRuimRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp); } public String getVoiceMailNumber() { - //TODO: Where can we get this value has to be clarified with QC - //return mSIMRecords.getVoiceMailNumber(); -// throw new RuntimeException(); - return "12345"; + String number = null; + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); + // TODO(Moto): The default value of voicemail number should be read from a system property + number = sp.getString(VM_NUMBER_CDMA, "*86"); + return number; + } + + /* Returns Number of Voicemails + * @hide + */ + public int getVoiceMessageCount() { + int voicemailCount = mRuimRecords.getVoiceMessageCount(); + // If mRuimRecords.getVoiceMessageCount returns zero, then there is possibility + // that phone was power cycled and would have lost the voicemail count. + // So get the count from preferences. + if (voicemailCount == 0) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); + voicemailCount = sp.getInt(VM_COUNT_CDMA, 0); + } + return voicemailCount; } public String getVoiceMailAlphaTag() { @@ -609,7 +731,15 @@ public class CDMAPhone extends PhoneBase { } public boolean enableDataConnectivity() { - return mDataConnection.setDataEnabled(true); + + // block data activities when phone is in emergency callback mode + if (mIsPhoneInECMState) { + Intent intent = new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS); + ActivityManagerNative.broadcastStickyIntent(intent, null); + return false; + } else { + return mDataConnection.setDataEnabled(true); + } } public void disableLocationUpdates() { @@ -652,7 +782,7 @@ public class CDMAPhone extends PhoneBase { return null; } - /** + /** * Notify any interested party of a Phone state change. */ /*package*/ void notifyPhoneStateChanged() { @@ -697,15 +827,23 @@ public class CDMAPhone extends PhoneBase { mUnknownConnectionRegistrants.notifyResult(this); } + void sendEmergencyCallbackModeChange(){ + //Send an Intent + Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); + intent.putExtra(PHONE_IN_ECM_STATE, mIsPhoneInECMState); + ActivityManagerNative.broadcastStickyIntent(intent,null); + } + /*package*/ void updateMessageWaitingIndicator(boolean mwi) { // this also calls notifyMessageWaitingIndicator() mRuimRecords.setVoiceMessageWaiting(1, mwi ? -1 : 0); } - public void - notifyMessageWaitingIndicator() { - mNotifier.notifyMessageWaitingChanged(this); + /* This function is overloaded to send number of voicemails instead of sending true/false */ + /*package*/ void + updateMessageWaitingIndicator(int mwi) { + mRuimRecords.setVoiceMessageWaiting(1, mwi); } /** @@ -722,6 +860,51 @@ public class CDMAPhone extends PhoneBase { mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, fc, null)); } + + @Override + public void exitEmergencyCallbackMode() { + // Send a message which will invoke handleExitEmergencyCallbackMode + mCM.exitEmergencyCallbackMode(h.obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE)); + } + + private void handleEnterEmergencyCallbackMode(Message msg) { + Log.d(LOG_TAG, "Event EVENT_EMERGENCY_CALLBACK_MODE Received"); + // if phone is not in ECM mode, and it's changed to ECM mode + if (mIsPhoneInECMState == false) { + mIsPhoneInECMState = true; + // notify change + sendEmergencyCallbackModeChange(); + setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true"); + + // Post this runnable so we will automatically exit + // if no one invokes exitEmergencyCallbackMode() directly. + long delayInMillis = SystemProperties.getLong( + TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE); + h.postDelayed(mExitEcmRunnable, delayInMillis); + } + } + + private void handleExitEmergencyCallbackMode(Message msg) { + Log.d(LOG_TAG, "Event EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE Received"); + AsyncResult ar = (AsyncResult)msg.obj; + + // Remove pending exit ECM runnable, if any + h.removeCallbacks(mExitEcmRunnable); + + if (mECMExitRespRegistrant != null) { + mECMExitRespRegistrant.notifyRegistrant(ar); + } + // if exiting ecm success + if (ar.exception == null) { + if (mIsPhoneInECMState) { + mIsPhoneInECMState = false; + setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false"); + } + // send an Intent + sendEmergencyCallbackModeChange(); + } + } + //***** Inner Classes class MyHandler extends Handler { MyHandler() { @@ -731,6 +914,7 @@ public class CDMAPhone extends PhoneBase { super(l); } + @Override public void handleMessage(Message msg) { AsyncResult ar; Message onComplete; @@ -751,7 +935,7 @@ public class CDMAPhone extends PhoneBase { } if (LOCAL_DEBUG) Log.d(LOG_TAG, "Baseband version: " + ar.result); - setSystemProperty(PROPERTY_BASEBAND_VERSION, (String)ar.result); + setSystemProperty(TelephonyProperties.PROPERTY_BASEBAND_VERSION, (String)ar.result); } break; @@ -767,6 +951,16 @@ public class CDMAPhone extends PhoneBase { } break; + case EVENT_EMERGENCY_CALLBACK_MODE_ENTER:{ + handleEnterEmergencyCallbackMode(msg); + } + break; + + case EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE:{ + handleExitEmergencyCallbackMode(msg); + } + break; + case EVENT_RUIM_RECORDS_LOADED:{ Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received"); } @@ -800,10 +994,30 @@ public class CDMAPhone extends PhoneBase { case EVENT_NV_READY:{ Log.d(LOG_TAG, "Event EVENT_NV_READY Received"); //Inform the Service State Tracker + mEriManager.loadEriFile(); mNvLoadedRegistrants.notifyRegistrants(); + if(mEriManager.isEriFileLoaded()) { + // when the ERI file is loaded + Log.d(LOG_TAG, "ERI read, notify registrants"); + mEriFileLoadedRegistrants.notifyRegistrants(); + } + setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE,"false"); } break; + case EVENT_SET_VM_NUMBER_DONE:{ + ar = (AsyncResult)msg.obj; + if (IccException.class.isInstance(ar.exception)) { + storeVoiceMailNumber(mVmNumber); + ar.exception = null; + } + onComplete = (Message) ar.userObj; + if (onComplete != null) { + AsyncResult.forMessage(onComplete, ar.result, ar.exception); + onComplete.sendToTarget(); + } + } + default:{ throw new RuntimeException("unexpected event not handled"); } @@ -811,26 +1025,26 @@ public class CDMAPhone extends PhoneBase { } } - /** - * Retrieves the PhoneSubInfo of the CDMAPhone - */ - public PhoneSubInfo getPhoneSubInfo(){ + /** + * Retrieves the PhoneSubInfo of the CDMAPhone + */ + public PhoneSubInfo getPhoneSubInfo() { return mSubInfo; - } + } - /** - * Retrieves the IccSmsInterfaceManager of the CDMAPhone - */ - public IccSmsInterfaceManager getIccSmsInterfaceManager(){ - return mRuimSmsInterfaceManager; - } + /** + * Retrieves the IccSmsInterfaceManager of the CDMAPhone + */ + public IccSmsInterfaceManager getIccSmsInterfaceManager() { + return mRuimSmsInterfaceManager; + } - /** - * Retrieves the IccPhoneBookInterfaceManager of the CDMAPhone - */ - public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){ - return mRuimPhoneBookInterfaceManager; - } + /** + * Retrieves the IccPhoneBookInterfaceManager of the CDMAPhone + */ + public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager() { + return mRuimPhoneBookInterfaceManager; + } public void registerForNvLoaded(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); @@ -841,71 +1055,193 @@ public class CDMAPhone extends PhoneBase { mNvLoadedRegistrants.remove(h); } - // override for allowing access from other classes of this package - /** - * {@inheritDoc} - */ - public final void setSystemProperty(String property, String value) { - super.setSystemProperty(property, value); - } + public void registerForEriFileLoaded(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mEriFileLoadedRegistrants.add(r); + } - /** - * {@inheritDoc} - */ - public Handler getHandler(){ - return h; - } + public void unregisterForEriFileLoaded(Handler h) { + mEriFileLoadedRegistrants.remove(h); + } - /** - * {@inheritDoc} - */ - public IccFileHandler getIccFileHandler(){ - return this.mIccFileHandler; - } + // override for allowing access from other classes of this package + /** + * {@inheritDoc} + */ + public final void setSystemProperty(String property, String value) { + super.setSystemProperty(property, value); + } - /** - * Set the TTY mode of the CDMAPhone - */ - public void setTTYModeEnabled(boolean enable, Message onComplete) { - this.mCM.setTTYModeEnabled(enable, onComplete); -} + /** + * {@inheritDoc} + */ + public Handler getHandler() { + return h; + } - /** - * Queries the TTY mode of the CDMAPhone - */ - public void queryTTYModeEnabled(Message onComplete) { - this.mCM.queryTTYModeEnabled(onComplete); - } + /** + * {@inheritDoc} + */ + public IccFileHandler getIccFileHandler() { + return this.mIccFileHandler; + } - /** - * Activate or deactivate cell broadcast SMS. - * - * @param activate - * 0 = activate, 1 = deactivate - * @param response - * Callback message is empty on completion - */ - public void activateCellBroadcastSms(int activate, Message response) { - mSMS.activateCellBroadcastSms(activate, response); - } + /** + * Set the TTY mode of the CDMAPhone + */ + public void setTTYMode(int ttyMode, Message onComplete) { + this.mCM.setTTYMode(ttyMode, onComplete); + } - /** - * Query the current configuration of cdma cell broadcast SMS. - * - * @param response - * Callback message is empty on completion - */ - public void getCellBroadcastSmsConfig(Message response){ - mSMS.getCellBroadcastSmsConfig(response); - } + /** + * Queries the TTY mode of the CDMAPhone + */ + public void queryTTYMode(Message onComplete) { + this.mCM.queryTTYMode(onComplete); + } + + /** + * Activate or deactivate cell broadcast SMS. + * + * @param activate 0 = activate, 1 = deactivate + * @param response Callback message is empty on completion + */ + public void activateCellBroadcastSms(int activate, Message response) { + mSMS.activateCellBroadcastSms(activate, response); + } + + /** + * Query the current configuration of cdma cell broadcast SMS. + * + * @param response Callback message is empty on completion + */ + public void getCellBroadcastSmsConfig(Message response) { + mSMS.getCellBroadcastSmsConfig(response); + } + + /** + * Configure cdma cell broadcast SMS. + * + * @param response Callback message is empty on completion + */ + public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) { + mSMS.setCellBroadcastConfig(configValuesArray, response); + } + + public static final String IS683A_FEATURE_CODE = "*228" ; + public static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4 ; + public static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2 ; + public static final int IS683A_SYS_SEL_CODE_OFFSET = 4; + + private static final int IS683_CONST_800MHZ_A_BAND = 0; + private static final int IS683_CONST_800MHZ_B_BAND = 1; + private static final int IS683_CONST_1900MHZ_A_BLOCK = 2; + private static final int IS683_CONST_1900MHZ_B_BLOCK = 3; + private static final int IS683_CONST_1900MHZ_C_BLOCK = 4; + private static final int IS683_CONST_1900MHZ_D_BLOCK = 5; + private static final int IS683_CONST_1900MHZ_E_BLOCK = 6; + private static final int IS683_CONST_1900MHZ_F_BLOCK = 7; + + private boolean isIs683OtaSpDialStr(String dialStr) { + int sysSelCodeInt; + boolean isOtaspDialString = false; + int dialStrLen = dialStr.length(); + + if (dialStrLen == IS683A_FEATURE_CODE_NUM_DIGITS) { + if (dialStr.equals(IS683A_FEATURE_CODE)) { + isOtaspDialString = true; + } + } else if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE, 0, + IS683A_FEATURE_CODE_NUM_DIGITS) == true) + && (dialStrLen >= + (IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS))) { + StringBuilder sb = new StringBuilder(dialStr); + // Separate the System Selection Code into its own string + char[] sysSel = new char[2]; + sb.delete(0, IS683A_SYS_SEL_CODE_OFFSET); + sb.getChars(0, IS683A_SYS_SEL_CODE_NUM_DIGITS, sysSel, 0); + + if ((PhoneNumberUtils.isISODigit(sysSel[0])) + && (PhoneNumberUtils.isISODigit(sysSel[1]))) { + String sysSelCode = new String(sysSel); + sysSelCodeInt = Integer.parseInt((String)sysSelCode); + switch (sysSelCodeInt) { + case IS683_CONST_800MHZ_A_BAND: + case IS683_CONST_800MHZ_B_BAND: + case IS683_CONST_1900MHZ_A_BLOCK: + case IS683_CONST_1900MHZ_B_BLOCK: + case IS683_CONST_1900MHZ_C_BLOCK: + case IS683_CONST_1900MHZ_D_BLOCK: + case IS683_CONST_1900MHZ_E_BLOCK: + case IS683_CONST_1900MHZ_F_BLOCK: + isOtaspDialString = true; + break; + + default: + break; + } + } + } + return isOtaspDialString; + } /** - * Configure cdma cell broadcast SMS. + * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier + * OTASP dial string. * - * @param response - * Callback message is empty on completion + * @param dialStr the number to look up. + * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string */ - public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){ - mSMS.setCellBroadcastConfig(configValuesArray, response); + @Override + public boolean isOtaSpNumber(String dialStr){ + boolean isOtaSpNum = false; + if(dialStr != null){ + isOtaSpNum=isIs683OtaSpDialStr(dialStr); + if(isOtaSpNum == false){ + //TO DO:Add carrier specific OTASP number detection here. + } + } + return isOtaSpNum; } + + @Override + public int getCdmaEriIconIndex() { + int roamInd = getServiceState().getCdmaRoamingIndicator(); + int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator(); + return mEriManager.getCdmaEriIconIndex(roamInd, defRoamInd); + } + + /** + * Returns the CDMA ERI icon mode, + * 0 - ON + * 1 - FLASHING + */ + @Override + public int getCdmaEriIconMode() { + int roamInd = getServiceState().getCdmaRoamingIndicator(); + int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator(); + return mEriManager.getCdmaEriIconMode(roamInd, defRoamInd); + } + + /** + * Returns the CDMA ERI text, + */ + @Override + public String getCdmaEriText() { + int roamInd = getServiceState().getCdmaRoamingIndicator(); + int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator(); + return mEriManager.getCdmaEriText(roamInd, defRoamInd); + } + + /** + * Store the voicemail number in preferences + */ + private void storeVoiceMailNumber(String number) { + // Update the preference value of voicemail number + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); + SharedPreferences.Editor editor = sp.edit(); + editor.putString(VM_NUMBER_CDMA, number); + editor.commit(); + } + } diff --git a/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java b/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java index ea557b2..fb5f0fa 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java +++ b/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java @@ -25,26 +25,31 @@ package com.android.internal.telephony.cdma; * */ public interface CallFailCause { - static final int NORMAL_CLEARING = 16; + static final int NORMAL_CLEARING = 16; // Busy Tone - static final int USER_BUSY = 17; - -// // No Tone -// static final int NUMBER_CHANGED = 22; -// static final int STATUS_ENQUIRY = 30; - static final int NORMAL_UNSPECIFIED = 31; -// -// // Congestion Tone -// static final int NO_CIRCUIT_AVAIL = 34; -// static final int TEMPORARY_FAILURE = 41; -// static final int SWITCHING_CONGESTION = 42; -// static final int CHANNEL_NOT_AVAIL = 44; -// static final int QOS_NOT_AVAIL = 49; -// static final int BEARER_NOT_AVAIL = 58; -// -// // others -// static final int ACM_LIMIT_EXCEEDED = 68; -// static final int CALL_BARRED = 240; -// static final int FDN_BLOCKED = 241; + static final int USER_BUSY = 17; + + static final int NORMAL_UNSPECIFIED = 31; + + // Congestion Tone + static final int NO_CIRCUIT_AVAIL = 34; + + // others + static final int ACM_LIMIT_EXCEEDED = 68; + static final int CALL_BARRED = 240; + static final int FDN_BLOCKED = 241; + + static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; + static final int CDMA_DROP = 1001; + static final int CDMA_INTERCEPT = 1002; + static final int CDMA_REORDER = 1003; + static final int CDMA_SO_REJECT = 1004; + static final int CDMA_RETRY_ORDER = 1005; + static final int CDMA_ACCESS_FAILURE = 1006; + static final int CDMA_PREEMPTED = 1007; + + // For non-emergency number dialed while in emergency callback mode. + static final int CDMA_NOT_EMERGENCY = 1008; + static final int ERROR_UNSPECIFIED = 0xffff; } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java index 34514d9..e8724c2 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java @@ -181,9 +181,7 @@ public final class CdmaCall extends Call { */ void onHangupLocal() { - for (int i = 0, s = connections.size() - ; i < s; i++ - ) { + for (int i = 0, s = connections.size(); i < s; i++) { CdmaConnection cn = (CdmaConnection)connections.get(i); cn.onHangupLocal(); diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java index a1d362f..ed2ea90 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java @@ -24,6 +24,7 @@ import android.os.RegistrantList; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; import android.util.Log; +import android.os.SystemProperties; import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.CallTracker; @@ -31,11 +32,12 @@ import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Connection; import com.android.internal.telephony.DriverCall; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.TelephonyProperties; import java.util.ArrayList; import java.util.List; + /** * {@hide} */ @@ -56,6 +58,7 @@ public final class CdmaCallTracker extends CallTracker { CdmaConnection connections[] = new CdmaConnection[MAX_CONNECTIONS]; RegistrantList voiceCallEndedRegistrants = new RegistrantList(); RegistrantList voiceCallStartedRegistrants = new RegistrantList(); + RegistrantList callWaitingRegistrants = new RegistrantList(); // connections dropped durin last poll @@ -69,11 +72,12 @@ public final class CdmaCallTracker extends CallTracker { CdmaConnection pendingMO; boolean hangupPendingMO; - + boolean pendingCallInECM=false; CDMAPhone phone; boolean desiredMute = false; // false = mute off + int pendingCallClirMode; Phone.State state = Phone.State.IDLE; @@ -90,13 +94,15 @@ public final class CdmaCallTracker extends CallTracker { cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null); cm.registerForOn(this, EVENT_RADIO_AVAILABLE, null); cm.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null); + cm.registerForCallWaitingInfo(this, EVENT_CALL_WAITING_INFO_CDMA, null); + foregroundCall.setGeneric(false); } public void dispose() { cm.unregisterForCallStateChanged(this); cm.unregisterForOn(this); cm.unregisterForNotAvailable(this); - + cm.unregisterForCallWaitingInfo(this); for(CdmaConnection c : connections) { try { if(c != null) hangup(c); @@ -115,6 +121,7 @@ public final class CdmaCallTracker extends CallTracker { } + @Override protected void finalize() { Log.d(LOG_TAG, "CdmaCallTracker finalized"); } @@ -139,6 +146,15 @@ public final class CdmaCallTracker extends CallTracker { voiceCallEndedRegistrants.remove(h); } + public void registerForCallWaiting(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + callWaitingRegistrants.add(r); + } + + public void unregisterForCallWaiting(Handler h) { + callWaitingRegistrants.remove(h); + } + private void fakeHoldForegroundBeforeDial() { List<Connection> connCopy; @@ -166,34 +182,24 @@ public final class CdmaCallTracker extends CallTracker { throw new CallStateException("cannot dial in current state"); } + + // We are initiating a call therefore even if we previously + // didn't know the state (i.e. Generic was true) we now know + // and therefore can set Generic to false. + foregroundCall.setGeneric(false); + // The new call must be assigned to the foreground call. // That call must be idle, so place anything that's // there on hold if (foregroundCall.getState() == CdmaCall.State.ACTIVE) { - // this will probably be done by the radio anyway - // but the dial might fail before this happens - // and we need to make sure the foreground call is clear - // for the newly dialed connection - switchWaitingOrHoldingAndActive(); - - // Fake local state so that - // a) foregroundCall is empty for the newly dialed connection - // b) hasNonHangupStateChanged remains false in the - // next poll, so that we don't clear a failed dialing call - fakeHoldForegroundBeforeDial(); - } - - if (foregroundCall.getState() != CdmaCall.State.IDLE) { - //we should have failed in !canDial() above before we get here - throw new CallStateException("cannot dial in current state"); + return dialThreeWay(dialString); } pendingMO = new CdmaConnection(phone.getContext(), dialString, this, foregroundCall); hangupPendingMO = false; if (pendingMO.address == null || pendingMO.address.length() == 0 - || pendingMO.address.indexOf(PhoneNumberUtils.WILD) >= 0 - ) { + || pendingMO.address.indexOf(PhoneNumberUtils.WILD) >= 0) { // Phone number is invalid pendingMO.cause = Connection.DisconnectCause.INVALID_NUMBER; @@ -204,7 +210,15 @@ public final class CdmaCallTracker extends CallTracker { // Always unmute when initiating a new call setMute(false); - cm.dial(pendingMO.address, clirMode, obtainCompleteMessage()); + String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); + if(inEcm.equals("false")) { + cm.dial(pendingMO.address, clirMode, obtainCompleteMessage()); + } else { + phone.exitEmergencyCallbackMode(); + phone.setOnEcbModeExitResponse(this,EVENT_EXIT_ECM_RESPONSE_CDMA, null); + pendingCallClirMode=clirMode; + pendingCallInECM=true; + } } updatePhoneState(); @@ -219,19 +233,35 @@ public final class CdmaCallTracker extends CallTracker { return dial(dialString, CommandsInterface.CLIR_DEFAULT); } - void - acceptCall () throws CallStateException { - // FIXME if SWITCH fails, should retry with ANSWER - // in case the active/holding call disappeared and this - // is no longer call waiting + private Connection + dialThreeWay (String dialString) { + if (!foregroundCall.isIdle()) { + // Attach the new connection to foregroundCall + pendingMO = new CdmaConnection(phone.getContext(), + dialString, this, foregroundCall); + cm.sendCDMAFeatureCode(pendingMO.address, + obtainMessage(EVENT_THREE_WAY_DIAL_L2_RESULT_CDMA)); + return pendingMO; + } + return null; + } + void + acceptCall() throws CallStateException { if (ringingCall.getState() == CdmaCall.State.INCOMING) { Log.i("phone", "acceptCall: incoming..."); // Always unmute when answering a new call setMute(false); cm.acceptCall(obtainCompleteMessage()); } else if (ringingCall.getState() == CdmaCall.State.WAITING) { - setMute(false); + CdmaConnection cwConn = (CdmaConnection)(ringingCall.getLatestConnection()); + + // Since there is no network response for supplimentary + // service for CDMA, we assume call waiting is answered. + // ringing Call state change to idle is in CdmaCall.detach + // triggered by updateParent. + cwConn.updateParent(ringingCall, foregroundCall); + cwConn.onConnectedInOrOut(); switchWaitingOrHoldingAndActive(); } else { throw new CallStateException("phone not ringing"); @@ -255,14 +285,14 @@ public final class CdmaCallTracker extends CallTracker { if (ringingCall.getState() == CdmaCall.State.INCOMING) { throw new CallStateException("cannot be in the incoming state"); } else { - cm.sendCDMAFeatureCode("", obtainCompleteMessage(EVENT_SWITCH_RESULT)); + flashAndSetGenericTrue(); } } void conference() throws CallStateException { - // three way calls in CDMA will be handled by feature codes - Log.e(LOG_TAG, "conference: not possible in CDMA"); + // Should we be checking state? + flashAndSetGenericTrue(); } void @@ -295,6 +325,7 @@ public final class CdmaCallTracker extends CallTracker { pendingMO == null && !ringingCall.isRinging() && (!foregroundCall.getState().isAlive() + || (foregroundCall.getState() == CdmaCall.State.ACTIVE) || !backgroundCall.getState().isAlive()); return ret; @@ -483,9 +514,20 @@ public final class CdmaCallTracker extends CallTracker { } hasNonHangupStateChanged = true; } else if (conn != null && dc == null) { - // Connection missing in CLCC response that we were - // tracking. - droppedDuringPoll.add(conn); + int count = foregroundCall.connections.size(); + if (count == 0) { + // Handle an unanswered MO/MT call, there is no + // foregroundCall connections at this time. + droppedDuringPoll.add(conn); + } else { + // Loop through foreground call connections as + // it contains the known logical connections. + for (int n = 0; n < count; n++) { + CdmaConnection cn = (CdmaConnection)foregroundCall.connections.get(n); + droppedDuringPoll.add(cn); + } + } + foregroundCall.setGeneric(false); // Dropped connections are removed from the CallTracker // list but kept in the Call list connections[i] = null; @@ -536,6 +578,9 @@ public final class CdmaCallTracker extends CallTracker { droppedDuringPoll.add(pendingMO); pendingMO = null; hangupPendingMO = false; + if( pendingCallInECM) { + pendingCallInECM = false; + } } if (newRinging != null) { @@ -619,6 +664,22 @@ public final class CdmaCallTracker extends CallTracker { if (Phone.DEBUG_PHONE) log("hangup: set hangupPendingMO to true"); hangupPendingMO = true; + } else if ((conn.getCall() == ringingCall) + && (ringingCall.getState() == CdmaCall.State.WAITING)) { + // Handle call waiting hang up case. + // + // The ringingCall state will change to IDLE in CdmaCall.detach + // if the ringing call connection size is 0. We don't specifically + // set the ringing call state to IDLE here to avoid a race condition + // where a new call waiting could get a hang up from an old call + // waiting ringingCall. + // + // PhoneApp does the call log itself since only PhoneApp knows + // the hangup reason is user ignoring or timing out. So conn.onDisconnect() + // is not called here. Instead, conn.onLocalDisconnect() is called. + conn.onLocalDisconnect(); + phone.notifyCallStateChanged(); + return; } else { try { cm.hangupConnection (conn.getCDMAIndex(), obtainCompleteMessage()); @@ -753,6 +814,16 @@ public final class CdmaCallTracker extends CallTracker { return null; } + private void flashAndSetGenericTrue() throws CallStateException { + cm.sendCDMAFeatureCode("", obtainMessage(EVENT_SWITCH_RESULT)); + + // Set generic to true because in CDMA it is not known what + // the status of the call is after a call waiting is answered, + // 3 way call merged or a switch between calls. + foregroundCall.setGeneric(true); + phone.notifyCallStateChanged(); + } + private Phone.SuppService getFailedService(int what) { switch (what) { case EVENT_SWITCH_RESULT: @@ -774,6 +845,30 @@ public final class CdmaCallTracker extends CallTracker { pollCallsWhenSafe(); } + private void notifyCallWaitingInfo(CdmaCallWaitingNotification obj) { + if (callWaitingRegistrants != null) { + callWaitingRegistrants.notifyRegistrants(new AsyncResult(null, obj, null)); + } + } + + private void handleCallWaitingInfo (CdmaCallWaitingNotification cw) { + // Check how many connections in foregroundCall. + // If the connection in foregroundCall is more + // than one, then the connection information is + // not reliable anymore since it means either + // call waiting is connected or 3 way call is + // dialed before, so set generic. + if (foregroundCall.connections.size() > 1 ) { + foregroundCall.setGeneric(true); + } + + // Create a new CdmaConnection which attaches itself to ringingCall. + ringingCall.setGeneric(false); + new CdmaConnection(phone.getContext(), cw, this, ringingCall); + + // Finally notify application + notifyCallWaitingInfo(cw); + } //****** Overridden from Handler public void @@ -796,13 +891,13 @@ public final class CdmaCallTracker extends CallTracker { break; case EVENT_OPERATION_COMPLETE: - ar = (AsyncResult)msg.obj; operationComplete(); break; case EVENT_SWITCH_RESULT: - ar = (AsyncResult)msg.obj; - operationComplete(); + // In GSM call operationComplete() here which gets the + // current call list. But in CDMA there is no list so + // there is nothing to do. break; case EVENT_GET_LAST_CALL_FAIL_CAUSE: @@ -835,6 +930,7 @@ public final class CdmaCallTracker extends CallTracker { droppedDuringPoll.clear(); break; + case EVENT_REPOLL_AFTER_DELAY: case EVENT_CALL_STATE_CHANGE: pollCallsWhenSafe(); break; @@ -847,8 +943,33 @@ public final class CdmaCallTracker extends CallTracker { handleRadioNotAvailable(); break; + case EVENT_EXIT_ECM_RESPONSE_CDMA: + //no matter the result, we still do the same here + if (pendingCallInECM) { + cm.dial(pendingMO.address, pendingCallClirMode, obtainCompleteMessage()); + pendingCallInECM = false; + } + phone.unsetOnEcbModeExitResponse(this); + break; + + case EVENT_CALL_WAITING_INFO_CDMA: + ar = (AsyncResult)msg.obj; + if (ar.exception == null) { + handleCallWaitingInfo((CdmaCallWaitingNotification)ar.result); + Log.d(LOG_TAG, "Event EVENT_CALL_WAITING_INFO_CDMA Received"); + } + break; + + case EVENT_THREE_WAY_DIAL_L2_RESULT_CDMA: + ar = (AsyncResult)msg.obj; + if (ar.exception == null) { + // Assume 3 way call is connected + pendingMO.onConnectedInOrOut(); + } + break; + default:{ - throw new RuntimeException("unexpected event not handled"); + throw new RuntimeException("unexpected event not handled"); } } } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java new file mode 100644 index 0000000..54dec48 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java @@ -0,0 +1,48 @@ +/* + * 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.cdma; + +/** + * Represents a Supplementary Service Notification received from the network. + * + * {@hide} + */ +public class CdmaCallWaitingNotification { + public String number =null; + public int numberPresentation = 0; + public String name = null; + public int namePresentation = 0; + public int isPresent = 0; + public int signalType = 0; + public int alertPitch = 0; + public int signal = 0; + + + public String toString() + { + return super.toString() + "Call Waiting Notification " + + " number: " + number + + " numberPresentation: " + numberPresentation + + " name: " + name + + " namePresentation: " + namePresentation + + " isPresent: " + isPresent + + " signalType: " + signalType + + " alertPitch: " + alertPitch + + " signal: " + signal ; + } + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java index cdad4a7..025382d 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java @@ -25,11 +25,14 @@ import android.os.Message; import android.os.PowerManager; import android.os.Registrant; import android.os.SystemClock; +import android.os.SystemProperties; import android.util.Config; import android.util.Log; +import android.text.TextUtils; + import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; - +import com.android.internal.telephony.TelephonyProperties; /** * {@hide} @@ -48,7 +51,7 @@ public class CdmaConnection extends Connection { String postDialString; // outgoing calls only boolean isIncoming; boolean disconnected; - + String cnapName; int index; // index in CdmaCallTracker.connections[], -1 if unassigned /* @@ -74,6 +77,8 @@ public class CdmaConnection extends Connection { DisconnectCause cause = DisconnectCause.NOT_DISCONNECTED; PostDialState postDialState = PostDialState.NOT_STARTED; int numberPresentation = Connection.PRESENTATION_ALLOWED; + int cnapNamePresentation = Connection.PRESENTATION_ALLOWED; + Handler h; @@ -84,11 +89,10 @@ public class CdmaConnection extends Connection { static final int EVENT_PAUSE_DONE = 2; static final int EVENT_NEXT_POST_DIAL = 3; static final int EVENT_WAKE_LOCK_TIMEOUT = 4; - + //***** Constants - static final int PAUSE_DELAY_FIRST_MILLIS = 100; - static final int PAUSE_DELAY_MILLIS = 3 * 1000; static final int WAKE_LOCK_TIMEOUT_MILLIS = 60*1000; + static final int PAUSE_DELAY_MILLIS = 2 * 1000; //***** Inner Classes @@ -126,6 +130,8 @@ public class CdmaConnection extends Connection { isIncoming = dc.isMT; createTime = System.currentTimeMillis(); + cnapName = dc.name; + cnapNamePresentation = dc.namePresentation; numberPresentation = dc.numberPresentation; this.index = index; @@ -134,16 +140,19 @@ public class CdmaConnection extends Connection { parent.attach(this, dc); } - /** This is an MO call, created when dialing */ + /** This is an MO call/three way call, created when dialing */ /*package*/ - CdmaConnection (Context context, String dialString, CdmaCallTracker ct, CdmaCall parent) { + CdmaConnection(Context context, String dialString, CdmaCallTracker ct, CdmaCall parent) { createWakeLock(context); acquireWakeLock(); - + owner = ct; h = new MyHandler(owner.getLooper()); this.dialString = dialString; + Log.d(LOG_TAG, "[CDMAConn] CdmaConnection: dialString=" + dialString); + dialString = formatDialString(dialString); + Log.d(LOG_TAG, "[CDMAConn] CdmaConnection:formated dialString=" + dialString); this.address = PhoneNumberUtils.extractNetworkPortion(dialString); this.postDialString = PhoneNumberUtils.extractPostDialPortion(dialString); @@ -151,10 +160,41 @@ public class CdmaConnection extends Connection { index = -1; isIncoming = false; + cnapName = null; + cnapNamePresentation = 0; + numberPresentation = 0; createTime = System.currentTimeMillis(); + if (parent != null) { + this.parent = parent; + + //for the three way call case, not change parent state + if (parent.state == CdmaCall.State.ACTIVE) { + parent.attachFake(this, CdmaCall.State.ACTIVE); + } else { + parent.attachFake(this, CdmaCall.State.DIALING); + } + } + } + + /** This is a Call waiting call*/ + CdmaConnection(Context context, CdmaCallWaitingNotification cw, CdmaCallTracker ct, + CdmaCall parent) { + createWakeLock(context); + acquireWakeLock(); + + owner = ct; + h = new MyHandler(owner.getLooper()); + address = cw.number; + numberPresentation = cw.numberPresentation; + cnapName = cw.name; + cnapNamePresentation = cw.namePresentation; + index = -1; + isIncoming = true; + createTime = System.currentTimeMillis(); + connectTime = 0; this.parent = parent; - parent.attachFake(this, CdmaCall.State.DIALING); + parent.attachFake(this, CdmaCall.State.WAITING); } public void dispose() { @@ -186,10 +226,22 @@ public class CdmaConnection extends Connection { return (isIncoming ? "incoming" : "outgoing"); } + public String getOrigDialString(){ + return dialString; + } + public String getAddress() { return address; } + public String getCnapName() { + return cnapName; + } + + public int getCnapNamePresentation() { + return cnapNamePresentation; + } + public CdmaCall getCall() { return parent; } @@ -344,6 +396,32 @@ public class CdmaConnection extends Connection { switch (causeCode) { case CallFailCause.USER_BUSY: return DisconnectCause.BUSY; + case CallFailCause.NO_CIRCUIT_AVAIL: + return DisconnectCause.CONGESTION; + case CallFailCause.ACM_LIMIT_EXCEEDED: + return DisconnectCause.LIMIT_EXCEEDED; + case CallFailCause.CALL_BARRED: + return DisconnectCause.CALL_BARRED; + case CallFailCause.FDN_BLOCKED: + return DisconnectCause.FDN_BLOCKED; + case CallFailCause.CDMA_LOCKED_UNTIL_POWER_CYCLE: + return DisconnectCause.CDMA_LOCKED_UNTIL_POWER_CYCLE; + case CallFailCause.CDMA_DROP: + return DisconnectCause.CDMA_DROP; + case CallFailCause.CDMA_INTERCEPT: + return DisconnectCause.CDMA_INTERCEPT; + case CallFailCause.CDMA_REORDER: + return DisconnectCause.CDMA_REORDER; + case CallFailCause.CDMA_SO_REJECT: + return DisconnectCause.CDMA_SO_REJECT; + case CallFailCause.CDMA_RETRY_ORDER: + return DisconnectCause.CDMA_RETRY_ORDER; + case CallFailCause.CDMA_ACCESS_FAILURE: + return DisconnectCause.CDMA_ACCESS_FAILURE; + case CallFailCause.CDMA_PREEMPTED: + return DisconnectCause.CDMA_PREEMPTED; + case CallFailCause.CDMA_NOT_EMERGENCY: + return DisconnectCause.CDMA_NOT_EMERGENCY; case CallFailCause.ERROR_UNSPECIFIED: case CallFailCause.NORMAL_CLEARING: default: @@ -352,7 +430,7 @@ public class CdmaConnection extends Connection { if (serviceState == ServiceState.STATE_POWER_OFF) { return DisconnectCause.POWER_OFF; } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE - || serviceState == ServiceState.STATE_EMERGENCY_ONLY ) { + || serviceState == ServiceState.STATE_EMERGENCY_ONLY) { return DisconnectCause.OUT_OF_SERVICE; } else if (phone.mCM.getRadioState() != CommandsInterface.RadioState.NV_READY && phone.getIccCard().getState() != RuimCard.State.READY) { @@ -374,12 +452,7 @@ public class CdmaConnection extends Connection { this.cause = cause; if (!disconnected) { - index = -1; - - disconnectTime = System.currentTimeMillis(); - duration = SystemClock.elapsedRealtime() - connectTimeReal; - disconnected = true; - + doDisconnect(); if (Config.LOGD) Log.d(LOG_TAG, "[CDMAConn] onDisconnect: cause=" + cause); @@ -392,6 +465,21 @@ public class CdmaConnection extends Connection { releaseWakeLock(); } + /** Called when the call waiting connection has been hung up */ + /*package*/ void + onLocalDisconnect() { + if (!disconnected) { + doDisconnect(); + if (Config.LOGD) Log.d(LOG_TAG, + "[CDMAConn] onLoalDisconnect" ); + + if (parent != null) { + parent.detach(this); + } + } + releaseWakeLock(); + } + // Returns true if state has changed, false if nothing changed /*package*/ boolean update (DriverCall dc) { @@ -408,6 +496,21 @@ public class CdmaConnection extends Connection { changed = true; } + // A null cnapName should be the same as "" + if (TextUtils.isEmpty(dc.name)) { + if (!TextUtils.isEmpty(cnapName)) { + changed = true; + cnapName = ""; + } + } else if (!dc.name.equals(cnapName)) { + changed = true; + cnapName = dc.name; + } + + log("--dssds----"+cnapName); + cnapNamePresentation = dc.namePresentation; + numberPresentation = dc.numberPresentation; + if (newParent != parent) { if (parent != null) { parent.detach(this); @@ -494,6 +597,14 @@ public class CdmaConnection extends Connection { } private void + doDisconnect() { + index = -1; + disconnectTime = System.currentTimeMillis(); + duration = SystemClock.elapsedRealtime() - connectTimeReal; + disconnected = true; + } + + private void onStartedHolding() { holdingStartTime = SystemClock.elapsedRealtime(); } @@ -507,25 +618,13 @@ public class CdmaConnection extends Connection { if (PhoneNumberUtils.is12Key(c)) { owner.cm.sendDtmf(c, h.obtainMessage(EVENT_DTMF_DONE)); } else if (c == PhoneNumberUtils.PAUSE) { - // From TS 22.101: - - // "The first occurrence of the "DTMF Control Digits Separator" - // shall be used by the ME to distinguish between the addressing - // digits (i.e. the phone number) and the DTMF digits...." + setPostDialState(PostDialState.PAUSE); - if (nextPostDialChar == 1) { - // The first occurrence. - // We don't need to pause here, but wait for just a bit anyway - h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE), - PAUSE_DELAY_FIRST_MILLIS); - } else { - // It continues... - // "Upon subsequent occurrences of the separator, the UE shall - // pause again for 3 seconds (\u00B1 20 %) before sending any - // further DTMF digits." - h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE), + // Upon occurrences of the separator, the UE shall + // pause again for 2 seconds before sending any + // further DTMF digits. + h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE), PAUSE_DELAY_MILLIS); - } } else if (c == PhoneNumberUtils.WAIT) { setPostDialState(PostDialState.WAIT); } else if (c == PhoneNumberUtils.WILD) { @@ -537,19 +636,38 @@ public class CdmaConnection extends Connection { return true; } - public String - getRemainingPostDialString() { + public String getRemainingPostDialString() { if (postDialState == PostDialState.CANCELLED - || postDialState == PostDialState.COMPLETE - || postDialString == null - || postDialString.length() <= nextPostDialChar - ) { + || postDialState == PostDialState.COMPLETE + || postDialString == null + || postDialString.length() <= nextPostDialChar) { return ""; } - return postDialString.substring(nextPostDialChar); + String subStr = postDialString.substring(nextPostDialChar); + if (subStr != null) { + int wIndex = subStr.indexOf(PhoneNumberUtils.WAIT); + int pIndex = subStr.indexOf(PhoneNumberUtils.PAUSE); + + if (wIndex > 0 && (wIndex < pIndex || pIndex <= 0)) { + subStr = subStr.substring(0, wIndex); + } else if (pIndex > 0) { + subStr = subStr.substring(0, pIndex); + } + } + return subStr; } - + + public void updateParent(CdmaCall oldParent, CdmaCall newParent){ + if (newParent != oldParent) { + if (oldParent != null) { + oldParent.detach(this); + } + newParent.attachFake(this, CdmaCall.State.ACTIVE); + parent = newParent; + } + } + @Override protected void finalize() { @@ -565,8 +683,7 @@ public class CdmaConnection extends Connection { releaseWakeLock(); } - private void - processNextPostDialChar() { + void processNextPostDialChar() { char c = 0; Registrant postDialHandler; @@ -583,7 +700,7 @@ public class CdmaConnection extends Connection { c = 0; } else { boolean isValid; - + setPostDialState(PostDialState.STARTED); c = postDialString.charAt(nextPostDialChar++); @@ -653,47 +770,164 @@ 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" - * state or after WAKE_LOCK_TIMEOUT_MILLIS. + * 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" + * state or after WAKE_LOCK_TIMEOUT_MILLIS. * @param s new PostDialState */ private void setPostDialState(PostDialState s) { - if (postDialState != PostDialState.STARTED + 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 + } else if (postDialState == PostDialState.STARTED && s != PostDialState.STARTED) { h.removeMessages(EVENT_WAKE_LOCK_TIMEOUT); releaseWakeLock(); } postDialState = s; } - - private void - createWakeLock(Context context) { - PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + + private void createWakeLock(Context context) { + PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); } - - private void - acquireWakeLock() { + + private void acquireWakeLock() { log("acquireWakeLock"); mPartialWakeLock.acquire(); } - private void - releaseWakeLock() { - synchronized(mPartialWakeLock) { + private void releaseWakeLock() { + synchronized (mPartialWakeLock) { if (mPartialWakeLock.isHeld()) { log("releaseWakeLock"); mPartialWakeLock.release(); } } } - + + private static boolean isPause(char c) { + return c == PhoneNumberUtils.PAUSE; + } + + private static boolean isWait(char c) { + return c == PhoneNumberUtils.WAIT; + } + + + + + // This function is to find the next PAUSE character index if + // multiple pauses in a row. Otherwise it finds the next non PAUSE or + // non WAIT character index. + private static int + findNextPCharOrNonPOrNonWCharIndex(String phoneNumber, int currIndex) { + boolean wMatched = false; + int index = currIndex + 1; + int length = phoneNumber.length(); + while (index < length) { + char cNext = phoneNumber.charAt(index); + // if there is any W inside P/W sequence,mark it + if (isWait(cNext)) { + wMatched = true; + } + // if any characters other than P/W chars after P/W sequence + // we break out the loop and append the correct + if (!isWait(cNext) && !isPause(cNext)) { + break; + } + index++; + } + + // It means the PAUSE character(s) is in the middle of dial string + // and it needs to be handled one by one. + if ((index < length) && (index > (currIndex + 1)) && + ((wMatched == false) && isPause(phoneNumber.charAt(currIndex)))) { + return (currIndex + 1); + } + return index; + } + + // This function returns either PAUSE or WAIT character to append. + // It is based on the next non PAUSE/WAIT character in the phoneNumber and the + // index for the current PAUSE/WAIT character + private static char + findPOrWCharToAppend(String phoneNumber, int currPwIndex, int nextNonPwCharIndex) { + char c = phoneNumber.charAt(currPwIndex); + char ret; + + // Append the PW char + ret = (isPause(c)) ? PhoneNumberUtils.PAUSE : PhoneNumberUtils.WAIT; + + // if there is a PAUSE in at the begining of PW character sequences, and this + // PW character sequences has more than 2 PAUSE and WAIT Characters,skip P, append W + if (isPause(c) && (nextNonPwCharIndex > (currPwIndex + 1))) { + ret = PhoneNumberUtils.WAIT; + } + return ret; + } + + + /** + * format orignal dial string + * 1) convert international dialing prefix "+" to + * string specified per region + * + * 2) handle corner cases for PAUSE/WAIT dialing: + * + * If PAUSE/WAIT sequence at the end, ignore them. + * + * If consecutive PAUSE/WAIT sequence in the middle of the string, + * and if there is any WAIT in PAUSE/WAIT sequence, treat them like WAIT. + */ + public static String formatDialString(String phoneNumber) { + if (phoneNumber == null) { + return null; + } + int length = phoneNumber.length(); + StringBuilder ret = new StringBuilder(); + char c; + int currIndex = 0; + while (currIndex < length) { + c = phoneNumber.charAt(currIndex); + if (PhoneNumberUtils.isDialable(c)) { + if (c == '+') { + String ps = null; + SystemProperties.get(TelephonyProperties.PROPERTY_IDP_STRING, ps); + if (TextUtils.isEmpty(ps)) { + ps = "011"; + } + ret.append(ps); + } else { + ret.append(c); + } + } else if (isPause(c) || isWait(c)) { + if (currIndex < length - 1) { + // if PW not at the end + int nextIndex = findNextPCharOrNonPOrNonWCharIndex(phoneNumber, currIndex); + // If there is non PW char following PW sequence + if (nextIndex < length) { + char pC = findPOrWCharToAppend(phoneNumber, currIndex, nextIndex); + ret.append(pC); + // If PW char is immediately followed by non-PW char + if (nextIndex > (currIndex + 1)) { + currIndex = nextIndex - 1; + } + } else if (nextIndex == length) { + // It means PW characters at the end, ignore + currIndex = length - 1; + } + } + } else { + ret.append(c); + } + currIndex++; + } + return ret.toString(); + } + private void log(String msg) { Log.d(LOG_TAG, "[CDMAConn] " + msg); } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java index 2cbad78..f2b07a8 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java @@ -146,12 +146,16 @@ public class CdmaDataConnection extends DataConnection { null, 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) { - if (phone.mCM.getRadioState().isOn()) { - phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg)); - } + tearDownData(msg); } else if (state == State.ACTIVATING) { receivedDisconnectReq = true; } else { @@ -229,7 +233,7 @@ public class CdmaDataConnection extends DataConnection { switch (rilCause) { case PS_NET_DOWN_REASON_OPERATOR_DETERMINED_BARRING: - cause = FailCause.BARRED; + cause = FailCause.OPERATOR_BARRED; break; case PS_NET_DOWN_REASON_AUTH_FAILED: cause = FailCause.USER_AUTHENTICATION; @@ -280,7 +284,7 @@ public class CdmaDataConnection extends DataConnection { // Don't bother reporting success if there's already a // pending disconnect request, since DataConnectionTracker // has already updated its state. - disconnect(onDisconnect); + tearDownData(onDisconnect); } else { String[] response = ((String[]) ar.result); cid = Integer.parseInt(response[0]); diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java index 651c505..c3818f5 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java @@ -26,38 +26,31 @@ import android.content.SharedPreferences; import android.net.NetworkInfo; import android.net.wifi.WifiManager; import android.os.AsyncResult; -import android.os.Handler; 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.Settings.SettingNotFoundException; import android.telephony.ServiceState; import android.telephony.TelephonyManager; -import android.util.EventLog; +import android.telephony.cdma.CdmaCellLocation; import android.text.TextUtils; +import android.util.EventLog; 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.DataConnectionTracker; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.TelephonyEventLog; import java.util.ArrayList; /** - * WINK:TODO: In GsmDataConnectionTracker there are - * EventLog's used quite a few places maybe - * more need to be added in this file? - * * {@hide} */ public final class CdmaDataConnectionTracker extends DataConnectionTracker { @@ -69,6 +62,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { // Indicates baseband will not auto-attach private boolean noAutoAttach = false; long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + private boolean mReregisterOnReconnectFailure = false; private boolean mIsScreenOn = true; //useful for debugging @@ -98,6 +92,14 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { "com.android.internal.telephony.cdma-reconnect"; private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason"; + /** + * Constants for the data connection activity: + * physical link down/up + */ + private static final int DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE = 0; + private static final int DATA_CONNECTION_ACTIVE_PH_LINK_DOWN = 1; + private static final int DATA_CONNECTION_ACTIVE_PH_LINK_UP = 2; + // 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. @@ -258,14 +260,6 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } /** - * Simply tear down data connections due to radio off - * and don't setup again. - */ - public void cleanConnectionBeforeRadioOff() { - cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); - } - - /** * The data connection is expected to be setup while device * 1. has ruim card or non-volatile data store * 2. registered to data connection service @@ -304,13 +298,14 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { Log.d(LOG_TAG, "setDataEnabled("+enable+") isEnabled=" + isEnabled); if (!isEnabled && enable) { setEnabled(EXTERNAL_NETWORK_DEFAULT_ID, true); - return trySetupData(Phone.REASON_DATA_ENABLED); + sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); } else if (!enable) { setEnabled(EXTERNAL_NETWORK_DEFAULT_ID, false); - cleanUpConnection(true, Phone.REASON_DATA_DISABLED); - return true; - } else // isEnabled && enable - + Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION); + msg.arg1 = 1; // tearDown is true + msg.obj = Phone.REASON_DATA_DISABLED; + sendMessage(msg); + } return true; } @@ -355,16 +350,16 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { int psState = mCdmaPhone.mSST.getCurrentCdmaDataConnectionState(); boolean roaming = phone.getServiceState().getRoaming(); + boolean desiredPowerState = mCdmaPhone.mSST.getDesiredPowerState(); if ((state == State.IDLE || state == State.SCANNING) - && (psState == ServiceState.RADIO_TECHNOLOGY_1xRTT || - psState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 || - psState == ServiceState.RADIO_TECHNOLOGY_EVDO_A) + && (psState == ServiceState.STATE_IN_SERVICE) && ((phone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) || mCdmaPhone.mRuimRecords.getRecordsLoaded()) && (mCdmaPhone.mSST.isConcurrentVoiceAndData() || phone.getState() == Phone.State.IDLE ) - && isDataAllowed()) { + && isDataAllowed() + && desiredPowerState) { return setupData(reason); @@ -379,7 +374,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { " phoneState=" + phone.getState() + " dataEnabled=" + getAnyDataEnabled() + " roaming=" + roaming + - " dataOnRoamingEnable=" + getDataOnRoamingEnabled()); + " dataOnRoamingEnable=" + getDataOnRoamingEnabled() + + " desiredPowerState=" + desiredPowerState); } return false; } @@ -405,6 +401,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { mReconnectIntent = null; } + setState(State.DISCONNECTING); + for (DataConnection connBase : dataConnectionList) { CdmaDataConnection conn = (CdmaDataConnection) connBase; @@ -420,24 +418,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { stopNetStatPoll(); - /* - * If we've been asked to tear down the connection, - * set the state to DISCONNECTING. However, there's - * a race that can occur if for some reason we were - * already in the IDLE state. In that case, the call - * to conn.disconnect() above will immediately post - * a message to the handler thread that the disconnect - * is done, and if the handler runs before the code - * below does, the handler will have set the state to - * IDLE before the code below runs. If we didn't check - * for that, future calls to trySetupData would fail, - * and we would never get out of the DISCONNECTING state. - */ if (!tearDown) { setState(State.IDLE); phone.notifyDataConnection(reason); - } else if (state != State.IDLE) { - setState(State.DISCONNECTING); } } @@ -478,6 +461,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { startNetStatPoll(); // reset reconnect timer nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mReregisterOnReconnectFailure = false; } private void resetPollStats() { @@ -515,7 +499,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { * override it with an unconditional power on. */ } - + private Runnable mPollNetStat = new Runnable() { public void run() { @@ -570,7 +554,14 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } if (sentSinceLastRecv >= NUMBER_SENT_PACKETS_OF_HANG) { - // we already have NUMBER_SENT_PACKETS sent without ack + // Packets sent without ack exceeded threshold. + + if (mNoRecvPollCount == 0) { + EventLog.writeEvent( + TelephonyEventLog.EVENT_LOG_RADIO_RESET_COUNTDOWN_TRIGGERED, + sentSinceLastRecv); + } + if (mNoRecvPollCount < NO_RECV_POLL_LIMIT) { mNoRecvPollCount++; // Slow down the poll interval to let things happen @@ -582,6 +573,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { netStatPollEnabled = false; stopNetStatPoll(); restartRadio(); + EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_RESET, + NO_RECV_POLL_LIMIT); } } else { mNoRecvPollCount = 0; @@ -608,22 +601,37 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * Return true if data connection need to be setup after disconnected due to * reason. - * + * * @param reason the reason why data is disconnected - * @return true if try setup data connection is need for this reason + * @return true if try setup data connection is need for this reason */ private boolean retryAfterDisconnected(String reason) { boolean retry = true; - + if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) || - Phone.REASON_DATA_DISABLED.equals(reason) ) { + Phone.REASON_DATA_DISABLED.equals(reason) ) { retry = false; } return retry; - } + } private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) { if (state == State.FAILED) { + if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) { + if (mReregisterOnReconnectFailure) { + // We have already tried to re-register to the network. + // This might be a problem with the data network. + nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS; + } else { + // Try to Re-register to the network. + Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network"); + mReregisterOnReconnectFailure = true; + mCdmaPhone.mSST.reRegisterNetwork(null); + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + return; + } + } + Log.d(LOG_TAG, "Data Connection activate failed. Scheduling next attempt for " + (nextReconnectDelay / 1000) + "s"); @@ -639,9 +647,6 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { // double it for next time nextReconnectDelay *= 2; - if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) { - nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS; - } if (!shouldPostNotification(lastFailCauseCode)) { Log.d(LOG_TAG,"NOT Posting Data Connection Unavailable notification " @@ -660,7 +665,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { if (state == State.FAILED) { cleanUpConnection(false, null); } - sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); + sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED)); } protected void onNVReady() { @@ -673,8 +678,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * @override com.android.internal.telephony.DataConnectionTracker */ - protected void onTrySetupData() { - trySetupData(null); + protected void onTrySetupData(String reason) { + trySetupData(reason); } /** @@ -721,6 +726,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { // Make sure our reconnect delay starts at the initial value // next time the radio comes on nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mReregisterOnReconnectFailure = false; if (phone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator @@ -751,13 +757,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { // No try for permanent failure if (cause.isPermanentFail()) { notifyNoData(cause); + return; } - - if (tryAgain(cause)) { - trySetupData(reason); - } else { - startDelayedRetry(cause, reason); - } + startDelayedRetry(cause, reason); } } @@ -800,17 +802,19 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { resetPollStats(); } } else { + // reset reconnect timer + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mReregisterOnReconnectFailure = false; // in case data setup was attempted when we were on a voice call trySetupData(Phone.REASON_VOICE_CALL_ENDED); } } - private boolean tryAgain(FailCause cause) { - return (cause != FailCause.RADIO_NOT_AVAILABLE) - && (cause != FailCause.RADIO_OFF) - && (cause != FailCause.RADIO_ERROR_RETRY) - && (cause != FailCause.NO_SIGNAL) - && (cause != FailCause.SIM_LOCKED); + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onCleanUpConnection(boolean tearDown, String reason) { + cleanUpConnection(tearDown, reason); } private void createAllDataConnectionList() { @@ -829,7 +833,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } } - private void onCdmaDataAttached() { + private void onCdmaDataDetached() { if (state == State.CONNECTED) { startNetStatPoll(); phone.notifyDataConnection(Phone.REASON_CDMA_DATA_DETACHED); @@ -837,12 +841,29 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { if (state == State.FAILED) { cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED); nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + + CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation()); + int bsid = (loc != null) ? loc.getBaseStationId() : -1; + + EventLog.List val = new EventLog.List(bsid, + TelephonyManager.getDefault().getNetworkType()); + EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CDMA_DATA_SETUP_FAILED, val); } trySetupData(Phone.REASON_CDMA_DATA_DETACHED); } } + private void writeEventLogCdmaDataDrop() { + CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation()); + int bsid = (loc != null) ? loc.getBaseStationId() : -1; + EventLog.List val = new EventLog.List(bsid, + TelephonyManager.getDefault().getNetworkType()); + EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CDMA_DATA_DROP, val); + } + protected void onDataStateChanged (AsyncResult ar) { + ArrayList<DataCallState> dataCallStates = (ArrayList<DataCallState>)(ar.result); + if (ar.exception != null) { // This is probably "radio not available" or something // of that sort. If so, the whole connection is going @@ -851,16 +872,37 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } if (state == State.CONNECTED) { - Log.i(LOG_TAG, "Data connection has changed."); - - int cid = -1; - EventLog.List val = new EventLog.List(cid, - TelephonyManager.getDefault().getNetworkType()); - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val); - - cleanUpConnection(true, null); + if (dataCallStates.size() >= 1) { + switch (dataCallStates.get(0).active) { + case DATA_CONNECTION_ACTIVE_PH_LINK_UP: + Log.v(LOG_TAG, "onDataStateChanged: active=LINK_ACTIVE && CONNECTED, ignore"); + activity = Activity.NONE; + phone.notifyDataActivity(); + 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(); + 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); + } + } else { + // TODO: Do we need to do anything? + Log.i(LOG_TAG, "onDataStateChanged: not connected, state=" + state + " ignoring"); } - Log.i(LOG_TAG, "Data connection has changed."); } String getInterfaceName() { @@ -912,7 +954,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { break; case EVENT_CDMA_DATA_DETACHED: - onCdmaDataAttached(); + onCdmaDataDetached(); break; case EVENT_DATA_STATE_CHANGED: diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaInformationRecords.java b/telephony/java/com/android/internal/telephony/cdma/CdmaInformationRecords.java new file mode 100644 index 0000000..7402769 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaInformationRecords.java @@ -0,0 +1,263 @@ +/* + * 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.cdma; +import static com.android.internal.telephony.RILConstants.*; +import android.os.Parcel; + +public final class CdmaInformationRecords { + public Object record; + + /** + * Record type identifier + */ + public static final int RIL_CDMA_DISPLAY_INFO_REC = 0; + public static final int RIL_CDMA_CALLED_PARTY_NUMBER_INFO_REC = 1; + public static final int RIL_CDMA_CALLING_PARTY_NUMBER_INFO_REC = 2; + public static final int RIL_CDMA_CONNECTED_NUMBER_INFO_REC = 3; + public static final int RIL_CDMA_SIGNAL_INFO_REC = 4; + public static final int RIL_CDMA_REDIRECTING_NUMBER_INFO_REC = 5; + public static final int RIL_CDMA_LINE_CONTROL_INFO_REC = 6; + public static final int RIL_CDMA_EXTENDED_DISPLAY_INFO_REC = 7; + public static final int RIL_CDMA_T53_CLIR_INFO_REC = 8; + public static final int RIL_CDMA_T53_RELEASE_INFO_REC = 9; + public static final int RIL_CDMA_T53_AUDIO_CONTROL_INFO_REC = 10; + + public CdmaInformationRecords(Parcel p) { + int id = p.readInt(); + switch (id) { + case RIL_CDMA_DISPLAY_INFO_REC: + case RIL_CDMA_EXTENDED_DISPLAY_INFO_REC: + record = new CdmaDisplayInfoRec(id, p.readString()); + break; + + case RIL_CDMA_CALLED_PARTY_NUMBER_INFO_REC: + case RIL_CDMA_CALLING_PARTY_NUMBER_INFO_REC: + case RIL_CDMA_CONNECTED_NUMBER_INFO_REC: + record = new CdmaNumberInfoRec(id, p.readString(), p.readInt(), p.readInt(), + p.readInt(), p.readInt()); + break; + + case RIL_CDMA_SIGNAL_INFO_REC: + record = new CdmaSignalInfoRec(p.readInt(), p.readInt(), p.readInt(), p.readInt()); + break; + + case RIL_CDMA_REDIRECTING_NUMBER_INFO_REC: + record = new CdmaRedirectingNumberInfoRec(p.readString(), p.readInt(), p.readInt(), + p.readInt(), p.readInt(), p.readInt()); + break; + + case RIL_CDMA_LINE_CONTROL_INFO_REC: + record = new CdmaLineControlInfoRec(p.readInt(), p.readInt(), p.readInt(), + p.readInt()); + break; + + case RIL_CDMA_T53_CLIR_INFO_REC: + record = new CdmaT53ClirInfoRec(p.readInt()); + break; + + case RIL_CDMA_T53_AUDIO_CONTROL_INFO_REC: + record = new CdmaT53AudioControlInfoRec(p.readInt(), p.readInt()); + break; + + case RIL_CDMA_T53_RELEASE_INFO_REC: + // TODO(Moto): 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) + " "); + + } + } + + public static String idToString(int id) { + switch(id) { + case RIL_CDMA_DISPLAY_INFO_REC: return "RIL_CDMA_DISPLAY_INFO_REC"; + case RIL_CDMA_CALLED_PARTY_NUMBER_INFO_REC: return "RIL_CDMA_CALLED_PARTY_NUMBER_INFO_REC"; + case RIL_CDMA_CALLING_PARTY_NUMBER_INFO_REC: return "RIL_CDMA_CALLING_PARTY_NUMBER_INFO_REC"; + case RIL_CDMA_CONNECTED_NUMBER_INFO_REC: return "RIL_CDMA_CONNECTED_NUMBER_INFO_REC"; + case RIL_CDMA_SIGNAL_INFO_REC: return "RIL_CDMA_SIGNAL_INFO_REC"; + case RIL_CDMA_REDIRECTING_NUMBER_INFO_REC: return "RIL_CDMA_REDIRECTING_NUMBER_INFO_REC"; + case RIL_CDMA_LINE_CONTROL_INFO_REC: return "RIL_CDMA_LINE_CONTROL_INFO_REC"; + case RIL_CDMA_EXTENDED_DISPLAY_INFO_REC: return "RIL_CDMA_EXTENDED_DISPLAY_INFO_REC"; + case RIL_CDMA_T53_CLIR_INFO_REC: return "RIL_CDMA_T53_CLIR_INFO_REC"; + case RIL_CDMA_T53_RELEASE_INFO_REC: return "RIL_CDMA_T53_RELEASE_INFO_REC"; + case RIL_CDMA_T53_AUDIO_CONTROL_INFO_REC: return "RIL_CDMA_T53_AUDIO_CONTROL_INFO_REC"; + default: return "<unknown record>"; + } + } + + /** + * Signal Information record from 3GPP2 C.S005 3.7.5.5 + */ + public static class CdmaSignalInfoRec { + public boolean isPresent; /* non-zero if signal information record is present */ + public int signalType; + public int alertPitch; + public int signal; + + public CdmaSignalInfoRec() {} + + public CdmaSignalInfoRec(int isPresent, int signalType, int alertPitch, int signal) { + this.isPresent = isPresent != 0; + this.signalType = signalType; + this.alertPitch = alertPitch; + this.signal = signal; + } + + @Override + public String toString() { + return "CdmaSignalInfo: {" + + " isPresent: " + isPresent + + ", signalType: " + signalType + + ", alertPitch: " + alertPitch + + ", signal: " + signal + + " }"; + } + } + + public static class CdmaDisplayInfoRec { + public int id; + public String alpha; + + public CdmaDisplayInfoRec(int id, String alpha) { + this.id = id; + this.alpha = alpha; + } + + @Override + public String toString() { + return "CdmaDisplayInfoRec: {" + + " id: " + CdmaInformationRecords.idToString(id) + + ", alpha: " + alpha + + " }"; + } + } + + public static class CdmaNumberInfoRec { + public int id; + public String number; + public byte numberType; + public byte numberPlan; + public byte pi; + public byte si; + + public CdmaNumberInfoRec(int id, String number, int numberType, int numberPlan, int pi, + int si) { + this.number = number; + this.numberType = (byte)numberType; + this.numberPlan = (byte)numberPlan; + this.pi = (byte)pi; + this.si = (byte)si; + } + + @Override + public String toString() { + return "CdmaNumberInfoRec: {" + + " id: " + CdmaInformationRecords.idToString(id) + + ", number: " + number + + ", numberType: " + numberType + + ", numberPlan: " + numberPlan + + ", pi: " + pi + + ", si: " + si + + " }"; + } + } + + public static class CdmaRedirectingNumberInfoRec { + public static final int REASON_UNKNOWN = 0; + public static final int REASON_CALL_FORWARDING_BUSY = 1; + public static final int REASON_CALL_FORWARDING_NO_REPLY = 2; + public static final int REASON_CALLED_DTE_OUT_OF_ORDER = 9; + public static final int REASON_CALL_FORWARDING_BY_THE_CALLED_DTE = 10; + public static final int REASON_CALL_FORWARDING_UNCONDITIONAL = 15; + + public CdmaNumberInfoRec numberInfoRec; + public int redirectingReason; + + public CdmaRedirectingNumberInfoRec(String number, int numberType, int numberPlan, + int pi, int si, int reason) { + numberInfoRec = new CdmaNumberInfoRec(RIL_CDMA_REDIRECTING_NUMBER_INFO_REC, + number, numberType, numberPlan, pi, si); + redirectingReason = reason; + } + + @Override + public String toString() { + return "CdmaNumberInfoRec: {" + + " numberInfoRec: " + numberInfoRec + + ", redirectingReason: " + redirectingReason + + " }"; + } + } + + public static class CdmaLineControlInfoRec { + public byte lineCtrlPolarityIncluded; + public byte lineCtrlToggle; + public byte lineCtrlReverse; + public byte lineCtrlPowerDenial; + + public CdmaLineControlInfoRec(int lineCtrlPolarityIncluded, int lineCtrlToggle, + int lineCtrlReverse, int lineCtrlPowerDenial) { + this.lineCtrlPolarityIncluded = (byte)lineCtrlPolarityIncluded; + this.lineCtrlToggle = (byte)lineCtrlToggle; + this.lineCtrlReverse = (byte)lineCtrlReverse; + this.lineCtrlPowerDenial = (byte)lineCtrlPowerDenial; + } + + @Override + public String toString() { + return "CdmaLineControlInfoRec: {" + + " lineCtrlPolarityIncluded: " + lineCtrlPolarityIncluded + + " lineCtrlToggle: " + lineCtrlToggle + + " lineCtrlReverse: " + lineCtrlReverse + + " lineCtrlPowerDenial: " + lineCtrlPowerDenial + + " }"; + } + } + + public static class CdmaT53ClirInfoRec { + public byte cause; + + public CdmaT53ClirInfoRec(int cause) { + this.cause = (byte)cause; + } + + @Override + public String toString() { + return "CdmaT53ClirInfoRec: {" + + " cause: " + cause + + " }"; + } + } + + public static class CdmaT53AudioControlInfoRec { + public byte uplink; + public byte downlink; + + public CdmaT53AudioControlInfoRec(int uplink, int downlink) { + this.uplink = (byte) uplink; + this.downlink = (byte) downlink; + } + + @Override + public String toString() { + return "CdmaT53AudioControlInfoRec: {" + + " uplink: " + uplink + + " downlink: " + downlink + + " }"; + } + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java index 42c0583..ecdc8f6 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java @@ -17,21 +17,27 @@ package com.android.internal.telephony.cdma; +import android.app.Activity; import android.app.PendingIntent; import android.content.ContentValues; +import android.content.SharedPreferences; import android.database.Cursor; import android.database.SQLException; import android.os.AsyncResult; import android.os.Message; +import android.provider.Telephony; +import android.provider.Telephony.Sms.Intents; +import android.preference.PreferenceManager; import android.util.Config; import android.util.Log; +import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; import com.android.internal.telephony.SMSDispatcher; -//import com.android.internal.telephony.SMSDispatcher.SmsTracker; import com.android.internal.telephony.cdma.SmsMessage; import com.android.internal.telephony.cdma.sms.SmsEnvelope; +import com.android.internal.telephony.cdma.sms.UserData; import com.android.internal.util.HexDump; import java.io.ByteArrayOutputStream; @@ -42,8 +48,11 @@ import java.util.HashMap; final class CdmaSMSDispatcher extends SMSDispatcher { private static final String TAG = "CDMA"; + private CDMAPhone mCdmaPhone; + CdmaSMSDispatcher(CDMAPhone phone) { super(phone); + mCdmaPhone = phone; } /** @@ -58,147 +67,88 @@ final class CdmaSMSDispatcher extends SMSDispatcher { Log.d(TAG, "handleStatusReport is a special GSM function, should never be called in CDMA!"); } - /** - * Dispatches an incoming SMS messages. - * - * @param smsb the incoming message from the phone - */ - protected void dispatchMessage(SmsMessageBase smsb) { + /** {@inheritDoc} */ + protected int dispatchMessage(SmsMessageBase smsb) { // If sms is null, means there was a parsing error. - // TODO: Should NAK this. if (smsb == null) { - return; + return Intents.RESULT_SMS_GENERIC_ERROR; } - SmsMessage sms = (SmsMessage) smsb; - int teleService; - boolean handled = false; // Decode BD stream and set sms variables. + SmsMessage sms = (SmsMessage) smsb; sms.parseSms(); - teleService = sms.getTeleService(); - - // Teleservices W(E)MT and VMN are handled together: - if ((SmsEnvelope.TELESERVICE_WMT == teleService) - ||(SmsEnvelope.TELESERVICE_WEMT == teleService) - ||(SmsEnvelope.TELESERVICE_VMN == teleService)){ - // From here on we need decoded BD. - // Special case the message waiting indicator messages - if (sms.isMWISetMessage()) { - ((CDMAPhone) mPhone).updateMessageWaitingIndicator(true); - - if (sms.isMwiDontStore()) { - handled = true; - } - - if (Config.LOGD) { - Log.d(TAG, - "Received voice mail indicator set SMS shouldStore=" + !handled); - } - } else if (sms.isMWIClearMessage()) { - ((CDMAPhone) mPhone).updateMessageWaitingIndicator(false); - - if (sms.isMwiDontStore()) { - handled = true; - } - - if (Config.LOGD) { - Log.d(TAG, - "Received voice mail indicator clear SMS shouldStore=" + !handled); - } - } - } + int teleService = sms.getTeleService(); + boolean handled = false; - if (null == sms.getUserData()){ - handled = true; + if (sms.getUserData() == null) { if (Config.LOGD) { Log.d(TAG, "Received SMS without user data"); } + handled = true; } - if (handled) return; - - if (SmsEnvelope.TELESERVICE_WAP == teleService){ - processCdmaWapPdu(sms.getUserData(), sms.messageRef, sms.getOriginatingAddress()); - return; + if (handled) { + return Intents.RESULT_SMS_HANDLED; } - // Parse the headers to see if this is partial, or port addressed - int referenceNumber = -1; - int count = 0; - int sequence = 0; - int destPort = -1; - // From here on we need BD distributed to SMS member variables. - - SmsHeader header = sms.getUserDataHeader(); - if (header != null) { - for (SmsHeader.Element element : header.getElements()) { - try { - switch (element.getID()) { - case SmsHeader.CONCATENATED_8_BIT_REFERENCE: { - byte[] data = element.getData(); - - referenceNumber = data[0] & 0xff; - count = data[1] & 0xff; - sequence = data[2] & 0xff; - - // Per TS 23.040, 9.2.3.24.1: If the count is zero, sequence - // is zero, or sequence > count, ignore the entire element - if (count == 0 || sequence == 0 || sequence > count) { - referenceNumber = -1; - } - break; - } - - case SmsHeader.CONCATENATED_16_BIT_REFERENCE: { - byte[] data = element.getData(); - - referenceNumber = (data[0] & 0xff) * 256 + (data[1] & 0xff); - count = data[2] & 0xff; - sequence = data[3] & 0xff; - - // Per TS 23.040, 9.2.3.24.8: If the count is zero, sequence - // is zero, or sequence > count, ignore the entire element - if (count == 0 || sequence == 0 || sequence > count) { - referenceNumber = -1; - } - break; - } - - case SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT: { - byte[] data = element.getData(); - - destPort = (data[0] & 0xff) << 8; - destPort |= (data[1] & 0xff); - - break; - } - } - } catch (ArrayIndexOutOfBoundsException e) { - Log.e(TAG, "Bad element in header", e); - return; // TODO: NACK the message or something, don't just discard. - } - } + if (SmsEnvelope.TELESERVICE_WAP == teleService){ + return processCdmaWapPdu(sms.getUserData(), sms.messageRef, + sms.getOriginatingAddress()); + } else if (SmsEnvelope.TELESERVICE_VMN == teleService) { + // handling Voicemail + int voicemailCount = sms.getNumOfVoicemails(); + Log.d(TAG, "Voicemail count=" + voicemailCount); + // Store the voicemail count in preferences. + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences( + ((CDMAPhone) mPhone).getContext()); + SharedPreferences.Editor editor = sp.edit(); + editor.putInt(CDMAPhone.VM_COUNT_CDMA, voicemailCount); + editor.commit(); + ((CDMAPhone) mPhone).updateMessageWaitingIndicator(voicemailCount); + return Intents.RESULT_SMS_HANDLED; } - if (referenceNumber == -1) { - // notify everyone of the message if it isn't partial + /** + * TODO(cleanup): Why are we using a getter method for this + * (and for so many other sms fields)? Trivial getters and + * setters like this are direct violations of the style guide. + * If the purpose is to protect agaist writes (by not + * providing a setter) then any protection is illusory (and + * hence bad) for cases where the values are not primitives, + * such as this call for the header. Since this is an issue + * with the public API it cannot be changed easily, but maybe + * something can be done eventually. + */ + SmsHeader smsHeader = sms.getUserDataHeader(); + + /** + * TODO(cleanup): Since both CDMA and GSM use the same header + * format, this dispatch processing is naturally identical, + * and code should probably not be replicated explicitly. + */ + // See if message is partial or port addressed. + if ((smsHeader == null) || (smsHeader.concatRef == null)) { + // Message is not partial (not part of concatenated sequence). byte[][] pdus = new byte[1][]; pdus[0] = sms.getPdu(); - if (destPort != -1) {// GSM-style WAP indication - if (destPort == SmsHeader.PORT_WAP_PUSH) { - mWapPush.dispatchWapPdu(sms.getUserData()); + if (smsHeader != null && smsHeader.portAddrs != null) { + if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) { + // GSM-style WAP indication + return mWapPush.dispatchWapPdu(sms.getUserData()); + } else { + // The message was sent to a port, so concoct a URI for it. + dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort); } - // The message was sent to a port, so concoct a URI for it - dispatchPortAddressedPdus(pdus, destPort); } else { - // It's a normal message, dispatch it + // Normal short and non-port-addressed message, dispatch it. dispatchPdus(pdus); } + return Activity.RESULT_OK; } else { - // Process the message part - processMessagePart(sms, referenceNumber, sequence, count, destPort); + // Process the message part. + return processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs); } } @@ -208,29 +158,35 @@ final class CdmaSMSDispatcher extends SMSDispatcher { * WDP segments are gathered until a datagram completes and gets dispatched. * * @param pdu The WAP-WDP PDU segment + * @return a result code from {@link Telephony.Sms.Intents}, or + * {@link Activity#RESULT_OK} if the message has been broadcast + * to applications */ - protected void processCdmaWapPdu(byte[] pdu, int referenceNumber, String address) { + protected int processCdmaWapPdu(byte[] pdu, int referenceNumber, String address) { int segment; int totalSegments; int index = 0; int msgType; - int sourcePort; - int destinationPort; + int sourcePort = 0; + int destinationPort = 0; msgType = pdu[index++]; if (msgType != 0){ Log.w(TAG, "Received a WAP SMS which is not WDP. Discard."); - return; + return Intents.RESULT_SMS_HANDLED; } totalSegments = pdu[index++]; // >=1 segment = pdu[index++]; // >=0 - //process WDP segment - sourcePort = (0xFF & pdu[index++]) << 8; - sourcePort |= 0xFF & pdu[index++]; - destinationPort = (0xFF & pdu[index++]) << 8; - destinationPort |= 0xFF & pdu[index++]; + // Only the first segment contains sourcePort and destination Port + if (segment == 0) { + //process WDP segment + sourcePort = (0xFF & pdu[index++]) << 8; + sourcePort |= 0xFF & pdu[index++]; + destinationPort = (0xFF & pdu[index++]) << 8; + destinationPort |= 0xFF & pdu[index++]; + } // Lookup all other related parts StringBuilder where = new StringBuilder("reference_number ="); @@ -260,7 +216,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher { mResolver.insert(mRawUri, values); - return; + return Intents.RESULT_SMS_HANDLED; } // All the parts are in place, deal with them @@ -271,6 +227,11 @@ final class CdmaSMSDispatcher extends SMSDispatcher { for (int i = 0; i < cursorCount; i++) { cursor.moveToNext(); int cursorSequence = (int)cursor.getLong(sequenceColumn); + // Read the destination port from the first segment + if (cursorSequence == 0) { + int destinationPortColumn = cursor.getColumnIndex("destination_port"); + destinationPort = (int)cursor.getLong(destinationPortColumn); + } pdus[cursorSequence] = HexDump.hexStringToByteArray( cursor.getString(pduColumn)); } @@ -280,7 +241,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher { mResolver.delete(mRawUri, where.toString(), whereArgs); } catch (SQLException e) { Log.e(TAG, "Can't access multipart SMS database", e); - return; // TODO: NACK the message or something, don't just discard. + return Intents.RESULT_SMS_GENERIC_ERROR; } finally { if (cursor != null) cursor.close(); } @@ -300,55 +261,66 @@ final class CdmaSMSDispatcher extends SMSDispatcher { switch (destinationPort) { case SmsHeader.PORT_WAP_PUSH: // Handle the PUSH - mWapPush.dispatchWapPdu(datagram); - break; + return mWapPush.dispatchWapPdu(datagram); default:{ pdus = new byte[1][]; pdus[0] = datagram; // The messages were sent to any other WAP port dispatchPortAddressedPdus(pdus, destinationPort); - break; + return Activity.RESULT_OK; } } } /** {@inheritDoc} */ - protected void sendMultipartText(String destinationAddress, String scAddress, + protected void sendMultipartText(String destAddr, String scAddr, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { - int ref = ++sConcatenatedRef & 0xff; + /** + * TODO(cleanup): There is no real code difference between + * this and the GSM version, and hence it should be moved to + * the base class or consolidated somehow, provided calling + * the proper submitpdu stuff can be arranged. + */ - for (int i = 0, count = parts.size(); i < count; i++) { - // build SmsHeader data - byte[] data = new byte[5]; - data[0] = (byte) SmsHeader.CONCATENATED_8_BIT_REFERENCE; - data[1] = (byte) 3; // 3 bytes follow - data[2] = (byte) ref; // reference #, unique per message - data[3] = (byte) count; // total part count - data[4] = (byte) (i + 1); // 1-based sequence + int refNumber = getNextConcatenatedRef() & 0x00FF; - PendingIntent sentIntent = null; - PendingIntent deliveryIntent = null; + for (int i = 0, msgCount = parts.size(); i < msgCount; i++) { + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = refNumber; + concatRef.seqNumber = i + 1; // 1-based sequence + concatRef.msgCount = msgCount; + concatRef.isEightBits = true; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + PendingIntent sentIntent = null; if (sentIntents != null && sentIntents.size() > i) { sentIntent = sentIntents.get(i); } + + PendingIntent deliveryIntent = null; if (deliveryIntents != null && deliveryIntents.size() > i) { deliveryIntent = deliveryIntents.get(i); } - SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, - parts.get(i), deliveryIntent != null, data); + UserData uData = new UserData(); + uData.payloadStr = parts.get(i); + uData.userDataHeader = smsHeader; + + SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(destAddr, + uData, deliveryIntent != null); - sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); + sendSubmitPdu(submitPdu, sentIntent, deliveryIntent); } } - protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, + protected void sendSubmitPdu(SmsMessage.SubmitPdu submitPdu, PendingIntent sentIntent, PendingIntent deliveryIntent) { - super.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); + sendRawPdu(submitPdu.encodedScAddress, submitPdu.encodedMessage, + sentIntent, deliveryIntent); } /** {@inheritDoc} */ @@ -369,16 +341,16 @@ final class CdmaSMSDispatcher extends SMSDispatcher { } /** {@inheritDoc} */ - protected void acknowledgeLastIncomingSms(boolean success, Message response){ + protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){ // FIXME unit test leaves cm == null. this should change if (mCm != null) { - mCm.acknowledgeLastIncomingCdmaSms(success, response); + mCm.acknowledgeLastIncomingCdmaSms(success, resultToCause(result), response); } } /** {@inheritDoc} */ protected void activateCellBroadcastSms(int activate, Message response) { - mCm.activateCdmaBroadcastSms(activate, response); + mCm.setCdmaBroadcastActivation((activate == 0), response); } /** {@inheritDoc} */ @@ -391,4 +363,17 @@ final class CdmaSMSDispatcher extends SMSDispatcher { mCm.setCdmaBroadcastConfig(configValuesArray, response); } + private int resultToCause(int rc) { + switch (rc) { + case Activity.RESULT_OK: + case Intents.RESULT_SMS_HANDLED: + // Cause code is ignored on success. + return 0; + case Intents.RESULT_SMS_OUT_OF_MEMORY: + return CommandsInterface.CDMA_SMS_FAIL_CAUSE_RESOURCE_SHORTAGE; + case Intents.RESULT_SMS_GENERIC_ERROR: + default: + return CommandsInterface.CDMA_SMS_FAIL_CAUSE_OTHER_TERMINAL_PROBLEM; + } + } } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java index d5cad1c..e75a333 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java @@ -19,11 +19,15 @@ package com.android.internal.telephony.cdma; import android.app.AlarmManager; import android.content.ContentResolver; import android.content.Context; +import android.content.ContentValues; import android.content.Intent; import android.database.ContentObserver; +import android.database.SQLException; +import android.net.Uri; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; +import android.os.PowerManager; import android.os.Registrant; import android.os.RegistrantList; import android.os.SystemClock; @@ -31,13 +35,17 @@ import android.os.SystemProperties; import android.provider.Checkin; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; +import android.provider.Telephony; import android.provider.Telephony.Intents; import android.telephony.ServiceState; +import android.telephony.SignalStrength; import android.telephony.cdma.CdmaCellLocation; import android.text.TextUtils; import android.util.EventLog; import android.util.Log; +import android.util.Config; import android.util.TimeUtils; +import java.util.Calendar; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; @@ -65,14 +73,12 @@ import java.util.TimeZone; * {@hide} */ final class CdmaServiceStateTracker extends ServiceStateTracker { + //***** Instance Variables CDMAPhone phone; CdmaCellLocation cellLoc; CdmaCellLocation newCellLoc; - int rssi = 99; // signal strength 0-31, 99=unknown - // That's "received signal strength indication" fyi - /** * The access technology currently in use: DATA_ACCESS_ */ @@ -80,35 +86,66 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { private int newNetworkType = 0; private boolean mCdmaRoaming = false; + private int mRoamingIndicator; + private boolean mIsInPrl; + private int mDefaultRoamingIndicator; - private int cdmaDataConnectionState = -1;//Initial we assume no data connection - private int newCdmaDataConnectionState = -1;//Initial we assume no data connection + // Initially we assume no data connection + private int cdmaDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE; + private int newCdmaDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE; private int mRegistrationState = -1; private RegistrantList cdmaDataConnectionAttachedRegistrants = new RegistrantList(); private RegistrantList cdmaDataConnectionDetachedRegistrants = new RegistrantList(); + // Sometimes we get the NITZ time before we know what country we are in. + // Keep the time zone information from the NITZ string so we can fix + // the time zone once know the country. + private boolean mNeedFixZone = false; + private int mZoneOffset; + private boolean mZoneDst; + private long mZoneTime; private boolean mGotCountryCode = false; + String mSavedTimeZone; + long mSavedTime; + long mSavedAtTime; // We can't register for SIM_RECORDS_LOADED immediately because the // SIMRecords object may not be instantiated yet. - private boolean mNeedToRegForRuimLoaded; + private boolean mNeedToRegForRuimLoaded = false; + + // Wake lock used while setting time of day. + private PowerManager.WakeLock mWakeLock; + private static final String WAKELOCK_TAG = "ServiceStateTracker"; // Keep track of SPN display rules, so we only broadcast intent if something changes. private String curSpn = null; - private String curPlmn = null; + private String curPlmn = null; // it contains the name of the registered network in CDMA can + // be the ONS or ERI text private int curSpnRule = 0; + private String mMdn; + private int mHomeSystemId; + private int mHomeNetworkId; + private String mMin; + + private boolean isEriTextLoaded = false; + private boolean isSubscriptionFromRuim = false; + + // Registration Denied Reason, General/Authentication Failure, used only for debugging purposes + private String mRegistrationDeniedReason; + //***** Constants static final String LOG_TAG = "CDMA"; - static final String TMUK = "23430"; private ContentResolver cr; + private String currentCarrier = null; private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { Log.i("CdmaServiceStateTracker", "Auto time state called ..."); - //NOTE in CDMA NITZ is not used + revertToNitz(); + } }; @@ -124,16 +161,23 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { newSS = new ServiceState(); cellLoc = new CdmaCellLocation(); newCellLoc = new CdmaCellLocation(); + mSignalStrength = new SignalStrength(); + + PowerManager powerManager = + (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE); + mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); cm.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); cm.registerForNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED_CDMA, null); + cm.setOnNITZTime(this, EVENT_NITZ_TIME, null); cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null); cm.registerForRUIMReady(this, EVENT_RUIM_READY, null); - phone.registerForNvLoaded(this, EVENT_NV_LOADED,null); + cm.registerForNVReady(this, EVENT_NV_READY, null); + phone.registerForEriFileLoaded(this, EVENT_ERI_FILE_LOADED, null); // system setting property AIRPLANE_MODE_ON is set in Settings. int airplaneMode = Settings.System.getInt( @@ -145,7 +189,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { cr.registerContentObserver( Settings.System.getUriFor(Settings.System.AUTO_TIME), true, mAutoTimeObserver); - setRssiDefaultValues(); + setSignalStrengthDefaultValues(); mNeedToRegForRuimLoaded = true; } @@ -156,14 +200,17 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { cm.unregisterForRadioStateChanged(this); cm.unregisterForNetworkStateChanged(this); cm.unregisterForRUIMReady(this); - phone.unregisterForNvLoaded(this); + cm.unregisterForNVReady(this); + phone.unregisterForEriFileLoaded(this); phone.mRuimRecords.unregisterForRecordsLoaded(this); cm.unSetOnSignalStrengthUpdate(this); + cm.unSetOnNITZTime(this); cr.unregisterContentObserver(this.mAutoTimeObserver); } + @Override protected void finalize() { - if(DBG) Log.d(LOG_TAG, "CdmaServiceStateTracker finalized"); + if (DBG) log("CdmaServiceStateTracker finalized"); } void registerForNetworkAttach(Handler h, int what, Object obj) { @@ -190,9 +237,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { Registrant r = new Registrant(h, what, obj); cdmaDataConnectionAttachedRegistrants.add(r); - if (cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT - || cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 - || cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A) { + if (cdmaDataConnectionState == ServiceState.STATE_IN_SERVICE) { r.notifyRegistrant(); } } @@ -211,9 +256,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { Registrant r = new Registrant(h, what, obj); cdmaDataConnectionDetachedRegistrants.add(r); - if (cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT - && cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0 - && cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A) { + if (cdmaDataConnectionState != ServiceState.STATE_IN_SERVICE) { r.notifyRegistrant(); } } @@ -228,10 +271,8 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { EVENT_GET_LOC_DONE_CDMA, onComplete)); } - - //***** Overridden from ServiceStateTracker - public void - handleMessage (Message msg) { + @Override + public void handleMessage (Message msg) { AsyncResult ar; int[] ints; String[] strings; @@ -246,13 +287,21 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { // The RUIM is now ready i.e if it was locked // it has been unlocked. At this stage, the radio is already // powered on. + isSubscriptionFromRuim = true; if (mNeedToRegForRuimLoaded) { phone.mRuimRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null); mNeedToRegForRuimLoaded = false; } // restore the previous network selection. - phone.restoreSavedNetworkSelection(null); + pollState(); + + // Signal strength polling stops when radio is off + queueNextSignalStrengthPoll(); + break; + + case EVENT_NV_READY: + isSubscriptionFromRuim = false; pollState(); // Signal strength polling stops when radio is off queueNextSignalStrengthPoll(); @@ -328,9 +377,9 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } break; - case EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA: //Fall through - case EVENT_POLL_STATE_REGISTRATION_CDMA: //Fall through + case EVENT_POLL_STATE_REGISTRATION_CDMA: case EVENT_POLL_STATE_OPERATOR_CDMA: + case EVENT_POLL_STATE_CDMA_SUBSCRIPTION: ar = (AsyncResult) msg.obj; handlePollStateResult(msg.what, ar); break; @@ -341,6 +390,15 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { cm.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH)); break; + case EVENT_NITZ_TIME: + ar = (AsyncResult) msg.obj; + + String nitzString = (String)((Object[])ar.result)[0]; + long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue(); + + setTimeFromNITZString(nitzString, nitzReceiveTime); + break; + case EVENT_SIGNAL_STRENGTH_UPDATE: // This is a notification from // CommandsInterface.setOnSignalStrengthUpdate @@ -355,7 +413,6 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { break; case EVENT_RUIM_RECORDS_LOADED: - case EVENT_NV_LOADED: updateSpnDisplay(); break; @@ -367,6 +424,12 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } break; + case EVENT_ERI_FILE_LOADED: + // Repoll the state once the ERI file has been loaded + if (DBG) log("[CdmaServiceStateTracker] ERI file has been loaded, repolling."); + pollState(); + break; + default: Log.e(LOG_TAG, "Unhandled message with number: " + msg.what); break; @@ -375,8 +438,8 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { //***** Private Instance Methods - protected void setPowerStateToDesired() - { + @Override + protected void setPowerStateToDesired() { // If we want it on and it's off, turn it on if (mDesiredPowerState && cm.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) { @@ -390,14 +453,18 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { (dcTracker.getAnyDataEnabled() ? 1 : 0) ); EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_DATA_STATE_RADIO_OFF, val); } - dcTracker.cleanConnectionBeforeRadioOff(); - - // poll data state up to 15 times, with a 100ms delay + 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); + + // 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."); + DataConnectionTracker.State currentState = dcTracker.getState(); + if (currentState != DataConnectionTracker.State.CONNECTED + && currentState != DataConnectionTracker.State.DISCONNECTING) { + if (DBG) log("Data shutdown complete."); break; } SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS); @@ -407,20 +474,31 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } // Otherwise, we're in the desired state } + @Override protected void updateSpnDisplay() { + String spn = ""; + boolean showSpn = false; + String plmn = ""; + boolean showPlmn = false; + int rule = 0; + if (cm.getRadioState().isRUIMReady()) { + // TODO RUIM SPN is not implemnted, EF_SPN has to be read and Display Condition + // Character Encoding, Language Indicator and SPN has to be set + // rule = phone.mRuimRecords.getDisplayRule(ss.getOperatorNumeric()); + // spn = phone.mSIMRecords.getServiceProvideName(); + plmn = ss.getOperatorAlphaLong(); // mOperatorAlphaLong contains the ONS + // showSpn = (rule & ... + showPlmn = true; // showPlmn = (rule & ... - // TODO Check this method again, because it is not sure at the moment how - // the RUIM handles the SIM stuff - - //int rule = phone.mRuimRecords.getDisplayRule(ss.getOperatorNumeric()); - String spn = null; //phone.mRuimRecords.getServiceProviderName(); - String plmn = ss.getOperatorAlphaLong(); + } else { + // In this case there is no SPN available from RUIM, we show the ERI text + plmn = ss.getOperatorAlphaLong(); // mOperatorAlphaLong contains the ERI text + showPlmn = true; + } - if (!TextUtils.equals(this.curPlmn, plmn)) { - //TODO (rule & SIMRecords.SPN_RULE_SHOW_SPN) == SIMRecords.SPN_RULE_SHOW_SPN; - boolean showSpn = false; - //TODO (rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN; - boolean showPlmn = true; + if (rule != curSpnRule + || !TextUtils.equals(spn, curSpn) + || !TextUtils.equals(plmn, curPlmn)) { Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION); intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn); intent.putExtra(Intents.EXTRA_SPN, spn); @@ -429,17 +507,17 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { phone.getContext().sendStickyBroadcast(intent); } - //curSpnRule = rule; - //curSpn = spn; - this.curPlmn = plmn; + curSpnRule = rule; + curSpn = spn; + curPlmn = plmn; } /** * Handle the result of one of the pollState()-related requests */ - protected void - handlePollStateResult (int what, AsyncResult ar) { + @Override + protected void handlePollStateResult (int what, AsyncResult ar) { int ints[]; String states[]; @@ -473,82 +551,129 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } } else try { switch (what) { - case EVENT_POLL_STATE_REGISTRATION_CDMA: - //offset, because we don't want the first 3 values in the int-array - final int offset = 3; + case EVENT_POLL_STATE_REGISTRATION_CDMA: // Handle RIL_REQUEST_REGISTRATION_STATE. states = (String[])ar.result; - int responseValuesRegistrationState[] = { - -1, //[0] radioTechnology - -1, //[1] baseStationId - -1, //[2] baseStationLatitude - -1, //[3] baseStationLongitude - 0, //[4] cssIndicator; init with 0, because it is treated as a boolean - -1, //[5] systemId - -1, //[6] networkId - -1, //[7] TSB-58 Roaming indicator // NEWRIL:TODO UNUSED - -1, //[8] Indicates if current system is in PRL // NEWRIL:TODO UNUSED - -1, //[9] Is default roaming indicator from PRL // NEWRIL:TODO UNUSED - -1, //[10] If registration state is 3 this is reason for denial // NEWRIL:TODO UNUSED - }; - - if (states.length > 0) { + int registrationState = 4; //[0] registrationState + int radioTechnology = -1; //[3] radioTechnology + int baseStationId = -1; //[4] baseStationId + int baseStationLatitude = -1; //[5] baseStationLatitude + int baseStationLongitude = -1; //[6] baseStationLongitude + int cssIndicator = 0; //[7] init with 0, because it is treated as a boolean + int systemId = 0; //[8] systemId + int networkId = 0; //[9] networkId + int roamingIndicator = -1; //[10] Roaming indicator + int systemIsInPrl = 0; //[11] Indicates if current system is in PRL + int defaultRoamingIndicator = 0; //[12] Is default roaming indicator from PRL + int reasonForDenial = 0; //[13] Denial reason if registrationState = 3 + + if (states.length == 14) { try { - this.mRegistrationState = Integer.parseInt(states[0]); - if (states.length >= 10) { - for(int i = 0; i < states.length - offset; i++) { - if (states[i + offset] != null - && states[i + offset].length() > 0) { - try { - responseValuesRegistrationState[i] = - Integer.parseInt(states[i + offset], 16); - } - catch(NumberFormatException ex) { - Log.w(LOG_TAG, "Warning! There is an unexpected value" - + "returned as response from " - + "RIL_REQUEST_REGISTRATION_STATE."); - } - } - } - } - else { - Log.e(LOG_TAG, "Too less parameters returned from" - + " RIL_REQUEST_REGISTRATION_STATE"); - } - } catch (NumberFormatException ex) { + registrationState = Integer.parseInt(states[0]); + radioTechnology = Integer.parseInt(states[3]); + baseStationId = Integer.parseInt(states[4], 16); + baseStationLatitude = Integer.parseInt(states[5], 16); + baseStationLongitude = Integer.parseInt(states[6], 16); + cssIndicator = Integer.parseInt(states[7]); + systemId = Integer.parseInt(states[8]); + networkId = Integer.parseInt(states[9]); + roamingIndicator = Integer.parseInt(states[10]); + systemIsInPrl = Integer.parseInt(states[11]); + defaultRoamingIndicator = Integer.parseInt(states[12]); + reasonForDenial = Integer.parseInt(states[13]); + } + catch(NumberFormatException ex) { Log.w(LOG_TAG, "error parsing RegistrationState: " + ex); } + } else { + throw new RuntimeException("Warning! Wrong number of parameters returned from " + + "RIL_REQUEST_REGISTRATION_STATE: expected 14 got " + + states.length); } - mCdmaRoaming = regCodeIsRoaming(this.mRegistrationState); - this.newCdmaDataConnectionState = - radioTechnologyToServiceState(responseValuesRegistrationState[0]); - newSS.setState (regCodeToServiceState(this.mRegistrationState)); - newSS.setRadioTechnology(responseValuesRegistrationState[0]); - newSS.setCssIndicator(responseValuesRegistrationState[4]); - newSS.setSystemAndNetworkId(responseValuesRegistrationState[5], - responseValuesRegistrationState[6]); + mRegistrationState = registrationState; + mCdmaRoaming = regCodeIsRoaming(registrationState); + newSS.setState (regCodeToServiceState(registrationState)); + + this.newCdmaDataConnectionState = radioTechnologyToDataServiceState(radioTechnology); + newSS.setRadioTechnology(radioTechnology); + newNetworkType = radioTechnology; + + newSS.setCssIndicator(cssIndicator); + newSS.setSystemAndNetworkId(systemId, networkId); + mRoamingIndicator = roamingIndicator; + mIsInPrl = (systemIsInPrl == 0) ? false : true; + mDefaultRoamingIndicator = defaultRoamingIndicator; - newNetworkType = responseValuesRegistrationState[0]; // values are -1 if not available - newCellLoc.setCellLocationData(responseValuesRegistrationState[1], - responseValuesRegistrationState[2], - responseValuesRegistrationState[3]); + newCellLoc.setCellLocationData(baseStationId, baseStationLatitude, + baseStationLongitude); + + if (reasonForDenial == 0) { + mRegistrationDeniedReason = ServiceStateTracker.REGISTRATION_DENIED_GEN; + } else if (reasonForDenial == 1) { + mRegistrationDeniedReason = ServiceStateTracker.REGISTRATION_DENIED_AUTH; + } else { + mRegistrationDeniedReason = ""; + } + + if (mRegistrationState == 3) { + if (DBG) log("Registration denied, " + mRegistrationDeniedReason); + } break; - case EVENT_POLL_STATE_OPERATOR_CDMA: + case EVENT_POLL_STATE_OPERATOR_CDMA: // Handle RIL_REQUEST_OPERATOR String opNames[] = (String[])ar.result; if (opNames != null && opNames.length >= 3) { - newSS.setOperatorName (opNames[0], opNames[1], opNames[2]); + if (cm.getRadioState().isNVReady()) { + // In CDMA in case on NV the ss.mOperatorAlphaLong is set later with the + // ERI text, so here it is ignored what is coming from the modem + newSS.setOperatorName(null, opNames[1], opNames[2]); + } else { + newSS.setOperatorName(opNames[0], opNames[1], opNames[2]); + } + + if (!(opNames[2].equals(currentCarrier))) { + // TODO(Moto): jsh asks, "This uses the MCC+MNC of the current registered + // network to set the "current" entry in the APN table. But the correct + // entry should be the MCC+MNC that matches the subscribed operator + // (eg, phone issuer). These can be different when roaming." + try { + // Set the current field of the telephony provider according to + // the CDMA's operator + Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"); + ContentValues map = new ContentValues(); + map.put(Telephony.Carriers.NUMERIC, opNames[2]); + cr.insert(uri, map); + // save current carrier for the next time check + currentCarrier = opNames[2]; + } catch (SQLException e) { + Log.e(LOG_TAG, "Can't store current operator", e); + } + } else { + Log.i(LOG_TAG, "current carrier is not changed"); + } + } else { + Log.w(LOG_TAG, "error parsing opNames"); } break; - case EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA: - ints = (int[])ar.result; - newSS.setIsManualSelection(ints[0] == 1); + case EVENT_POLL_STATE_CDMA_SUBSCRIPTION: // Handle RIL_CDMA_SUBSCRIPTION + String cdmaSubscription[] = (String[])ar.result; + + if (cdmaSubscription != null && cdmaSubscription.length >= 4) { + mMdn = cdmaSubscription[0]; + mHomeSystemId = Integer.parseInt(cdmaSubscription[1], 16); + mHomeNetworkId = Integer.parseInt(cdmaSubscription[2], 16); + mMin = cdmaSubscription[3]; + + } else { + Log.w(LOG_TAG, "error parsing cdmaSubscription"); + } break; + default: Log.e(LOG_TAG, "RIL response handle in wrong phone!" + " Expected CDMA RIL request and get GSM RIL request."); @@ -563,29 +688,55 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { pollingContext[0]--; if (pollingContext[0] == 0) { - newSS.setRoaming(isRoamingBetweenOperators(mCdmaRoaming, newSS)); + boolean namMatch = false; + if ((mHomeSystemId != 0) && (mHomeSystemId == newSS.getSystemId()) ) { + namMatch = true; + } - switch(this.mRegistrationState) { - case ServiceState.REGISTRATION_STATE_HOME_NETWORK: - newSS.setExtendedCdmaRoaming(ServiceState.REGISTRATION_STATE_HOME_NETWORK); - break; - case ServiceState.REGISTRATION_STATE_ROAMING: - newSS.setExtendedCdmaRoaming(ServiceState.REGISTRATION_STATE_ROAMING); - break; - case ServiceState.REGISTRATION_STATE_ROAMING_AFFILIATE: - newSS.setExtendedCdmaRoaming(ServiceState.REGISTRATION_STATE_ROAMING_AFFILIATE); - break; - default: - Log.w(LOG_TAG, "Received a different registration state, " - + "but don't changed the extended cdma roaming mode."); + // Setting SS Roaming (general) + if (isSubscriptionFromRuim) { + newSS.setRoaming(isRoamingBetweenOperators(mCdmaRoaming, newSS)); + } else { + newSS.setRoaming(mCdmaRoaming); + } + + // Setting SS CdmaRoamingIndicator and CdmaDefaultRoamingIndicator + // TODO(Teleca): Validate this is correct. + if (mIsInPrl) { + if (namMatch && (mRoamingIndicator <= 2)) { + // System is acquired, prl match, nam match and mRoamingIndicator <= 2 + newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF); + } else { + // System is acquired, prl match, no nam match or mRoamingIndicator > 2 + newSS.setCdmaRoamingIndicator(mRoamingIndicator); + } + } else { + if (mRegistrationState == 5) { + // System is acquired but prl not loaded or no prl match + newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_FLASH); + } else { + // Use the default indicator + } + } + + newSS.setCdmaDefaultRoamingIndicator(mDefaultRoamingIndicator); + + // NOTE: Some operator may require to override the mCdmaRoaming (set by the modem) + // depending on the mRoamingIndicator. + + if (DBG) { + log("Set CDMA Roaming Indicator to: " + newSS.getCdmaRoamingIndicator() + + ". mCdmaRoaming = " + mCdmaRoaming + ", namMatch = " + namMatch + + ", mIsInPrl = " + mIsInPrl + ", mRoamingIndicator = " + mRoamingIndicator + + ", mDefaultRoamingIndicator= " + mDefaultRoamingIndicator); } pollStateDone(); } } - private void setRssiDefaultValues() { - rssi = 99; + private void setSignalStrengthDefaultValues() { + mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1, false); } /** @@ -606,7 +757,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { case RADIO_UNAVAILABLE: newSS.setStateOutOfService(); newCellLoc.setStateInvalid(); - setRssiDefaultValues(); + setSignalStrengthDefaultValues(); mGotCountryCode = false; pollStateDone(); @@ -615,7 +766,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { case RADIO_OFF: newSS.setStateOff(); newCellLoc.setStateInvalid(); - setRssiDefaultValues(); + setSignalStrengthDefaultValues(); mGotCountryCode = false; pollStateDone(); @@ -627,10 +778,10 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { log("Radio Technology Change ongoing, setting SS to off"); newSS.setStateOff(); newCellLoc.setStateInvalid(); - setRssiDefaultValues(); + setSignalStrengthDefaultValues(); mGotCountryCode = false; - pollStateDone(); + //NOTE: pollStateDone() is not needed in this case break; default: @@ -639,20 +790,21 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { // are allowed to arrive out-of-order pollingContext[0]++; - //RIL_REQUEST_OPERATOR is necessary for CDMA - cm.getOperator( - obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext)); - - pollingContext[0]++; - //RIL_REQUEST_REGISTRATION_STATE is necessary for CDMA - cm.getRegistrationState( - obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA, pollingContext)); - - pollingContext[0]++; - //RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE necessary for CDMA - cm.getNetworkSelectionMode( - obtainMessage(EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA, pollingContext)); - break; + // RIL_REQUEST_CDMA_SUBSCRIPTION is necessary for CDMA + cm.getCDMASubscription( + obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION, pollingContext)); + + pollingContext[0]++; + // RIL_REQUEST_OPERATOR is necessary for CDMA + cm.getOperator( + obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext)); + + pollingContext[0]++; + // RIL_REQUEST_REGISTRATION_STATE is necessary for CDMA + cm.getRegistrationState( + obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA, pollingContext)); + + break; } } @@ -683,14 +835,45 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { return ret; } - private void - pollStateDone() { - if (DBG) { - Log.d(LOG_TAG, "Poll ServiceState done: " + - " oldSS=[" + ss ); - Log.d(LOG_TAG, "Poll ServiceState done: " + - " newSS=[" + newSS); + private void fixTimeZone(String isoCountryCode) { + TimeZone zone = null; + // If the offset is (0, false) and the time zone property + // is set, use the time zone property rather than GMT. + String zoneName = SystemProperties.get(TIMEZONE_PROPERTY); + if ((mZoneOffset == 0) && (mZoneDst == false) && (zoneName != null) + && (zoneName.length() > 0) + && (Arrays.binarySearch(GMT_COUNTRY_CODES, isoCountryCode) < 0)) { + // For NITZ string without time zone, + // need adjust time to reflect default time zone setting + zone = TimeZone.getDefault(); + long tzOffset; + tzOffset = zone.getOffset(System.currentTimeMillis()); + if (getAutoTime()) { + setAndBroadcastNetworkSetTime(System.currentTimeMillis() - tzOffset); + } else { + // Adjust the saved NITZ time to account for tzOffset. + mSavedTime = mSavedTime - tzOffset; + } + } else if (isoCountryCode.equals("")) { + // Country code not found. This is likely a test network. + // Get a TimeZone based only on the NITZ parameters (best guess). + zone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime); + } else { + zone = TimeUtils.getTimeZone(mZoneOffset, mZoneDst, mZoneTime, isoCountryCode); + } + + mNeedFixZone = false; + + if (zone != null) { + if (getAutoTime()) { + setAndBroadcastNetworkSetTimeZone(zone.getID()); + } + saveNitzTimeZone(zone.getID()); } + } + + private void pollStateDone() { + if (DBG) log("Poll ServiceState done: oldSS=[" + ss + "] newSS=[" + newSS + "]"); boolean hasRegistered = ss.getState() != ServiceState.STATE_IN_SERVICE @@ -701,20 +884,12 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { && newSS.getState() != ServiceState.STATE_IN_SERVICE; boolean hasCdmaDataConnectionAttached = - (this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT - && this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0 - && this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A) - && (this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT - || this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 - || this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A); + this.cdmaDataConnectionState != ServiceState.STATE_IN_SERVICE + && this.newCdmaDataConnectionState == ServiceState.STATE_IN_SERVICE; boolean hasCdmaDataConnectionDetached = - (this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT - || this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 - || this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A) - && (this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT - && this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0 - && this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A); + this.cdmaDataConnectionState == ServiceState.STATE_IN_SERVICE + && this.newCdmaDataConnectionState != ServiceState.STATE_IN_SERVICE; boolean hasCdmaDataConnectionChanged = cdmaDataConnectionState != newCdmaDataConnectionState; @@ -757,6 +932,20 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } if (hasChanged) { + if (cm.getRadioState().isNVReady()) { + String eriText; + // Now the CDMAPhone sees the new ServiceState so it can get the new ERI text + if (ss.getState() == ServiceState.STATE_IN_SERVICE) { + eriText = phone.getCdmaEriText(); + } else { + // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used for + // mRegistrationState 0,2,3 and 4 + eriText = phone.getContext().getText( + com.android.internal.R.string.roamingTextSearching).toString(); + } + ss.setCdmaEriText(eriText); + } + String operatorNumeric; phone.setSystemProperty(PROPERTY_OPERATOR_ALPHA, @@ -768,9 +957,9 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { if (operatorNumeric == null) { phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, ""); } else { - String iso = ""; + String isoCountryCode = ""; try{ - iso = MccTable.countryCodeForMcc(Integer.parseInt( + isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt( operatorNumeric.substring(0,3))); } catch ( NumberFormatException ex){ Log.w(LOG_TAG, "countryCodeForMcc error" + ex); @@ -778,14 +967,15 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { Log.w(LOG_TAG, "countryCodeForMcc error" + ex); } - phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, iso); + phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, isoCountryCode); mGotCountryCode = true; + if (mNeedFixZone) { + fixTimeZone(isoCountryCode); + } } phone.setSystemProperty(PROPERTY_OPERATOR_ISROAMING, ss.getRoaming() ? "true" : "false"); - phone.setSystemProperty(PROPERTY_OPERATOR_ISMANUAL, - ss.getIsManualSelection() ? "true" : "false"); updateSpnDisplay(); phone.notifyServiceStateChanged(ss); @@ -825,10 +1015,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { // Couldn't find a proper timezone. Perhaps the DST data is wrong. guess = findTimeZone(offset, !dst, when); } - if (DBG) { - Log.d(LOG_TAG, "getNitzTimeZone returning " - + (guess == null ? guess : guess.getID())); - } + if (DBG) log("getNitzTimeZone returning " + (guess == null ? guess : guess.getID())); return guess; } @@ -852,6 +1039,12 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { return guess; } + /** + * TODO: This code is exactly the same as in GsmServiceStateTracker + * and has a TODO to not poll signal strength if screen is off. + * This code should probably be hoisted to the base class so + * the fix, when added, works for both. + */ private void queueNextSignalStrengthPoll() { if (dontPollSignalStrength || (cm.getRadioState().isGsm())) { @@ -865,48 +1058,56 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { msg = obtainMessage(); msg.what = EVENT_POLL_SIGNAL_STRENGTH; - // TODO Done't poll signal strength if screen is off + // TODO Don't poll signal strength if screen is off sendMessageDelayed(msg, POLL_PERIOD_MILLIS); } /** - * send signal-strength-changed notification if rssi changed + * send signal-strength-changed notification if changed * Called both for solicited and unsolicited signal stength updates */ private void onSignalStrengthResult(AsyncResult ar) { - int oldRSSI = rssi; + SignalStrength oldSignalStrength = mSignalStrength; if (ar.exception != null) { - // 99 = unknown - // most likely radio is resetting/disconnected - rssi = 99; + // Most likely radio is resetting/disconnected change to default values. + setSignalStrengthDefaultValues(); } else { int[] ints = (int[])ar.result; - - // bug 658816 seems to be a case where the result is 0-length - if (ints.length != 0) { - rssi = ints[0]; - } else { - Log.e(LOG_TAG, "Bogus signal strength response"); - rssi = 99; + int offset = 2; + + int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -1; + int cdmaEcio = (ints[offset+1] > 0) ? -ints[offset+1] : -1; + + int evdoRssi = -1; + int evdoEcio = -1; + int evdoSnr = -1; + if ((networkType == ServiceState.RADIO_TECHNOLOGY_EVDO_0) + || (networkType == ServiceState.RADIO_TECHNOLOGY_EVDO_A)) { + evdoRssi = (ints[offset+2] > 0) ? -ints[offset+2] : -1; + evdoEcio = (ints[offset+3] > 0) ? -ints[offset+3] : -1; + evdoSnr = ((ints[offset+4] > 0) && (ints[offset+4] <= 8)) ? ints[offset+4] : -1; } + + mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio, + evdoRssi, evdoEcio, evdoSnr, false); } - if (rssi != oldRSSI) { + if (!mSignalStrength.equals(oldSignalStrength)) { try { // This takes care of delayed EVENT_POLL_SIGNAL_STRENGTH (scheduled after // POLL_PERIOD_MILLIS) during Radio Technology Change) phone.notifySignalStrength(); } catch (NullPointerException ex) { - log("onSignalStrengthResult() Phone already destroyed: " + ex - + "Signal Stranth not notified"); + log("onSignalStrengthResult() Phone already destroyed: " + ex + + "SignalStrength not notified"); } } } - private int radioTechnologyToServiceState(int code) { - int retVal = ServiceState.RADIO_TECHNOLOGY_UNKNOWN; + private int radioTechnologyToDataServiceState(int code) { + int retVal = ServiceState.STATE_OUT_OF_SERVICE; switch(code) { case 0: case 1: @@ -915,14 +1116,10 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { case 4: case 5: break; - case 6: - retVal = ServiceState.RADIO_TECHNOLOGY_1xRTT; - break; - case 7: - retVal = ServiceState.RADIO_TECHNOLOGY_EVDO_0; - break; - case 8: - retVal = ServiceState.RADIO_TECHNOLOGY_EVDO_A; + case 6: // RADIO_TECHNOLOGY_1xRTT + case 7: // RADIO_TECHNOLOGY_EVDO_0 + case 8: // RADIO_TECHNOLOGY_EVDO_A + retVal = ServiceState.STATE_IN_SERVICE; break; default: Log.e(LOG_TAG, "Wrong radioTechnology code."); @@ -943,9 +1140,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { case 3: // 3 is "registration denied", fall through case 4: // 4 is "unknown" no vaild in current baseband return ServiceState.STATE_OUT_OF_SERVICE; - case 5:// fall through - case 6: - // Registered and: roaming (5) or roaming affiliates (6) + case 5:// 5 is "Registered, roaming" return ServiceState.STATE_IN_SERVICE; default: @@ -983,6 +1178,8 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { boolean isRoamingBetweenOperators(boolean cdmaRoaming, ServiceState s) { String spn = SystemProperties.get(PROPERTY_ICC_OPERATOR_ALPHA, "empty"); + // NOTE: in case of RUIM we should completely ignore the ERI data file and + // mOperatorAlphaLong is set from RIL_REQUEST_OPERATOR response 0 (alpha ONS) String onsl = s.getOperatorAlphaLong(); String onss = s.getOperatorAlphaShort(); @@ -992,6 +1189,169 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { return cdmaRoaming && !(equalsOnsl || equalsOnss); } + + /** + * nitzReceiveTime is time_t that the NITZ time was posted + */ + + private + void setTimeFromNITZString (String nitz, long nitzReceiveTime) + { + // "yy/mm/dd,hh:mm:ss(+/-)tz" + // tz is in number of quarter-hours + + long start = SystemClock.elapsedRealtime(); + Log.i(LOG_TAG, "NITZ: " + nitz + "," + nitzReceiveTime + + " start=" + start + " delay=" + (start - nitzReceiveTime)); + + try { + /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone + * offset as well (which we won't worry about until later) */ + Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + + c.clear(); + c.set(Calendar.DST_OFFSET, 0); + + String[] nitzSubs = nitz.split("[/:,+-]"); + + int year = 2000 + Integer.parseInt(nitzSubs[0]); + c.set(Calendar.YEAR, year); + + // month is 0 based! + int month = Integer.parseInt(nitzSubs[1]) - 1; + c.set(Calendar.MONTH, month); + + int date = Integer.parseInt(nitzSubs[2]); + c.set(Calendar.DATE, date); + + int hour = Integer.parseInt(nitzSubs[3]); + c.set(Calendar.HOUR, hour); + + int minute = Integer.parseInt(nitzSubs[4]); + c.set(Calendar.MINUTE, minute); + + int second = Integer.parseInt(nitzSubs[5]); + c.set(Calendar.SECOND, second); + + boolean sign = (nitz.indexOf('-') == -1); + + int tzOffset = Integer.parseInt(nitzSubs[6]); + + int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7]) + : 0; + + // The zone offset received from NITZ is for current local time, + // so DST correction is already applied. Don't add it again. + // + // tzOffset += dst * 4; + // + // We could unapply it if we wanted the raw offset. + + tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000; + + TimeZone zone = null; + + // As a special extension, the Android emulator appends the name of + // the host computer's timezone to the nitz string. this is zoneinfo + // timezone name of the form Area!Location or Area!Location!SubLocation + // so we need to convert the ! into / + if (nitzSubs.length >= 9) { + String tzname = nitzSubs[8].replace('!','/'); + zone = TimeZone.getTimeZone( tzname ); + } + + String iso = SystemProperties.get(PROPERTY_OPERATOR_ISO_COUNTRY); + + if (zone == null) { + + if (mGotCountryCode) { + if (iso != null && iso.length() > 0) { + zone = TimeUtils.getTimeZone(tzOffset, dst != 0, + c.getTimeInMillis(), + iso); + } else { + // We don't have a valid iso country code. This is + // most likely because we're on a test network that's + // using a bogus MCC (eg, "001"), so get a TimeZone + // based only on the NITZ parameters. + zone = getNitzTimeZone(tzOffset, (dst != 0), c.getTimeInMillis()); + } + } + } + + if (zone == null) { + // We got the time before the country, so we don't know + // how to identify the DST rules yet. Save the information + // and hope to fix it up later. + + mNeedFixZone = true; + mZoneOffset = tzOffset; + mZoneDst = dst != 0; + mZoneTime = c.getTimeInMillis(); + } + + if (zone != null) { + if (getAutoTime()) { + setAndBroadcastNetworkSetTimeZone(zone.getID()); + } + saveNitzTimeZone(zone.getID()); + } + + String ignore = SystemProperties.get("gsm.ignore-nitz"); + if (ignore != null && ignore.equals("yes")) { + Log.i(LOG_TAG, "NITZ: Not setting clock because gsm.ignore-nitz is set"); + return; + } + + try { + mWakeLock.acquire(); + + if (getAutoTime()) { + long millisSinceNitzReceived + = SystemClock.elapsedRealtime() - nitzReceiveTime; + + if (millisSinceNitzReceived < 0) { + // Sanity check: something is wrong + Log.i(LOG_TAG, "NITZ: not setting time, clock has rolled " + + "backwards since NITZ time was received, " + + nitz); + return; + } + + if (millisSinceNitzReceived > Integer.MAX_VALUE) { + // If the time is this far off, something is wrong > 24 days! + Log.i(LOG_TAG, "NITZ: not setting time, processing has taken " + + (millisSinceNitzReceived / (1000 * 60 * 60 * 24)) + + " days"); + return; + } + + // Note: with range checks above, cast to int is safe + c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived); + + Log.i(LOG_TAG, "NITZ: Setting time of day to " + c.getTime() + + " NITZ receive delay(ms): " + millisSinceNitzReceived + + " gained(ms): " + + (c.getTimeInMillis() - System.currentTimeMillis()) + + " from " + nitz); + + setAndBroadcastNetworkSetTime(c.getTimeInMillis()); + Log.i(LOG_TAG, "NITZ: after Setting time of day"); + } + SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis())); + saveNitzTime(c.getTimeInMillis()); + if (Config.LOGV) { + long end = SystemClock.elapsedRealtime(); + Log.v(LOG_TAG, "NITZ: end=" + end + " dur=" + (end - start)); + } + } finally { + mWakeLock.release(); + } + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "NITZ: Parsing NITZ time " + nitz, ex); + } + } + private boolean getAutoTime() { try { return Settings.System.getInt(phone.getContext().getContentResolver(), @@ -1001,6 +1361,58 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } } + private void saveNitzTimeZone(String zoneId) { + mSavedTimeZone = zoneId; + } + + private void saveNitzTime(long time) { + mSavedTime = time; + mSavedAtTime = SystemClock.elapsedRealtime(); + } + + /** + * Set the timezone and send out a sticky broadcast so the system can + * determine if the timezone was set by the carrier. + * + * @param zoneId timezone set by carrier + */ + private void setAndBroadcastNetworkSetTimeZone(String zoneId) { + AlarmManager alarm = + (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); + alarm.setTimeZone(zoneId); + Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE); + intent.putExtra("time-zone", zoneId); + phone.getContext().sendStickyBroadcast(intent); + } + + /** + * Set the time and Send out a sticky broadcast so the system can determine + * if the time was set by the carrier. + * + * @param time time set by network + */ + private void setAndBroadcastNetworkSetTime(long time) { + SystemClock.setCurrentTimeMillis(time); + Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME); + intent.putExtra("time", time); + phone.getContext().sendStickyBroadcast(intent); + } + + private void revertToNitz() { + if (Settings.System.getInt(phone.getContext().getContentResolver(), + Settings.System.AUTO_TIME, 0) == 0) { + return; + } + Log.d(LOG_TAG, "Reverting to NITZ: tz='" + mSavedTimeZone + + "' mSavedTime=" + mSavedTime + + " mSavedAtTime=" + mSavedAtTime); + if (mSavedTimeZone != null && mSavedTime != 0 && mSavedAtTime != 0) { + setAndBroadcastNetworkSetTimeZone(mSavedTimeZone); + setAndBroadcastNetworkSetTime(mSavedTime + + (SystemClock.elapsedRealtime() - mSavedAtTime)); + } + } + /** * @return true if phone is camping on a technology * that could support voice and data simultaneously. @@ -1017,4 +1429,12 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { Log.d(LOG_TAG, "[CdmaServiceStateTracker] " + s); } + public String getMdnNumber() { + return mMdn; + } + + public String getCdmaMin() { + return mMin; + } + } diff --git a/telephony/java/com/android/internal/telephony/cdma/EriInfo.java b/telephony/java/com/android/internal/telephony/cdma/EriInfo.java new file mode 100644 index 0000000..5c8e23e --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/EriInfo.java @@ -0,0 +1,43 @@ +/* + * 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; + +public final class EriInfo { + + public static final int ROAMING_INDICATOR_ON = 0; + public static final int ROAMING_INDICATOR_OFF = 1; + public static final int ROAMING_INDICATOR_FLASH = 2; + + public static final int ROAMING_ICON_MODE_NORMAL = 0; + public static final int ROAMING_ICON_MODE_FLASH = 1; + + public int mRoamingIndicator; + public int mIconIndex; + public int mIconMode; + public String mEriText; + public int mCallPromptId; + public int mAlertId; + + public EriInfo (int roamingIndicator, int iconIndex, int iconMode, String eriText, + int callPromptId, int alertId) { + + this.mRoamingIndicator = roamingIndicator; + this.mIconIndex = iconIndex; + this.mIconMode = iconMode; + this.mEriText = eriText; + this.mCallPromptId = callPromptId; + this.mAlertId = alertId; + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/EriManager.java b/telephony/java/com/android/internal/telephony/cdma/EriManager.java new file mode 100644 index 0000000..6c1384c --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/EriManager.java @@ -0,0 +1,436 @@ +/* + * 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; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.XmlResourceParser; +import android.os.Message; +import android.util.Log; + +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneBase; + +import com.android.internal.util.XmlUtils; + +import java.util.HashMap; + +/** + * EriManager loads the ERI file definitions and manages the CDMA roaming information. + * + */ +public final class EriManager { + + class EriFile { + + public int mVersionNumber; // File version number + public int mNumberOfEriEntries; // Number of entries + public int mEriFileType; // Eri Phase 0/1 + //public int mNumberOfIconImages; // reserved for future use + //public int mIconImageType; // reserved for future use + public String[] mCallPromptId; // reserved for future use + public HashMap<Integer, EriInfo> mRoamIndTable; // Roaming Indicator Table + + public EriFile() { + this.mVersionNumber = -1; + this.mNumberOfEriEntries = 0; + this.mEriFileType = -1; + this.mCallPromptId = new String[] { "", "", "" }; + this.mRoamIndTable = new HashMap<Integer, EriInfo>(); + } + } + + class EriDisplayInformation { + public int mEriIconIndex; + public int mEriIconMode; + public String mEriIconText; + + public EriDisplayInformation(int eriIconIndex, int eriIconMode, String eriIconText) { + mEriIconIndex = eriIconIndex; + mEriIconMode = eriIconMode; + mEriIconText = eriIconText; + } + +// public void setParameters(int eriIconIndex, int eriIconMode, String eriIconText){ +// this.mEriIconIndex = eriIconIndex; +// this.mEriIconMode = eriIconMode; +// this.mEriIconText = eriIconText; +// } + + @Override + public String toString() { + return "EriDisplayInformation: {" + " IconIndex: " + mEriIconIndex + " EriIconMode: " + + mEriIconMode + " EriIconText: " + mEriIconText + " }"; + } + } + + static final String LOG_TAG = "CDMA"; + + public static final int ERI_FROM_XML = 0; + public static final int ERI_FROM_FILE_SYSTEM = 1; + public static final int ERI_FROM_MODEM = 2; + + private PhoneBase mPhone; + private Context mContext; + private int mEriFileSource = ERI_FROM_XML; + private boolean isEriFileLoaded; + private EriFile mEriFile; + + public EriManager(PhoneBase phone, Context context, int eriFileSource) { + this.mPhone = phone; + this.mContext = context; + this.mEriFileSource = eriFileSource; + this.mEriFile = new EriFile(); + } + + public void dispose() { + mEriFile = new EriFile(); + isEriFileLoaded = false; + } + + + public void loadEriFile() { + switch (mEriFileSource) { + case ERI_FROM_MODEM: + loadEriFileFromModem(); + break; + + case ERI_FROM_FILE_SYSTEM: + loadEriFileFromFileSystem(); + break; + + case ERI_FROM_XML: + default: + loadEriFileFromXml(); + break; + } + } + + /** + * Load the ERI file from the MODEM through chipset specific RIL_REQUEST_OEM_HOOK + * + * In this case the ERI file can be updated from the Phone Support Tool available + * from the Chipset vendor + */ + private void loadEriFileFromModem() { + // NOT IMPLEMENTED, Chipset vendor/Operator specific + } + + /** + * Load the ERI file from a File System file + * + * In this case the a Phone Support Tool to update the ERI file must be provided + * to the Operator + */ + private void loadEriFileFromFileSystem() { + // NOT IMPLEMENTED, Chipset vendor/Operator specific + } + + /** + * Load the ERI file from the application framework resources encoded in XML + * + */ + private void loadEriFileFromXml() { + Resources r = mContext.getResources(); + XmlResourceParser parser = r.getXml(com.android.internal.R.xml.eri); + try { + XmlUtils.beginDocument(parser, "EriFile"); + mEriFile.mVersionNumber = Integer.parseInt( + parser.getAttributeValue(null, "VersionNumber")); + mEriFile.mNumberOfEriEntries = Integer.parseInt( + parser.getAttributeValue(null, "NumberOfEriEntries")); + mEriFile.mEriFileType = Integer.parseInt( + parser.getAttributeValue(null, "EriFileType")); + + int parsedEriEntries = 0; + while(true) { + XmlUtils.nextElement(parser); + String name = parser.getName(); + if (name == null) { + if (parsedEriEntries != mEriFile.mNumberOfEriEntries) + Log.e(LOG_TAG, "Error Parsing ERI file: " + mEriFile.mNumberOfEriEntries + + " defined, " + parsedEriEntries + " parsed!"); + break; + } else if (name.equals("CallPromptId")) { + int id = Integer.parseInt(parser.getAttributeValue(null, "Id")); + String text = parser.getAttributeValue(null, "CallPromptText"); + if (id >= 0 && id <= 2) { + mEriFile.mCallPromptId[id] = text; + } else { + Log.e(LOG_TAG, "Error Parsing ERI file: found" + id + " CallPromptId"); + } + + } else if (name.equals("EriInfo")) { + int roamingIndicator = Integer.parseInt( + parser.getAttributeValue(null, "RoamingIndicator")); + int iconIndex = Integer.parseInt(parser.getAttributeValue(null, "IconIndex")); + int iconMode = Integer.parseInt(parser.getAttributeValue(null, "IconMode")); + String eriText = parser.getAttributeValue(null, "EriText"); + int callPromptId = Integer.parseInt( + parser.getAttributeValue(null, "CallPromptId")); + int alertId = Integer.parseInt(parser.getAttributeValue(null, "AlertId")); + parsedEriEntries++; + mEriFile.mRoamIndTable.put(roamingIndicator, new EriInfo (roamingIndicator, + iconIndex, iconMode, eriText, callPromptId, alertId)); + } + } + + isEriFileLoaded = true; + + } catch (Exception e) { + Log.e(LOG_TAG, "Got exception while loading ERI file.", e); + } finally { + parser.close(); + } + } + + /** + * Returns the version of the ERI file + * + */ + public int getEriFileVersion() { + return mEriFile.mVersionNumber; + } + + /** + * Returns the number of ERI entries parsed + * + */ + public int getEriNumberOfEntries() { + return mEriFile.mNumberOfEriEntries; + } + + /** + * Returns the ERI file type value ( 0 for Phase 0, 1 for Phase 1) + * + */ + public int getEriFileType() { + return mEriFile.mEriFileType; + } + + /** + * Returns if the ERI file has been loaded + * + */ + public boolean isEriFileLoaded() { + return isEriFileLoaded; + } + + /** + * Returns the EriInfo record associated with roamingIndicator + * or null if the entry is not found + */ + private EriInfo getEriInfo(int roamingIndicator) { + if (mEriFile.mRoamIndTable.containsKey(roamingIndicator)) { + return mEriFile.mRoamIndTable.get(roamingIndicator); + } else { + return null; + } + } + + private EriDisplayInformation getEriDisplayInformation(int roamInd, int defRoamInd){ + //int iconIndex = -1; + //int iconMode = -1; + //String iconText = "ERI text"; + EriDisplayInformation ret; + + switch (roamInd) { + // Handling the standard roaming indicator (non-ERI) + case EriInfo.ROAMING_INDICATOR_ON: + ret = new EriDisplayInformation( + EriInfo.ROAMING_INDICATOR_ON, + EriInfo.ROAMING_ICON_MODE_NORMAL, + mContext.getText(com.android.internal.R.string.roamingText0).toString()); + break; + + case EriInfo.ROAMING_INDICATOR_OFF: + ret = new EriDisplayInformation( + EriInfo.ROAMING_INDICATOR_OFF, + EriInfo.ROAMING_ICON_MODE_NORMAL, + mContext.getText(com.android.internal.R.string.roamingText1).toString()); + break; + + case EriInfo.ROAMING_INDICATOR_FLASH: + ret = new EriDisplayInformation( + EriInfo.ROAMING_INDICATOR_FLASH, + EriInfo.ROAMING_ICON_MODE_FLASH, + mContext.getText(com.android.internal.R.string.roamingText2).toString()); + break; + + + // Handling the standard ERI + case 3: + ret = new EriDisplayInformation( + roamInd, + EriInfo.ROAMING_ICON_MODE_NORMAL, + mContext.getText(com.android.internal.R.string.roamingText3).toString()); + break; + + case 4: + ret = new EriDisplayInformation( + roamInd, + EriInfo.ROAMING_ICON_MODE_NORMAL, + mContext.getText(com.android.internal.R.string.roamingText4).toString()); + break; + + case 5: + ret = new EriDisplayInformation( + roamInd, + EriInfo.ROAMING_ICON_MODE_NORMAL, + mContext.getText(com.android.internal.R.string.roamingText5).toString()); + break; + + case 6: + ret = new EriDisplayInformation( + roamInd, + EriInfo.ROAMING_ICON_MODE_NORMAL, + mContext.getText(com.android.internal.R.string.roamingText6).toString()); + break; + + case 7: + ret = new EriDisplayInformation( + roamInd, + EriInfo.ROAMING_ICON_MODE_NORMAL, + mContext.getText(com.android.internal.R.string.roamingText7).toString()); + break; + + case 8: + ret = new EriDisplayInformation( + roamInd, + EriInfo.ROAMING_ICON_MODE_NORMAL, + mContext.getText(com.android.internal.R.string.roamingText8).toString()); + break; + + case 9: + ret = new EriDisplayInformation( + roamInd, + EriInfo.ROAMING_ICON_MODE_NORMAL, + mContext.getText(com.android.internal.R.string.roamingText9).toString()); + break; + + case 10: + ret = new EriDisplayInformation( + roamInd, + EriInfo.ROAMING_ICON_MODE_NORMAL, + mContext.getText(com.android.internal.R.string.roamingText10).toString()); + break; + + case 11: + ret = new EriDisplayInformation( + roamInd, + EriInfo.ROAMING_ICON_MODE_NORMAL, + mContext.getText(com.android.internal.R.string.roamingText11).toString()); + break; + + case 12: + ret = new EriDisplayInformation( + roamInd, + EriInfo.ROAMING_ICON_MODE_NORMAL, + mContext.getText(com.android.internal.R.string.roamingText12).toString()); + break; + + // Handling the non standard Enhanced Roaming Indicator (roamInd > 63) + default: + if (!isEriFileLoaded) { + // ERI file NOT loaded + Log.d(LOG_TAG, "ERI File not loaded"); + if(defRoamInd > 2) { + Log.d(LOG_TAG, "ERI defRoamInd > 2 ...flashing"); + ret = new EriDisplayInformation( + EriInfo.ROAMING_INDICATOR_FLASH, + EriInfo.ROAMING_ICON_MODE_FLASH, + mContext.getText(com.android.internal + .R.string.roamingText2).toString()); + } else { + Log.d(LOG_TAG, "ERI defRoamInd <= 2"); + switch (defRoamInd) { + case EriInfo.ROAMING_INDICATOR_ON: + ret = new EriDisplayInformation( + EriInfo.ROAMING_INDICATOR_ON, + EriInfo.ROAMING_ICON_MODE_NORMAL, + mContext.getText(com.android.internal + .R.string.roamingText0).toString()); + break; + + case EriInfo.ROAMING_INDICATOR_OFF: + ret = new EriDisplayInformation( + EriInfo.ROAMING_INDICATOR_OFF, + EriInfo.ROAMING_ICON_MODE_NORMAL, + mContext.getText(com.android.internal + .R.string.roamingText1).toString()); + break; + + case EriInfo.ROAMING_INDICATOR_FLASH: + ret = new EriDisplayInformation( + EriInfo.ROAMING_INDICATOR_FLASH, + EriInfo.ROAMING_ICON_MODE_FLASH, + mContext.getText(com.android.internal + .R.string.roamingText2).toString()); + break; + + default: + ret = new EriDisplayInformation(-1, -1, "ERI text"); + } + } + } else { + // ERI file loaded + Log.d(LOG_TAG, "ERI File loaded"); + EriInfo eriInfo = getEriInfo(roamInd); + EriInfo defEriInfo = getEriInfo(defRoamInd); + if (eriInfo == null) { + Log.d(LOG_TAG, "ERI roamInd " + roamInd + + " not found in ERI file ...using defRoamInd " + defRoamInd); + if(defEriInfo == null) { + Log.e(LOG_TAG, "ERI defRoamInd " + defRoamInd + + " not found in ERI file ...on"); + ret = new EriDisplayInformation( + EriInfo.ROAMING_INDICATOR_ON, + EriInfo.ROAMING_ICON_MODE_NORMAL, + mContext.getText(com.android.internal + .R.string.roamingText0).toString()); + + } else { + Log.d(LOG_TAG, "ERI defRoamInd " + defRoamInd + " found in ERI file"); + ret = new EriDisplayInformation( + defEriInfo.mIconIndex, + defEriInfo.mIconMode, + defEriInfo.mEriText); + } + } else { + Log.d(LOG_TAG, "ERI roamInd " + roamInd + " found in ERI file"); + ret = new EriDisplayInformation( + eriInfo.mIconIndex, + eriInfo.mIconMode, + eriInfo.mEriText); + } + } + break; + } + Log.d(LOG_TAG, "Displaying ERI " + ret.toString()); + return ret; + } + + public int getCdmaEriIconIndex(int roamInd, int defRoamInd){ + return getEriDisplayInformation(roamInd, defRoamInd).mEriIconIndex; + } + + public int getCdmaEriIconMode(int roamInd, int defRoamInd){ + return getEriDisplayInformation(roamInd, defRoamInd).mEriIconMode; + } + + public String getCdmaEriText(int roamInd, int defRoamInd){ + return getEriDisplayInformation(roamInd, defRoamInd).mEriIconText; + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java b/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java index c226b62..23a4ac7 100644 --- a/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java +++ b/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java @@ -84,7 +84,6 @@ public final class FeatureCode extends Handler implements MmiCode { CDMAPhone phone; Context context; - String action; // '*' in CDMA String sc; // Service Code String poundString; // Entire Flash string @@ -237,10 +236,9 @@ public final class FeatureCode extends Handler implements MmiCode { } /** Process a Flash Code...anything that isn't a dialing number */ - void processCode () { + void processCode() { Log.d(LOG_TAG, "send feature code..."); - phone.mCM.sendCDMAFeatureCode(this.poundString, - obtainMessage(EVENT_CDMA_FLASH_COMPLETED)); + phone.mCM.sendCDMAFeatureCode(this.poundString, obtainMessage(EVENT_CDMA_FLASH_COMPLETED)); } /** Called from CDMAPhone.handleMessage; not a Handler subclass */ diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java index 9de6c42..3e2a29b 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java @@ -68,7 +68,12 @@ public final class RuimFileHandler extends IccFileHandler { } protected String getEFPath(int efid) { - // TODO(): Implement for CDMA EFs. + switch(efid) { + case EF_SMS: + case EF_CST: + case EF_RUIM_SPN: + return MF_SIM + DF_CDMA; + } return getCommonIccEFPath(efid); } diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java index b18a3f1..c7e61da 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java @@ -16,19 +16,17 @@ package com.android.internal.telephony.cdma; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.os.Registrant; import android.util.Log; -import static com.android.internal.telephony.TelephonyProperties.*; import com.android.internal.telephony.AdnRecord; import com.android.internal.telephony.AdnRecordCache; import com.android.internal.telephony.AdnRecordLoader; import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.TelephonyProperties; import com.android.internal.telephony.cdma.RuimCard; import com.android.internal.telephony.gsm.MccTable; @@ -39,6 +37,10 @@ import com.android.internal.telephony.IccRecords; import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.TelephonyIntents; +import android.app.ActivityManagerNative; +import android.content.Intent; + /** * {@hide} @@ -47,15 +49,17 @@ public final class RuimRecords extends IccRecords { static final String LOG_TAG = "CDMA"; private static final boolean DBG = true; + private boolean m_ota_commited=false; //***** Instance Variables - String imsi_m; - String mdn = null; // My mobile number - String h_sid; - String h_nid; - String min2_min1; // 10 digit MIN value MIN2+MIN1 NEWRIL:TODO currently unused - // is not initialized + private String mImsi; + private String mMyMobileNumber; + private String mSid; + private String mNid; + private String mMin2Min1; + + private String mPrlVersion; //***** Event Constants @@ -63,6 +67,7 @@ public final class RuimRecords extends IccRecords { private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2; private static final int EVENT_GET_DEVICE_IDENTITY_DONE = 4; private static final int EVENT_GET_ICCID_DONE = 5; + private static final int EVENT_NV_READY = 9; private static final int EVENT_GET_CDMA_SUBSCRIPTION_DONE = 10; private static final int EVENT_UPDATE_DONE = 14; private static final int EVENT_GET_SST_DONE = 17; @@ -73,8 +78,7 @@ public final class RuimRecords extends IccRecords { private static final int EVENT_GET_SMS_DONE = 22; private static final int EVENT_RUIM_REFRESH = 31; - - //***** Constructor + private static final int EVENT_OTA_PROVISION_STATUS_CHANGE = 32; RuimRecords(CDMAPhone p) { super(p); @@ -88,12 +92,14 @@ public final class RuimRecords extends IccRecords { p.mCM.registerForRUIMReady(this, EVENT_RUIM_READY, null); + p.mCM.registerForNVReady(this, EVENT_NV_READY, null); p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); // NOTE the EVENT_SMS_ON_RUIM is not registered p.mCM.setOnIccRefresh(this, EVENT_RUIM_REFRESH, null); // Start off by setting empty state onRadioOffOrNotAvailable(); + p.mCM.registerForCdmaOtaProvision(this,EVENT_OTA_PROVISION_STATUS_CHANGE, null); } @@ -102,12 +108,16 @@ public final class RuimRecords extends IccRecords { phone.mCM.unregisterForRUIMReady(this); phone.mCM.unregisterForOffOrNotAvailable( this); phone.mCM.unSetOnIccRefresh(this); + phone.mCM.unregisterForNVReady(this); + phone.mCM.unregisterForCdmaOtaProvision(this); } + @Override protected void finalize() { if(DBG) Log.d(LOG_TAG, "RuimRecords finalized"); } + @Override protected void onRadioOffOrNotAvailable() { countVoiceMessages = 0; mncLength = 0; @@ -115,8 +125,8 @@ public final class RuimRecords extends IccRecords { adnCache.reset(); - phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, null); - phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null); + phone.setSystemProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, null); + phone.setSystemProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null); // recordsRequested is set to false indicating that the SIM // read requests made so far are not valid. This is set to @@ -124,17 +134,26 @@ public final class RuimRecords extends IccRecords { recordsRequested = false; } - //***** Public Methods - /** Returns null if RUIM is not yet ready */ public String getIMSI_M() { - return imsi_m; + // TODO(Moto): mImsi is not initialized, fix. + return mImsi; } public String getMdnNumber() { - return mdn; + return mMyMobileNumber; + } + + public String getCdmaMin() { + return mMin2Min1; } + /** Returns null if RUIM is not yet ready */ + public String getPrlVersion() { + return mPrlVersion; + } + + @Override public void setVoiceMailNumber(String alphaTag, String voiceNumber, Message onComplete){ // In CDMA this is Operator/OEM dependent AsyncResult.forMessage((onComplete)).exception = @@ -148,6 +167,7 @@ public final class RuimRecords extends IccRecords { * @param fileChanged indicates whether any files changed * @param fileList if non-null, a list of EF files that changed */ + @Override public void onRefresh(boolean fileChanged, int[] fileList) { if (fileChanged) { // A future optimization would be to inspect fileList and @@ -157,32 +177,31 @@ public final class RuimRecords extends IccRecords { } } - /** Returns the 5 or 6 digit MCC/MNC of the operator that + /** + * Returns the 5 or 6 digit MCC/MNC of the operator that * provided the RUIM card. Returns null of RUIM is not yet ready */ - String getRUIMOperatorNumeric() { - if (imsi_m == null) { + public String getRUIMOperatorNumeric() { + if (mImsi == null) { return null; } + // TODO(Moto): mncLength is not set anywhere. if (mncLength != 0) { // Length = length of MCC + length of MNC // TODO: change spec name // length of mcc = 3 (3GPP2 C.S0005 - Section 2.3) - return imsi_m.substring(0, 3 + mncLength); + return mImsi.substring(0, 3 + mncLength); } // Guess the MNC length based on the MCC if we don't // have a valid value in ef[ad] - int mcc; - - mcc = Integer.parseInt(imsi_m.substring(0,3)); - - return imsi_m.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc)); + int mcc = Integer.parseInt(mImsi.substring(0,3)); + return mImsi.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc)); } - //***** Overridden from Handler + @Override public void handleMessage(Message msg) { AsyncResult ar; @@ -194,7 +213,9 @@ public final class RuimRecords extends IccRecords { case EVENT_RUIM_READY: onRuimReady(); break; - + case EVENT_NV_READY: + onNvReady(); + break; case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: onRadioOffOrNotAvailable(); break; @@ -211,15 +232,22 @@ public final class RuimRecords extends IccRecords { if (ar.exception != null) { break; } - - mdn = localTemp[0]; - h_sid = localTemp[1]; - h_nid = localTemp[2]; - if (localTemp.length >= 3) { // NEWRIL:TODO remove when new ril always returns min2_min1 - min2_min1 = localTemp[3]; + if (m_ota_commited) { + if (mMyMobileNumber != localTemp[0]) { + Intent intent = new Intent(TelephonyIntents.ACTION_CDMA_OTA_MDN_CHANGED); + intent.putExtra("mdn", localTemp[0]); + Log.d(LOG_TAG,"Broadcasting intent MDN Change in OTA "); + ActivityManagerNative.broadcastStickyIntent(intent, null); + } + m_ota_commited = false; } + mMyMobileNumber = localTemp[0]; + mSid = localTemp[1]; + mNid = localTemp[2]; + mMin2Min1 = localTemp[3]; + mPrlVersion = localTemp[4]; - Log.d(LOG_TAG, "MDN: " + mdn); + Log.d(LOG_TAG, "MDN: " + mMyMobileNumber + " MIN: " + mMin2Min1); break; @@ -266,6 +294,21 @@ public final class RuimRecords extends IccRecords { } break; + case EVENT_OTA_PROVISION_STATUS_CHANGE: + m_ota_commited=false; + ar = (AsyncResult)msg.obj; + if (ar.exception == null) { + int[] ints = (int[]) ar.result; + int otaStatus = ints[0]; + if (otaStatus == phone.CDMA_OTA_PROVISION_STATUS_COMMITTED) { + m_ota_commited=true; + phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE)); + } else if (otaStatus == phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED) { + phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE)); + } + } + break; + }}catch (RuntimeException exc) { // I don't want these exceptions to be fatal Log.w(LOG_TAG, "Exception parsing RUIM record", exc); @@ -277,6 +320,7 @@ public final class RuimRecords extends IccRecords { } } + @Override protected void onRecordLoaded() { // One record loaded successfully or failed, In either case // we need to update the recordsToLoad count @@ -290,6 +334,7 @@ public final class RuimRecords extends IccRecords { } } + @Override protected void onAllRecordsLoaded() { Log.d(LOG_TAG, "RuimRecords: record load complete"); @@ -301,9 +346,6 @@ public final class RuimRecords extends IccRecords { RuimCard.INTENT_VALUE_ICC_LOADED, null); } - - //***** Private Methods - private void onRuimReady() { /* broadcast intent ICC_READY here so that we can make sure READY is sent before IMSI ready @@ -318,6 +360,11 @@ public final class RuimRecords extends IccRecords { } + private void onNvReady() { + phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE)); + + } + private void fetchRuimRecords() { recordsRequested = true; @@ -364,17 +411,17 @@ public final class RuimRecords extends IccRecords { switch ((result[0])) { case CommandsInterface.SIM_REFRESH_FILE_UPDATED: - if (DBG) log("handleRuimRefresh with SIM_REFRESH_FILE_UPDATED"); + if (DBG) log("handleRuimRefresh with SIM_REFRESH_FILE_UPDATED"); adnCache.reset(); fetchRuimRecords(); break; case CommandsInterface.SIM_REFRESH_INIT: - if (DBG) log("handleRuimRefresh with SIM_REFRESH_INIT"); + if (DBG) log("handleRuimRefresh with SIM_REFRESH_INIT"); // need to reload all files (that we care about) fetchRuimRecords(); break; case CommandsInterface.SIM_REFRESH_RESET: - if (DBG) log("handleRuimRefresh with SIM_REFRESH_RESET"); + if (DBG) log("handleRuimRefresh with SIM_REFRESH_RESET"); phone.mCM.setRadioPower(false, null); /* Note: no need to call setRadioPower(true). Assuming the desired * radio power state is still ON (as tracked by ServiceStateTracker), @@ -386,14 +433,14 @@ public final class RuimRecords extends IccRecords { break; default: // unknown refresh operation - if (DBG) log("handleRuimRefresh with unknown operation"); + if (DBG) log("handleRuimRefresh with unknown operation"); break; } } + @Override protected void log(String s) { Log.d(LOG_TAG, "[RuimRecords] " + s); } } - diff --git a/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java b/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java new file mode 100644 index 0000000..44958e9 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java @@ -0,0 +1,280 @@ +/* + * 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.cdma; + +import java.util.HashMap; +import java.util.HashSet; +import android.util.Log; +import android.media.ToneGenerator; + +public class SignalToneUtil { + /** A marker that isn't a valid TONE */ + public static final int CDMA_INVALID_TONE = -1; + + // public final int int IS95_CONST_IR_SIGNAL_TYPE_TYPE; + static public final int IS95_CONST_IR_SIGNAL_TONE = 0; + static public final int IS95_CONST_IR_SIGNAL_ISDN = 1; + static public final int IS95_CONST_IR_SIGNAL_IS54B = 2; + static public final int IS95_CONST_IR_SIGNAL_USR_DEFD_ALERT = 4; + + // public final int int IS95_CONST_IR_ALERT_PITCH_TYPE; + static public final int IS95_CONST_IR_ALERT_MED = 0; + static public final int IS95_CONST_IR_ALERT_HIGH = 1; + static public final int IS95_CONST_IR_ALERT_LOW = 2; + static public final int TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN = 255; + + // public final int int IS95_CONST_IR_SIGNAL_TYPE; + static public final int IS95_CONST_IR_SIG_ISDN_NORMAL = 0; + static public final int IS95_CONST_IR_SIG_ISDN_INTGRP = 1; + static public final int IS95_CONST_IR_SIG_ISDN_SP_PRI = 2; + static public final int IS95_CONST_IR_SIG_ISDN_PAT_3 = 3; + static public final int IS95_CONST_IR_SIG_ISDN_PING = 4; + static public final int IS95_CONST_IR_SIG_ISDN_PAT_5 = 5; + static public final int IS95_CONST_IR_SIG_ISDN_PAT_6 = 6; + static public final int IS95_CONST_IR_SIG_ISDN_PAT_7 = 7; + static public final int IS95_CONST_IR_SIG_ISDN_OFF = 15; + static public final int IS95_CONST_IR_SIG_TONE_DIAL = 0; + static public final int IS95_CONST_IR_SIG_TONE_RING = 1; + static public final int IS95_CONST_IR_SIG_TONE_INT = 2; + static public final int IS95_CONST_IR_SIG_TONE_ABB_INT = 3; + static public final int IS95_CONST_IR_SIG_TONE_REORDER = 4; + static public final int IS95_CONST_IR_SIG_TONE_ABB_RE = 5; + static public final int IS95_CONST_IR_SIG_TONE_BUSY = 6; + static public final int IS95_CONST_IR_SIG_TONE_CONFIRM = 7; + static public final int IS95_CONST_IR_SIG_TONE_ANSWER = 8; + static public final int IS95_CONST_IR_SIG_TONE_CALL_W = 9; + static public final int IS95_CONST_IR_SIG_TONE_PIP = 10; + static public final int IS95_CONST_IR_SIG_TONE_NO_TONE = 63; + static public final int IS95_CONST_IR_SIG_IS54B_NO_TONE = 0; + static public final int IS95_CONST_IR_SIG_IS54B_L = 1; + static public final int IS95_CONST_IR_SIG_IS54B_SS = 2; + static public final int IS95_CONST_IR_SIG_IS54B_SSL = 3; + static public final int IS95_CONST_IR_SIG_IS54B_SS_2 = 4; + static public final int IS95_CONST_IR_SIG_IS54B_SLS = 5; + static public final int IS95_CONST_IR_SIG_IS54B_S_X4 = 6; + static public final int IS95_CONST_IR_SIG_IS54B_PBX_L = 7; + static public final int IS95_CONST_IR_SIG_IS54B_PBX_SS = 8; + static public final int IS95_CONST_IR_SIG_IS54B_PBX_SSL = 9; + static public final int IS95_CONST_IR_SIG_IS54B_PBX_SLS = 10; + static public final int IS95_CONST_IR_SIG_IS54B_PBX_S_X4 = 11; + static public final int IS95_CONST_IR_SIG_TONE_ABBR_ALRT = 0; + + // Hashmap to map signalInfo To AudioTone + static private HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>(); + + private static Integer signalParamHash(int signalType, int alertPitch, int signal) { + if ((signalType < 0) || (signalType > 256) || (alertPitch > 256) || + (alertPitch < 0) || (signal > 256) || (signal < 0)) { + return new Integer(CDMA_INVALID_TONE); + } + return new Integer(signalType * 256 * 256 + alertPitch * 256 + signal); + } + + public static int getAudioToneFromSignalInfo(int signalType, int alertPitch, int signal) { + Integer result = hm.get(signalParamHash(signalType, alertPitch, signal)); + if (result == null) { + return CDMA_INVALID_TONE; + } + return result; + } + + static { + + /* SIGNAL_TYPE_ISDN */ + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_ISDN_NORMAL), ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_NORMAL); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_ISDN_INTGRP), + ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_INTERGROUP); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_ISDN_SP_PRI), ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_SP_PRI); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_ISDN_PAT_3), ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_PAT3); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_ISDN_PING), ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_PING_RING); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_ISDN_PAT_5), ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_PAT5); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_ISDN_PAT_6), ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_PAT6); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_ISDN_PAT_7), ToneGenerator.TONE_CDMA_CALL_SIGNAL_ISDN_PAT7); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_ISDN, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_ISDN_OFF), ToneGenerator.TONE_CDMA_SIGNAL_OFF); + + /* SIGNAL_TYPE_TONE */ + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_TONE_DIAL), ToneGenerator.TONE_CDMA_DIAL_TONE_LITE); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_TONE_RING), ToneGenerator.TONE_CDMA_NETWORK_USA_RINGBACK); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_TONE_INT), ToneGenerator.TONE_SUP_INTERCEPT); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_TONE_ABB_INT), ToneGenerator.TONE_SUP_INTERCEPT_ABBREV); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_TONE_REORDER), ToneGenerator.TONE_CDMA_REORDER); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_TONE_ABB_RE), ToneGenerator.TONE_CDMA_ABBR_REORDER); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_TONE_BUSY), ToneGenerator.TONE_CDMA_NETWORK_BUSY); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_TONE_CONFIRM), ToneGenerator.TONE_SUP_CONFIRM); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + 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); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_TONE_PIP), ToneGenerator.TONE_CDMA_PIP); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_TONE_NO_TONE), ToneGenerator.TONE_CDMA_SIGNAL_OFF); + + /* SIGNAL_TYPE_IS54B */ + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH, + IS95_CONST_IR_SIG_IS54B_L), ToneGenerator.TONE_CDMA_HIGH_L); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED, + IS95_CONST_IR_SIG_IS54B_L), ToneGenerator.TONE_CDMA_MED_L); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW, + IS95_CONST_IR_SIG_IS54B_L), ToneGenerator.TONE_CDMA_LOW_L); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH, + IS95_CONST_IR_SIG_IS54B_SS), ToneGenerator.TONE_CDMA_HIGH_SS); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED, + IS95_CONST_IR_SIG_IS54B_SS), ToneGenerator.TONE_CDMA_MED_SS); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW, + IS95_CONST_IR_SIG_IS54B_SS), ToneGenerator.TONE_CDMA_LOW_SS); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH, + IS95_CONST_IR_SIG_IS54B_SSL), ToneGenerator.TONE_CDMA_HIGH_SSL); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED, + IS95_CONST_IR_SIG_IS54B_SSL), ToneGenerator.TONE_CDMA_MED_SSL); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW, + IS95_CONST_IR_SIG_IS54B_SSL), ToneGenerator.TONE_CDMA_LOW_SSL); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH, + IS95_CONST_IR_SIG_IS54B_SS_2), ToneGenerator.TONE_CDMA_HIGH_SS_2); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED, + IS95_CONST_IR_SIG_IS54B_SS_2), ToneGenerator.TONE_CDMA_MED_SS_2); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW, + IS95_CONST_IR_SIG_IS54B_SS_2), ToneGenerator.TONE_CDMA_LOW_SS_2); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH, + IS95_CONST_IR_SIG_IS54B_SLS), ToneGenerator.TONE_CDMA_HIGH_SLS); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED, + IS95_CONST_IR_SIG_IS54B_SLS), ToneGenerator.TONE_CDMA_MED_SLS); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW, + IS95_CONST_IR_SIG_IS54B_SLS), ToneGenerator.TONE_CDMA_LOW_SLS); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH, + IS95_CONST_IR_SIG_IS54B_S_X4), ToneGenerator.TONE_CDMA_HIGH_S_X4); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED, + IS95_CONST_IR_SIG_IS54B_S_X4), ToneGenerator.TONE_CDMA_MED_S_X4); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW, + IS95_CONST_IR_SIG_IS54B_S_X4), ToneGenerator.TONE_CDMA_LOW_S_X4); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH, + IS95_CONST_IR_SIG_IS54B_PBX_L), ToneGenerator.TONE_CDMA_HIGH_PBX_L); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED, + IS95_CONST_IR_SIG_IS54B_PBX_L), ToneGenerator.TONE_CDMA_MED_PBX_L); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW, + IS95_CONST_IR_SIG_IS54B_PBX_L), ToneGenerator.TONE_CDMA_LOW_PBX_L); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH, + IS95_CONST_IR_SIG_IS54B_PBX_SS), ToneGenerator.TONE_CDMA_HIGH_PBX_SS); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED, + IS95_CONST_IR_SIG_IS54B_PBX_SS), ToneGenerator.TONE_CDMA_MED_PBX_SS); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW, + IS95_CONST_IR_SIG_IS54B_PBX_SS), ToneGenerator.TONE_CDMA_LOW_PBX_SS); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH, + IS95_CONST_IR_SIG_IS54B_PBX_SSL), ToneGenerator.TONE_CDMA_HIGH_PBX_SSL); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED, + IS95_CONST_IR_SIG_IS54B_PBX_SSL), ToneGenerator.TONE_CDMA_MED_PBX_SSL); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW, + IS95_CONST_IR_SIG_IS54B_PBX_SSL), ToneGenerator.TONE_CDMA_LOW_PBX_SSL); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH, + IS95_CONST_IR_SIG_IS54B_PBX_SLS), ToneGenerator.TONE_CDMA_HIGH_PBX_SLS); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED, + IS95_CONST_IR_SIG_IS54B_PBX_SLS), ToneGenerator.TONE_CDMA_MED_PBX_SLS); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW, + IS95_CONST_IR_SIG_IS54B_PBX_SLS), ToneGenerator.TONE_CDMA_LOW_PBX_SLS); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_HIGH, + IS95_CONST_IR_SIG_IS54B_PBX_S_X4), ToneGenerator.TONE_CDMA_HIGH_PBX_S_X4); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_MED, + IS95_CONST_IR_SIG_IS54B_PBX_S_X4), ToneGenerator.TONE_CDMA_MED_PBX_S_X4); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, IS95_CONST_IR_ALERT_LOW, + IS95_CONST_IR_SIG_IS54B_PBX_S_X4), ToneGenerator.TONE_CDMA_LOW_PBX_S_X4); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_IS54B, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, + IS95_CONST_IR_SIG_IS54B_NO_TONE), ToneGenerator.TONE_CDMA_SIGNAL_OFF); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_USR_DEFD_ALERT, + TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, IS95_CONST_IR_SIG_TONE_ABBR_ALRT), + ToneGenerator.TONE_CDMA_ABBR_ALERT); + + hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_USR_DEFD_ALERT, + TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, IS95_CONST_IR_SIG_TONE_NO_TONE), + ToneGenerator.TONE_CDMA_ABBR_ALERT); + + } + + // suppress default constructor for noninstantiability + private SignalToneUtil() { + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java index 343a22e..3a92064 100644 --- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java @@ -277,6 +277,15 @@ public class SmsMessage extends SmsMessageBase { } /** + * TODO(cleanup): why do getSubmitPdu methods take an scAddr input + * and do nothing with it? GSM allows us to specify a SC (eg, + * when responding to an SMS that explicitly requests the response + * is sent to a specific SC), or pass null to use the default + * value. Is there no similar notion in CDMA? Or do we just not + * have it hooked up? + */ + + /** * Get an SMS-SUBMIT PDU for a destination address and a message * * @param scAddr Service Centre address. Null means use default. @@ -290,88 +299,53 @@ public class SmsMessage extends SmsMessageBase { * Returns null on encode error. * @hide */ - public static SubmitPdu getSubmitPdu(String scAddr, - String destAddr, String message, - boolean statusReportRequested, byte[] headerData) { + public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, String message, + boolean statusReportRequested, SmsHeader smsHeader) { + /** - * TODO(cleanup): why does this method take an scAddr input - * and do nothing with it? GSM allows us to specify a SC (eg, - * when responding to an SMS that explicitly requests the - * response is sent to a specific SC), or pass null to use the - * default value. Is there no similar notion in CDMA? Or do - * we just not have it hooked up? + * TODO(cleanup): Do we really want silent failure like this? + * Would it not be much more reasonable to make sure we don't + * call this function if we really want nothing done? */ - if (message == null || destAddr == null) { return null; } UserData uData = new UserData(); uData.payloadStr = message; - if(headerData != null) { - /** - * TODO(cleanup): we force the outside to deal with _all_ - * of the raw details of properly constructing serialized - * headers, unserialze here, and then promptly reserialze - * during encoding -- rather undesirable. - */ - uData.userDataHeader = SmsHeader.parse(headerData); - } - - return privateGetSubmitPdu(destAddr, statusReportRequested, uData, (headerData == null)); - } - - - /** - * Get an SMS-SUBMIT PDU for a destination address and a message - * - * @param scAddress Service Centre address. Null means use default. - * @return a <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. - * Returns null on encode error. - */ - public static SubmitPdu getSubmitPdu(String scAddress, - String destinationAddress, String message, - boolean statusReportRequested) { - return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null); + uData.userDataHeader = smsHeader; + return privateGetSubmitPdu(destAddr, statusReportRequested, uData); } /** * Get an SMS-SUBMIT PDU for a data message to a destination address & port * - * @param scAddress Service Centre address. null == use default - * @param destinationAddress the address of the destination for the message - * @param destinationPort the port to deliver the message to at the + * @param scAddr Service Centre address. null == use default + * @param destAddr the address of the destination for the message + * @param destPort the port to deliver the message to at the * destination * @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. */ - public static SubmitPdu getSubmitPdu(String scAddress, - String destAddr, short destinationPort, byte[] data, - boolean statusReportRequested) { + public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, short destPort, + byte[] data, boolean statusReportRequested) { /** - * TODO(cleanup): if we had properly exposed SmsHeader - * information, this mess of many getSubmitPdu public - * interface methods that currently pollute the api could have - * been much more cleanly collapsed into one. + * TODO(cleanup): this is not a general-purpose SMS creation + * method, but rather something specialized to messages + * containing OCTET encoded (meaning non-human-readable) user + * data. The name should reflect that, and not just overload. */ - /** - * TODO(cleanup): header serialization should be put somewhere - * canonical to allow proper debugging and reuse. - */ - byte[] destPort = new byte[4]; - destPort[0] = (byte) ((destinationPort >> 8) & 0xFF); // MSB of destination port - destPort[1] = (byte) (destinationPort & 0xFF); // LSB of destination port - destPort[2] = 0x00; // MSB of originating port - destPort[3] = 0x00; // LSB of originating port + SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs(); + portAddrs.destPort = destPort; + portAddrs.origPort = 0; + portAddrs.areEightBits = false; + SmsHeader smsHeader = new SmsHeader(); - smsHeader.add( - new SmsHeader.Element(SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT, destPort)); - smsHeader.nbrOfHeaders = smsHeader.getElements().size(); + smsHeader.portAddrs = portAddrs; UserData uData = new UserData(); uData.userDataHeader = smsHeader; @@ -379,40 +353,22 @@ public class SmsMessage extends SmsMessageBase { uData.msgEncodingSet = true; uData.payload = data; - return privateGetSubmitPdu(destAddr, statusReportRequested, uData, true); + return privateGetSubmitPdu(destAddr, statusReportRequested, uData); } - static class PduParser { - - PduParser() { - } - - /** - * Parses an SC timestamp and returns a currentTimeMillis()-style - * timestamp - */ - static long getSCTimestampMillis(byte[] timestamp) { - // TP-Service-Centre-Time-Stamp - int year = IccUtils.beBcdByteToInt(timestamp[0]); - int month = IccUtils.beBcdByteToInt(timestamp[1]); - int day = IccUtils.beBcdByteToInt(timestamp[2]); - int hour = IccUtils.beBcdByteToInt(timestamp[3]); - int minute = IccUtils.beBcdByteToInt(timestamp[4]); - int second = IccUtils.beBcdByteToInt(timestamp[5]); - - Time time = new Time(Time.TIMEZONE_UTC); - - // C.S0015-B v2.0, 4.5.4: range is 1996-2095 - time.year = year >= 96 ? year + 1900 : year + 2000; - time.month = month - 1; - time.monthDay = day; - time.hour = hour; - time.minute = minute; - time.second = second; - - return time.toMillis(true); - } - + /** + * Get an SMS-SUBMIT PDU for a data message to a destination address & port + * + * @param destAddr the address of the destination for the message + * @param userDara the data for the message + * @param statusReportRequested Indicates whether a report is requested for this message. + * @return a <code>SubmitPdu</code> containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + */ + public static SubmitPdu getSubmitPdu(String destAddr, UserData userData, + boolean statusReportRequested) { + return privateGetSubmitPdu(destAddr, statusReportRequested, userData); } /** @@ -445,31 +401,23 @@ public class SmsMessage extends SmsMessageBase { * {@inheritDoc} */ public boolean isMWIClearMessage() { - if ((mBearerData != null) && (0 == mBearerData.numberOfMessages)) { - return true; - } - return false; + return ((mBearerData != null) && (mBearerData.numberOfMessages == 0)); } /** * {@inheritDoc} */ public boolean isMWISetMessage() { - if ((mBearerData != null) && (mBearerData.numberOfMessages >0)) { - return true; - } - return false; + return ((mBearerData != null) && (mBearerData.numberOfMessages > 0)); } /** * {@inheritDoc} */ public boolean isMwiDontStore() { - if ((mBearerData != null) && (mBearerData.numberOfMessages >0) - && (null == mBearerData.userData)) { - return true; - } - return false; + return ((mBearerData != null) && + (mBearerData.numberOfMessages > 0) && + (mBearerData.userData == null)); } /** @@ -478,7 +426,7 @@ public class SmsMessage extends SmsMessageBase { * shifted to the bits 31-16. */ public int getStatus() { - return(status<<16); + return (status << 16); } /** @@ -498,6 +446,18 @@ public class SmsMessage extends SmsMessageBase { } /** + * Calculate the number of septets needed to encode the message. + * + * @param messageBody the message to encode + * @param use7bitOnly ignore (but still count) illegal characters if true + * @return TextEncodingDetails + */ + public static TextEncodingDetails calculateLength(CharSequence messageBody, + boolean use7bitOnly) { + return BearerData.calcTextEncodingDetails(messageBody.toString(), use7bitOnly); + } + + /** * Returns the teleservice type of the message. * @return the teleservice: * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_NOT_SET}, @@ -518,7 +478,7 @@ public class SmsMessage extends SmsMessageBase { */ private void parsePdu(byte[] pdu) { ByteArrayInputStream bais = new ByteArrayInputStream(pdu); - DataInputStream dis = new DataInputStream(new BufferedInputStream(bais)); + DataInputStream dis = new DataInputStream(bais); byte length; int bearerDataLength; SmsEnvelope env = new SmsEnvelope(); @@ -568,90 +528,42 @@ public class SmsMessage extends SmsMessageBase { protected void parseSms() { mBearerData = BearerData.decode(mEnvelope.bearerData); messageRef = mBearerData.messageId; + if (mBearerData.userData != null) { + userData = mBearerData.userData.payload; + userDataHeader = mBearerData.userData.userDataHeader; + messageBody = mBearerData.userData.payloadStr; + } - // TP-Message-Type-Indicator - // (See 3GPP2 C.S0015-B, v2, 4.5.1) - int messageType = mBearerData.messageType; - - switch (messageType) { + // TP-Message-Type-Indicator (See 3GPP2 C.S0015-B, v2, 4.5.1) + switch (mBearerData.messageType) { case BearerData.MESSAGE_TYPE_USER_ACK: case BearerData.MESSAGE_TYPE_READ_ACK: case BearerData.MESSAGE_TYPE_DELIVER: - // Deliver (mobile-terminated only) - parseSmsDeliver(); - break; case BearerData.MESSAGE_TYPE_DELIVERY_ACK: - parseSmsDeliveryAck(); break; - default: - // the rest of these - throw new RuntimeException("Unsupported message type: " + messageType); + throw new RuntimeException("Unsupported message type: " + mBearerData.messageType); } - } - /** - * TODO(cleanup): why are there two nearly identical functions - * below? More rubbish... - */ - - /** - * Parses a SMS-DELIVER message. (mobile-terminated only) - * See 3GPP2 C.S0015-B, v2, 4.4.1 - */ - private void parseSmsDeliver() { if (originatingAddress != null) { originatingAddress.address = new String(originatingAddress.origBytes); if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: " + originatingAddress.address); } - if (mBearerData.timeStamp != null) { - scTimeMillis = PduParser.getSCTimestampMillis(mBearerData.timeStamp); + if (mBearerData.msgCenterTimeStamp != null) { + scTimeMillis = mBearerData.msgCenterTimeStamp.toMillis(true); } if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis); - parseUserData(mBearerData.userData); - } - - /** - * Parses a SMS-DELIVER message. (mobile-terminated only) - * See 3GPP2 C.S0015-B, v2, 4.4.1 - */ - private void parseSmsDeliveryAck() { - if (originatingAddress != null) { - originatingAddress.address = new String(originatingAddress.origBytes); - if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: " - + originatingAddress.address); - } - - if (mBearerData.timeStamp != null) { - scTimeMillis = PduParser.getSCTimestampMillis(mBearerData.timeStamp); - } - - if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis); - - if (mBearerData.errorClass != BearerData.ERROR_UNDEFINED) { + // TODO(Teleca): do we really want this test to occur only for DELIVERY_ACKs? + if ((mBearerData.messageType == BearerData.MESSAGE_TYPE_DELIVERY_ACK) && + (mBearerData.errorClass != BearerData.ERROR_UNDEFINED)) { status = mBearerData.errorClass << 8; status |= mBearerData.messageStatus; } - parseUserData(mBearerData.userData); - } - - /** - * Copy parsed user data out from internal datastructures. - */ - private void parseUserData(UserData uData) { - if (uData == null) { - return; - } - - userData = uData.payload; - userDataHeader = uData.userDataHeader; - messageBody = uData.payloadStr; - if (messageBody != null) { if (Config.LOGV) Log.v(LOG_TAG, "SMS message body: '" + messageBody + "'"); parseMessageBody(); @@ -708,7 +620,7 @@ public class SmsMessage extends SmsMessageBase { * @return byte stream for SubmitPdu. */ private static SubmitPdu privateGetSubmitPdu(String destAddrStr, boolean statusReportRequested, - UserData userData, boolean useNewId) { + UserData userData) { /** * TODO(cleanup): give this function a more meaningful name. @@ -720,7 +632,7 @@ public class SmsMessage extends SmsMessageBase { BearerData bearerData = new BearerData(); bearerData.messageType = BearerData.MESSAGE_TYPE_SUBMIT; - if (useNewId) setNextMessageId(); + if (userData != null) setNextMessageId(); bearerData.messageId = nextMessageId; bearerData.deliveryAckReq = statusReportRequested; @@ -731,12 +643,15 @@ public class SmsMessage extends SmsMessageBase { bearerData.userData = userData; bearerData.hasUserDataHeader = (userData.userDataHeader != null); + int teleservice = bearerData.hasUserDataHeader ? + SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT; + byte[] encodedBearerData = BearerData.encode(bearerData); if (encodedBearerData == null) return null; SmsEnvelope envelope = new SmsEnvelope(); envelope.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT; - envelope.teleService = SmsEnvelope.TELESERVICE_WMT; + envelope.teleService = teleservice; envelope.destAddress = destAddr; envelope.bearerReply = RETURN_ACK; envelope.bearerData = encodedBearerData; @@ -812,6 +727,15 @@ public class SmsMessage extends SmsMessageBase { dos.write(env.bearerData, 0, env.bearerData.length); dos.close(); + /** + * TODO(cleanup) -- This is the only place where mPdu is + * defined, and this is not obviously the only place where + * it needs to be defined. It would be much nicer if + * accessing the serialized representation used a less + * fragile mechanism. Maybe the getPdu method could + * generate a representation if there was not yet one? + */ + mPdu = baos.toByteArray(); } catch (IOException ex) { Log.e(LOG_TAG, "createPdu: conversion from object to byte array failed: " + ex); @@ -849,6 +773,12 @@ public class SmsMessage extends SmsMessageBase { return asciiDigit; } + /** This function shall be called to get the number of voicemails. + * @hide + */ + /*package*/ int getNumOfVoicemails() { + return mBearerData.numberOfMessages; + } } diff --git a/telephony/java/com/android/internal/telephony/cdma/package.html b/telephony/java/com/android/internal/telephony/cdma/package.html index cf1ad4a..4eb1f9c 100644 --- a/telephony/java/com/android/internal/telephony/cdma/package.html +++ b/telephony/java/com/android/internal/telephony/cdma/package.html @@ -1,6 +1,6 @@ <HTML> <BODY> -Provides classes to control or read data from CDMA phones. +Provides classes to control or read data from CDMA phones. @hide </BODY> </HTML> diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java index e64d022..ef3afff 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java @@ -17,12 +17,17 @@ package com.android.internal.telephony.cdma.sms; import android.util.Log; +import android.util.SparseIntArray; import android.telephony.SmsMessage; +import android.text.format.Time; + +import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.cdma.sms.UserData; +import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails; import com.android.internal.util.HexDump; import com.android.internal.util.BitwiseInputStream; @@ -32,21 +37,22 @@ import com.android.internal.util.BitwiseOutputStream; /** * An object to encode and decode CDMA SMS bearer data. */ -public final class BearerData{ +public final class BearerData { private final static String LOG_TAG = "SMS"; /** * Bearer Data Subparameter Indentifiers * (See 3GPP2 C.S0015-B, v2.0, table 4.5-1) + * NOTE: Commented subparameter types are not implemented. */ private final static byte SUBPARAM_MESSAGE_IDENTIFIER = 0x00; private final static byte SUBPARAM_USER_DATA = 0x01; private final static byte SUBPARAM_USER_REPONSE_CODE = 0x02; private final static byte SUBPARAM_MESSAGE_CENTER_TIME_STAMP = 0x03; - //private final static byte SUBPARAM_VALIDITY_PERIOD_ABSOLUTE = 0x04; - //private final static byte SUBPARAM_VALIDITY_PERIOD_RELATIVE = 0x05; - //private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE = 0x06; - //private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE = 0x07; + private final static byte SUBPARAM_VALIDITY_PERIOD_ABSOLUTE = 0x04; + private final static byte SUBPARAM_VALIDITY_PERIOD_RELATIVE = 0x05; + private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE = 0x06; + private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE = 0x07; private final static byte SUBPARAM_PRIORITY_INDICATOR = 0x08; private final static byte SUBPARAM_PRIVACY_INDICATOR = 0x09; private final static byte SUBPARAM_REPLY_OPTION = 0x0A; @@ -56,7 +62,7 @@ public final class BearerData{ private final static byte SUBPARAM_CALLBACK_NUMBER = 0x0E; private final static byte SUBPARAM_MESSAGE_DISPLAY_MODE = 0x0F; //private final static byte SUBPARAM_MULTIPLE_ENCODING_USER_DATA = 0x10; - //private final static byte SUBPARAM_MESSAGE_DEPOSIT_INDEX = 0x11; + private final static byte SUBPARAM_MESSAGE_DEPOSIT_INDEX = 0x11; //private final static byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA = 0x12; //private final static byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_RESULTS = 0x13; private final static byte SUBPARAM_MESSAGE_STATUS = 0x14; @@ -77,7 +83,7 @@ public final class BearerData{ public static final int MESSAGE_TYPE_DELIVER_REPORT = 0x07; public static final int MESSAGE_TYPE_SUBMIT_REPORT = 0x08; - public byte messageType; + public int messageType; /** * 16-bit value indicating the message ID, which increments modulo 65536. @@ -96,7 +102,7 @@ public final class BearerData{ public static final int PRIORITY_EMERGENCY = 0x3; public boolean priorityIndicatorSet = false; - public byte priority = PRIORITY_NORMAL; + public int priority = PRIORITY_NORMAL; /** * Supported privacy modes for CDMA SMS messages @@ -108,7 +114,7 @@ public final class BearerData{ public static final int PRIVACY_SECRET = 0x3; public boolean privacyIndicatorSet = false; - public byte privacy = PRIVACY_NOT_RESTRICTED; + public int privacy = PRIVACY_NOT_RESTRICTED; /** * Supported alert priority modes for CDMA SMS messages @@ -133,7 +139,7 @@ public final class BearerData{ public static final int DISPLAY_MODE_USER = 0x2; public boolean displayModeSet = false; - public byte displayMode = DISPLAY_MODE_DEFAULT; + public int displayMode = DISPLAY_MODE_DEFAULT; /** * Language Indicator values. NOTE: the spec (3GPP2 C.S0015-B, @@ -189,8 +195,12 @@ public final class BearerData{ public int messageStatus = STATUS_UNDEFINED; /** - * 1-bit value that indicates whether a User Data Header is present. + * 1-bit value that indicates whether a User Data Header (UDH) is present. * (See 3GPP2 C.S0015-B, v2, 4.5.1) + * + * NOTE: during encoding, this value will be set based on the + * presence of a UDH in the structured data, any existing setting + * will be overwritten. */ public boolean hasUserDataHeader; @@ -201,23 +211,94 @@ public final class BearerData{ */ public UserData userData; - //public UserResponseCode userResponseCode; + /** + * The User Response Code subparameter is used in the SMS User + * Acknowledgment Message to respond to previously received short + * messages. This message center-specific element carries the + * identifier of a predefined response. (See 3GPP2 C.S.0015-B, v2, + * 4.5.3) + */ + public boolean userResponseCodeSet = false; + public int userResponseCode; /** * 6-byte-field, see 3GPP2 C.S0015-B, v2, 4.5.4 - * year, month, day, hours, minutes, seconds; */ - public byte[] timeStamp; + public static class TimeStamp extends Time { - //public SmsTime validityPeriodAbsolute; - //public SmsRelTime validityPeriodRelative; - //public SmsTime deferredDeliveryTimeAbsolute; - //public SmsRelTime deferredDeliveryTimeRelative; + public TimeStamp() { + super(Time.TIMEZONE_UTC); + } + + public static TimeStamp fromByteArray(byte[] data) { + TimeStamp ts = new TimeStamp(); + // C.S0015-B v2.0, 4.5.4: range is 1996-2095 + int year = IccUtils.beBcdByteToInt(data[0]); + if (year > 99 || year < 0) return null; + ts.year = year >= 96 ? year + 1900 : year + 2000; + int month = IccUtils.beBcdByteToInt(data[1]); + if (month < 1 || month > 12) return null; + ts.month = month - 1; + int day = IccUtils.beBcdByteToInt(data[2]); + if (day < 1 || day > 31) return null; + ts.monthDay = day; + int hour = IccUtils.beBcdByteToInt(data[3]); + if (hour < 0 || hour > 23) return null; + ts.hour = hour; + int minute = IccUtils.beBcdByteToInt(data[4]); + if (minute < 0 || minute > 59) return null; + ts.minute = minute; + int second = IccUtils.beBcdByteToInt(data[5]); + if (second < 0 || second > 59) return null; + ts.second = second; + return ts; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("TimeStamp "); + builder.append("{ year=" + year); + builder.append(", month=" + month); + builder.append(", day=" + monthDay); + builder.append(", hour=" + hour); + builder.append(", minute=" + minute); + builder.append(", second=" + second); + builder.append(" }"); + return builder.toString(); + } + } + + public TimeStamp msgCenterTimeStamp; + public TimeStamp validityPeriodAbsolute; + public TimeStamp deferredDeliveryTimeAbsolute; + + /** + * Relative time is specified as one byte, the value of which + * falls into a series of ranges, as specified below. The idea is + * that shorter time intervals allow greater precision -- the + * value means minutes from zero until the MINS_LIMIT (inclusive), + * upon which it means hours until the HOURS_LIMIT, and so + * forth. (See 3GPP2 C.S0015-B, v2, 4.5.6-1) + */ + public static final int RELATIVE_TIME_MINS_LIMIT = 143; + public static final int RELATIVE_TIME_HOURS_LIMIT = 167; + public static final int RELATIVE_TIME_DAYS_LIMIT = 196; + public static final int RELATIVE_TIME_WEEKS_LIMIT = 244; + public static final int RELATIVE_TIME_INDEFINITE = 245; + public static final int RELATIVE_TIME_NOW = 246; + public static final int RELATIVE_TIME_MOBILE_INACTIVE = 247; + public static final int RELATIVE_TIME_RESERVED = 248; + + public boolean validityPeriodRelativeSet; + public int validityPeriodRelative; + public boolean deferredDeliveryTimeRelativeSet; + public int deferredDeliveryTimeRelative; /** - * Reply Option - * 1-bit values which indicate whether SMS acknowledgment is requested or not. - * (See 3GPP2 C.S0015-B, v2, 4.5.11) + * The Reply Option subparameter contains 1-bit values which + * indicate whether SMS acknowledgment is requested or not. (See + * 3GPP2 C.S0015-B, v2, 4.5.11) */ public boolean userAckReq; public boolean deliveryAckReq; @@ -225,14 +306,28 @@ public final class BearerData{ public boolean reportReq; /** - * The number of Messages element (8-bit value) is a decimal number in the 0 to 99 range - * representing the number of messages stored at the Voice Mail System. This element is - * used by the Voice Mail Notification service. - * (See 3GPP2 C.S0015-B, v2, 4.5.12) + * The Number of Messages subparameter (8-bit value) is a decimal + * number in the 0 to 99 range representing the number of messages + * stored at the Voice Mail System. This element is used by the + * Voice Mail Notification service. (See 3GPP2 C.S0015-B, v2, + * 4.5.12) */ public int numberOfMessages; /** + * The Message Deposit Index subparameter is assigned by the + * message center as a unique index to the contents of the User + * Data subparameter in each message sent to a particular mobile + * station. The mobile station, when replying to a previously + * received short message which included a Message Deposit Index + * subparameter, may include the Message Deposit Index of the + * received message to indicate to the message center that the + * original contents of the message are to be included in the + * reply. (See 3GPP2 C.S0015-B, v2, 4.5.18) + */ + public int depositIndex; + + /** * 4-bit or 8-bit value that indicates the number to be dialed in reply to a * received SMS message. * (See 3GPP2 C.S0015-B, v2, 4.5.15) @@ -248,25 +343,36 @@ public final class BearerData{ @Override public String toString() { StringBuilder builder = new StringBuilder(); - builder.append("BearerData:\n"); - builder.append(" messageType: " + messageType + "\n"); - builder.append(" messageId: " + (int)messageId + "\n"); - builder.append(" priority: " + (priorityIndicatorSet ? priority : "not set") + "\n"); - builder.append(" privacy: " + (privacyIndicatorSet ? privacy : "not set") + "\n"); - builder.append(" alert: " + (alertIndicatorSet ? alert : "not set") + "\n"); - builder.append(" displayMode: " + (displayModeSet ? displayMode : "not set") + "\n"); - builder.append(" language: " + (languageIndicatorSet ? language : "not set") + "\n"); - builder.append(" errorClass: " + (messageStatusSet ? errorClass : "not set") + "\n"); - builder.append(" msgStatus: " + (messageStatusSet ? messageStatus : "not set") + "\n"); - builder.append(" hasUserDataHeader: " + hasUserDataHeader + "\n"); - builder.append(" timeStamp: " + timeStamp + "\n"); - builder.append(" userAckReq: " + userAckReq + "\n"); - builder.append(" deliveryAckReq: " + deliveryAckReq + "\n"); - builder.append(" readAckReq: " + readAckReq + "\n"); - builder.append(" reportReq: " + reportReq + "\n"); - builder.append(" numberOfMessages: " + numberOfMessages + "\n"); - builder.append(" callbackNumber: " + callbackNumber + "\n"); - builder.append(" userData: " + userData + "\n"); + builder.append("BearerData "); + builder.append("{ messageType=" + messageType); + builder.append(", messageId=" + (int)messageId); + builder.append(", priority=" + (priorityIndicatorSet ? priority : "unset")); + builder.append(", privacy=" + (privacyIndicatorSet ? privacy : "unset")); + builder.append(", alert=" + (alertIndicatorSet ? alert : "unset")); + builder.append(", displayMode=" + (displayModeSet ? displayMode : "unset")); + builder.append(", language=" + (languageIndicatorSet ? language : "unset")); + builder.append(", errorClass=" + (messageStatusSet ? errorClass : "unset")); + builder.append(", msgStatus=" + (messageStatusSet ? messageStatus : "unset")); + builder.append(", msgCenterTimeStamp=" + + ((msgCenterTimeStamp != null) ? msgCenterTimeStamp : "unset")); + builder.append(", validityPeriodAbsolute=" + + ((validityPeriodAbsolute != null) ? validityPeriodAbsolute : "unset")); + builder.append(", validityPeriodRelative=" + + ((validityPeriodRelativeSet) ? validityPeriodRelative : "unset")); + builder.append(", deferredDeliveryTimeAbsolute=" + + ((deferredDeliveryTimeAbsolute != null) ? deferredDeliveryTimeAbsolute : "unset")); + builder.append(", deferredDeliveryTimeRelative=" + + ((deferredDeliveryTimeRelativeSet) ? deferredDeliveryTimeRelative : "unset")); + builder.append(", userAckReq=" + userAckReq); + builder.append(", deliveryAckReq=" + deliveryAckReq); + builder.append(", readAckReq=" + readAckReq); + builder.append(", reportReq=" + reportReq); + builder.append(", numberOfMessages=" + numberOfMessages); + builder.append(", callbackNumber=" + callbackNumber); + builder.append(", depositIndex=" + depositIndex); + builder.append(", hasUserDataHeader=" + hasUserDataHeader); + builder.append(", userData=" + userData); + builder.append(" }"); return builder.toString(); } @@ -281,25 +387,60 @@ public final class BearerData{ outStream.skip(3); } - private static byte[] encode7bitAscii(String msg) + private static int countAsciiSeptets(CharSequence msg, boolean force) { + int msgLen = msg.length(); + if (force) return msgLen; + for (int i = 0; i < msgLen; i++) { + if (UserData.charToAscii.get(msg.charAt(i), -1) == -1) { + return -1; + } + } + return msgLen; + } + + /** + * Calculate the message text encoding length, fragmentation, and other details. + * + * @param force ignore (but still count) illegal characters if true + * @return septet count, or -1 on failure + */ + public static TextEncodingDetails calcTextEncodingDetails(CharSequence msg, + boolean force7BitEncoding) { + TextEncodingDetails ted; + int septets = countAsciiSeptets(msg, force7BitEncoding); + if (septets != -1 && septets <= SmsMessage.MAX_USER_DATA_SEPTETS) { + ted = new TextEncodingDetails(); + ted.msgCount = 1; + ted.codeUnitCount = septets; + ted.codeUnitsRemaining = SmsMessage.MAX_USER_DATA_SEPTETS - septets; + ted.codeUnitSize = SmsMessage.ENCODING_7BIT; + } else { + ted = com.android.internal.telephony.gsm.SmsMessage.calculateLength( + msg, force7BitEncoding); + } + return ted; + } + + private static byte[] encode7bitAscii(String msg, boolean force) throws CodingException { try { BitwiseOutputStream outStream = new BitwiseOutputStream(msg.length()); - byte[] expandedData = msg.getBytes("US-ASCII"); - for (int i = 0; i < expandedData.length; i++) { - int charCode = expandedData[i]; - // Test ourselves for ASCII membership, since Java seems not to care. - if ((charCode < UserData.PRINTABLE_ASCII_MIN_INDEX) || - (charCode > UserData.PRINTABLE_ASCII_MAX_INDEX)) { - throw new CodingException("illegal ASCII code (" + charCode + ")"); + int msgLen = msg.length(); + for (int i = 0; i < msgLen; i++) { + int charCode = UserData.charToAscii.get(msg.charAt(i), -1); + if (charCode == -1) { + if (force) { + outStream.write(7, UserData.UNENCODABLE_7_BIT_CHAR); + } else { + throw new CodingException("cannot ASCII encode (" + msg.charAt(i) + ")"); + } + } else { + outStream.write(7, charCode); } - outStream.write(7, expandedData[i]); } return outStream.toByteArray(); - } catch (java.io.UnsupportedEncodingException ex) { - throw new CodingException("7bit ASCII encode failed: " + ex); - } catch (BitwiseOutputStream.AccessException ex) { + } catch (BitwiseOutputStream.AccessException ex) { throw new CodingException("7bit ASCII encode failed: " + ex); } } @@ -308,24 +449,31 @@ public final class BearerData{ throws CodingException { try { - return msg.getBytes("utf-16be"); // XXX(do not submit) -- make sure decode matches + return msg.getBytes("utf-16be"); } catch (java.io.UnsupportedEncodingException ex) { throw new CodingException("UTF-16 encode failed: " + ex); } } - private static byte[] encode7bitGsm(String msg) + private static int calcUdhSeptetPadding(int userDataHeaderLen) { + int udhBits = userDataHeaderLen * 8; + int udhSeptets = (udhBits + 6) / 7; + int paddingBits = (udhSeptets * 7) - udhBits; + return paddingBits; + } + + private static byte[] encode7bitGsm(String msg, int paddingBits) throws CodingException { try { - /** - * TODO(cleanup): find some way to do this without the copy. + /* + * TODO(cleanup): It would be nice if GsmAlphabet provided + * an option to produce just the data without prepending + * the length. */ - byte []fullData = GsmAlphabet.stringToGsm7BitPacked(msg); + byte []fullData = GsmAlphabet.stringToGsm7BitPacked(msg, 0, -1, paddingBits, true); byte []data = new byte[fullData.length - 1]; - for (int i = 0; i < data.length; i++) { - data[i] = fullData[i + 1]; - } + System.arraycopy(fullData, 1, data, 0, fullData.length - 1); return data; } catch (com.android.internal.telephony.EncodeException ex) { throw new CodingException("7bit GSM encode failed: " + ex); @@ -335,51 +483,85 @@ public final class BearerData{ private static void encodeUserDataPayload(UserData uData) throws CodingException { + // TODO(cleanup): UDH can only occur in EMS mode, meaning + // encapsulation of GSM encoding, and so the logic here should + // be refactored to more cleanly reflect this constraint. + + byte[] headerData = null; + if (uData.userDataHeader != null) headerData = SmsHeader.toByteArray(uData.userDataHeader); + int headerDataLen = (headerData == null) ? 0 : headerData.length + 1; // + length octet + + byte[] payloadData; + int codeUnitCount; if (uData.msgEncodingSet) { if (uData.msgEncoding == UserData.ENCODING_OCTET) { if (uData.payload == null) { Log.e(LOG_TAG, "user data with octet encoding but null payload"); - // TODO(code_review): reasonable for fail case? or maybe bail on encoding? - uData.payload = new byte[0]; + payloadData = new byte[0]; + codeUnitCount = 0; + } else { + payloadData = uData.payload; + codeUnitCount = uData.payload.length; } } else { if (uData.payloadStr == null) { Log.e(LOG_TAG, "non-octet user data with null payloadStr"); - // TODO(code_review): reasonable for fail case? or maybe bail on encoding? uData.payloadStr = ""; } if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) { - uData.payload = encode7bitGsm(uData.payloadStr); + int paddingBits = calcUdhSeptetPadding(headerDataLen); + payloadData = encode7bitGsm(uData.payloadStr, paddingBits); + codeUnitCount = ((payloadData.length + headerDataLen) * 8) / 7; } else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) { - uData.payload = encode7bitAscii(uData.payloadStr); + payloadData = encode7bitAscii(uData.payloadStr, true); + codeUnitCount = uData.payloadStr.length(); } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) { - uData.payload = encodeUtf16(uData.payloadStr); + payloadData = encodeUtf16(uData.payloadStr); + codeUnitCount = uData.payloadStr.length(); } else { throw new CodingException("unsupported user data encoding (" + uData.msgEncoding + ")"); } - uData.numFields = uData.payloadStr.length(); } } else { if (uData.payloadStr == null) { Log.e(LOG_TAG, "user data with null payloadStr"); - // TODO(code_review): reasonable for fail case? or maybe bail on encoding? uData.payloadStr = ""; } try { - uData.payload = encode7bitAscii(uData.payloadStr); - uData.msgEncoding = UserData.ENCODING_7BIT_ASCII; + if (headerData == null) { + payloadData = encode7bitAscii(uData.payloadStr, false); + codeUnitCount = uData.payloadStr.length(); + uData.msgEncoding = UserData.ENCODING_7BIT_ASCII; + } else { + // If there is a header, we are in EMS mode, in + // which case we use GSM encodings. + int paddingBits = calcUdhSeptetPadding(headerDataLen); + payloadData = encode7bitGsm(uData.payloadStr, paddingBits); + codeUnitCount = ((payloadData.length + headerDataLen) * 8) / 7; + uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET; + } } catch (CodingException ex) { - uData.payload = encodeUtf16(uData.payloadStr); + payloadData = encodeUtf16(uData.payloadStr); + codeUnitCount = uData.payloadStr.length(); uData.msgEncoding = UserData.ENCODING_UNICODE_16; } uData.msgEncodingSet = true; - uData.numFields = uData.payloadStr.length(); } - if (uData.payload.length > SmsMessage.MAX_USER_DATA_BYTES) { - throw new CodingException("encoded user data too large (" + uData.payload.length + + + int totalLength = payloadData.length + headerDataLen; + if (totalLength > SmsMessage.MAX_USER_DATA_BYTES) { + throw new CodingException("encoded user data too large (" + totalLength + " > " + SmsMessage.MAX_USER_DATA_BYTES + " bytes)"); } + + uData.numFields = codeUnitCount; + uData.payload = new byte[totalLength]; + if (headerData != null) { + uData.payload[0] = (byte)headerData.length; + System.arraycopy(headerData, 0, uData.payload, 1, headerData.length); + } + System.arraycopy(payloadData, 0, uData.payload, headerDataLen, payloadData.length); } private static void encodeUserData(BearerData bData, BitwiseOutputStream outStream) @@ -394,11 +576,6 @@ public final class BearerData{ * */ int dataBits = (bData.userData.payload.length * 8) - bData.userData.paddingBits; - byte[] headerData = null; - if (bData.hasUserDataHeader) { - headerData = bData.userData.userDataHeader.toByteArray(); - dataBits += headerData.length * 8; - } int paramBits = dataBits + 13; if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) || (bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) { @@ -413,7 +590,6 @@ public final class BearerData{ outStream.write(8, bData.userData.msgType); } outStream.write(8, bData.userData.numFields); - if (headerData != null) outStream.writeByteArray(headerData.length * 8, headerData); outStream.writeByteArray(dataBits, bData.userData.payload); if (paddingBits > 0) outStream.write(paddingBits, 0); } @@ -502,11 +678,11 @@ public final class BearerData{ outStream.write(8, bData.numberOfMessages); } - private static void encodeMsgCenterTimeStamp(BearerData bData, BitwiseOutputStream outStream) + private static void encodeValidityPeriodRel(BearerData bData, BitwiseOutputStream outStream) throws BitwiseOutputStream.AccessException { - outStream.write(8, 6); - outStream.writeByteArray(6 * 8, bData.timeStamp); + outStream.write(8, 1); + outStream.write(8, bData.validityPeriodRelative); } private static void encodePrivacyIndicator(BearerData bData, BitwiseOutputStream outStream) @@ -557,6 +733,8 @@ public final class BearerData{ * @return data byta array of raw encoded SMS bearer data. */ public static byte[] encode(BearerData bData) { + bData.hasUserDataHeader = ((bData.userData != null) && + (bData.userData.userDataHeader != null)); try { BitwiseOutputStream outStream = new BitwiseOutputStream(200); outStream.write(8, SUBPARAM_MESSAGE_IDENTIFIER); @@ -577,9 +755,9 @@ public final class BearerData{ outStream.write(8, SUBPARAM_NUMBER_OF_MESSAGES); encodeMsgCount(bData, outStream); } - if (bData.timeStamp != null) { - outStream.write(8, SUBPARAM_MESSAGE_CENTER_TIME_STAMP); - encodeMsgCenterTimeStamp(bData, outStream); + if (bData.validityPeriodRelativeSet) { + outStream.write(8, SUBPARAM_VALIDITY_PERIOD_RELATIVE); + encodeValidityPeriodRel(bData, outStream); } if (bData.privacyIndicatorSet) { outStream.write(8, SUBPARAM_PRIVACY_INDICATOR); @@ -630,7 +808,7 @@ public final class BearerData{ private static void decodeUserData(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException { - byte paramBytes = inStream.read(8); + int paramBytes = inStream.read(8); bData.userData = new UserData(); bData.userData.msgEncoding = inStream.read(5); bData.userData.msgEncodingSet = true; @@ -698,7 +876,7 @@ public final class BearerData{ inStream.skip(offset); byte[] expandedData = new byte[numFields]; for (int i = 0; i < numFields; i++) { - expandedData[i] = inStream.read(7); + expandedData[i] = (byte)inStream.read(7); } return new String(expandedData, 0, numFields, "US-ASCII"); } catch (java.io.UnsupportedEncodingException ex) { @@ -711,7 +889,12 @@ public final class BearerData{ private static String decode7bitGsm(byte[] data, int offset, int numFields) throws CodingException { - String result = GsmAlphabet.gsm7BitPackedToString(data, offset, numFields); + int paddingBits = calcUdhSeptetPadding(offset); + numFields -= (((offset * 8) + paddingBits) / 7); + // TODO: It seems wrong that only Gsm7 bit encodings would + // take into account the header in numFields calculations. + // This should be verified. + String result = GsmAlphabet.gsm7BitPackedToString(data, offset, numFields, paddingBits); if (result == null) { throw new CodingException("7bit GSM decoding failed"); } @@ -723,11 +906,11 @@ public final class BearerData{ { int offset = 0; if (hasUserDataHeader) { - int udhLen = userData.payload[0]; - offset += udhLen; + int udhLen = userData.payload[0] & 0x00FF; + offset += udhLen + 1; byte[] headerData = new byte[udhLen]; System.arraycopy(userData.payload, 1, headerData, 0, udhLen); - userData.userDataHeader = SmsHeader.parse(headerData); + userData.userDataHeader = SmsHeader.fromByteArray(headerData); } switch (userData.msgEncoding) { case UserData.ENCODING_OCTET: @@ -750,10 +933,126 @@ public final class BearerData{ } } + /** + * IS-91 Voice Mail message decoding + * (See 3GPP2 C.S0015-A, Table 4.3.1.4.1-1) + * (For character encodings, see TIA/EIA/IS-91, Annex B) + * + * Protocol Summary: The user data payload may contain 3-14 + * characters. The first two characters are parsed as a number + * and indicate the number of voicemails. The third character is + * either a SPACE or '!' to indicate normal or urgent priority, + * respectively. Any following characters are treated as normal + * text user data payload. + * + * Note that the characters encoding is 6-bit packed. + */ + private static void decodeIs91VoicemailStatus(BearerData bData) + throws BitwiseInputStream.AccessException, CodingException + { + BitwiseInputStream inStream = new BitwiseInputStream(bData.userData.payload); + int dataLen = inStream.available() / 6; // 6-bit packed character encoding. + int numFields = bData.userData.numFields; + if ((dataLen > 14) || (dataLen < 3) || (dataLen < numFields)) { + throw new CodingException("IS-91 voicemail status decoding failed"); + } + try { + StringBuffer strbuf = new StringBuffer(dataLen); + while (inStream.available() >= 6) { + strbuf.append(UserData.IA5_MAP[inStream.read(6)]); + } + String data = strbuf.toString(); + bData.numberOfMessages = Integer.parseInt(data.substring(0, 2)); + char prioCode = data.charAt(2); + if (prioCode == ' ') { + bData.priority = PRIORITY_NORMAL; + } else if (prioCode == '!') { + bData.priority = PRIORITY_URGENT; + } else { + throw new CodingException("IS-91 voicemail status decoding failed: " + + "illegal priority setting (" + prioCode + ")"); + } + bData.priorityIndicatorSet = true; + bData.userData.payloadStr = data.substring(3, numFields - 3); + } catch (java.lang.NumberFormatException ex) { + throw new CodingException("IS-91 voicemail status decoding failed: " + ex); + } catch (java.lang.IndexOutOfBoundsException ex) { + throw new CodingException("IS-91 voicemail status decoding failed: " + ex); + } + } + + /** + * IS-91 Short Message decoding + * (See 3GPP2 C.S0015-A, Table 4.3.1.4.1-1) + * (For character encodings, see TIA/EIA/IS-91, Annex B) + * + * Protocol Summary: The user data payload may contain 1-14 + * characters, which are treated as normal text user data payload. + * Note that the characters encoding is 6-bit packed. + */ + private static void decodeIs91ShortMessage(BearerData bData) + throws BitwiseInputStream.AccessException, CodingException + { + BitwiseInputStream inStream = new BitwiseInputStream(bData.userData.payload); + int dataLen = inStream.available() / 6; // 6-bit packed character encoding. + int numFields = bData.userData.numFields; + if ((dataLen > 14) || (dataLen < numFields)) { + throw new CodingException("IS-91 voicemail status decoding failed"); + } + StringBuffer strbuf = new StringBuffer(dataLen); + for (int i = 0; i < numFields; i++) { + strbuf.append(UserData.IA5_MAP[inStream.read(6)]); + } + bData.userData.payloadStr = strbuf.toString(); + } + + /** + * IS-91 CLI message (callback number) decoding + * (See 3GPP2 C.S0015-A, Table 4.3.1.4.1-1) + * + * Protocol Summary: The data payload may contain 1-32 digits, + * encoded using standard 4-bit DTMF, which are treated as a + * callback number. + */ + private static void decodeIs91Cli(BearerData bData) throws CodingException { + BitwiseInputStream inStream = new BitwiseInputStream(bData.userData.payload); + int dataLen = inStream.available() / 4; // 4-bit packed DTMF digit encoding. + int numFields = bData.userData.numFields; + if ((dataLen > 14) || (dataLen < 3) || (dataLen < numFields)) { + throw new CodingException("IS-91 voicemail status decoding failed"); + } + CdmaSmsAddress addr = new CdmaSmsAddress(); + addr.digitMode = CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF; + addr.origBytes = bData.userData.payload; + addr.numberOfDigits = (byte)numFields; + decodeSmsAddress(addr); + bData.callbackNumber = addr; + } + + private static void decodeIs91(BearerData bData) + throws BitwiseInputStream.AccessException, CodingException + { + switch (bData.userData.msgType) { + case UserData.IS91_MSG_TYPE_VOICEMAIL_STATUS: + decodeIs91VoicemailStatus(bData); + break; + case UserData.IS91_MSG_TYPE_CLI: + decodeIs91Cli(bData); + break; + case UserData.IS91_MSG_TYPE_SHORT_MESSAGE_FULL: + case UserData.IS91_MSG_TYPE_SHORT_MESSAGE: + decodeIs91ShortMessage(bData); + break; + default: + throw new CodingException("unsupported IS-91 message type (" + + bData.userData.msgType + ")"); + } + } + private static void decodeReplyOption(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - byte paramBytes = inStream.read(8); + int paramBytes = inStream.read(8); if (paramBytes != 1) { throw new CodingException("REPLY_OPTION subparam size incorrect"); } @@ -773,6 +1072,15 @@ public final class BearerData{ bData.numberOfMessages = inStream.read(8); } + private static void decodeDepositIndex(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + if (inStream.read(8) != 2) { + throw new CodingException("MESSAGE_DEPOSIT_INDEX subparam size incorrect"); + } + bData.depositIndex = (inStream.read(8) << 8) | inStream.read(8); + } + private static String decodeDtmfSmsAddress(byte[] rawData, int numFields) throws CodingException { @@ -807,7 +1115,7 @@ public final class BearerData{ private static void decodeCallbackNumber(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - byte paramBytes = inStream.read(8); + int paramBytes = inStream.read(8); CdmaSmsAddress addr = new CdmaSmsAddress(); addr.digitMode = inStream.read(1); byte fieldBits = 4; @@ -845,14 +1153,51 @@ public final class BearerData{ bData.messageStatusSet = true; } - private static void decodeMsgCenterTimeStamp(BearerData bData, - BitwiseInputStream inStream) + private static void decodeMsgCenterTimeStamp(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { if (inStream.read(8) != 6) { throw new CodingException("MESSAGE_CENTER_TIME_STAMP subparam size incorrect"); } - bData.timeStamp = inStream.readByteArray(6 * 8); + bData.msgCenterTimeStamp = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8)); + } + + private static void decodeValidityAbs(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + if (inStream.read(8) != 6) { + throw new CodingException("VALIDITY_PERIOD_ABSOLUTE subparam size incorrect"); + } + bData.validityPeriodAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8)); + } + + private static void decodeDeferredDeliveryAbs(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + if (inStream.read(8) != 6) { + throw new CodingException("DEFERRED_DELIVERY_TIME_ABSOLUTE subparam size incorrect"); + } + bData.deferredDeliveryTimeAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8)); + } + + private static void decodeValidityRel(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + if (inStream.read(8) != 1) { + throw new CodingException("VALIDITY_PERIOD_RELATIVE subparam size incorrect"); + } + bData.deferredDeliveryTimeRelative = inStream.read(8); + bData.deferredDeliveryTimeRelativeSet = true; + } + + private static void decodeDeferredDeliveryRel(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + if (inStream.read(8) != 1) { + throw new CodingException("DEFERRED_DELIVERY_TIME_RELATIVE subparam size incorrect"); + } + bData.validityPeriodRelative = inStream.read(8); + bData.validityPeriodRelativeSet = true; } private static void decodePrivacyIndicator(BearerData bData, BitwiseInputStream inStream) @@ -909,6 +1254,16 @@ public final class BearerData{ bData.alertIndicatorSet = true; } + private static void decodeUserResponseCode(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + if (inStream.read(8) != 1) { + throw new CodingException("USER_REPONSE_CODE subparam size incorrect"); + } + bData.userResponseCode = inStream.read(8); + bData.userResponseCodeSet = true; + } + /** * Create BearerData object from serialized representation. * (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details) @@ -937,6 +1292,9 @@ public final class BearerData{ case SUBPARAM_USER_DATA: decodeUserData(bData, inStream); break; + case SUBPARAM_USER_REPONSE_CODE: + decodeUserResponseCode(bData, inStream); + break; case SUBPARAM_REPLY_OPTION: decodeReplyOption(bData, inStream); break; @@ -952,6 +1310,18 @@ public final class BearerData{ case SUBPARAM_MESSAGE_CENTER_TIME_STAMP: decodeMsgCenterTimeStamp(bData, inStream); break; + case SUBPARAM_VALIDITY_PERIOD_ABSOLUTE: + decodeValidityAbs(bData, inStream); + break; + case SUBPARAM_VALIDITY_PERIOD_RELATIVE: + decodeValidityRel(bData, inStream); + break; + case SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE: + decodeDeferredDeliveryAbs(bData, inStream); + break; + case SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE: + decodeDeferredDeliveryRel(bData, inStream); + break; case SUBPARAM_PRIVACY_INDICATOR: decodePrivacyIndicator(bData, inStream); break; @@ -967,6 +1337,9 @@ public final class BearerData{ case SUBPARAM_ALERT_ON_MESSAGE_DELIVERY: decodeMsgDeliveryAlert(bData, inStream); break; + case SUBPARAM_MESSAGE_DEPOSIT_INDEX: + decodeDepositIndex(bData, inStream); + break; default: throw new CodingException("unsupported bearer data subparameter (" + subparamId + ")"); @@ -976,7 +1349,18 @@ public final class BearerData{ throw new CodingException("missing MESSAGE_IDENTIFIER subparam"); } if (bData.userData != null) { - decodeUserDataPayload(bData.userData, bData.hasUserDataHeader); + if (bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) { + if ((foundSubparamMask ^ + (1 << SUBPARAM_MESSAGE_IDENTIFIER) ^ + (1 << SUBPARAM_USER_DATA)) + != 0) { + Log.e(LOG_TAG, "IS-91 must occur without extra subparams (" + + foundSubparamMask + ")"); + } + decodeIs91(bData); + } else { + decodeUserDataPayload(bData.userData, bData.hasUserDataHeader); + } } return bData; } catch (BitwiseInputStream.AccessException ex) { diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java index 440debb..4d79966 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java @@ -20,23 +20,31 @@ import com.android.internal.telephony.SmsAddress; import com.android.internal.util.HexDump; public class CdmaSmsAddress extends SmsAddress { + /** - * digit mode indicators - * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + * Digit Mode Indicator is a 1-bit value that indicates whether + * the address digits are 4-bit DTMF codes or 8-bit codes. (See + * 3GPP2 C.S0015-B, v2, 3.4.3.3) */ static public final int DIGIT_MODE_4BIT_DTMF = 0x00; static public final int DIGIT_MODE_8BIT_CHAR = 0x01; + public int digitMode; + /** - * number mode indicators - * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + * Number Mode Indicator is 1-bit value that indicates whether the + * address type is a data network address or not. (See 3GPP2 + * C.S0015-B, v2, 3.4.3.3) */ static public final int NUMBER_MODE_NOT_DATA_NETWORK = 0x00; static public final int NUMBER_MODE_DATA_NETWORK = 0x01; + public int numberMode; + /** - * number types for data networks - * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + * Number Types for data networks. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + * NOTE: value is stored in the parent class ton field. */ static public final int TON_UNKNOWN = 0x00; static public final int TON_INTERNATIONAL_OR_IP = 0x01; @@ -48,14 +56,21 @@ public class CdmaSmsAddress extends SmsAddress { static public final int TON_RESERVED = 0x07; /** - * maximum lengths for fields as defined in ril_cdma_sms.h + * Maximum lengths for fields as defined in ril_cdma_sms.h. */ static public final int SMS_ADDRESS_MAX = 36; static public final int SMS_SUBADDRESS_MAX = 36; /** - * Supported numbering plan identification - * (See C.S005-D, v1.0, table 2.7.1.3.2.4-3) + * This field shall be set to the number of address digits + * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + */ + public int numberOfDigits; + + /** + * Numbering Plan identification is a 0 or 4-bit value that + * indicates which numbering plan identification is set. (See + * 3GPP2, C.S0015-B, v2, 3.4.3.3 and C.S005-D, table2.7.1.3.2.4-3) */ static public final int NUMBERING_PLAN_UNKNOWN = 0x0; static public final int NUMBERING_PLAN_ISDN_TELEPHONY = 0x1; @@ -63,50 +78,29 @@ public class CdmaSmsAddress extends SmsAddress { //static protected final int NUMBERING_PLAN_TELEX = 0x4; //static protected final int NUMBERING_PLAN_PRIVATE = 0x9; - /** - * 1-bit value that indicates whether the address digits are 4-bit DTMF codes - * or 8-bit codes. - * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) - */ - public byte digitMode; - - /** - * 1-bit value that indicates whether the address type is a data network address or not. - * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) - */ - public byte numberMode; - - // use parent class member ton instead public byte numberType; + public int numberPlan; /** - * 0 or 4-bit value that indicates which numbering plan identification is set. - * (See 3GPP2, C.S0015-B, v2, 3.4.3.3 and C.S005-D, table2.7.1.3.2.4-3) + * NOTE: the parsed string address and the raw byte array values + * are stored in the parent class address and origBytes fields, + * respectively. */ - public byte numberPlan; - - /** - * This field shall be set to the number of address digits - * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) - */ - public byte numberOfDigits; - - // use parent class member orig_bytes instead of public byte[] digits; - // Constructor public CdmaSmsAddress(){ } @Override public String toString() { StringBuilder builder = new StringBuilder(); - builder.append("CdmaSmsAddress:\n"); - builder.append(" digitMode: " + digitMode + "\n"); - builder.append(" numberMode: " + numberMode + "\n"); - builder.append(" numberPlan: " + numberPlan + "\n"); - builder.append(" numberOfDigits: " + numberOfDigits + "\n"); - builder.append(" ton: " + ton + "\n"); - builder.append(" address: " + address + "\n"); - builder.append(" origBytes: " + HexDump.toHexString(origBytes) + "\n"); + builder.append("CdmaSmsAddress "); + builder.append("{ digitMode=" + digitMode); + builder.append(", numberMode=" + numberMode); + builder.append(", numberPlan=" + numberPlan); + builder.append(", numberOfDigits=" + numberOfDigits); + builder.append(", ton=" + ton); + builder.append(", address=" + address); + builder.append(", origBytes=" + HexDump.toHexString(origBytes)); + builder.append(" }"); return builder.toString(); } diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java index 02e94ad..34cbbfa 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.cdma.sms; +import android.util.SparseIntArray; + import com.android.internal.telephony.SmsHeader; import com.android.internal.util.HexDump; @@ -38,8 +40,26 @@ public class UserData { public static final int ENCODING_GSM_DCS = 0x0A; /** + * IS-91 message types. + * (See TIA/EIS/IS-91-A-ENGL 1999, table 3.7.1.1-3) + */ + public static final int IS91_MSG_TYPE_VOICEMAIL_STATUS = 0x82; + public static final int IS91_MSG_TYPE_SHORT_MESSAGE_FULL = 0x83; + public static final int IS91_MSG_TYPE_CLI = 0x84; + public static final int IS91_MSG_TYPE_SHORT_MESSAGE = 0x85; + + /** * IA5 data encoding character mappings. * (See CCITT Rec. T.50 Tables 1 and 3) + * + * Note this mapping is the the same as for printable ASCII + * characters, with a 0x20 offset, meaning that the ASCII SPACE + * character occurs with code 0x20. + * + * Note this mapping is also equivalent to that used by the IS-91 + * protocol, except for the latter using only 6 bits, and hence + * mapping only entries up to the '_' character. + * */ public static final char[] IA5_MAP = { ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', @@ -50,10 +70,27 @@ public class UserData { 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~'}; /** + * Character to use when forced to encode otherwise unencodable + * characters, meaning those not in the respective ASCII or GSM + * 7-bit encoding tables. Current choice is SPACE, which is 0x20 + * in both the GSM-7bit and ASCII-7bit encodings. + */ + static final byte UNENCODABLE_7_BIT_CHAR = 0x20; + + /** * Only elements between these indices in the ASCII table are printable. */ public static final int PRINTABLE_ASCII_MIN_INDEX = 0x20; - public static final int PRINTABLE_ASCII_MAX_INDEX = 0x7F; + public static final int ASCII_LF_INDEX = 0x0A; + public static final int ASCII_CR_INDEX = 0x0D; + public static final SparseIntArray charToAscii = new SparseIntArray(); + static { + for (int i = 0; i < IA5_MAP.length; i++) { + charToAscii.put(IA5_MAP[i], PRINTABLE_ASCII_MIN_INDEX + i); + } + charToAscii.put('\r', ASCII_LF_INDEX); + charToAscii.put('\n', ASCII_CR_INDEX); + } /** * Mapping for IA5 values less than 32 are flow control signals @@ -73,7 +110,6 @@ public class UserData { public int msgEncoding; public boolean msgEncodingSet = false; - // XXX needed when encoding is IS91 or DCS (not supported yet): public int msgType; /** @@ -93,14 +129,15 @@ public class UserData { @Override public String toString() { StringBuilder builder = new StringBuilder(); - builder.append("UserData:\n"); - builder.append(" msgEncoding: " + (msgEncodingSet ? msgEncoding : "not set") + "\n"); - builder.append(" msgType: " + msgType + "\n"); - builder.append(" paddingBits: " + paddingBits + "\n"); - builder.append(" numFields: " + (int)numFields + "\n"); - builder.append(" userDataHeader: " + userDataHeader + "\n"); - builder.append(" payload: '" + HexDump.toHexString(payload) + "'"); - builder.append(", payloadStr: '" + payloadStr + "'"); + builder.append("UserData "); + builder.append("{ msgEncoding=" + (msgEncodingSet ? msgEncoding : "unset")); + builder.append(", msgType=" + msgType); + builder.append(", paddingBits=" + paddingBits); + builder.append(", numFields=" + (int)numFields); + builder.append(", userDataHeader=" + userDataHeader); + builder.append(", payload='" + HexDump.toHexString(payload) + "'"); + builder.append(", payloadStr='" + payloadStr + "'"); + builder.append(" }"); return builder.toString(); } diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/package.html b/telephony/java/com/android/internal/telephony/cdma/sms/package.html index 48e1034..b2bc736 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/package.html +++ b/telephony/java/com/android/internal/telephony/cdma/sms/package.html @@ -1,6 +1,6 @@ <HTML> <BODY> -Provides CDMA-specific features for text/data/PDU SMS messages +Provides CDMA-specific features for text/data/PDU SMS messages @hide </BODY> </HTML> diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java index a2d3c5e..d1e4b4f 100755 --- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java @@ -34,6 +34,7 @@ import android.provider.Telephony; import android.telephony.CellLocation; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; +import android.telephony.SignalStrength; import android.text.TextUtils; import android.util.Log; @@ -67,6 +68,7 @@ import com.android.internal.telephony.PhoneNotifier; import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.PhoneSubInfo; import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.TelephonyProperties; import com.android.internal.telephony.gsm.stk.StkService; import com.android.internal.telephony.test.SimulatedRadioControl; import com.android.internal.telephony.IccVmNotSupportedException; @@ -203,9 +205,9 @@ public class GSMPhone extends PhoneBase { } } - //Change the system setting - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.CURRENT_ACTIVE_PHONE, RILConstants.GSM_PHONE); + //Change the system property + SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE, + new Integer(RILConstants.GSM_PHONE).toString()); } public void dispose() { @@ -285,9 +287,8 @@ public class GSMPhone extends PhoneBase { return mDataConnection.getActiveApnString(); } - public int - getSignalStrengthASU() { - return mSST.rssi == 99 ? -1 : mSST.rssi; + public SignalStrength getSignalStrength() { + return mSST.mSignalStrength; } public boolean @@ -447,11 +448,6 @@ public class GSMPhone extends PhoneBase { } public void - notifyMessageWaitingIndicator() { - mNotifier.notifyMessageWaitingChanged(this); - } - - public void notifyCallForwardingIndicator() { mNotifier.notifyCallForwardingChanged(this); } @@ -825,6 +821,11 @@ public class GSMPhone extends PhoneBase { } public void + sendBurstDtmf(String dtmfString) { + Log.e(LOG_TAG, "[GSMPhone] sendBurstDtmf() is a CDMA method"); + } + + public void setRadioPower(boolean power) { mSST.setRadioPower(power); } @@ -832,21 +833,21 @@ public class GSMPhone extends PhoneBase { private void storeVoiceMailNumber(String number) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); SharedPreferences.Editor editor = sp.edit(); - editor.putString(VM_NUMBER, number); + editor.putString(VM_NUMBER, number); editor.commit(); setVmSimImsi(getSubscriberId()); } public String getVoiceMailNumber() { // Read from the SIM. If its null, try reading from the shared preference area. - String number = mSIMRecords.getVoiceMailNumber(); + String number = mSIMRecords.getVoiceMailNumber(); if (TextUtils.isEmpty(number)) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); number = sp.getString(VM_NUMBER, null); - } + } return number; } - + private String getVmSimImsi() { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); return sp.getString(VM_SIM_IMSI, null); @@ -858,7 +859,7 @@ public class GSMPhone extends PhoneBase { editor.putString(VM_SIM_IMSI, imsi); editor.commit(); } - + public String getVoiceMailAlphaTag() { String ret; @@ -922,13 +923,13 @@ public class GSMPhone extends PhoneBase { public void setVoiceMailNumber(String alphaTag, String voiceMailNumber, Message onComplete) { - - Message resp; + + Message resp; mVmNumber = voiceMailNumber; resp = h.obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete); mSIMRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp); } - + private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) { switch (commandInterfaceCFReason) { case CF_REASON_UNCONDITIONAL: @@ -1307,11 +1308,11 @@ public class GSMPhone extends PhoneBase { case EVENT_SIM_RECORDS_LOADED: updateCurrentCarrierInProvider(); - + // Check if this is a different SIM than the previous one. If so unset the // voice mail number. String imsi = getVmSimImsi(); - if (imsi != null && !getSubscriberId().equals(imsi)) { + if (imsi != null && !getSubscriberId().equals(imsi)) { storeVoiceMailNumber(null); setVmSimImsi(null); } @@ -1393,7 +1394,7 @@ public class GSMPhone extends PhoneBase { onComplete.sendToTarget(); } break; - + case EVENT_SET_VM_NUMBER_DONE: ar = (AsyncResult)msg.obj; if (IccVmNotSupportedException.class.isInstance(ar.exception)) { @@ -1407,7 +1408,7 @@ public class GSMPhone extends PhoneBase { } break; - + case EVENT_GET_CALL_FORWARD_DONE: ar = (AsyncResult)msg.obj; if (ar.exception == null) { @@ -1450,7 +1451,7 @@ public class GSMPhone extends PhoneBase { /** * Sets the "current" field in the telephony provider according to the SIM's operator - * + * * @return true for success; false otherwise. */ boolean updateCurrentCarrierInProvider() { diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java index 2b2f077..d93ca1d 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java @@ -83,7 +83,7 @@ public class GsmConnection extends Connection { static final int EVENT_PAUSE_DONE = 2; static final int EVENT_NEXT_POST_DIAL = 3; static final int EVENT_WAKE_LOCK_TIMEOUT = 4; - + //***** Constants static final int PAUSE_DELAY_FIRST_MILLIS = 100; static final int PAUSE_DELAY_MILLIS = 3 * 1000; @@ -117,7 +117,7 @@ public class GsmConnection extends Connection { GsmConnection (Context context, DriverCall dc, GsmCallTracker ct, int index) { createWakeLock(context); acquireWakeLock(); - + owner = ct; h = new MyHandler(owner.getLooper()); @@ -138,7 +138,7 @@ public class GsmConnection extends Connection { GsmConnection (Context context, String dialString, GsmCallTracker ct, GsmCall parent) { createWakeLock(context); acquireWakeLock(); - + owner = ct; h = new MyHandler(owner.getLooper()); @@ -375,7 +375,7 @@ public class GsmConnection extends Connection { return DisconnectCause.ICC_ERROR; } else if (causeCode == CallFailCause.ERROR_UNSPECIFIED) { if (phone.mSST.rs.isCsRestricted()) { - return DisconnectCause.CS_RESTRICTED; + return DisconnectCause.CS_RESTRICTED; } else if (phone.mSST.rs.isCsEmergencyRestricted()) { return DisconnectCause.CS_RESTRICTED_EMERGENCY; } else if (phone.mSST.rs.isCsNormalRestricted()) { @@ -575,7 +575,7 @@ public class GsmConnection extends Connection { return postDialString.substring(nextPostDialChar); } - + @Override protected void finalize() { @@ -609,7 +609,7 @@ public class GsmConnection extends Connection { c = 0; } else { boolean isValid; - + setPostDialState(PostDialState.STARTED); c = postDialString.charAt(nextPostDialChar++); @@ -680,31 +680,31 @@ public class GsmConnection 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" - * state or after WAKE_LOCK_TIMEOUT_MILLIS. + * 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" + * state or after WAKE_LOCK_TIMEOUT_MILLIS. * @param s new PostDialState */ private void setPostDialState(PostDialState s) { - if (postDialState != PostDialState.STARTED + 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 + } else if (postDialState == PostDialState.STARTED && s != PostDialState.STARTED) { h.removeMessages(EVENT_WAKE_LOCK_TIMEOUT); releaseWakeLock(); } postDialState = s; } - + private void createWakeLock(Context context) { PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); } - + private void acquireWakeLock() { log("acquireWakeLock"); @@ -720,7 +720,7 @@ public class GsmConnection extends Connection { } } } - + private void log(String msg) { Log.d(LOG_TAG, "[GSMConn] " + msg); } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index 9e6ebc4..c33d4b6 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -28,10 +28,9 @@ import android.content.SharedPreferences; import android.database.ContentObserver; import android.database.Cursor; import android.net.NetworkInfo; -import android.net.wifi.WifiManager; import android.net.Uri; +import android.net.wifi.WifiManager; import android.os.AsyncResult; -import android.os.Handler; import android.os.INetStatService; import android.os.Message; import android.os.RemoteException; @@ -42,7 +41,6 @@ import android.preference.PreferenceManager; import android.provider.Checkin; import android.provider.Settings; import android.provider.Telephony; -import android.provider.Settings.SettingNotFoundException; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.telephony.gsm.GsmCellLocation; @@ -50,12 +48,12 @@ import android.text.TextUtils; import android.util.EventLog; import android.util.Log; +import com.android.internal.telephony.DataCallState; import com.android.internal.telephony.DataConnection; -import com.android.internal.telephony.DataConnection.FailCause; import com.android.internal.telephony.DataConnectionTracker; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.TelephonyEventLog; +import com.android.internal.telephony.DataConnection.FailCause; import java.io.IOException; import java.util.ArrayList; @@ -67,6 +65,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private static final String LOG_TAG = "GSM"; private static final boolean DBG = true; + private GSMPhone mGsmPhone; /** * Handles changes to the APN db. */ @@ -87,6 +86,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // Indicates baseband will not auto-attach private boolean noAutoAttach = false; long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + private boolean mReregisterOnReconnectFailure = false; private ContentResolver mResolver; private boolean mPingTestActive = false; @@ -150,7 +150,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private static final int POLL_PDP_MILLIS = 5 * 1000; - //WINK:TODO: Teleca, is this really gsm specific, what about CDMA? private static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.gprs-reconnect"; private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason"; @@ -177,9 +176,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON); if (state == State.FAILED) { - cleanUpConnection(false, reason); + Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION); + msg.arg1 = 0; // tearDown is false + msg.obj = (String) reason; + sendMessage(msg); } - trySetupData(reason); + sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { final android.net.NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); @@ -204,6 +206,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { GsmDataConnectionTracker(GSMPhone p) { super(p); + mGsmPhone = p; p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); @@ -250,17 +253,17 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { //Unregister for all events phone.mCM.unregisterForAvailable(this); phone.mCM.unregisterForOffOrNotAvailable(this); - ((GSMPhone) phone).mSIMRecords.unregisterForRecordsLoaded(this); + mGsmPhone.mSIMRecords.unregisterForRecordsLoaded(this); phone.mCM.unregisterForDataStateChanged(this); - ((GSMPhone) phone).mCT.unregisterForVoiceCallEnded(this); - ((GSMPhone) phone).mCT.unregisterForVoiceCallStarted(this); - ((GSMPhone) phone).mSST.unregisterForGprsAttached(this); - ((GSMPhone) phone).mSST.unregisterForGprsDetached(this); - ((GSMPhone) phone).mSST.unregisterForRoamingOn(this); - ((GSMPhone) phone).mSST.unregisterForRoamingOff(this); - ((GSMPhone) phone).mSST.unregisterForPsRestrictedEnabled(this); - ((GSMPhone) phone).mSST.unregisterForPsRestrictedDisabled(this); - + mGsmPhone.mCT.unregisterForVoiceCallEnded(this); + mGsmPhone.mCT.unregisterForVoiceCallStarted(this); + mGsmPhone.mSST.unregisterForGprsAttached(this); + mGsmPhone.mSST.unregisterForGprsDetached(this); + mGsmPhone.mSST.unregisterForRoamingOn(this); + mGsmPhone.mSST.unregisterForRoamingOff(this); + mGsmPhone.mSST.unregisterForPsRestrictedEnabled(this); + mGsmPhone.mSST.unregisterForPsRestrictedDisabled(this); + phone.getContext().unregisterReceiver(this.mIntentReceiver); phone.getContext().getContentResolver().unregisterContentObserver(this.apnObserver); @@ -362,7 +365,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * The APN of the specified type is no longer needed. Ensure that if * use of the default APN has not been explicitly disabled, we are connected * to the default APN. - * @param type the APN type. The only valid values are currently + * @param type the APN type. The only valid values are currently * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}. * @return */ @@ -374,10 +377,14 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { removeMessages(EVENT_RESTORE_DEFAULT_APN); setEnabled(type, false); if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { + mRequestedApnType = Phone.APN_TYPE_DEFAULT; if (dataEnabled[APN_DEFAULT_ID]) { return Phone.APN_ALREADY_ACTIVE; } else { - cleanUpConnection(true, Phone.REASON_DATA_DISABLED); + Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION); + msg.arg1 = 1; // tearDown is true; + msg.obj = Phone.REASON_DATA_DISABLED; + sendMessage(msg); return Phone.APN_REQUEST_STARTED; } } else { @@ -407,10 +414,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { public boolean isDataConnectionAsDesired() { boolean roaming = phone.getServiceState().getRoaming(); - if (((GSMPhone) phone).mSIMRecords.getRecordsLoaded() && - ((GSMPhone) phone).mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE && + if (mGsmPhone.mSIMRecords.getRecordsLoaded() && + mGsmPhone.mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE && (!roaming || getDataOnRoamingEnabled()) && - !mIsWifiConnected && + !mIsWifiConnected && !mIsPsRestricted ) { return (state == State.CONNECTED); } @@ -477,7 +484,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { setEnabled(Phone.APN_TYPE_DEFAULT, true); // trySetupData() will be a no-op if we are currently // connected to the MMS APN - return trySetupData(Phone.REASON_DATA_ENABLED); + sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); + return true; } else if (!enable) { setEnabled(Phone.APN_TYPE_DEFAULT, false); // Don't tear down if there is an active APN and it handles MMS or SUPL. @@ -486,21 +494,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { (isApnTypeActive(Phone.APN_TYPE_SUPL) && isEnabled(Phone.APN_TYPE_SUPL))) { return false; } - cleanUpConnection(true, Phone.REASON_DATA_DISABLED); + Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION); + msg.arg1 = 1; // tearDown is true + msg.obj = Phone.REASON_DATA_DISABLED; + sendMessage(msg); return true; } else { // isEnabled && enable return true; } } - - /** - * Simply tear down data connections due to radio off - * and don't setup again. - */ - public void cleanConnectionBeforeRadioOff() { - cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); - } /** * Report the current state of data connectivity (enabled or disabled) for @@ -565,7 +568,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason)); Log.d(LOG_TAG, "[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted); - + if (phone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator // FIXME this can be improved @@ -576,22 +579,23 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return true; } - int gprsState = ((GSMPhone) phone).mSST.getCurrentGprsState(); + int gprsState = mGsmPhone.mSST.getCurrentGprsState(); boolean roaming = phone.getServiceState().getRoaming(); + boolean desiredPowerState = mGsmPhone.mSST.getDesiredPowerState(); if ((state == State.IDLE || state == State.SCANNING) && (gprsState == ServiceState.STATE_IN_SERVICE || noAutoAttach) - && ((GSMPhone) phone).mSIMRecords.getRecordsLoaded() - && ( ((GSMPhone) phone).mSST.isConcurrentVoiceAndData() || - phone.getState() == Phone.State.IDLE ) + && mGsmPhone.mSIMRecords.getRecordsLoaded() + && phone.getState() == Phone.State.IDLE && isDataAllowed() - && !mIsPsRestricted ) { + && !mIsPsRestricted + && desiredPowerState ) { if (state == State.IDLE) { waitingApns = buildWaitingApns(); if (waitingApns.isEmpty()) { if (DBG) log("No APN found"); - notifyNoData(PdpConnection.FailCause.BAD_APN); + notifyNoData(PdpConnection.FailCause.MISSING_UKNOWN_APN); return false; } else { log ("Create from allApns : " + apnListToString(allApns)); @@ -607,13 +611,14 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { log("trySetupData: Not ready for data: " + " dataState=" + state + " gprsState=" + gprsState + - " sim=" + ((GSMPhone) phone).mSIMRecords.getRecordsLoaded() + - " UMTS=" + ((GSMPhone) phone).mSST.isConcurrentVoiceAndData() + + " sim=" + mGsmPhone.mSIMRecords.getRecordsLoaded() + + " UMTS=" + mGsmPhone.mSST.isConcurrentVoiceAndData() + " phoneState=" + phone.getState() + " dataEnabled=" + getAnyDataEnabled() + " roaming=" + roaming + " dataOnRoamingEnable=" + getDataOnRoamingEnabled() + - " ps restricted=" + mIsPsRestricted); + " ps restricted=" + mIsPsRestricted + + " desiredPowerState=" + desiredPowerState); return false; } } @@ -638,6 +643,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { mReconnectIntent = null; } + setState(State.DISCONNECTING); + for (DataConnection conn : pdpList) { PdpConnection pdp = (PdpConnection) conn; if (tearDown) { @@ -649,25 +656,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } stopNetStatPoll(); - /* - * If we've been asked to tear down the connection, - * set the state to DISCONNECTING. However, there's - * a race that can occur if for some reason we were - * already in the IDLE state. In that case, the call - * to pdp.disconnect() above will immediately post - * a message to the handler thread that the disconnect - * is done, and if the handler runs before the code - * below does, the handler will have set the state to - * IDLE before the code below runs. If we didn't check - * for that, future calls to trySetupData would fail, - * and we would never get out of the DISCONNECTING state. - */ if (!tearDown) { setState(State.IDLE); phone.notifyDataConnection(reason); mActiveApn = null; - } else if (state != State.IDLE) { - setState(State.DISCONNECTING); } } @@ -779,7 +771,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } private boolean - pdpStatesHasCID (ArrayList<PDPContextState> states, int cid) { + pdpStatesHasCID (ArrayList<DataCallState> states, int cid) { for (int i = 0, s = states.size() ; i < s ; i++) { if (states.get(i).cid == cid) return true; } @@ -788,9 +780,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } private boolean - pdpStatesHasActiveCID (ArrayList<PDPContextState> states, int cid) { + pdpStatesHasActiveCID (ArrayList<DataCallState> states, int cid) { for (int i = 0, s = states.size() ; i < s ; i++) { - if (states.get(i).cid == cid) return (states.get(i).active != 0); + if ((states.get(i).cid == cid) && (states.get(i).active != 0)) { + return true; + } } return false; @@ -805,7 +799,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { isConnected = (state != State.IDLE && state != State.FAILED); // The "current" may no longer be valid. MMS depends on this to send properly. - ((GSMPhone) phone).updateCurrentCarrierInProvider(); + mGsmPhone.updateCurrentCarrierInProvider(); // TODO: It'd be nice to only do this if the changed entrie(s) // match the current operator. @@ -813,6 +807,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (state != State.DISCONNECTING) { cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED); if (!isConnected) { + // reset reconnect timer + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mReregisterOnReconnectFailure = false; trySetupData(Phone.REASON_APN_CHANGED); } } @@ -825,9 +822,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * previous state */ protected void onPdpStateChanged (AsyncResult ar, boolean explicitPoll) { - ArrayList<PDPContextState> pdpStates; + ArrayList<DataCallState> pdpStates; - pdpStates = (ArrayList<PDPContextState>)(ar.result); + pdpStates = (ArrayList<DataCallState>)(ar.result); if (ar.exception != null) { // This is probably "radio not available" or something @@ -893,6 +890,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { startNetStatPoll(); // reset reconnect timer nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mReregisterOnReconnectFailure = false; } private void setupDnsProperties() { @@ -963,7 +961,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } else { mPdpResetCount = 0; EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_REREGISTER_NETWORK, sentSinceLastRecv); - ((GSMPhone) phone).mSST.reRegisterNetwork(null); + mGsmPhone.mSST.reRegisterNetwork(null); } // TODO: Add increasingly drastic recovery steps, eg, // reset the radio, reset the device. @@ -1056,7 +1054,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } int watchdogTrigger = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, + Settings.Gservices.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, NUMBER_SENT_PACKETS_OF_HANG); if (sentSinceLastRecv >= watchdogTrigger) { @@ -1079,7 +1077,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // Slow down the poll interval to let things happen netStatPollPeriod = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS, + Settings.Gservices.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS, POLL_NETSTAT_SLOW_MILLIS); } else { if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) + @@ -1112,7 +1110,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } }; - + private void runPingTest () { int status = -1; try { @@ -1161,22 +1159,36 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { /** * Return true if data connection need to be setup after disconnected due to * reason. - * + * * @param reason the reason why data is disconnected - * @return true if try setup data connection is need for this reason + * @return true if try setup data connection is need for this reason */ private boolean retryAfterDisconnected(String reason) { boolean retry = true; - + if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) || - Phone.REASON_DATA_DISABLED.equals(reason) ) { + Phone.REASON_DATA_DISABLED.equals(reason) ) { retry = false; } return retry; - } + } private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) { if (state == State.FAILED) { + if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) { + if (mReregisterOnReconnectFailure) { + // We have already tried to re-register to the network. + // This might be a problem with the data network. + nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS; + } else { + // Try to Re-register to the network. + Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network"); + mReregisterOnReconnectFailure = true; + mGsmPhone.mSST.reRegisterNetwork(null); + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + return; + } + } Log.d(LOG_TAG, "PDP activate failed. Scheduling next attempt for " + (nextReconnectDelay / 1000) + "s"); @@ -1192,9 +1204,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // double it for next time nextReconnectDelay *= 2; - if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) { - nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS; - } if (!shouldPostNotification(lastFailCauseCode)) { Log.d(LOG_TAG,"NOT Posting GPRS Unavailable notification " @@ -1214,7 +1223,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (state == State.FAILED) { cleanUpConnection(false, null); } - sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); + sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED)); } protected void onEnableNewApn() { @@ -1223,17 +1232,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { cleanUpConnection(true, Phone.REASON_APN_SWITCHED); } - protected void onTrySetupData() { - trySetupData(null); + protected void onTrySetupData(String reason) { + trySetupData(reason); } protected void onRestoreDefaultApn() { if (DBG) Log.d(LOG_TAG, "Restore default APN"); setEnabled(Phone.APN_TYPE_MMS, false); - + mRequestedApnType = Phone.APN_TYPE_DEFAULT; if (!isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { cleanUpConnection(true, Phone.REASON_RESTORE_DEFAULT_APN); - mRequestedApnType = Phone.APN_TYPE_DEFAULT; } } @@ -1269,6 +1277,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // Make sure our reconnect delay starts at the initial value // next time the radio comes on nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mReregisterOnReconnectFailure = false; if (phone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator @@ -1326,19 +1335,13 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { cause = (PdpConnection.FailCause) (ar.result); if(DBG) log("PDP setup failed " + cause); // Log this failure to the Event Logs. - if (cause == PdpConnection.FailCause.BAD_APN || - cause == PdpConnection.FailCause.BAD_PAP_SECRET || - cause == PdpConnection.FailCause.BARRED || - cause == PdpConnection.FailCause.RADIO_ERROR_RETRY || - cause == PdpConnection.FailCause.SUSPENED_TEMPORARY || - cause == PdpConnection.FailCause.UNKNOWN || - cause == PdpConnection.FailCause.USER_AUTHENTICATION) { + 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, + cause.ordinal(), cid, TelephonyManager.getDefault().getNetworkType()); EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_PDP_SETUP_FAIL, val); } @@ -1346,20 +1349,20 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // No try for permanent failure if (cause.isPermanentFail()) { notifyNoData(cause); + return; } - if (tryNextApn(cause)) { - waitingApns.remove(0); - if (waitingApns.isEmpty()) { - // No more to try, start delayed retry - startDelayedRetry(cause, reason); - } else { - // we still have more apns to try - setState(State.SCANNING); - trySetupData(reason); - } - } else { + waitingApns.remove(0); + if (waitingApns.isEmpty()) { + // No more to try, start delayed retry startDelayedRetry(cause, reason); + } else { + // we still have more apns to try + setState(State.SCANNING); + // Wait a bit before trying the next APN, so that + // we're not tying up the RIL command channel + sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason), + RECONNECT_DELAY_INITIAL_MILLIS); } } } @@ -1387,7 +1390,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } protected void onVoiceCallStarted() { - if (state == State.CONNECTED && !((GSMPhone) phone).mSST.isConcurrentVoiceAndData()) { + if (state == State.CONNECTED && ! mGsmPhone.mSST.isConcurrentVoiceAndData()) { stopNetStatPoll(); phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); } @@ -1395,7 +1398,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { protected void onVoiceCallEnded() { if (state == State.CONNECTED) { - if (!((GSMPhone) phone).mSST.isConcurrentVoiceAndData()) { + if (!mGsmPhone.mSST.isConcurrentVoiceAndData()) { startNetStatPoll(); phone.notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); } else { @@ -1403,17 +1406,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { resetPollStats(); } } else { + // reset reconnect timer + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mReregisterOnReconnectFailure = false; // in case data setup was attempted when we were on a voice call trySetupData(Phone.REASON_VOICE_CALL_ENDED); } } - private boolean tryNextApn(FailCause cause) { - return (cause != FailCause.RADIO_NOT_AVAILABLE) - && (cause != FailCause.RADIO_OFF) - && (cause != FailCause.RADIO_ERROR_RETRY) - && (cause != FailCause.NO_SIGNAL) - && (cause != FailCause.SIM_LOCKED); + protected void onCleanUpConnection(boolean tearDown, String reason) { + cleanUpConnection(tearDown, reason); } private int getRestoreDefaultApnDelay() { @@ -1436,7 +1438,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { */ private void createAllApnList() { allApns = new ArrayList<ApnSetting>(); - String operator = ((GSMPhone) phone).mSIMRecords.getSIMOperatorNumeric(); + String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric(); if (operator != null) { String selection = "numeric = '" + operator + "'"; @@ -1462,7 +1464,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (allApns.isEmpty()) { if (DBG) log("No APN found for carrier: " + operator); preferredApn = null; - notifyNoData(PdpConnection.FailCause.BAD_APN); + notifyNoData(PdpConnection.FailCause.MISSING_UKNOWN_APN); } else { preferredApn = getPreferredApn(); Log.d(LOG_TAG, "Get PreferredAPN"); @@ -1478,7 +1480,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { DataConnection pdp; for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) { - pdp = new PdpConnection((GSMPhone) phone); + pdp = new PdpConnection(mGsmPhone); pdpList.add(pdp); } } @@ -1497,7 +1499,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { */ private ArrayList<ApnSetting> buildWaitingApns() { ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>(); - String operator = ((GSMPhone )phone).mSIMRecords.getSIMOperatorNumeric(); + String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric(); if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { if (canSetPreferApn && preferredApn != null) { @@ -1568,7 +1570,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { ContentResolver resolver = phone.getContext().getContentResolver(); resolver.delete(PREFERAPN_URI, null, null); - if (pos >= 0) { + if (pos >= 0) { ContentValues values = new ContentValues(); values.put(APN_ID, pos); resolver.insert(PREFERAPN_URI, values); @@ -1581,7 +1583,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } Cursor cursor = phone.getContext().getContentResolver().query( - PREFERAPN_URI, new String[] { "_id", "name", "apn" }, + PREFERAPN_URI, new String[] { "_id", "name", "apn" }, null, null, Telephony.Carriers.DEFAULT_SORT_ORDER); if (cursor != null) { @@ -1665,9 +1667,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * PDP context and notify us with PDP_CONTEXT_CHANGED. * But we should stop the network polling and prevent reset PDP. */ - Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); + Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); stopNetStatPoll(); - mIsPsRestricted = true; + mIsPsRestricted = true; break; case EVENT_PS_RESTRICT_DISABLED: @@ -1683,6 +1685,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (state == State.FAILED) { cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED); nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mReregisterOnReconnectFailure = false; } trySetupData(Phone.REASON_PS_RESTRICT_ENABLED); } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java index 4db8fc6..18e6375 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java @@ -621,7 +621,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { if (isInterrogate()) { phone.mCM.queryFacilityLock(facility, password, serviceClass, obtainMessage(EVENT_QUERY_COMPLETE, this)); - } else if (isActivate() || isDeactivate()) { + } else if (isActivate() || isDeactivate()) { phone.mCM.setFacilityLock(facility, isActivate(), password, serviceClass, obtainMessage(EVENT_SET_COMPLETE, this)); } else { @@ -1186,9 +1186,9 @@ public final class GsmMmiCode extends Handler implements MmiCode { sb.append(createQueryCallWaitingResultMessage(ints[1])); } else if (isServiceCodeCallBarring(sc)) { // ints[0] for Call Barring is a bit vector of services - sb.append(createQueryCallBarringResultMessage(ints[0])); + sb.append(createQueryCallBarringResultMessage(ints[0])); } else if (ints[0] == 1) { - // for all other services, treat it as a boolean + // for all other services, treat it as a boolean sb.append(context.getText(com.android.internal.R.string.serviceEnabled)); } else { sb.append(context.getText(com.android.internal.R.string.mmiError)); @@ -1224,9 +1224,9 @@ public final class GsmMmiCode extends Handler implements MmiCode { { StringBuilder sb = new StringBuilder(context.getText(com.android.internal.R.string.serviceEnabledFor)); - for (int classMask = 1 + for (int classMask = 1 ; classMask <= SERVICE_CLASS_MAX - ; classMask <<= 1 + ; classMask <<= 1 ) { if ((classMask & serviceClass) != 0) { sb.append("\n"); @@ -1235,7 +1235,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { } return sb; } - + /*** * TODO: It would be nice to have a method here that can take in a dialstring and * figure out if there is an MMI code embedded within it. This code would replace diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java index 3e73caf..2770ddc 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java @@ -22,12 +22,14 @@ import android.app.PendingIntent.CanceledException; import android.content.Intent; import android.os.AsyncResult; import android.os.Message; +import android.provider.Telephony.Sms.Intents; import android.telephony.ServiceState; import android.util.Config; import android.util.Log; import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.gsm.SmsMessage; +import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.SMSDispatcher; import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; @@ -39,8 +41,11 @@ import java.util.HashMap; final class GsmSMSDispatcher extends SMSDispatcher { private static final String TAG = "GSM"; + private GSMPhone mGsmPhone; + GsmSMSDispatcher(GSMPhone phone) { super(phone); + mGsmPhone = phone; } /** @@ -73,134 +78,61 @@ final class GsmSMSDispatcher extends SMSDispatcher { } } } - - if (mCm != null) { - mCm.acknowledgeLastIncomingSMS(true, null); - } + acknowledgeLastIncomingSms(true, Intents.RESULT_SMS_HANDLED, null); } - /** - * Dispatches an incoming SMS messages. - * - * @param sms the incoming message from the phone - */ - protected void dispatchMessage(SmsMessageBase smsb) { + /** {@inheritDoc} */ + protected int dispatchMessage(SmsMessageBase smsb) { // If sms is null, means there was a parsing error. - // TODO: Should NAK this. if (smsb == null) { - return; + return Intents.RESULT_SMS_GENERIC_ERROR; } SmsMessage sms = (SmsMessage) smsb; boolean handled = false; // Special case the message waiting indicator messages if (sms.isMWISetMessage()) { - ((GSMPhone) mPhone).updateMessageWaitingIndicator(true); - - if (sms.isMwiDontStore()) { - handled = true; - } - + mGsmPhone.updateMessageWaitingIndicator(true); + handled |= sms.isMwiDontStore(); if (Config.LOGD) { - Log.d(TAG, - "Received voice mail indicator set SMS shouldStore=" - + !handled); + Log.d(TAG, "Received voice mail indicator set SMS shouldStore=" + !handled); } } else if (sms.isMWIClearMessage()) { - ((GSMPhone) mPhone).updateMessageWaitingIndicator(false); - - if (sms.isMwiDontStore()) { - handled = true; - } - + mGsmPhone.updateMessageWaitingIndicator(false); + handled |= sms.isMwiDontStore(); if (Config.LOGD) { - Log.d(TAG, - "Received voice mail indicator clear SMS shouldStore=" - + !handled); + Log.d(TAG, "Received voice mail indicator clear SMS shouldStore=" + !handled); } } if (handled) { - return; + return Intents.RESULT_SMS_HANDLED; } - // Parse the headers to see if this is partial, or port addressed - int referenceNumber = -1; - int count = 0; - int sequence = 0; - int destPort = -1; - - SmsHeader header = sms.getUserDataHeader(); - if (header != null) { - for (SmsHeader.Element element : header.getElements()) { - try { - switch (element.getID()) { - case SmsHeader.CONCATENATED_8_BIT_REFERENCE: { - byte[] data = element.getData(); - - referenceNumber = data[0] & 0xff; - count = data[1] & 0xff; - sequence = data[2] & 0xff; - - // Per TS 23.040, 9.2.3.24.1: If the count is zero, sequence - // is zero, or sequence > count, ignore the entire element - if (count == 0 || sequence == 0 || sequence > count) { - referenceNumber = -1; - } - break; - } - - case SmsHeader.CONCATENATED_16_BIT_REFERENCE: { - byte[] data = element.getData(); - - referenceNumber = (data[0] & 0xff) * 256 + (data[1] & 0xff); - count = data[2] & 0xff; - sequence = data[3] & 0xff; - - // Per TS 23.040, 9.2.3.24.8: If the count is zero, sequence - // is zero, or sequence > count, ignore the entire element - if (count == 0 || sequence == 0 || sequence > count) { - referenceNumber = -1; - } - break; - } - - case SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT: { - byte[] data = element.getData(); - - destPort = (data[0] & 0xff) << 8; - destPort |= (data[1] & 0xff); - - break; - } - } - } catch (ArrayIndexOutOfBoundsException e) { - Log.e(TAG, "Bad element in header", e); - return; // TODO: NACK the message or something, don't just discard. - } - } - } - - if (referenceNumber == -1) { - // notify everyone of the message if it isn't partial + SmsHeader smsHeader = sms.getUserDataHeader(); + // See if message is partial or port addressed. + if ((smsHeader == null) || (smsHeader.concatRef == null)) { + // Message is not partial (not part of concatenated sequence). byte[][] pdus = new byte[1][]; pdus[0] = sms.getPdu(); - if (destPort != -1) { - if (destPort == SmsHeader.PORT_WAP_PUSH) { - mWapPush.dispatchWapPdu(sms.getUserData()); + if (smsHeader != null && smsHeader.portAddrs != null) { + if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) { + return mWapPush.dispatchWapPdu(sms.getUserData()); + } else { + // The message was sent to a port, so concoct a URI for it. + dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort); } - // The message was sent to a port, so concoct a URI for it - dispatchPortAddressedPdus(pdus, destPort); } else { - // It's a normal message, dispatch it + // Normal short and non-port-addressed message, dispatch it. dispatchPdus(pdus); } + return Activity.RESULT_OK; } else { - // Process the message part - processMessagePart(sms, referenceNumber, sequence, count, destPort); + // Process the message part. + return processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs); } } @@ -208,28 +140,36 @@ final class GsmSMSDispatcher extends SMSDispatcher { protected void sendMultipartText(String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { - int ref = ++sConcatenatedRef & 0xff; - - for (int i = 0, count = parts.size(); i < count; i++) { - // build SmsHeader - byte[] data = new byte[3]; - data[0] = (byte) ref; // reference #, unique per message - data[1] = (byte) count; // total part count - data[2] = (byte) (i + 1); // 1-based sequence - SmsHeader header = new SmsHeader(); - header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data)); - PendingIntent sentIntent = null; - PendingIntent deliveryIntent = null; + int refNumber = getNextConcatenatedRef() & 0x00FF; + + for (int i = 0, msgCount = parts.size(); i < msgCount; i++) { + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = refNumber; + concatRef.seqNumber = i + 1; // 1-based sequence + concatRef.msgCount = msgCount; + // TODO: We currently set this to true since our messaging app will never + // send more than 255 parts (it converts the message to MMS well before that). + // However, we should support 3rd party messaging apps that might need 16-bit + // references + // Note: It's not sufficient to just flip this bit to true; it will have + // ripple effects (several calculations assume 8-bit ref). + concatRef.isEightBits = true; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + + PendingIntent sentIntent = null; if (sentIntents != null && sentIntents.size() > i) { sentIntent = sentIntents.get(i); } + + PendingIntent deliveryIntent = null; if (deliveryIntents != null && deliveryIntents.size() > i) { deliveryIntent = deliveryIntents.get(i); } SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, - parts.get(i), deliveryIntent != null, header.toByteArray()); + parts.get(i), deliveryIntent != null, SmsHeader.toByteArray(smsHeader)); sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); } @@ -239,7 +179,7 @@ final class GsmSMSDispatcher extends SMSDispatcher { * Send a multi-part text based SMS which already passed SMS control check. * * It is the working function for sendMultipartText(). - * + * * @param destinationAddress the address to send the message to * @param scAddress is the service center address or null to use * the current default SMSC @@ -259,18 +199,16 @@ final class GsmSMSDispatcher extends SMSDispatcher { * to the recipient. The raw pdu of the status report is in the * extended data ("pdu"). */ - private void sendMultipartTextWithPermit(String destinationAddress, + private void sendMultipartTextWithPermit(String destinationAddress, String scAddress, ArrayList<String> parts, - ArrayList<PendingIntent> sentIntents, + ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { - - PendingIntent sentIntent = null; - PendingIntent deliveryIntent = null; - + // check if in service int ss = mPhone.getServiceState().getState(); if (ss != ServiceState.STATE_IN_SERVICE) { for (int i = 0, count = parts.size(); i < count; i++) { + PendingIntent sentIntent = null; if (sentIntents != null && sentIntents.size() > i) { sentIntent = sentIntents.get(i); } @@ -280,26 +218,29 @@ final class GsmSMSDispatcher extends SMSDispatcher { return; } - int ref = ++sConcatenatedRef & 0xff; - - for (int i = 0, count = parts.size(); i < count; i++) { - // build SmsHeader - byte[] data = new byte[3]; - data[0] = (byte) ref; // reference #, unique per message - data[1] = (byte) count; // total part count - data[2] = (byte) (i + 1); // 1-based sequence - SmsHeader header = new SmsHeader(); - header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data)); - + int refNumber = getNextConcatenatedRef() & 0x00FF; + + for (int i = 0, msgCount = parts.size(); i < msgCount; i++) { + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = refNumber; + concatRef.seqNumber = i + 1; // 1-based sequence + concatRef.msgCount = msgCount; + concatRef.isEightBits = false; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + + PendingIntent sentIntent = null; if (sentIntents != null && sentIntents.size() > i) { sentIntent = sentIntents.get(i); } + + PendingIntent deliveryIntent = null; if (deliveryIntents != null && deliveryIntents.size() > i) { deliveryIntent = deliveryIntents.get(i); } SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, - parts.get(i), deliveryIntent != null, header.toByteArray()); + parts.get(i), deliveryIntent != null, SmsHeader.toByteArray(smsHeader)); HashMap<String, Object> map = new HashMap<String, Object>(); map.put("smsc", pdus.encodedScAddress); @@ -307,7 +248,7 @@ final class GsmSMSDispatcher extends SMSDispatcher { SmsTracker tracker = SmsTrackerFactory(map, sentIntent, deliveryIntent); sendSms(tracker); - } + } } /** {@inheritDoc} */ @@ -324,33 +265,33 @@ final class GsmSMSDispatcher extends SMSDispatcher { /** * Send the multi-part SMS based on multipart Sms tracker - * + * * @param tracker holds the multipart Sms tracker ready to be sent */ protected void sendMultipartSms (SmsTracker tracker) { ArrayList<String> parts; ArrayList<PendingIntent> sentIntents; ArrayList<PendingIntent> deliveryIntents; - + HashMap map = tracker.mData; - + String destinationAddress = (String) map.get("destination"); String scAddress = (String) map.get("scaddress"); - + parts = (ArrayList<String>) map.get("parts"); sentIntents = (ArrayList<PendingIntent>) map.get("sentIntents"); deliveryIntents = (ArrayList<PendingIntent>) map.get("deliveryIntents"); - - sendMultipartTextWithPermit(destinationAddress, + + sendMultipartTextWithPermit(destinationAddress, scAddress, parts, sentIntents, deliveryIntents); } /** {@inheritDoc} */ - protected void acknowledgeLastIncomingSms(boolean success, Message response){ + protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){ // FIXME unit test leaves cm == null. this should change if (mCm != null) { - mCm.acknowledgeLastIncomingSMS(success, response); + mCm.acknowledgeLastIncomingGsmSms(success, resultToCause(result), response); } } @@ -375,5 +316,17 @@ final class GsmSMSDispatcher extends SMSDispatcher { response.recycle(); } + private int resultToCause(int rc) { + switch (rc) { + case Activity.RESULT_OK: + case Intents.RESULT_SMS_HANDLED: + // Cause code is ignored on success. + return 0; + case Intents.RESULT_SMS_OUT_OF_MEMORY: + return CommandsInterface.GSM_SMS_FAIL_CAUSE_MEMORY_CAPACITY_EXCEEDED; + case Intents.RESULT_SMS_GENERIC_ERROR: + default: + return CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR; + } + } } - diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java index 9ab1002..b3b4345 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java @@ -16,7 +16,13 @@ package com.android.internal.telephony.gsm; -import com.android.internal.telephony.Phone; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ALPHA; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISROAMING; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_NUMERIC; import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; @@ -38,6 +44,7 @@ import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.provider.Telephony.Intents; import android.telephony.ServiceState; +import android.telephony.SignalStrength; import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; import android.util.Config; @@ -49,21 +56,11 @@ import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.DataConnectionTracker; import com.android.internal.telephony.IccCard; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneProxy; 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 static com.android.internal.telephony.TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ALPHA; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISROAMING; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_NUMERIC; - import java.util.Arrays; import java.util.Calendar; import java.util.Date; @@ -73,6 +70,7 @@ import java.util.TimeZone; * {@hide} */ final class GsmServiceStateTracker extends ServiceStateTracker { + //***** Instance Variables GSMPhone phone; GsmCellLocation cellLoc; @@ -80,9 +78,6 @@ final class GsmServiceStateTracker extends ServiceStateTracker { int mPreferredNetworkType; RestrictedState rs; - int rssi = 99; // signal strength 0-31, 99=unknown - // That's "received signal strength indication" fyi - private int gprsState = ServiceState.STATE_OUT_OF_SERVICE; private int newGPRSState = ServiceState.STATE_OUT_OF_SERVICE; @@ -121,7 +116,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { private boolean mStartedGprsRegCheck = false; // Already sent the event-log for no gprs register private boolean mReportedGprsNoReg = false; - + /** * The Notification object given to the NotificationManager. */ @@ -151,9 +146,9 @@ final class GsmServiceStateTracker extends ServiceStateTracker { static final int CS_DISABLED = 1004; // Access Control enables all voice/sms service static final int CS_NORMAL_ENABLED = 1005; // Access Control blocks normal voice/sms service static final int CS_EMERGENCY_ENABLED = 1006; // Access Control blocks emergency call service - + // notification id - static final int PS_NOTIFICATION = 888; //id to update and cancel PS restricted + static final int PS_NOTIFICATION = 888; //id to update and cancel PS restricted static final int CS_NOTIFICATION = 999; //id to update and cancel CS restricted private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) { @@ -177,6 +172,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { cellLoc = new GsmCellLocation(); newCellLoc = new GsmCellLocation(); rs = new RestrictedState(); + mSignalStrength = new SignalStrength(); PowerManager powerManager = (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE); @@ -201,7 +197,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { cr.registerContentObserver( Settings.System.getUriFor(Settings.System.AUTO_TIME), true, mAutoTimeObserver); - setRssiDefaultValues(); + setSignalStrengthDefaultValues(); mNeedToRegForSimLoaded = true; } @@ -280,7 +276,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { * @param obj placed in Message.obj */ /*protected*/ void registerForPsRestrictedEnabled(Handler h, int what, Object obj) { - Log.d(LOG_TAG, "[DSAC DEB] " + "registerForPsRestrictedEnabled "); + Log.d(LOG_TAG, "[DSAC DEB] " + "registerForPsRestrictedEnabled "); Registrant r = new Registrant(h, what, obj); psRestrictEnabledRegistrants.add(r); @@ -300,7 +296,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { * @param obj placed in Message.obj */ /*protected*/ void registerForPsRestrictedDisabled(Handler h, int what, Object obj) { - Log.d(LOG_TAG, "[DSAC DEB] " + "registerForPsRestrictedDisabled "); + Log.d(LOG_TAG, "[DSAC DEB] " + "registerForPsRestrictedDisabled "); Registrant r = new Registrant(h, what, obj); psRestrictDisabledRegistrants.add(r); @@ -308,7 +304,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { r.notifyRegistrant(); } } - + /*protected*/ void unregisterForPsRestrictedDisabled(Handler h) { psRestrictDisabledRegistrants.remove(h); } @@ -506,13 +502,13 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } mStartedGprsRegCheck = false; break; - + case EVENT_RESTRICTED_STATE_CHANGED: // This is a notification from // CommandsInterface.setOnRestrictedStateChanged Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_RESTRICTED_STATE_CHANGED"); - + ar = (AsyncResult) msg.obj; onRestrictedStateChanged(ar); @@ -541,12 +537,15 @@ final class GsmServiceStateTracker extends ServiceStateTracker { (dcTracker.getAnyDataEnabled() ? 1 : 0) ); EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_DATA_STATE_RADIO_OFF, val); } - dcTracker.cleanConnectionBeforeRadioOff(); - + 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 + if (dcTracker.getState() != DataConnectionTracker.State.CONNECTED && dcTracker.getState() != DataConnectionTracker.State.DISCONNECTING) { Log.d(LOG_TAG, "Data shutdown complete."); break; @@ -557,7 +556,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { cm.setRadioPower(false, null); } // Otherwise, we're in the desired state } - + protected void updateSpnDisplay() { int rule = phone.mSIMRecords.getDisplayRule(ss.getOperatorNumeric()); String spn = phone.mSIMRecords.getServiceProviderName(); @@ -699,9 +698,8 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } - private void - setRssiDefaultValues() { - rssi = 99; + private void setSignalStrengthDefaultValues() { + mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1, true); } /** @@ -722,7 +720,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { case RADIO_UNAVAILABLE: newSS.setStateOutOfService(); newCellLoc.setStateInvalid(); - setRssiDefaultValues(); + setSignalStrengthDefaultValues(); mGotCountryCode = false; pollStateDone(); @@ -731,7 +729,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { case RADIO_OFF: newSS.setStateOff(); newCellLoc.setStateInvalid(); - setRssiDefaultValues(); + setSignalStrengthDefaultValues(); mGotCountryCode = false; pollStateDone(); @@ -745,10 +743,10 @@ final class GsmServiceStateTracker extends ServiceStateTracker { Log.d(LOG_TAG, "Radio Technology Change ongoing, setting SS to off"); newSS.setStateOff(); newCellLoc.setStateInvalid(); - setRssiDefaultValues(); + setSignalStrengthDefaultValues(); mGotCountryCode = false; - pollStateDone(); + //NOTE: pollStateDone() is not needed in this case break; default: @@ -1044,17 +1042,18 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } /** - * send signal-strength-changed notification if rssi changed + * send signal-strength-changed notification if changed * Called both for solicited and unsolicited signal stength updates */ private void onSignalStrengthResult(AsyncResult ar) { - int oldRSSI = rssi; + SignalStrength oldSignalStrength = mSignalStrength; + int rssi = 99; if (ar.exception != null) { - // 99 = unknown + // -1 = unknown // most likely radio is resetting/disconnected - rssi = 99; + setSignalStrengthDefaultValues(); } else { int[] ints = (int[])ar.result; @@ -1067,13 +1066,16 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } } - if (rssi != oldRSSI) { + mSignalStrength = new SignalStrength(rssi, -1, -1, -1, + -1, -1, -1, true); + + if (!mSignalStrength.equals(oldSignalStrength)) { try { // This takes care of delayed EVENT_POLL_SIGNAL_STRENGTH (scheduled after // POLL_PERIOD_MILLIS) during Radio Technology Change) phone.notifySignalStrength(); } catch (NullPointerException ex) { - Log.d(LOG_TAG, "onSignalStrengthResult() Phone already destroyed: " + ex - + "Signal Stranth not notified"); + log("onSignalStrengthResult() Phone already destroyed: " + ex + + "SignalStrength not notified"); } } } @@ -1089,27 +1091,27 @@ final class GsmServiceStateTracker extends ServiceStateTracker { { Log.d(LOG_TAG, "[DSAC DEB] " + "onRestrictedStateChanged"); RestrictedState newRs = new RestrictedState(); - + Log.d(LOG_TAG, "[DSAC DEB] " + "current rs at enter "+ rs); - + if (ar.exception == null) { int[] ints = (int[])ar.result; int state = ints[0]; - + newRs.setCsEmergencyRestricted( ((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) || ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) ); //ignore the normal call and data restricted state before SIM READY - if (phone.getIccCard().getState() == IccCard.State.READY) { + if (phone.getIccCard().getState() == IccCard.State.READY) { newRs.setCsNormalRestricted( ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) || ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) ); newRs.setPsRestricted( (state & RILConstants.RIL_RESTRICTED_STATE_PS_ALL)!= 0); } - - Log.d(LOG_TAG, "[DSAC DEB] " + "new rs "+ newRs); - + + Log.d(LOG_TAG, "[DSAC DEB] " + "new rs "+ newRs); + if (!rs.isPsRestricted() && newRs.isPsRestricted()) { psRestrictEnabledRegistrants.notifyRegistrants(); setNotification(PS_ENABLED); @@ -1117,9 +1119,9 @@ final class GsmServiceStateTracker extends ServiceStateTracker { psRestrictDisabledRegistrants.notifyRegistrants(); setNotification(PS_DISABLED); } - + /** - * There are two kind of cs restriction, normal and emergency. So + * There are two kind of cs restriction, normal and emergency. So * there are 4 x 4 combinations in current and new restricted states * and we only need to notify when state is changed. */ @@ -1129,32 +1131,32 @@ final class GsmServiceStateTracker extends ServiceStateTracker { setNotification(CS_DISABLED); } else if (!newRs.isCsNormalRestricted()) { // remove normal restriction - setNotification(CS_EMERGENCY_ENABLED); + setNotification(CS_EMERGENCY_ENABLED); } else if (!newRs.isCsEmergencyRestricted()) { // remove emergency restriction - setNotification(CS_NORMAL_ENABLED); + setNotification(CS_NORMAL_ENABLED); } } else if (rs.isCsEmergencyRestricted() && !rs.isCsNormalRestricted()) { if (!newRs.isCsRestricted()) { // remove all restriction - setNotification(CS_DISABLED); + setNotification(CS_DISABLED); } else if (newRs.isCsRestricted()) { // enable all restriction setNotification(CS_ENABLED); } else if (newRs.isCsNormalRestricted()) { // remove emergency restriction and enable normal restriction - setNotification(CS_NORMAL_ENABLED); + setNotification(CS_NORMAL_ENABLED); } } else if (!rs.isCsEmergencyRestricted() && rs.isCsNormalRestricted()) { if (!newRs.isCsRestricted()) { // remove all restriction - setNotification(CS_DISABLED); + setNotification(CS_DISABLED); } else if (newRs.isCsRestricted()) { // enable all restriction setNotification(CS_ENABLED); } else if (newRs.isCsEmergencyRestricted()) { // remove normal restriction and enable emergency restriction - setNotification(CS_EMERGENCY_ENABLED); + setNotification(CS_EMERGENCY_ENABLED); } } else { if (newRs.isCsRestricted()) { @@ -1162,10 +1164,10 @@ final class GsmServiceStateTracker extends ServiceStateTracker { setNotification(CS_ENABLED); } else if (newRs.isCsEmergencyRestricted()) { // enable emergency restriction - setNotification(CS_EMERGENCY_ENABLED); + setNotification(CS_EMERGENCY_ENABLED); } else if (newRs.isCsNormalRestricted()) { // enable normal restriction - setNotification(CS_NORMAL_ENABLED); + setNotification(CS_NORMAL_ENABLED); } } @@ -1527,7 +1529,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { /** * Post a notification to NotificationManager for restricted state - * + * * @param notifyType is one state of PS/CS_*_ENABLE/DISABLE */ private void setNotification(int notifyType) { @@ -1546,7 +1548,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { CharSequence details = ""; CharSequence title = context.getText(com.android.internal.R.string.RestrictedChangedTitle); int notificationId = CS_NOTIFICATION; - + switch (notifyType) { case PS_ENABLED: notificationId = PS_NOTIFICATION; @@ -1557,24 +1559,24 @@ final class GsmServiceStateTracker extends ServiceStateTracker { break; case CS_ENABLED: details = context.getText(com.android.internal.R.string.RestrictedOnAll);; - break; + break; case CS_NORMAL_ENABLED: details = context.getText(com.android.internal.R.string.RestrictedOnNormal);; - break; + break; case CS_EMERGENCY_ENABLED: details = context.getText(com.android.internal.R.string.RestrictedOnEmergency);; - break; + break; case CS_DISABLED: // do nothing and cancel the notification later - break; + break; } - + Log.d(LOG_TAG, "[DSAC DEB] " + "put notification " + title + " / " +details); mNotification.tickerText = title; - mNotification.setLatestEventInfo(context, title, details, + mNotification.setLatestEventInfo(context, title, details, mNotification.contentIntent); - - NotificationManager notificationManager = (NotificationManager) + + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); if (notifyType == PS_DISABLED || notifyType == CS_DISABLED) { @@ -1585,4 +1587,8 @@ final class GsmServiceStateTracker extends ServiceStateTracker { notificationManager.notify(notificationId, mNotification); } } + + private void log(String s) { + Log.d(LOG_TAG, "[GsmServiceStateTracker] " + s); + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/MccTable.java b/telephony/java/com/android/internal/telephony/gsm/MccTable.java index 6198979..e18da56 100644 --- a/telephony/java/com/android/internal/telephony/gsm/MccTable.java +++ b/telephony/java/com/android/internal/telephony/gsm/MccTable.java @@ -182,7 +182,7 @@ public final class MccTable table.add(new MccEntry(222,"it",2,"Europe/Rome","it")); //Italy table.add(new MccEntry(225,"va",2,"Europe/Rome","it")); //Vatican City State table.add(new MccEntry(226,"ro",2)); //Romania - table.add(new MccEntry(228,"ch",2,"Europe/Zurich","en")); //Switzerland (Confederation of) + table.add(new MccEntry(228,"ch",2,"Europe/Zurich","de")); //Switzerland (Confederation of) table.add(new MccEntry(230,"cz",2,"Europe/Prague","cs")); //Czech Republic table.add(new MccEntry(231,"sk",2)); //Slovak Republic table.add(new MccEntry(232,"at",2,"Europe/Vienna","de")); //Austria diff --git a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java index 88acb1b..55e5adc 100644 --- a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java @@ -35,32 +35,32 @@ public class PdpConnection extends DataConnection { private static final String LOG_TAG = "GSM"; private static final boolean DBG = true; - private static final boolean FAKE_FAIL = false; /** Fail cause of last PDP activate, from RIL_LastPDPActivateFailCause */ - private static final int PDP_FAIL_RIL_BARRED = 8; - private static final int PDP_FAIL_RIL_BAD_APN = 27; - private static final int PDP_FAIL_RIL_USER_AUTHENTICATION = 29; - private static final int PDP_FAIL_RIL_SERVICE_OPTION_NOT_SUPPORTED = 32; - private static final int PDP_FAIL_RIL_SERVICE_OPTION_NOT_SUBSCRIBED = 33; - private static final int PDP_FAIL_RIL_ERROR_UNSPECIFIED = 0xffff; + 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; - // dataLink is only used to support pppd link - private DataLink dataLink; - //***** Constructor PdpConnection(GSMPhone phone) { super(phone); - this.dataLink = null; - - if (SystemProperties.get("ro.radio.use-ppp","no").equals("yes")) { - dataLink = new PppLink((GsmDataConnectionTracker) phone.mDataConnection, phone); - dataLink.setOnLinkChange(this, EVENT_LINK_STATE_CHANGED, null); - } } /** @@ -83,28 +83,20 @@ public class PdpConnection extends DataConnection { lastFailCause = FailCause.NONE; receivedDisconnectReq = false; - if (FAKE_FAIL) { - // for debug before baseband implement error in setup PDP - if (apn.apn.equalsIgnoreCase("badapn")){ - notifyFail(FailCause.BAD_APN, onConnectCompleted); - return; - } - } - phone.mCM.setupDataCall(Integer.toString(RILConstants.GSM_PHONE), null, apn.apn, apn.user, apn.password, 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) { - if (dataLink != null) { - dataLink.disconnect(); - } - - if (phone.mCM.getRadioState().isOn()) { - phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg)); - } + tearDownData(msg); } else if (state == State.ACTIVATING) { receivedDisconnectReq = true; } else { @@ -186,21 +178,51 @@ public class PdpConnection extends DataConnection { FailCause cause; switch (rilCause) { - case PDP_FAIL_RIL_BARRED: - cause = FailCause.BARRED; + case PDP_FAIL_OPERATOR_BARRED: + cause = FailCause.OPERATOR_BARRED; + break; + case PDP_FAIL_INSUFFICIENT_RESOURCES: + cause = FailCause.INSUFFICIENT_RESOURCES; break; - case PDP_FAIL_RIL_BAD_APN: - cause = FailCause.BAD_APN; + case PDP_FAIL_MISSING_UKNOWN_APN: + cause = FailCause.MISSING_UKNOWN_APN; break; - case PDP_FAIL_RIL_USER_AUTHENTICATION: + 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_RIL_SERVICE_OPTION_NOT_SUPPORTED: + 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_RIL_SERVICE_OPTION_NOT_SUBSCRIBED: + 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; } @@ -243,7 +265,7 @@ public class PdpConnection extends DataConnection { // Don't bother reporting success if there's already a // pending disconnect request, since DataConnectionTracker // has already updated its state. - disconnect(onDisconnect); + tearDownData(onDisconnect); } else { String[] response = ((String[]) ar.result); cid = Integer.parseInt(response[0]); @@ -278,11 +300,7 @@ public class PdpConnection extends DataConnection { } } - if (dataLink != null) { - dataLink.connect(); - } else { - onLinkStateChanged(DataLink.LinkState.LINK_UP); - } + onLinkStateChanged(DataLink.LinkState.LINK_UP); if (DBG) log("PDP setup on cid = " + cid); } diff --git a/telephony/java/com/android/internal/telephony/gsm/PppLink.java b/telephony/java/com/android/internal/telephony/gsm/PppLink.java deleted file mode 100644 index 9627696..0000000 --- a/telephony/java/com/android/internal/telephony/gsm/PppLink.java +++ /dev/null @@ -1,219 +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.database.Cursor; -import android.os.Message; -import android.os.SystemProperties; -import android.os.SystemService; -import android.util.Log; - -import com.android.internal.telephony.DataLink; -import com.android.internal.telephony.DataConnectionTracker.State; -import com.android.internal.telephony.PhoneBase; -import com.android.internal.util.ArrayUtils; - -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.RandomAccessFile; - -/** - * Represents a PPP link. - * - * Ideally this would be managed by the RIL implementation, but - * we currently have implementations where this is not the case. - * - * {@hide} - */ -final class PppLink extends DataLink { - private static final String LOG_TAG = "GSM"; - - static final String PATH_PPP_OPERSTATE = "/sys/class/net/ppp0/operstate"; - static final String SERVICE_PPPD_GPRS = "pppd_gprs"; - static final String PROPERTY_PPPD_EXIT_CODE = "net.gprs.ppp-exit"; - static final int POLL_SYSFS_MILLIS = 5 * 1000; - static final int EVENT_POLL_DATA_CONNECTION = 2; - static final int EVENT_PPP_OPERSTATE_CHANGED = 8; - static final int EVENT_PPP_PIDFILE_CHANGED = 9; - - static final byte[] UP_ASCII_STRING = new byte[] { - 'u' & 0xff, - 'p' & 0xff, - }; - static final byte[] DOWN_ASCII_STRING = new byte[] { - 'd' & 0xff, - 'o' & 0xff, - 'w' & 0xff, - 'n' & 0xff, - }; - static final byte[] UNKNOWN_ASCII_STRING = new byte[] { - 'u' & 0xff, - 'n' & 0xff, - 'k' & 0xff, - 'n' & 0xff, - 'o' & 0xff, - 'w' & 0xff, - 'n' & 0xff, - }; - private final byte[] mCheckPPPBuffer = new byte[32]; - - private PhoneBase phone; - - int lastPppdExitCode = EXIT_OK; - - - PppLink(GsmDataConnectionTracker dc, GSMPhone p) { - super(dc); - this.phone = p; - } - - public void connect() { - // Clear any previous exit code - SystemProperties.set(PROPERTY_PPPD_EXIT_CODE, ""); - SystemService.start(SERVICE_PPPD_GPRS); - removeMessages(EVENT_POLL_DATA_CONNECTION); - Message poll = obtainMessage(); - poll.what = EVENT_POLL_DATA_CONNECTION; - sendMessageDelayed(poll, POLL_SYSFS_MILLIS); - } - - public void disconnect() { - SystemService.stop(SERVICE_PPPD_GPRS); - } - - public int getLastLinkExitCode() { - return lastPppdExitCode; - } - - public void setPasswordInfo(Cursor cursor) { - StringBuilder builder = new StringBuilder(); - FileOutputStream output = null; - - try { - output = new FileOutputStream("/etc/ppp/pap-secrets"); - if (cursor.moveToFirst()) { - do { - builder.append(cursor.getString(cursor.getColumnIndex("user"))); - builder.append(" "); - builder.append(cursor.getString(cursor.getColumnIndex("server"))); - builder.append(" "); - builder.append(cursor.getString(cursor.getColumnIndex("password"))); - builder.append("\n"); - } while (cursor.moveToNext()); - } - - output.write(builder.toString().getBytes()); - } catch (java.io.IOException e) { - Log.e(LOG_TAG, "Could not create '/etc/ppp/pap-secrets'", e); - } finally { - try { - if (output != null) output.close(); - } catch (java.io.IOException e) { - Log.e(LOG_TAG, "Error closing '/etc/ppp/pap-secrets'", e); - } - } - } - - public void handleMessage (Message msg) { - - switch (msg.what) { - - case EVENT_POLL_DATA_CONNECTION: - checkPPP(); - - // keep polling in case interface goes down - if (dataConnection.getState() != State.IDLE) { - Message poll = obtainMessage(); - poll.what = EVENT_POLL_DATA_CONNECTION; - sendMessageDelayed(poll, POLL_SYSFS_MILLIS); - } - break; - } - } - - private void checkPPP() { - boolean connecting = (dataConnection.getState() == State.CONNECTING); - - try { - RandomAccessFile file = new RandomAccessFile(PATH_PPP_OPERSTATE, "r"); - file.read(mCheckPPPBuffer); - file.close(); - - // Unfortunately, we're currently seeing operstate - // "unknown" where one might otherwise expect "up" - if (ArrayUtils.equals(mCheckPPPBuffer, UP_ASCII_STRING, UP_ASCII_STRING.length) - || ArrayUtils.equals(mCheckPPPBuffer, UNKNOWN_ASCII_STRING, - UNKNOWN_ASCII_STRING.length) - && dataConnection.getState() == State.CONNECTING) { - - Log.i(LOG_TAG, - "found ppp interface. Notifying GPRS connected"); - - if (mLinkChangeRegistrant != null) { - mLinkChangeRegistrant.notifyResult(LinkState.LINK_UP); - } - - connecting = false; - } else if (dataConnection.getState() == State.CONNECTED - && ArrayUtils.equals(mCheckPPPBuffer, DOWN_ASCII_STRING, - DOWN_ASCII_STRING.length)) { - - Log.i(LOG_TAG, - "ppp interface went down. Reconnecting..."); - - if (mLinkChangeRegistrant != null) { - mLinkChangeRegistrant.notifyResult(LinkState.LINK_DOWN); - } - } - } catch (IOException ex) { - if (! (ex instanceof FileNotFoundException)) { - Log.i(LOG_TAG, "Poll ppp0 ex " + ex.toString()); - } - - if (dataConnection.getState() == State.CONNECTED && - mLinkChangeRegistrant != null) { - mLinkChangeRegistrant.notifyResult(LinkState.LINK_DOWN); - } - } - - // CONNECTING means pppd has started but negotiation is not complete - // If we're still CONNECTING here, check to see if pppd has - // already exited - if (connecting) { - String exitCode; - - exitCode = SystemProperties.get(PROPERTY_PPPD_EXIT_CODE, ""); - - if (!exitCode.equals("")) { - // pppd has exited. Let's figure out why - lastPppdExitCode = Integer.parseInt(exitCode); - - Log.d(LOG_TAG,"pppd exited with " + exitCode); - - if (mLinkChangeRegistrant != null) { - mLinkChangeRegistrant.notifyResult(LinkState.LINK_EXITED); - } - } - } - - } - - protected void log(String s) { - Log.d(LOG_TAG, "[PppLink] " + s); - } -} diff --git a/telephony/java/com/android/internal/telephony/gsm/RestrictedState.java b/telephony/java/com/android/internal/telephony/gsm/RestrictedState.java index d17f134..3f7d5d7 100644 --- a/telephony/java/com/android/internal/telephony/gsm/RestrictedState.java +++ b/telephony/java/com/android/internal/telephony/gsm/RestrictedState.java @@ -19,7 +19,7 @@ package com.android.internal.telephony.gsm; import android.telephony.ServiceState; public class RestrictedState { - + /** * Set true to block packet data access due to restriction */ @@ -32,7 +32,7 @@ public class RestrictedState { * Set true to block emergency call due to restriction */ private boolean mCsEmergencyRestricted; - + public RestrictedState() { setPsRestricted(false); setCsNormalRestricted(false); @@ -80,11 +80,11 @@ public class RestrictedState { public boolean isPsRestricted() { return mPsRestricted; } - + public boolean isCsRestricted() { return mCsNormalRestricted && mCsEmergencyRestricted; } - + @Override public boolean equals (Object o) { RestrictedState s; @@ -107,7 +107,7 @@ public class RestrictedState { @Override public String toString() { String csString = "none"; - + if (mCsEmergencyRestricted && mCsNormalRestricted) { csString = "all"; } else if (mCsEmergencyRestricted && !mCsNormalRestricted) { @@ -115,7 +115,7 @@ public class RestrictedState { } else if (!mCsEmergencyRestricted && mCsNormalRestricted) { csString = "normal call"; } - + return "Restricted State CS: " + csString + " PS:" + mPsRestricted; } diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java index f9015d9..e25de81 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java +++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java @@ -67,7 +67,7 @@ public final class SIMRecords extends IccRecords { SpnOverride mSpnOverride; - + //***** Cached SIM State; cleared on channel close String imsi; @@ -92,7 +92,6 @@ public final class SIMRecords extends IccRecords { byte[] mEfCfis = null; - String spn; int spnDisplayCondition; // Numeric network codes listed in TS 51.011 EF[SPDI] ArrayList<String> spdiNetworks = null; @@ -204,7 +203,7 @@ public final class SIMRecords extends IccRecords { // -1 means no EF_SPN found; treat accordingly. spnDisplayCondition = -1; efMWIS = null; - efCPHS_MWI = null; + efCPHS_MWI = null; spdiNetworks = null; pnnHomeName = null; @@ -483,7 +482,7 @@ public final class SIMRecords extends IccRecords { return imsi.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc)); } - + /** * If the timezone is not already set, set it based on the MCC of the SIM. * @param mcc Mobile Country Code of the SIM @@ -492,7 +491,7 @@ public final class SIMRecords extends IccRecords { String timezone = SystemProperties.get(TIMEZONE_PROPERTY); if (timezone == null || timezone.length() == 0) { String zoneId = MccTable.defaultTimeZoneForMcc(mcc); - + if (zoneId != null && zoneId.length() > 0) { // Set time zone based on MCC AlarmManager alarm = @@ -1011,7 +1010,7 @@ public final class SIMRecords extends IccRecords { IccUtils.bytesToHexString(data)); mEfCfis = data; - + // Refer TS 51.011 Section 10.3.46 for the content description callForwardingEnabled = ((data[1] & 0x01) != 0); diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java b/telephony/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java new file mode 100644 index 0000000..45f50bc --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java @@ -0,0 +1,133 @@ +/* + * 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; + +/** + * SmsBroadcastConfigInfo defines one configuration of Cell Broadcast + * Message (CBM) to be received by the ME + * + * fromServiceId - toServiceId defines a range of CBM message identifiers + * whose value is 0x0000 - 0xFFFF as defined in TS 23.041 9.4.1.2.2 for GMS + * and 9.4.4.2.2 for UMTS. All other values can be treated as empty + * CBM message ID. + * + * fromCodeScheme - toCodeScheme defines a range of CBM data coding schemes + * whose value is 0x00 - 0xFF as defined in TS 23.041 9.4.1.2.3 for GMS + * and 9.4.4.2.3 for UMTS. + * All other values can be treated as empty CBM data coding scheme. + * + * selected false means message types specified in <fromServiceId, toServiceId> + * and <fromCodeScheme, toCodeScheme>are not accepted, while true means accepted. + * + */ +public class SmsBroadcastConfigInfo { + private int fromServiceId; + private int toServiceId; + private int fromCodeScheme; + private int toCodeScheme; + private boolean selected; + + /** + * Initialize the object from rssi and cid. + */ + public SmsBroadcastConfigInfo(int fromId, int toId, int fromScheme, + int toScheme, boolean selected) { + setFromServiceId(fromId); + setToServiceId(toId); + setFromCodeScheme(fromScheme); + setToCodeScheme(toScheme); + this.setSelected(selected); + } + + /** + * @param fromServiceId the fromServiceId to set + */ + public void setFromServiceId(int fromServiceId) { + this.fromServiceId = fromServiceId; + } + + /** + * @return the fromServiceId + */ + public int getFromServiceId() { + return fromServiceId; + } + + /** + * @param toServiceId the toServiceId to set + */ + public void setToServiceId(int toServiceId) { + this.toServiceId = toServiceId; + } + + /** + * @return the toServiceId + */ + public int getToServiceId() { + return toServiceId; + } + + /** + * @param fromCodeScheme the fromCodeScheme to set + */ + public void setFromCodeScheme(int fromCodeScheme) { + this.fromCodeScheme = fromCodeScheme; + } + + /** + * @return the fromCodeScheme + */ + public int getFromCodeScheme() { + return fromCodeScheme; + } + + /** + * @param toCodeScheme the toCodeScheme to set + */ + public void setToCodeScheme(int toCodeScheme) { + this.toCodeScheme = toCodeScheme; + } + + /** + * @return the toCodeScheme + */ + public int getToCodeScheme() { + return toCodeScheme; + } + + /** + * @param selected the selected to set + */ + public void setSelected(boolean selected) { + this.selected = selected; + } + + /** + * @return the selected + */ + public boolean isSelected() { + return selected; + } + + @Override + public String toString() { + return "SmsBroadcastConfigInfo: Id [" + + getFromServiceId() + "," + getToServiceId() + "] Code [" + + getFromCodeScheme() + "," + getToCodeScheme() + "] " + + (isSelected() ? "ENABLED" : "DISABLED"); + } +}
\ No newline at end of file diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java index 867b719..f1207e4 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java @@ -26,6 +26,7 @@ import com.android.internal.telephony.EncodeException; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; @@ -250,6 +251,12 @@ public class SmsMessage extends SmsMessageBase{ // TP-Data-Coding-Scheme // Default encoding, uncompressed + // To test writing messages to the SIM card, change this value 0x00 + // to 0x12, which means "bits 1 and 0 contain message class, and the + // class is 2". Note that this takes effect for the sender. In other + // words, messages sent by the phone with this change will end up on + // the receiver's SIM card. You can then send messages to yourself + // (on a phone with this change) and they'll end up on the SIM card. bo.write(0x00); // (no TP-Validity-Period) @@ -330,9 +337,20 @@ public class SmsMessage extends SmsMessageBase{ public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, short destinationPort, byte[] data, boolean statusReportRequested) { - if (data.length > (MAX_USER_DATA_BYTES - 7 /* UDH size */)) { + + SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs(); + portAddrs.destPort = destinationPort; + portAddrs.origPort = 0; + portAddrs.areEightBits = false; + + SmsHeader smsHeader = new SmsHeader(); + smsHeader.portAddrs = portAddrs; + + byte[] smsHeaderData = SmsHeader.toByteArray(smsHeader); + + if ((data.length + smsHeaderData.length + 1) > MAX_USER_DATA_BYTES) { Log.e(LOG_TAG, "SMS data message may only contain " - + (MAX_USER_DATA_BYTES - 7) + " bytes"); + + (MAX_USER_DATA_BYTES - smsHeaderData.length - 1) + " bytes"); return null; } @@ -348,21 +366,12 @@ public class SmsMessage extends SmsMessageBase{ // (no TP-Validity-Period) - // User data size - bo.write(data.length + 7); - - // User data header size - bo.write(0x06); // header is 6 octets + // Total size + bo.write(data.length + smsHeaderData.length + 1); - // User data header, indicating the destination port - bo.write(SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT); // port - // addressing - // header - bo.write(0x04); // each port is 2 octets - bo.write((destinationPort >> 8) & 0xFF); // MSB of destination port - bo.write(destinationPort & 0xFF); // LSB of destination port - bo.write(0x00); // MSB of originating port - bo.write(0x00); // LSB of originating port + // User data header + bo.write(smsHeaderData.length); + bo.write(smsHeaderData, 0, smsHeaderData.length); // User data bo.write(data, 0, data.length); @@ -556,13 +565,14 @@ public class SmsMessage extends SmsMessageBase{ int offset = cur; int userDataLength = pdu[offset++] & 0xff; int headerSeptets = 0; + int userDataHeaderLength = 0; if (hasUserDataHeader) { - int userDataHeaderLength = pdu[offset++] & 0xff; + userDataHeaderLength = pdu[offset++] & 0xff; byte[] udh = new byte[userDataHeaderLength]; System.arraycopy(pdu, offset, udh, 0, userDataHeaderLength); - userDataHeader = SmsHeader.parse(udh); + userDataHeader = SmsHeader.fromByteArray(udh); offset += userDataHeaderLength; int headerBits = (userDataHeaderLength + 1) * 8; @@ -571,19 +581,34 @@ public class SmsMessage extends SmsMessageBase{ mUserDataSeptetPadding = (headerSeptets * 7) - headerBits; } - /* - * Here we just create the user data length to be the remainder of - * the pdu minus the user data hearder. This is because the count - * could mean the number of uncompressed sepets if the userdata is - * encoded in 7-bit. - */ - userData = new byte[pdu.length - offset]; + int bufferLen; + if (dataInSeptets) { + /* + * Here we just create the user data length to be the remainder of + * the pdu minus the user data header, since userDataLength means + * the number of uncompressed sepets. + */ + bufferLen = pdu.length - offset; + } else { + /* + * userDataLength is the count of octets, so just subtract the + * user data header. + */ + bufferLen = userDataLength - (hasUserDataHeader ? (userDataHeaderLength + 1) : 0); + if (bufferLen < 0) { + bufferLen = 0; + } + } + + userData = new byte[bufferLen]; System.arraycopy(pdu, offset, userData, 0, userData.length); cur = offset; if (dataInSeptets) { // Return the number of septets - return userDataLength - headerSeptets; + int count = userDataLength - headerSeptets; + // If count < 0, return 0 (means UDL was probably incorrect) + return count < 0 ? 0 : count; } else { // Return the number of octets return userData.length; @@ -613,8 +638,6 @@ public class SmsMessage extends SmsMessageBase{ /** * Returns an object representing the user data headers * - * @return an object representing the user data headers - * * {@hide} */ SmsHeader getUserDataHeader() { @@ -717,6 +740,44 @@ public class SmsMessage extends SmsMessageBase{ } } + /** + * Calculate the number of septets needed to encode the message. + * + * @param msgBody the message to encode + * @param use7bitOnly ignore (but still count) illegal characters if true + * @return TextEncodingDetails + */ + public static TextEncodingDetails calculateLength(CharSequence msgBody, + boolean use7bitOnly) { + TextEncodingDetails ted = new TextEncodingDetails(); + try { + int septets = GsmAlphabet.countGsmSeptets(msgBody, !use7bitOnly); + ted.codeUnitCount = septets; + if (septets > MAX_USER_DATA_SEPTETS) { + ted.msgCount = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1; + ted.codeUnitsRemaining = MAX_USER_DATA_SEPTETS_WITH_HEADER + - (septets % MAX_USER_DATA_SEPTETS_WITH_HEADER); + } else { + ted.msgCount = 1; + ted.codeUnitsRemaining = MAX_USER_DATA_SEPTETS - septets; + } + ted.codeUnitSize = ENCODING_7BIT; + } catch (EncodeException ex) { + int octets = msgBody.length() * 2; + ted.codeUnitCount = msgBody.length(); + if (octets > MAX_USER_DATA_BYTES) { + ted.msgCount = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1; + ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES_WITH_HEADER + - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2; + } else { + ted.msgCount = 1; + ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES - octets)/2; + } + ted.codeUnitSize = ENCODING_16BIT; + } + return ted; + } + /** {@inheritDoc} */ public int getProtocolIdentifier() { return protocolIdentifier; diff --git a/telephony/java/com/android/internal/telephony/gsm/SuppServiceNotification.java b/telephony/java/com/android/internal/telephony/gsm/SuppServiceNotification.java index 11ad52d..e68655e 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SuppServiceNotification.java +++ b/telephony/java/com/android/internal/telephony/gsm/SuppServiceNotification.java @@ -34,7 +34,7 @@ public class SuppServiceNotification { public int type; /** TS 27.007 7.17 "number" (MT only) */ public String number; - + static public final int MO_CODE_UNCONDITIONAL_CF_ACTIVE = 0; static public final int MO_CODE_SOME_CF_ACTIVE = 1; static public final int MO_CODE_CALL_FORWARDED = 2; @@ -44,7 +44,7 @@ public class SuppServiceNotification { static public final int MO_CODE_INCOMING_CALLS_BARRED = 6; static public final int MO_CODE_CLIR_SUPPRESSION_REJECTED = 7; static public final int MO_CODE_CALL_DEFLECTED = 8; - + static public final int MT_CODE_FORWARDED_CALL = 0; static public final int MT_CODE_CUG_CALL = 1; static public final int MT_CODE_CALL_ON_HOLD = 2; diff --git a/telephony/java/com/android/internal/telephony/gsm/package.html b/telephony/java/com/android/internal/telephony/gsm/package.html index 4b1cf99..fed8399 100755 --- a/telephony/java/com/android/internal/telephony/gsm/package.html +++ b/telephony/java/com/android/internal/telephony/gsm/package.html @@ -1,6 +1,6 @@ <HTML> <BODY> -Provides classes to control or read data from GSM phones. +Provides classes to control or read data from GSM phones. @hide </BODY> </HTML> diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/AppInterface.java b/telephony/java/com/android/internal/telephony/gsm/stk/AppInterface.java index c002729..58f1f97 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/AppInterface.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/AppInterface.java @@ -24,15 +24,15 @@ package com.android.internal.telephony.gsm.stk; public interface AppInterface { /* - * Intent's actions which are broadcasted by the Telephony once a new STK + * Intent's actions which are broadcasted by the Telephony once a new STK * proactive command, session end arrive. */ - public static final String STK_CMD_ACTION = + public static final String STK_CMD_ACTION = "android.intent.action.stk.command"; - public static final String STK_SESSION_END_ACTION = + public static final String STK_SESSION_END_ACTION = "android.intent.action.stk.session_end"; - - /* + + /* * Callback function from app to telephony to pass a result code and user's * input back to the SIM. */ @@ -44,20 +44,20 @@ public interface AppInterface { * implementation should support those. */ public static enum CommandType { - DISPLAY_TEXT(0x21), - GET_INKEY(0x22), - GET_INPUT(0x23), - LAUNCH_BROWSER(0x15), - PLAY_TONE(0x20), - REFRESH(0x01), - SELECT_ITEM(0x24), - SEND_SS(0x11), - SEND_USSD(0x12), - SEND_SMS(0x13), - SEND_DTMF(0x14), - SET_UP_EVENT_LIST(0x05), - SET_UP_IDLE_MODE_TEXT(0x28), - SET_UP_MENU(0x25), + DISPLAY_TEXT(0x21), + GET_INKEY(0x22), + GET_INPUT(0x23), + LAUNCH_BROWSER(0x15), + PLAY_TONE(0x20), + REFRESH(0x01), + SELECT_ITEM(0x24), + SEND_SS(0x11), + SEND_USSD(0x12), + SEND_SMS(0x13), + SEND_DTMF(0x14), + SET_UP_EVENT_LIST(0x05), + SET_UP_IDLE_MODE_TEXT(0x28), + SET_UP_MENU(0x25), SET_UP_CALL(0x10); private int mValue; @@ -72,7 +72,7 @@ public interface AppInterface { /** * Create a CommandType object. - * + * * @param value Integer value to be converted to a CommandType object. * @return CommandType object whose "Type of Command" value is {@code * value}. If no CommandType object has that value, null is diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/CommandDetails.java b/telephony/java/com/android/internal/telephony/gsm/stk/CommandDetails.java index 168361a..e81ff98 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/CommandDetails.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/CommandDetails.java @@ -36,17 +36,17 @@ class CommandDetails extends ValueObject implements Parcelable { public ComprehensionTlvTag getTag() { return ComprehensionTlvTag.COMMAND_DETAILS; } - + CommandDetails() { } public boolean compareTo(CommandDetails other) { return (this.compRequired == other.compRequired && this.commandNumber == other.commandNumber && - this.commandQualifier == other.commandQualifier && + this.commandQualifier == other.commandQualifier && this.typeOfCommand == other.typeOfCommand); } - + public CommandDetails(Parcel in) { compRequired = true; commandNumber = in.readInt(); @@ -60,7 +60,7 @@ class CommandDetails extends ValueObject implements Parcelable { dest.writeInt(commandQualifier); } - public static final Parcelable.Creator<CommandDetails> CREATOR = + public static final Parcelable.Creator<CommandDetails> CREATOR = new Parcelable.Creator<CommandDetails>() { public CommandDetails createFromParcel(Parcel in) { return new CommandDetails(in); @@ -85,7 +85,7 @@ class DeviceIdentities extends ValueObject { } } -// Container class to hold icon identifier value. +// Container class to hold icon identifier value. class IconId extends ValueObject { int recordNumber; boolean selfExplanatory; @@ -95,7 +95,7 @@ class IconId extends ValueObject { } } -// Container class to hold item icon identifier list value. +// Container class to hold item icon identifier list value. class ItemsIconId extends ValueObject { int [] recordNumbers; boolean selfExplanatory; diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java b/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java index a27c582..3da652f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java @@ -158,7 +158,7 @@ class GetInputParams extends CommandParams { this.input = input; } - boolean setIcon(Bitmap icon) { + boolean setIcon(Bitmap icon) { if (icon != null && input != null) { input.icon = icon; } 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 06b36a4..bfde616 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java @@ -635,7 +635,7 @@ class CommandParamsFactory extends Handler { /** * Processes SET_UP_EVENT_LIST proactive command from the SIM card. - * + * * @param cmdDet Command Details object retrieved. * @param ctlvs List of ComprehensionTlv objects following Command Details * object and Device Identities object within the proactive command diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java b/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java index 4f746ac..ffde6a3 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java @@ -33,7 +33,7 @@ class ComprehensionTlv { private int mLength; private int mValueIndex; private byte[] mRawValue; - + /** * Constructor. Private on purpose. Use * {@link #decodeMany(byte[], int) decodeMany} or @@ -165,9 +165,9 @@ class ComprehensionTlv { } else { throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); } - + return new ComprehensionTlv(tag, cr, length, data, curIndex); - + } catch (IndexOutOfBoundsException e) { throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); } diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/Input.java b/telephony/java/com/android/internal/telephony/gsm/stk/Input.java index 1f0d971..19f724b 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/Input.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/Input.java @@ -21,13 +21,13 @@ import android.os.Parcel; import android.os.Parcelable; /** - * Container class for STK GET INPUT, GET IN KEY commands parameters. + * Container class for STK GET INPUT, GET IN KEY commands parameters. * */ public class Input implements Parcelable { public String text; public String defaultText; - public Bitmap icon; + public Bitmap icon; public int minLen; public int maxLen; public boolean ucs2; diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/Menu.java b/telephony/java/com/android/internal/telephony/gsm/stk/Menu.java index 40a6b37..331f69d 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/Menu.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/Menu.java @@ -24,7 +24,7 @@ import java.util.ArrayList; import java.util.List; /** - * Container class for STK menu (SET UP MENU, SELECT ITEM) parameters. + * Container class for STK menu (SET UP MENU, SELECT ITEM) parameters. * */ public class Menu implements Parcelable { diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ResponseData.java b/telephony/java/com/android/internal/telephony/gsm/stk/ResponseData.java index 810afd2..afd1bba 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/ResponseData.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ResponseData.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2006-2007 Google Inc. - * + * * 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 @@ -56,7 +56,7 @@ class GetInkeyInputResponseData extends ResponseData { private boolean mIsYesNo; private boolean mYesNoResponse; public String mInData; - + // GetInKey Yes/No response characters constants. protected static final byte GET_INKEY_YES = 0x01; protected static final byte GET_INKEY_NO = 0x00; diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkCmdMessage.java b/telephony/java/com/android/internal/telephony/gsm/stk/StkCmdMessage.java index 62a778e..5425a43 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/StkCmdMessage.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/StkCmdMessage.java @@ -20,9 +20,9 @@ import android.os.Parcel; import android.os.Parcelable; /** - * Class used to pass STK messages from telephony to application. Application + * Class used to pass STK messages from telephony to application. Application * should call getXXX() to get commands's specific values. - * + * */ public class StkCmdMessage implements Parcelable { // members diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkLog.java b/telephony/java/com/android/internal/telephony/gsm/stk/StkLog.java index f6e5685..bd6bc8f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/StkLog.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/StkLog.java @@ -30,7 +30,7 @@ public abstract class StkLog { Log.d("STK", className.substring(className.lastIndexOf('.') + 1) + ": " + msg); } - + public static void d(String caller, String msg) { if (!DEBUG) { return; 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 3de14f0..9268037 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java @@ -25,8 +25,6 @@ import android.os.Message; import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.CommandsInterface; -import com.android.internal.telephony.EncodeException; -import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.gsm.SimCard; import com.android.internal.telephony.gsm.SIMFileHandler; import com.android.internal.telephony.gsm.SIMRecords; @@ -34,8 +32,6 @@ import com.android.internal.telephony.gsm.SIMRecords; import android.util.Config; import java.io.ByteArrayOutputStream; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; /** * Enumeration for representing the tag value of COMPREHENSION-TLV objects. If @@ -119,7 +115,7 @@ public class StkService extends Handler implements AppInterface { // Class members private static SIMRecords mSimRecords; - + // Service members. private static StkService sInstance; private CommandsInterface mCmdIf; @@ -174,6 +170,9 @@ public class StkService extends Handler implements AppInterface { // Register for SIM ready event. mSimRecords.registerForRecordsLoaded(this, MSG_ID_SIM_LOADED, null); + + mCmdIf.reportStkServiceIsRunning(null); + StkLog.d(this, "StkService: is running"); } public void dispose() { @@ -184,9 +183,6 @@ public class StkService extends Handler implements AppInterface { mCmdIf.unSetOnStkCallSetUp(this); this.removeCallbacksAndMessages(null); - - //removing instance - sInstance = null; } protected void finalize() { @@ -450,7 +446,7 @@ public class StkService extends Handler implements AppInterface { } /** - * Used for instantiating the Service from the GsmPhone constructor. + * Used for instantiating/updating the Service from the GsmPhone constructor. * * @param ci CommandsInterface object * @param sr SIMRecords object @@ -560,15 +556,15 @@ public class StkService extends Handler implements AppInterface { } private void handleCmdResponse(StkResponseMessage resMsg) { - // Make sure the response details match the last valid command. An invalid + // Make sure the response details match the last valid command. An invalid // response is a one that doesn't have a corresponding proactive command - // and sending it can "confuse" the baseband/ril. - // One reason for out of order responses can be UI glitches. For example, - // if the application launch an activity, and that activity is stored + // and sending it can "confuse" the baseband/ril. + // One reason for out of order responses can be UI glitches. For example, + // if the application launch an activity, and that activity is stored // by the framework inside the history stack. That activity will be - // available for relaunch using the latest application dialog - // (long press on the home button). Relaunching that activity can send - // the same command's result again to the StkService and can cause it to + // available for relaunch using the latest application dialog + // (long press on the home button). Relaunching that activity can send + // the same command's result again to the StkService and can cause it to // get out of sync with the SIM. if (!validateResponse(resMsg)) { return; @@ -621,7 +617,7 @@ public class StkService extends Handler implements AppInterface { mCmdIf.handleCallSetupRequestFromSim(resMsg.usersConfirm, null); // No need to send terminal response for SET UP CALL. The user's // confirmation result is send back using a dedicated ril message - // invoked by the CommandInterface call above. + // invoked by the CommandInterface call above. mCurrntCmd = null; return; } diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ToneSettings.java b/telephony/java/com/android/internal/telephony/gsm/stk/ToneSettings.java index bbc925e..90cc6c1 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/ToneSettings.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ToneSettings.java @@ -20,7 +20,7 @@ import android.os.Parcel; import android.os.Parcelable; /** - * Container class for PlayTone commands parameters. + * Container class for PlayTone commands parameters. * */ public class ToneSettings implements Parcelable { diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ValueParser.java b/telephony/java/com/android/internal/telephony/gsm/stk/ValueParser.java index 8c8f977..09a860e 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/ValueParser.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ValueParser.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2006-2007 Google Inc. - * + * * 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 @@ -28,7 +28,7 @@ abstract class ValueParser { /** * Search for a Command Details object from a list. - * + * * @param ctlvs List of ComprehensionTlv objects used for search * @return An CtlvCommandDetails object found from the objects. If no * Command Details object is found, ResultException is thrown. @@ -53,7 +53,7 @@ abstract class ValueParser { /** * Search for a Device Identities object from a list. - * + * * @param ctlvs List of ComprehensionTlv objects used for search * @return An CtlvDeviceIdentities object found from the objects. If no * Command Details object is found, ResultException is thrown. @@ -77,7 +77,7 @@ abstract class ValueParser { /** * Retrieves Duration information from the Duration COMPREHENSION-TLV * object. - * + * * @param ctlv A Text Attribute COMPREHENSION-TLV object * @return A Duration object * @throws ResultException @@ -100,7 +100,7 @@ abstract class ValueParser { /** * Retrieves Item information from the COMPREHENSION-TLV object. - * + * * @param ctlv A Text Attribute COMPREHENSION-TLV object * @return An Item * @throws ResultException @@ -130,7 +130,7 @@ abstract class ValueParser { /** * Retrieves Item id information from the COMPREHENSION-TLV object. - * + * * @param ctlv A Text Attribute COMPREHENSION-TLV object * @return An Item id * @throws ResultException @@ -152,7 +152,7 @@ abstract class ValueParser { /** * Retrieves icon id from an Icon Identifier COMPREHENSION-TLV object - * + * * @param ctlv An Icon Identifier COMPREHENSION-TLV object * @return IconId instance * @throws ResultException @@ -175,7 +175,7 @@ abstract class ValueParser { /** * Retrieves item icons id from an Icon Identifier List COMPREHENSION-TLV * object - * + * * @param ctlv An Item Icon List Identifier COMPREHENSION-TLV object * @return ItemsIconId instance * @throws ResultException @@ -206,7 +206,7 @@ abstract class ValueParser { /** * Retrieves text attribute information from the Text Attribute * COMPREHENSION-TLV object. - * + * * @param ctlv A Text Attribute COMPREHENSION-TLV object * @return A list of TextAttribute objects * @throws ResultException @@ -266,7 +266,7 @@ abstract class ValueParser { /** * Retrieves alpha identifier from an Alpha Identifier COMPREHENSION-TLV * object. - * + * * @param ctlv An Alpha Identifier COMPREHENSION-TLV object * @return String corresponding to the alpha identifier * @throws ResultException @@ -290,7 +290,7 @@ abstract class ValueParser { /** * Retrieves text from the Text COMPREHENSION-TLV object, and decodes it * into a Java String. - * + * * @param ctlv A Text COMPREHENSION-TLV object * @return A Java String object decoded from the Text object * @throws ResultException diff --git a/telephony/java/com/android/internal/telephony/test/ModelInterpreter.java b/telephony/java/com/android/internal/telephony/test/ModelInterpreter.java index 25d2026..b116c35 100644 --- a/telephony/java/com/android/internal/telephony/test/ModelInterpreter.java +++ b/telephony/java/com/android/internal/telephony/test/ModelInterpreter.java @@ -75,7 +75,7 @@ class LineReader * Returns NULL on EOF */ - String + String getNextLine(boolean ctrlZ) { int i = 0; @@ -131,7 +131,7 @@ class InterpreterEx extends Exception String result; } -public class ModelInterpreter +public class ModelInterpreter implements Runnable, SimulatedRadioControl { static final int MAX_CALLS = 6; @@ -153,14 +153,14 @@ public class ModelInterpreter SimulatedGsmCallState simulatedCallState; HandlerThread mHandlerThread; - + int pausedResponseCount; Object pausedResponseMonitor = new Object(); //***** Events static final int PROGRESS_CALL_STATE = 1; - + //***** Constructor public @@ -181,7 +181,7 @@ public class ModelInterpreter ss.bind(sa); init(); - } + } private void init() @@ -190,7 +190,7 @@ public class ModelInterpreter mHandlerThread = new HandlerThread("ModelInterpreter"); mHandlerThread.start(); Looper looper = mHandlerThread.getLooper(); - simulatedCallState = new SimulatedGsmCallState(looper); + simulatedCallState = new SimulatedGsmCallState(looper); } //***** Runnable Implementation @@ -204,7 +204,7 @@ public class ModelInterpreter try { s = ss.accept(); } catch (java.io.IOException ex) { - Log.w(LOG_TAG, + Log.w(LOG_TAG, "IOException on socket.accept(); stopping", ex); return; } @@ -213,15 +213,15 @@ public class ModelInterpreter in = s.getInputStream(); out = s.getOutputStream(); } catch (java.io.IOException ex) { - Log.w(LOG_TAG, + Log.w(LOG_TAG, "IOException on accepted socket(); re-listening", ex); continue; } Log.i(LOG_TAG, "New connection accepted"); } - - + + lineReader = new LineReader (in); println ("Welcome"); @@ -271,14 +271,14 @@ public class ModelInterpreter //***** Instance Methods - + /** Start the simulated phone ringing */ public void triggerRing(String number) { synchronized (this) { boolean success; - + success = simulatedCallState.triggerRing(number); if (success) { @@ -307,10 +307,10 @@ public class ModelInterpreter */ public void setAutoProgressConnectingCall(boolean b) - { + { simulatedCallState.setAutoProgressConnectingCall(b); } - + public void setNextDialFailImmediately(boolean b) { @@ -321,7 +321,7 @@ public class ModelInterpreter { //FIXME implement } - + /** hangup ringing, dialing, or actuve calls */ public void @@ -373,7 +373,7 @@ public class ModelInterpreter public void triggerSsn(int a, int b) {} public void triggerIncomingUssd(String statusCode, String message) {} - + public void triggerIncomingSMS(String message) { @@ -386,7 +386,7 @@ public class ModelInterpreter // source address: +18005551212 pdu.append("918100551521F0"); - + // protocol ID and data coding scheme pdu.append("0000"); @@ -421,7 +421,7 @@ public class ModelInterpreter pausedResponseMonitor.notifyAll(); } } - } + } //***** Private Instance Methods @@ -429,11 +429,11 @@ public class ModelInterpreter onAnswer() throws InterpreterEx { boolean success; - + success = simulatedCallState.onAnswer(); if (!success) { - throw new InterpreterEx("ERROR"); + throw new InterpreterEx("ERROR"); } } @@ -445,7 +445,7 @@ public class ModelInterpreter success = simulatedCallState.onAnswer(); if (!success) { - throw new InterpreterEx("ERROR"); + throw new InterpreterEx("ERROR"); } finalResponse = "NO CARRIER"; @@ -471,12 +471,12 @@ public class ModelInterpreter throw new InterpreterEx("ERROR"); } } - + private void releaseHeldOrUDUB() throws InterpreterEx { boolean success; - + success = simulatedCallState.releaseHeldOrUDUB(); if (!success) { @@ -488,19 +488,19 @@ public class ModelInterpreter releaseActiveAcceptHeldOrWaiting() throws InterpreterEx { boolean success; - + success = simulatedCallState.releaseActiveAcceptHeldOrWaiting(); if (!success) { throw new InterpreterEx("ERROR"); } - } + } private void switchActiveAndHeldOrWaiting() throws InterpreterEx { boolean success; - + success = simulatedCallState.switchActiveAndHeldOrWaiting(); if (!success) { @@ -512,7 +512,7 @@ public class ModelInterpreter separateCall(int index) throws InterpreterEx { boolean success; - + success = simulatedCallState.separateCall(index); if (!success) { @@ -524,7 +524,7 @@ public class ModelInterpreter conference() throws InterpreterEx { boolean success; - + success = simulatedCallState.conference(); if (!success) { @@ -536,7 +536,7 @@ public class ModelInterpreter onDial(String command) throws InterpreterEx { boolean success; - + success = simulatedCallState.onDial(command.substring(1)); if (!success) { @@ -566,7 +566,7 @@ public class ModelInterpreter println("+CMGS: 1"); } - + void processLine (String line) throws InterpreterEx { @@ -645,8 +645,8 @@ public class ModelInterpreter } ***/ } - - void + + void println (String s) { synchronized(this) { @@ -663,7 +663,7 @@ public class ModelInterpreter } } - void + void print (String s) { synchronized(this) { @@ -714,8 +714,8 @@ public class ModelInterpreter {"+CIMI", "320720000000000\r"}, {"+CSCS=?", "+CSCS: (\"HEX\",\"UCS2\")\r"}, {"+CFUN?", "+CFUN: 1\r"}, - {"+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?", - "+COPS: 0,0,\"Android\"\r" + {"+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?", + "+COPS: 0,0,\"Android\"\r" + "+COPS: 0,1,\"Android\"\r" + "+COPS: 0,2,\"310995\"\r"}, {"+CREG?", "+CREG: 2,5, \"0113\", \"6614\"\r"}, diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java index 5c69017..22adc19 100644 --- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java +++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java @@ -26,8 +26,9 @@ import android.util.Log; import com.android.internal.telephony.BaseCommands; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.DataCallState; import com.android.internal.telephony.gsm.CallFailCause; -import com.android.internal.telephony.gsm.PDPContextState; +import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; import com.android.internal.telephony.gsm.SuppServiceNotification; import com.android.internal.telephony.Phone; @@ -59,7 +60,7 @@ public final class SimulatedCommands extends BaseCommands private final static String SIM_PUK2_CODE = "87654321"; //***** Instance Variables - + SimulatedGsmCallState simulatedCallState; HandlerThread mHandlerThread; SimLockState mSimLockedState; @@ -79,7 +80,7 @@ public final class SimulatedCommands extends BaseCommands ArrayList<Message> pausedResponses = new ArrayList<Message>(); int nextCallFailCause = CallFailCause.NORMAL_CLEARING; - + //***** Constructor public @@ -88,9 +89,9 @@ public final class SimulatedCommands extends BaseCommands mHandlerThread = new HandlerThread("SimulatedCommands"); mHandlerThread.start(); Looper looper = mHandlerThread.getLooper(); - + simulatedCallState = new SimulatedGsmCallState(looper); - + setRadioState(RadioState.RADIO_OFF); mSimLockedState = INITIAL_LOCK_STATE; mSimLockEnabled = (mSimLockedState != SimLockState.NONE); @@ -353,11 +354,11 @@ public final class SimulatedCommands extends BaseCommands public void setSuppServiceNotifications(boolean enable, Message result) { resultSuccess(result, null); - + if (enable && mSsnNotifyOn) { Log.w(LOG_TAG, "Supp Service Notifications already enabled!"); } - + mSsnNotifyOn = enable; } @@ -465,7 +466,7 @@ public final class SimulatedCommands extends BaseCommands unimplemented(result); } - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -479,13 +480,13 @@ public final class SimulatedCommands extends BaseCommands resultSuccess(result, simulatedCallState.getDriverCalls()); } else { //Log.i("GSM", "[SimCmds] getCurrentCalls: SIM not ready!"); - resultFail(result, + resultFail(result, new CommandException( CommandException.Error.RADIO_NOT_AVAILABLE)); } } - /** + /** * @deprecated */ public void getPDPContextList(Message result) { @@ -497,13 +498,13 @@ public final class SimulatedCommands extends BaseCommands * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj - * ar.result contains a List of PDPContextState + * ar.result contains a List of DataCallState */ public void getDataCallList(Message result) { - resultSuccess(result, new ArrayList<PDPContextState>(0)); + resultSuccess(result, new ArrayList<DataCallState>(0)); } - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -520,7 +521,7 @@ public final class SimulatedCommands extends BaseCommands resultSuccess(result, null); } - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -531,7 +532,7 @@ public final class SimulatedCommands extends BaseCommands resultSuccess(result, "012345678901234"); } - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -542,7 +543,7 @@ public final class SimulatedCommands extends BaseCommands resultSuccess(result, "012345678901234"); } - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -553,7 +554,7 @@ public final class SimulatedCommands extends BaseCommands resultSuccess(result, "99"); } - /** + /** * Hang up one individual connection. * returned message * retMsg.obj = AsyncResult ar @@ -566,7 +567,7 @@ public final class SimulatedCommands extends BaseCommands */ public void hangupConnection (int gsmIndex, Message result) { boolean success; - + success = simulatedCallState.onChld('1', (char)('0'+gsmIndex)); if (!success){ @@ -588,7 +589,7 @@ public final class SimulatedCommands extends BaseCommands */ public void hangupWaitingOrBackground (Message result) { boolean success; - + success = simulatedCallState.onChld('0', '\0'); if (!success){ @@ -600,7 +601,7 @@ public final class SimulatedCommands extends BaseCommands /** * 3GPP 22.030 6.5.5 - * "Releases all active calls (if any exist) and accepts + * "Releases all active calls (if any exist) and accepts * the other (held or waiting) call." * * ar.exception carries exception on failure @@ -609,7 +610,7 @@ public final class SimulatedCommands extends BaseCommands */ public void hangupForegroundResumeBackground (Message result) { boolean success; - + success = simulatedCallState.onChld('1', '\0'); if (!success){ @@ -621,7 +622,7 @@ public final class SimulatedCommands extends BaseCommands /** * 3GPP 22.030 6.5.5 - * "Places all active calls (if any exist) on hold and accepts + * "Places all active calls (if any exist) on hold and accepts * the other (held or waiting) call." * * ar.exception carries exception on failure @@ -630,7 +631,7 @@ public final class SimulatedCommands extends BaseCommands */ public void switchWaitingOrHoldingAndActive (Message result) { boolean success; - + success = simulatedCallState.onChld('2', '\0'); if (!success){ @@ -647,10 +648,10 @@ public final class SimulatedCommands extends BaseCommands * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure - */ + */ public void conference (Message result) { boolean success; - + success = simulatedCallState.onChld('3', '\0'); if (!success){ @@ -682,7 +683,7 @@ public final class SimulatedCommands extends BaseCommands /** * 3GPP 22.030 6.5.5 - * "Places all active calls on hold except call X with which + * "Places all active calls on hold except call X with which * communication shall be supported." */ public void separateConnection (int gsmIndex, Message result) { @@ -703,10 +704,10 @@ public final class SimulatedCommands extends BaseCommands * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure - */ + */ public void acceptCall (Message result) { boolean success; - + success = simulatedCallState.onAnswer(); if (!success){ @@ -716,15 +717,15 @@ public final class SimulatedCommands extends BaseCommands } } - /** + /** * also known as UDUB * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure - */ + */ public void rejectCall (Message result) { boolean success; - + success = simulatedCallState.onChld('0', '\0'); if (!success){ @@ -734,7 +735,7 @@ public final class SimulatedCommands extends BaseCommands } } - /** + /** * cause code returned as Integer in Message.obj.response * Returns integer cause code defined in TS 24.008 * Annex H or closest approximation. @@ -765,11 +766,11 @@ public final class SimulatedCommands extends BaseCommands public void getMute (Message result) {unimplemented(result);} - /** + /** * response.obj is an AsyncResult * response.obj.result is an int[2] - * response.obj.result[0] is received signal strength (0-31, 99) - * response.obj.result[1] is bit error rate (0-7, 99) + * response.obj.result[0] is received signal strength (0-31, 99) + * response.obj.result[1] is bit error rate (0-7, 99) * as defined in TS 27.007 8.5 */ public void getSignalStrength (Message result) { @@ -893,7 +894,7 @@ public final class SimulatedCommands extends BaseCommands * response.obj.result[0] is long alpha or null if unregistered * response.obj.result[1] is short alpha or null if unregistered * response.obj.result[2] is numeric or null if unregistered - */ + */ public void getOperator(Message result) { String[] ret = new String[3]; @@ -908,7 +909,7 @@ public final class SimulatedCommands extends BaseCommands * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure - */ + */ public void sendDtmf(char c, Message result) { resultSuccess(result, null); } @@ -932,10 +933,19 @@ public final class SimulatedCommands extends BaseCommands } /** + * ar.exception carries exception on failure + * ar.userObject contains the orignal value of result.obj + * ar.result is null on success and failure + */ + public void sendBurstDtmf(String dtmfString, Message result) { + resultSuccess(result, null); + } + + /** * smscPDU is smsc address in PDU form GSM BCD format prefixed * by a length byte (as expected by TS 27.005) or NULL for default SMSC * pdu is SMS in PDU format as an ASCII hex string - * less the SMSC address + * less the SMSC address */ public void sendSMS (String smscPDU, String pdu, Message result) {unimplemented(result);} @@ -1009,6 +1019,14 @@ public final class SimulatedCommands extends BaseCommands unimplemented(result); } + public void reportSmsMemoryStatus(boolean available, Message result) { + unimplemented(result); + } + + public void reportStkServiceIsRunning(Message result) { + resultSuccess(result, null); + } + private boolean isSimLocked() { if (mSimLockedState != SimLockState.NONE) { return true; @@ -1032,16 +1050,16 @@ public final class SimulatedCommands extends BaseCommands } - public void acknowledgeLastIncomingSMS(boolean success, Message result) { + public void acknowledgeLastIncomingGsmSms(boolean success, int cause, Message result) { unimplemented(result); } - public void acknowledgeLastIncomingCdmaSms(boolean success, Message result) { + public void acknowledgeLastIncomingCdmaSms(boolean success, int cause, Message result) { unimplemented(result); } - /** - * parameters equivilient to 27.007 AT+CRSM command + /** + * parameters equivilient to 27.007 AT+CRSM command * response.obj will be an AsyncResult * response.obj.userObj will be a SimIoResult on success */ @@ -1052,7 +1070,7 @@ public final class SimulatedCommands extends BaseCommands /** * (AsyncResult)response.obj).result is an int[] with element [0] set to - * 1 for "CLIP is provisioned", and 0 for "CLIP is not provisioned". + * 1 for "CLIP is provisioned", and 0 for "CLIP is not provisioned". * * @param response is callback message */ @@ -1063,46 +1081,46 @@ public final class SimulatedCommands extends BaseCommands * response.obj will be a an int[2] * * response.obj[0] will be TS 27.007 +CLIR parameter 'n' - * 0 presentation indicator is used according to the subscription of the CLIR service - * 1 CLIR invocation - * 2 CLIR suppression + * 0 presentation indicator is used according to the subscription of the CLIR service + * 1 CLIR invocation + * 2 CLIR suppression * * response.obj[1] will be TS 27.007 +CLIR parameter 'm' - * 0 CLIR not provisioned - * 1 CLIR provisioned in permanent mode - * 2 unknown (e.g. no network, etc.) - * 3 CLIR temporary mode presentation restricted - * 4 CLIR temporary mode presentation allowed + * 0 CLIR not provisioned + * 1 CLIR provisioned in permanent mode + * 2 unknown (e.g. no network, etc.) + * 3 CLIR temporary mode presentation restricted + * 4 CLIR temporary mode presentation allowed */ public void getCLIR(Message result) {unimplemented(result);} - + /** * clirMode is one of the CLIR_* constants above * * response.obj is null */ - + public void setCLIR(int clirMode, Message result) {unimplemented(result);} /** * (AsyncResult)response.obj).result is an int[] with element [0] set to - * 0 for disabled, 1 for enabled. + * 0 for disabled, 1 for enabled. * * @param serviceClass is a sum of SERVICE_CLASS_* * @param response is callback message */ - + public void queryCallWaiting(int serviceClass, Message response) { unimplemented(response); } - + /** * @param enable is true to enable, false to disable * @param serviceClass is a sum of SERVICE_CLASS_* * @param response is callback message */ - + public void setCallWaiting(boolean enable, int serviceClass, Message response) { unimplemented(response); @@ -1111,9 +1129,9 @@ public final class SimulatedCommands extends BaseCommands /** * @param action is one of CF_ACTION_* * @param cfReason is one of CF_REASON_* - * @param serviceClass is a sum of SERVICE_CLASSS_* + * @param serviceClass is a sum of SERVICE_CLASSS_* */ - public void setCallForward(int action, int cfReason, int serviceClass, + public void setCallForward(int action, int cfReason, int serviceClass, String number, int timeSeconds, Message result) {unimplemented(result);} /** @@ -1121,14 +1139,14 @@ public final class SimulatedCommands extends BaseCommands * * ((AsyncResult)response.obj).result will be an array of * CallForwardInfo's - * + * * An array of length 0 means "disabled for all codes" */ public void queryCallForwardStatus(int cfReason, int serviceClass, String number, Message result) {unimplemented(result);} public void setNetworkSelectionModeAutomatic(Message result) {unimplemented(result);} - + public void exitEmergencyCallbackMode(Message result) {unimplemented(result);} public void setNetworkSelectionModeManual( String operatorNumeric, Message result) {unimplemented(result);} @@ -1155,7 +1173,7 @@ public final class SimulatedCommands extends BaseCommands public void getAvailableNetworks(Message result) {unimplemented(result);} public void getBasebandVersion (Message result) { - resultSuccess(result, "SimulatedCommands"); + resultSuccess(result, "SimulatedCommands"); } /** @@ -1167,7 +1185,7 @@ public final class SimulatedCommands extends BaseCommands public void triggerIncomingUssd(String statusCode, String message) { if (mUSSDRegistrant != null) { String[] result = {statusCode, message}; - mUSSDRegistrant.notifyResult(result); + mUSSDRegistrant.notifyResult(result); } } @@ -1215,7 +1233,7 @@ public final class SimulatedCommands extends BaseCommands //***** SimulatedRadioControl - + /** Start the simulated phone ringing */ public void triggerRing(String number) { @@ -1249,9 +1267,9 @@ public final class SimulatedCommands extends BaseCommands simulatedCallState.setNextDialFailImmediately(b); } - public void + public void setNextCallFailCause(int gsmCause) { - nextCallFailCause = gsmCause; + nextCallFailCause = gsmCause; } public void @@ -1319,7 +1337,7 @@ public final class SimulatedCommands extends BaseCommands private void unimplemented(Message result) { if (result != null) { - AsyncResult.forMessage(result).exception + AsyncResult.forMessage(result).exception = new RuntimeException("Unimplemented"); if (pausedResponseCount > 0) { @@ -1359,13 +1377,13 @@ public final class SimulatedCommands extends BaseCommands unimplemented(response); } - public void + public void getCDMASubscription(Message response) { Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); unimplemented(response); } - public void + public void setCdmaSubscription(int cdmaSubscriptionType, Message response) { Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); unimplemented(response); @@ -1403,7 +1421,7 @@ public final class SimulatedCommands extends BaseCommands * @param serviceClass is a sum of SERVICE_CLASS_* * @param response is callback message */ - public void setTTYModeEnabled(boolean enable, Message response) { + public void setTTYMode(int ttyMode, Message response) { Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); unimplemented(response); } @@ -1411,12 +1429,12 @@ public final class SimulatedCommands extends BaseCommands /** * Query the TTY mode for the CDMA phone * (AsyncResult)response.obj).result is an int[] with element [0] set to - * 0 for disabled, 1 for enabled. - * + * 0 for disabled, 1 for enabled. + * * @param serviceClass is a sum of SERVICE_CLASS_* * @param response is callback message */ - public void queryTTYModeEnabled(Message response) { + public void queryTTYMode(Message response) { Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); unimplemented(response); } @@ -1436,19 +1454,36 @@ public final class SimulatedCommands extends BaseCommands Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); } - public void activateCdmaBroadcastSms(int activate, Message result) { - // TODO Auto-generated method stub + public void setCdmaBroadcastActivation(boolean activate, Message response) { + unimplemented(response); } - public void getCdmaBroadcastConfig(Message result) { - // TODO Auto-generated method stub + public void getCdmaBroadcastConfig(Message response) { + unimplemented(response); } - public void setCdmaBroadcastConfig(int[] configValuesArray, Message result) { - // TODO Auto-generated method stub + public void setCdmaBroadcastConfig(int[] configValuesArray, Message response) { + unimplemented(response); } + public void forceDataDormancy(Message response) { + unimplemented(response); + } + + + public void setGsmBroadcastActivation(boolean activate, Message response) { + unimplemented(response); + } + + + public void setGsmBroadcastConfig(SmsBroadcastConfigInfo[] config, Message response) { + unimplemented(response); + } + + public void getGsmBroadcastConfig(Message response) { + unimplemented(response); + } } diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedGsmCallState.java b/telephony/java/com/android/internal/telephony/test/SimulatedGsmCallState.java index 803735c..c6c301d 100644 --- a/telephony/java/com/android/internal/telephony/test/SimulatedGsmCallState.java +++ b/telephony/java/com/android/internal/telephony/test/SimulatedGsmCallState.java @@ -37,7 +37,7 @@ class CallInfo { WAITING(5); // MT call only State (int value) {this.value = value;} - + private final int value; public int value() {return value;}; }; @@ -73,7 +73,7 @@ class CallInfo { String toCLCCLine(int index) { - return + return "+CLCC: " + index + "," + (isMT ? "1" : "0") +"," + state.value() + ",0," + (isMpty ? "1" : "0") @@ -82,7 +82,7 @@ class CallInfo { DriverCall toDriverCall(int index) { - DriverCall ret; + DriverCall ret; ret = new DriverCall(); @@ -136,7 +136,7 @@ class SimulatedGsmCallState extends Handler { private boolean autoProgressConnecting = true; private boolean nextDialFailImmediately; - + //***** Event Constants @@ -169,8 +169,8 @@ class SimulatedGsmCallState extends Handler { //***** Public Methods - /** - * Start the simulated phone ringing + /** + * Start the simulated phone ringing * true if succeeded, false if failed */ public boolean @@ -185,7 +185,7 @@ class SimulatedGsmCallState extends Handler { if (call == null && empty < 0) { empty = i; - } else if (call != null + } else if (call != null && (call.state == CallInfo.State.INCOMING || call.state == CallInfo.State.WAITING) ) { @@ -208,7 +208,7 @@ class SimulatedGsmCallState extends Handler { if (isCallWaiting) { calls[empty].state = CallInfo.State.WAITING; } - + } return true; } @@ -225,11 +225,11 @@ class SimulatedGsmCallState extends Handler { if (autoProgressConnecting) { sendMessageDelayed( - obtainMessage(EVENT_PROGRESS_CALL_STATE, call), + obtainMessage(EVENT_PROGRESS_CALL_STATE, call), CONNECTING_PAUSE_MSEC); } break; - } else if (call != null + } else if (call != null && call.state == CallInfo.State.ALERTING ) { call.state = CallInfo.State.ACTIVE; @@ -246,7 +246,7 @@ class SimulatedGsmCallState extends Handler { for (int i = 0 ; i < calls.length ; i++) { CallInfo call = calls[i]; - if (call != null && (call.state == CallInfo.State.DIALING + if (call != null && (call.state == CallInfo.State.DIALING || call.state == CallInfo.State.ALERTING) ) { call.state = CallInfo.State.ACTIVE; @@ -263,13 +263,13 @@ class SimulatedGsmCallState extends Handler { setAutoProgressConnectingCall(boolean b) { autoProgressConnecting = b; } - + public void setNextDialFailImmediately(boolean b) { nextDialFailImmediately = b; } - /** + /** * hangup ringing, dialing, or active calls * returns true if call was hung up, false if not */ @@ -283,7 +283,7 @@ class SimulatedGsmCallState extends Handler { for (int i = 0 ; i < calls.length ; i++) { CallInfo call = calls[i]; - if (call != null + if (call != null && (call.state == CallInfo.State.INCOMING || call.state == CallInfo.State.WAITING) ) { @@ -295,7 +295,7 @@ class SimulatedGsmCallState extends Handler { for (int i = 0 ; i < calls.length ; i++) { CallInfo call = calls[i]; - if (call != null + if (call != null && (call.state == CallInfo.State.DIALING || call.state == CallInfo.State.ACTIVE || call.state == CallInfo.State.ALERTING) @@ -308,7 +308,7 @@ class SimulatedGsmCallState extends Handler { } } - /** + /** * hangup holding calls * returns true if call was hung up, false if not */ @@ -330,7 +330,7 @@ class SimulatedGsmCallState extends Handler { } } - /** + /** * hangup all * returns true if call was hung up, false if not */ @@ -359,7 +359,7 @@ class SimulatedGsmCallState extends Handler { for (int i = 0 ; i < calls.length ; i++) { CallInfo call = calls[i]; - if (call != null + if (call != null && (call.state == CallInfo.State.INCOMING || call.state == CallInfo.State.WAITING) ) { @@ -399,7 +399,7 @@ class SimulatedGsmCallState extends Handler { return false; } } - + switch (c0) { case '0': ret = releaseHeldOrUDUB(); @@ -442,7 +442,7 @@ class SimulatedGsmCallState extends Handler { return ret; } - + public boolean releaseHeldOrUDUB() { boolean found = false; @@ -493,8 +493,8 @@ class SimulatedGsmCallState extends Handler { for (int i = 0 ; i < calls.length ; i++) { CallInfo c = calls[i]; - if (c != null - && (c.state == CallInfo.State.DIALING + if (c != null + && (c.state == CallInfo.State.DIALING || c.state == CallInfo.State.ALERTING) ) { calls[i] = null; @@ -531,7 +531,7 @@ class SimulatedGsmCallState extends Handler { public boolean switchActiveAndHeldOrWaiting() { boolean hasHeld = false; - + // first, are there held calls? for (int i = 0 ; i < calls.length ; i++) { CallInfo c = calls[i]; @@ -595,7 +595,7 @@ class SimulatedGsmCallState extends Handler { } return true; - } catch (InvalidStateEx ex) { + } catch (InvalidStateEx ex) { return false; } } @@ -612,7 +612,7 @@ class SimulatedGsmCallState extends Handler { if (c != null) { countCalls++; - + if (c.isConnecting()) { return false; } @@ -624,7 +624,7 @@ class SimulatedGsmCallState extends Handler { if (c != null) { c.state = CallInfo.State.ACTIVE; if (countCalls > 0) { - c.isMpty = true; + c.isMpty = true; } } } @@ -659,12 +659,12 @@ class SimulatedGsmCallState extends Handler { int freeSlot = -1; Log.d("GSM", "SC> dial '" + address + "'"); - + if (nextDialFailImmediately) { nextDialFailImmediately = false; Log.d("GSM", "SC< dial fail (per request)"); - return false; + return false; } String phNum = PhoneNumberUtils.extractNetworkPortion(address); @@ -696,15 +696,15 @@ class SimulatedGsmCallState extends Handler { if (freeSlot < 0 && calls[i] == null) { freeSlot = i; } - + if (calls[i] != null && !calls[i].isActiveOrHeld()) { - // Can't make outgoing calls when there is a ringing or + // Can't make outgoing calls when there is a ringing or // connecting outgoing call Log.d("GSM", "SC< dial fail (invalid call state)"); return false; } else if (calls[i] != null && calls[i].state == CallInfo.State.ACTIVE) { // All active calls behome held - calls[i].state = CallInfo.State.HOLDING; + calls[i].state = CallInfo.State.HOLDING; } } @@ -717,7 +717,7 @@ class SimulatedGsmCallState extends Handler { if (autoProgressConnecting) { sendMessageDelayed( - obtainMessage(EVENT_PROGRESS_CALL_STATE, calls[freeSlot]), + obtainMessage(EVENT_PROGRESS_CALL_STATE, calls[freeSlot]), CONNECTING_PAUSE_MSEC); } @@ -776,7 +776,7 @@ class SimulatedGsmCallState extends Handler { if (call != null) { if (!hasMpty && call.isMpty) { mptyIsHeld = call.state == CallInfo.State.HOLDING; - } else if (call.isMpty && mptyIsHeld + } else if (call.isMpty && mptyIsHeld && call.state == CallInfo.State.ACTIVE ) { Log.e("ModelInterpreter", "Invalid state"); diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedRadioControl.java b/telephony/java/com/android/internal/telephony/test/SimulatedRadioControl.java index 9e1a7c5..054d370 100644 --- a/telephony/java/com/android/internal/telephony/test/SimulatedRadioControl.java +++ b/telephony/java/com/android/internal/telephony/test/SimulatedRadioControl.java @@ -45,7 +45,7 @@ public interface SimulatedRadioControl /** see pauseResponses */ public void resumeResponses(); - + public void triggerSsn(int type, int code); /** Generates an incoming USSD message. */ |