diff options
author | Wink Saville <> | 2009-04-02 01:37:02 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-04-02 01:37:02 -0700 |
commit | 767a662ecde33c3979bf02b793d392aca0403162 (patch) | |
tree | f55548c33a8267c39acc60f72051f9856e95e672 /telephony/java/com | |
parent | e9c08056fafab720856ab8516ea0e623a5c0e360 (diff) | |
download | frameworks_base-767a662ecde33c3979bf02b793d392aca0403162.zip frameworks_base-767a662ecde33c3979bf02b793d392aca0403162.tar.gz frameworks_base-767a662ecde33c3979bf02b793d392aca0403162.tar.bz2 |
AI 144185: Integrate cdma into the main code base.
Automated import of CL 144185
Diffstat (limited to 'telephony/java/com')
125 files changed, 20405 insertions, 6287 deletions
diff --git a/telephony/java/com/android/internal/telephony/ATResponseParser.java b/telephony/java/com/android/internal/telephony/ATResponseParser.java index 93ec455..fdb0526 100644 --- a/telephony/java/com/android/internal/telephony/ATResponseParser.java +++ b/telephony/java/com/android/internal/telephony/ATResponseParser.java @@ -34,7 +34,7 @@ public class ATResponseParser { this.line = line; } - + public boolean nextBoolean() { @@ -147,7 +147,7 @@ public class ATResponseParser } } - + /** Throws ATParseEx if whitespace extends to the end of string */ private char skipWhiteSpace (char c) diff --git a/telephony/java/com/android/internal/telephony/gsm/AdnRecord.aidl b/telephony/java/com/android/internal/telephony/AdnRecord.aidl index 68d9a7c..b4a1a29 100644 --- a/telephony/java/com/android/internal/telephony/gsm/AdnRecord.aidl +++ b/telephony/java/com/android/internal/telephony/AdnRecord.aidl @@ -14,6 +14,7 @@ ** limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; parcelable AdnRecord; + diff --git a/telephony/java/com/android/internal/telephony/AdnRecord.java b/telephony/java/com/android/internal/telephony/AdnRecord.java new file mode 100644 index 0000000..5f40579 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/AdnRecord.java @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.PhoneNumberUtils; +import android.util.Log; + +import com.android.internal.telephony.GsmAlphabet; + + +/** + * + * Used to load or store ADNs (Abbreviated Dialing Numbers). + * + * {@hide} + * + */ +public class AdnRecord implements Parcelable { + static final String LOG_TAG = "GSM"; + + //***** Instance Variables + + String alphaTag = ""; + String number = ""; + int extRecord = 0xff; + int efid; // or 0 if none + int recordNumber; // or 0 if none + + + //***** Constants + + // In an ADN record, everything but the alpha identifier + // is in a footer that's 14 bytes + static final int FOOTER_SIZE_BYTES = 14; + + // Maximum size of the un-extended number field + static final int MAX_NUMBER_SIZE_BYTES = 11; + + static final int EXT_RECORD_LENGTH_BYTES = 13; + static final int EXT_RECORD_TYPE_ADDITIONAL_DATA = 2; + static final int EXT_RECORD_TYPE_MASK = 3; + static final int MAX_EXT_CALLED_PARTY_LENGTH = 0xa; + + // ADN offset + static final int ADN_BCD_NUMBER_LENGTH = 0; + static final int ADN_TON_AND_NPI = 1; + static final int ADN_DAILING_NUMBER_START = 2; + static final int ADN_DAILING_NUMBER_END = 11; + static final int ADN_CAPABILITY_ID = 12; + static final int ADN_EXTENSION_ID = 13; + + //***** Static Methods + + public static final Parcelable.Creator<AdnRecord> CREATOR + = new Parcelable.Creator<AdnRecord>() { + public AdnRecord createFromParcel(Parcel source) { + int efid; + int recordNumber; + String alphaTag; + String number; + + efid = source.readInt(); + recordNumber = source.readInt(); + alphaTag = source.readString(); + number = source.readString(); + + return new AdnRecord(efid, recordNumber, alphaTag, number); + } + + public AdnRecord[] newArray(int size) { + return new AdnRecord[size]; + } + }; + + + //***** Constructor + public + AdnRecord (byte[] record) { + this(0, 0, record); + } + + public + AdnRecord (int efid, int recordNumber, byte[] record) { + this.efid = efid; + this.recordNumber = recordNumber; + parseRecord(record); + } + + public + AdnRecord (String alphaTag, String number) { + this(0, 0, alphaTag, number); + } + + public + AdnRecord (int efid, int recordNumber, String alphaTag, String number) { + this.efid = efid; + this.recordNumber = recordNumber; + this.alphaTag = alphaTag; + this.number = number; + } + + //***** Instance Methods + + public String getAlphaTag() { + return alphaTag; + } + + public String getNumber() { + return number; + } + + public String toString() { + return "ADN Record '" + alphaTag + "' '" + number + "'"; + } + + public boolean isEmpty() { + return alphaTag.equals("") && number.equals(""); + } + + public boolean hasExtendedRecord() { + return extRecord != 0 && extRecord != 0xff; + } + + public boolean isEqual(AdnRecord adn) { + return ( alphaTag.equals(adn.getAlphaTag()) && + number.equals(adn.getNumber()) ); + } + //***** Parcelable Implementation + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(efid); + dest.writeInt(recordNumber); + dest.writeString(alphaTag); + dest.writeString(number); + } + + /** + * Build adn hex byte array based on record size + * The format of byte array is defined in 51.011 10.5.1 + * + * @param recordSize is the size X of EF record + * @return hex byte[recordSize] to be written to EF record + * return nulll for wrong format of dialing nubmer or tag + */ + public byte[] buildAdnString(int recordSize) { + byte[] bcdNumber; + byte[] byteTag; + byte[] adnString = null; + int footerOffset = recordSize - FOOTER_SIZE_BYTES; + + if (number == null || number.equals("") || + alphaTag == null || alphaTag.equals("")) { + + Log.w(LOG_TAG, "[buildAdnString] Empty alpha tag or number"); + adnString = new byte[recordSize]; + for (int i = 0; i < recordSize; i++) { + adnString[i] = (byte) 0xFF; + } + } else if (number.length() + > (ADN_DAILING_NUMBER_END - ADN_DAILING_NUMBER_START + 1) * 2) { + Log.w(LOG_TAG, + "[buildAdnString] Max length of dailing number is 20"); + } else if (alphaTag.length() > footerOffset) { + Log.w(LOG_TAG, + "[buildAdnString] Max length of tag is " + footerOffset); + } else { + + adnString = new byte[recordSize]; + for (int i = 0; i < recordSize; i++) { + adnString[i] = (byte) 0xFF; + } + + bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(number); + + System.arraycopy(bcdNumber, 0, adnString, + footerOffset + ADN_TON_AND_NPI, bcdNumber.length); + + adnString[footerOffset + ADN_BCD_NUMBER_LENGTH] + = (byte) (bcdNumber.length); + adnString[footerOffset + ADN_CAPABILITY_ID] + = (byte) 0xFF; // Capacility Id + adnString[footerOffset + ADN_EXTENSION_ID] + = (byte) 0xFF; // Extension Record Id + + byteTag = GsmAlphabet.stringToGsm8BitPacked(alphaTag); + System.arraycopy(byteTag, 0, adnString, 0, byteTag.length); + + } + + return adnString; + } + + /** + * See TS 51.011 10.5.10 + */ + public void + appendExtRecord (byte[] extRecord) { + try { + if (extRecord.length != EXT_RECORD_LENGTH_BYTES) { + return; + } + + if ((extRecord[0] & EXT_RECORD_TYPE_MASK) + != EXT_RECORD_TYPE_ADDITIONAL_DATA) { + return; + } + + if ((0xff & extRecord[1]) > MAX_EXT_CALLED_PARTY_LENGTH) { + // invalid or empty record + return; + } + + number += PhoneNumberUtils.calledPartyBCDFragmentToString( + extRecord, 2, 0xff & extRecord[1]); + + // We don't support ext record chaining. + + } catch (RuntimeException ex) { + Log.w(LOG_TAG, "Error parsing AdnRecord ext record", ex); + } + } + + //***** Private Methods + + /** + * alphaTag and number are set to null on invalid format + */ + private void + parseRecord(byte[] record) { + try { + alphaTag = IccUtils.adnStringFieldToString( + record, 0, record.length - FOOTER_SIZE_BYTES); + + int footerOffset = record.length - FOOTER_SIZE_BYTES; + + int numberLength = 0xff & record[footerOffset]; + + if (numberLength > MAX_NUMBER_SIZE_BYTES) { + // Invalid number length + number = ""; + return; + } + + // Please note 51.011 10.5.1: + // + // "If the Dialling Number/SSC String does not contain + // a dialling number, e.g. a control string deactivating + // a service, the TON/NPI byte shall be set to 'FF' by + // the ME (see note 2)." + + number = PhoneNumberUtils.calledPartyBCDToString( + record, footerOffset + 1, numberLength); + + + extRecord = 0xff & record[record.length - 1]; + + } catch (RuntimeException ex) { + Log.w(LOG_TAG, "Error parsing AdnRecord", ex); + number = ""; + alphaTag = ""; + } + } +} diff --git a/telephony/java/com/android/internal/telephony/gsm/AdnRecordCache.java b/telephony/java/com/android/internal/telephony/AdnRecordCache.java index 9da18e3..c270ae5 100644 --- a/telephony/java/com/android/internal/telephony/gsm/AdnRecordCache.java +++ b/telephony/java/com/android/internal/telephony/AdnRecordCache.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.util.SparseArray; import android.util.Log; @@ -23,18 +23,18 @@ import android.os.Handler; import android.os.AsyncResult; import java.util.ArrayList; import java.util.Iterator; +import com.android.internal.telephony.IccConstants; /** * {@hide} */ -public final class AdnRecordCache extends Handler implements SimConstants -{ +public final class AdnRecordCache extends Handler implements IccConstants { //***** Instance Variables - GSMPhone phone; + PhoneBase phone; // Indexed by EF ID - SparseArray<ArrayList<AdnRecord>> adnLikeFiles + SparseArray<ArrayList<AdnRecord>> adnLikeFiles = new SparseArray<ArrayList<AdnRecord>>(); // People waiting for ADN-like files to be loaded @@ -52,9 +52,8 @@ public final class AdnRecordCache extends Handler implements SimConstants //***** Constructor - /*package*/ - AdnRecordCache(GSMPhone phone) - { + + public AdnRecordCache(PhoneBase phone) { this.phone = phone; } @@ -63,14 +62,12 @@ public final class AdnRecordCache extends Handler implements SimConstants /** * Called from SIMRecords.onRadioNotAvailable and SIMRecords.handleSimRefresh. */ - /*package*/ void - reset() - { + public void reset() { adnLikeFiles.clear(); clearWaiters(); clearUserWriters(); - + } private void clearWaiters() { @@ -95,29 +92,27 @@ public final class AdnRecordCache extends Handler implements SimConstants * @return List of AdnRecords for efid if we've already loaded them this * radio session, or null if we haven't */ - /*package*/ ArrayList<AdnRecord> - getRecordsIfLoaded(int efid) - { + public ArrayList<AdnRecord> + getRecordsIfLoaded(int efid) { return adnLikeFiles.get(efid); } /** - * Returns extension ef associated with ADN-like EF or -1 if + * Returns extension ef associated with ADN-like EF or -1 if * we don't know. * * See 3GPP TS 51.011 for this mapping */ private int - extensionEfForEf(int efid) - { + extensionEfForEf(int efid) { switch (efid) { case EF_MBDN: return EF_EXT6; case EF_ADN: return EF_EXT1; case EF_SDN: return EF_EXT3; case EF_FDN: return EF_EXT2; - case EF_MSISDN: return EF_EXT1; + case EF_MSISDN: return EF_EXT1; default: return -1; - } + } } private void sendErrorResponse(Message response, String errString) { @@ -138,7 +133,7 @@ public final class AdnRecordCache extends Handler implements SimConstants * @param response message to be posted when done * response.exception hold the exception in error */ - void updateAdnByIndex(int efid, AdnRecord adn, int recordIndex, String pin2, + public void updateAdnByIndex(int efid, AdnRecord adn, int recordIndex, String pin2, Message response) { int extensionEF = extensionEfForEf(efid); @@ -174,7 +169,7 @@ public final class AdnRecordCache extends Handler implements SimConstants * @param response message to be posted when done * response.exception hold the exception in error */ - void updateAdnBySearch(int efid, AdnRecord oldAdn, AdnRecord newAdn, + public void updateAdnBySearch(int efid, AdnRecord oldAdn, AdnRecord newAdn, String pin2, Message response) { int extensionEF; @@ -227,9 +222,8 @@ public final class AdnRecordCache extends Handler implements SimConstants * Responds with exception (in response) if efid is not a known ADN-like * record */ - /*package*/ void - requestLoadAllAdnLike (int efid, Message response) - { + public void + requestLoadAllAdnLike (int efid, Message response) { ArrayList<Message> waiters; ArrayList<AdnRecord> result; @@ -256,25 +250,25 @@ public final class AdnRecordCache extends Handler implements SimConstants waiters.add(response); return; } - + // Start loading efid - + waiters = new ArrayList<Message>(); waiters.add(response); adnLikeWaiters.put(efid, waiters); int extensionEF = extensionEfForEf(efid); - + if (extensionEF < 0) { // respond with error if not known ADN-like record if (response != null) { - AsyncResult.forMessage(response).exception + AsyncResult.forMessage(response).exception = new RuntimeException("EF is not known ADN-like EF:" + efid); response.sendToTarget(); } - + return; } @@ -285,8 +279,7 @@ public final class AdnRecordCache extends Handler implements SimConstants //***** Private methods private void - notifyWaiters(ArrayList<Message> waiters, AsyncResult ar) - { + notifyWaiters(ArrayList<Message> waiters, AsyncResult ar) { if (waiters == null) { return; diff --git a/telephony/java/com/android/internal/telephony/AdnRecordLoader.java b/telephony/java/com/android/internal/telephony/AdnRecordLoader.java new file mode 100644 index 0000000..cfb5aaa --- /dev/null +++ b/telephony/java/com/android/internal/telephony/AdnRecordLoader.java @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import java.util.ArrayList; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + + +public class AdnRecordLoader extends Handler { + static String LOG_TAG; + + //***** Instance Variables + + PhoneBase phone; + int ef; + int extensionEF; + int pendingExtLoads; + Message userResponse; + String pin2; + + // For "load one" + int recordNumber; + + // for "load all" + ArrayList<AdnRecord> adns; // only valid after EVENT_ADN_LOAD_ALL_DONE + + // Either an AdnRecord or a reference to adns depending + // if this is a load one or load all operation + Object result; + + //***** Event Constants + + static final int EVENT_ADN_LOAD_DONE = 1; + static final int EVENT_EXT_RECORD_LOAD_DONE = 2; + static final int EVENT_ADN_LOAD_ALL_DONE = 3; + static final int EVENT_EF_LINEAR_RECORD_SIZE_DONE = 4; + static final int EVENT_UPDATE_RECORD_DONE = 5; + + //***** Constructor + + public AdnRecordLoader(PhoneBase phone) { + // The telephony unit-test cases may create AdnRecords + // in secondary threads + super(phone.getHandler().getLooper()); + + this.phone = phone; + LOG_TAG = phone.getPhoneName(); + } + + /** + * Resulting AdnRecord is placed in response.obj.result + * or response.obj.exception is set + */ + public void + loadFromEF(int ef, int extensionEF, int recordNumber, + Message response) { + this.ef = ef; + this.extensionEF = extensionEF; + this.recordNumber = recordNumber; + this.userResponse = response; + + phone.mIccFileHandler.loadEFLinearFixed( + ef, recordNumber, + obtainMessage(EVENT_ADN_LOAD_DONE)); + + } + + + /** + * Resulting ArrayList<adnRecord> is placed in response.obj.result + * or response.obj.exception is set + */ + public void + loadAllFromEF(int ef, int extensionEF, + Message response) { + this.ef = ef; + this.extensionEF = extensionEF; + this.userResponse = response; + + phone.mIccFileHandler.loadEFLinearFixedAll( + ef, + obtainMessage(EVENT_ADN_LOAD_ALL_DONE)); + + } + + /** + * Write adn to a EF SIM record + * It will get the record size of EF record and compose hex adn array + * then write the hex array to EF record + * + * @param adn is set with alphaTag and phoneNubmer + * @param ef EF fileid + * @param extensionEF extension EF fileid + * @param recordNumber 1-based record index + * @param pin2 for CHV2 operations, must be null if pin2 is not needed + * @param response will be sent to its handler when completed + */ + public void + updateEF(AdnRecord adn, int ef, int extensionEF, int recordNumber, + String pin2, Message response) { + this.ef = ef; + this.extensionEF = extensionEF; + this.recordNumber = recordNumber; + this.userResponse = response; + this.pin2 = pin2; + + phone.mIccFileHandler.getEFLinearRecordSize( ef, + obtainMessage(EVENT_EF_LINEAR_RECORD_SIZE_DONE, adn)); + } + + //***** Overridden from Handler + + public void + handleMessage(Message msg) { + AsyncResult ar; + byte data[]; + AdnRecord adn; + + try { + switch (msg.what) { + case EVENT_EF_LINEAR_RECORD_SIZE_DONE: + ar = (AsyncResult)(msg.obj); + adn = (AdnRecord)(ar.userObj); + + if (ar.exception != null) { + throw new RuntimeException("get EF record size failed", + ar.exception); + } + + int[] recordSize = (int[])ar.result; + // recordSize is int[3] array + // int[0] is the record length + // int[1] is the total length of the EF file + // int[2] is the number of records in the EF file + // So int[0] * int[2] = int[1] + if (recordSize.length != 3 || recordNumber > recordSize[2]) { + throw new RuntimeException("get wrong EF record size format", + ar.exception); + } + + data = adn.buildAdnString(recordSize[0]); + + if(data == null) { + throw new RuntimeException("worong ADN format", + ar.exception); + } + + phone.mIccFileHandler.updateEFLinearFixed(ef, recordNumber, + data, pin2, obtainMessage(EVENT_UPDATE_RECORD_DONE)); + + pendingExtLoads = 1; + + break; + case EVENT_UPDATE_RECORD_DONE: + ar = (AsyncResult)(msg.obj); + if (ar.exception != null) { + throw new RuntimeException("update EF adn record failed", + ar.exception); + } + pendingExtLoads = 0; + result = null; + break; + case EVENT_ADN_LOAD_DONE: + ar = (AsyncResult)(msg.obj); + data = (byte[])(ar.result); + + if (ar.exception != null) { + throw new RuntimeException("load failed", ar.exception); + } + + if (false) { + Log.d(LOG_TAG,"ADN EF: 0x" + + Integer.toHexString(ef) + + ":" + recordNumber + + "\n" + IccUtils.bytesToHexString(data)); + } + + adn = new AdnRecord(ef, recordNumber, data); + result = adn; + + if (adn.hasExtendedRecord()) { + // If we have a valid value in the ext record field, + // we're not done yet: we need to read the corresponding + // ext record and append it + + pendingExtLoads = 1; + + phone.mIccFileHandler.loadEFLinearFixed( + extensionEF, adn.extRecord, + obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn)); + } + break; + + case EVENT_EXT_RECORD_LOAD_DONE: + ar = (AsyncResult)(msg.obj); + data = (byte[])(ar.result); + adn = (AdnRecord)(ar.userObj); + + if (ar.exception != null) { + throw new RuntimeException("load failed", ar.exception); + } + + Log.d(LOG_TAG,"ADN extention EF: 0x" + + Integer.toHexString(extensionEF) + + ":" + adn.extRecord + + "\n" + IccUtils.bytesToHexString(data)); + + adn.appendExtRecord(data); + + pendingExtLoads--; + // result should have been set in + // EVENT_ADN_LOAD_DONE or EVENT_ADN_LOAD_ALL_DONE + break; + + case EVENT_ADN_LOAD_ALL_DONE: + ar = (AsyncResult)(msg.obj); + ArrayList<byte[]> datas = (ArrayList<byte[]>)(ar.result); + + if (ar.exception != null) { + throw new RuntimeException("load failed", ar.exception); + } + + adns = new ArrayList<AdnRecord>(datas.size()); + result = adns; + pendingExtLoads = 0; + + for(int i = 0, s = datas.size() ; i < s ; i++) { + adn = new AdnRecord(ef, 1 + i, datas.get(i)); + adns.add(adn); + + if (adn.hasExtendedRecord()) { + // If we have a valid value in the ext record field, + // we're not done yet: we need to read the corresponding + // ext record and append it + + pendingExtLoads++; + + phone.mIccFileHandler.loadEFLinearFixed( + extensionEF, adn.extRecord, + obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn)); + } + } + break; + } + } catch (RuntimeException exc) { + if (userResponse != null) { + AsyncResult.forMessage(userResponse) + .exception = exc; + userResponse.sendToTarget(); + // Loading is all or nothing--either every load succeeds + // or we fail the whole thing. + userResponse = null; + } + return; + } + + if (userResponse != null && pendingExtLoads == 0) { + AsyncResult.forMessage(userResponse).result + = result; + + userResponse.sendToTarget(); + userResponse = null; + } + } + + +} diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java new file mode 100644 index 0000000..11e7461 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/BaseCommands.java @@ -0,0 +1,580 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + + +import android.content.Context; +import android.os.RegistrantList; +import android.os.Registrant; +import android.os.Handler; +import android.os.AsyncResult; +import android.provider.Checkin; +import android.util.Config; +import android.util.Log; + +/** + * {@hide} + */ +public abstract class BaseCommands implements CommandsInterface { + static final String LOG_TAG = "RILB"; + + //***** Instance Variables + protected Context mContext; + protected RadioState mState = RadioState.RADIO_UNAVAILABLE; + protected Object mStateMonitor = new Object(); + + protected RegistrantList mRadioStateChangedRegistrants = new RegistrantList(); + protected RegistrantList mOnRegistrants = new RegistrantList(); + protected RegistrantList mAvailRegistrants = new RegistrantList(); + protected RegistrantList mOffOrNotAvailRegistrants = new RegistrantList(); + protected RegistrantList mNotAvailRegistrants = new RegistrantList(); + protected RegistrantList mSIMReadyRegistrants = new RegistrantList(); + protected RegistrantList mSIMLockedRegistrants = new RegistrantList(); + protected RegistrantList mRUIMReadyRegistrants = new RegistrantList(); + protected RegistrantList mRUIMLockedRegistrants = new RegistrantList(); + protected RegistrantList mNVReadyRegistrants = new RegistrantList(); + protected RegistrantList mCallStateRegistrants = new RegistrantList(); + protected RegistrantList mNetworkStateRegistrants = new RegistrantList(); + protected RegistrantList mDataConnectionRegistrants = new RegistrantList(); + protected RegistrantList mRadioTechnologyChangedRegistrants = new RegistrantList(); + protected RegistrantList mIccStatusChangedRegistrants = new RegistrantList(); + protected RegistrantList mVoicePrivacyOnRegistrants = new RegistrantList(); + protected RegistrantList mVoicePrivacyOffRegistrants = 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 mIccRefreshRegistrant; + /** Registrant for handling RING notifications */ + protected Registrant mRingRegistrant; + /** Registrant for handling RESTRICTED STATE changed notification */ + protected Registrant mRestrictedStateRegistrant; + + //Network Mode received from PhoneFactory + protected int mNetworkMode; + //CDMA subscription received from PhoneFactory + protected int mCdmaSubscription; + //Type of Phone, GSM or CDMA. Set by CDMAPhone or GSMPhone. + protected int mPhoneType; + + + public BaseCommands(Context context) { + mContext = context; // May be null (if so we won't log statistics) + } + + //***** CommandsInterface implementation + + public RadioState getRadioState() { + return mState; + } + + + public void registerForRadioStateChanged(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mRadioStateChangedRegistrants.add(r); + r.notifyRegistrant(); + } + } + + public void unregisterForRadioStateChanged(Handler h) { + synchronized (mStateMonitor) { + mRadioStateChangedRegistrants.remove(h); + } + } + + public void registerForOn(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mOnRegistrants.add(r); + + if (mState.isOn()) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + public void unregisterForOn(Handler h) { + synchronized (mStateMonitor) { + mOnRegistrants.remove(h); + } + } + + + public void registerForAvailable(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mAvailRegistrants.add(r); + + if (mState.isAvailable()) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + + public void unregisterForAvailable(Handler h) { + synchronized(mStateMonitor) { + mAvailRegistrants.remove(h); + } + } + + public void registerForNotAvailable(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mNotAvailRegistrants.add(r); + + if (!mState.isAvailable()) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + + public void unregisterForNotAvailable(Handler h) { + synchronized (mStateMonitor) { + mNotAvailRegistrants.remove(h); + } + } + + public void registerForOffOrNotAvailable(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mOffOrNotAvailRegistrants.add(r); + + if (mState == RadioState.RADIO_OFF || !mState.isAvailable()) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + public void unregisterForOffOrNotAvailable(Handler h) { + synchronized(mStateMonitor) { + mOffOrNotAvailRegistrants.remove(h); + } + } + + + /** Any transition into SIM_READY */ + public void registerForSIMReady(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mSIMReadyRegistrants.add(r); + + if (mState.isSIMReady()) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + + public void unregisterForSIMReady(Handler h) { + synchronized (mStateMonitor) { + mSIMReadyRegistrants.remove(h); + } + } + + /** Any transition into RUIM_READY */ + public void registerForRUIMReady(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mRUIMReadyRegistrants.add(r); + + if (mState.isRUIMReady()) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + + public void unregisterForRUIMReady(Handler h) { + synchronized(mStateMonitor) { + mRUIMReadyRegistrants.remove(h); + } + } + + /** Any transition into NV_READY */ + public void registerForNVReady(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mNVReadyRegistrants.add(r); + + if (mState.isNVReady()) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + + public void unregisterForNVReady(Handler h) { + synchronized (mStateMonitor) { + mNVReadyRegistrants.remove(h); + } + } + + public void registerForSIMLockedOrAbsent(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mSIMLockedRegistrants.add(r); + + if (mState == RadioState.SIM_LOCKED_OR_ABSENT) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + + public void unregisterForSIMLockedOrAbsent(Handler h) { + synchronized (mStateMonitor) { + mSIMLockedRegistrants.remove(h); + } + } + + public void registerForRUIMLockedOrAbsent(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mRUIMLockedRegistrants.add(r); + + if (mState == RadioState.RUIM_LOCKED_OR_ABSENT) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + + public void unregisterForRUIMLockedOrAbsent(Handler h) { + synchronized (mStateMonitor) { + mRUIMLockedRegistrants.remove(h); + } + } + + public void registerForCallStateChanged(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + mCallStateRegistrants.add(r); + } + + public void unregisterForCallStateChanged(Handler h) { + mCallStateRegistrants.remove(h); + } + + public void registerForNetworkStateChanged(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + mNetworkStateRegistrants.add(r); + } + + public void unregisterForNetworkStateChanged(Handler h) { + mNetworkStateRegistrants.remove(h); + } + + public void registerForDataStateChanged(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + mDataConnectionRegistrants.add(r); + } + + public void unregisterForDataStateChanged(Handler h) { + mDataConnectionRegistrants.remove(h); + } + + public void registerForRadioTechnologyChanged(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mRadioTechnologyChangedRegistrants.add(r); + } + + public void unregisterForRadioTechnologyChanged(Handler h) { + mRadioTechnologyChangedRegistrants.remove(h); + } + + public void registerForIccStatusChanged(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mIccStatusChangedRegistrants.add(r); + } + + public void unregisterForIccStatusChanged(Handler h) { + mIccStatusChangedRegistrants.remove(h); + } + + public void setOnNewSMS(Handler h, int what, Object obj) { + mSMSRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnNewSMS(Handler h) { + mSMSRegistrant.clear(); + } + + public void setOnSmsOnSim(Handler h, int what, Object obj) { + mSmsOnSimRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnSmsOnSim(Handler h) { + mSmsOnSimRegistrant.clear(); + } + + public void setOnSmsStatus(Handler h, int what, Object obj) { + mSmsStatusRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnSmsStatus(Handler h) { + mSmsStatusRegistrant.clear(); + } + + public void setOnSignalStrengthUpdate(Handler h, int what, Object obj) { + mSignalStrengthRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnSignalStrengthUpdate(Handler h) { + mSignalStrengthRegistrant.clear(); + } + + public void setOnNITZTime(Handler h, int what, Object obj) { + mNITZTimeRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnNITZTime(Handler h) { + mNITZTimeRegistrant.clear(); + } + + public void setOnUSSD(Handler h, int what, Object obj) { + mUSSDRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnUSSD(Handler h) { + mUSSDRegistrant.clear(); + } + + public void setOnSuppServiceNotification(Handler h, int what, Object obj) { + mSsnRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnSuppServiceNotification(Handler h) { + mSsnRegistrant.clear(); + } + + public void setOnStkSessionEnd(Handler h, int what, Object obj) { + mStkSessionEndRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnStkSessionEnd(Handler h) { + mStkSessionEndRegistrant.clear(); + } + + public void setOnStkProactiveCmd(Handler h, int what, Object obj) { + mStkProCmdRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnStkProactiveCmd(Handler h) { + mStkProCmdRegistrant.clear(); + } + + public void setOnStkEvent(Handler h, int what, Object obj) { + mStkEventRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnStkEvent(Handler h) { + mStkEventRegistrant.clear(); + } + + public void setOnStkCallSetUp(Handler h, int what, Object obj) { + mStkCallSetUpRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnStkCallSetUp(Handler h) { + mStkCallSetUpRegistrant.clear(); + } + + public void setOnIccSmsFull(Handler h, int what, Object obj) { + mIccSmsFullRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnIccSmsFull(Handler h) { + mIccSmsFullRegistrant.clear(); + } + + public void setOnIccRefresh(Handler h, int what, Object obj) { + mIccRefreshRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnIccRefresh(Handler h) { + mIccRefreshRegistrant.clear(); + } + + public void setOnCallRing(Handler h, int what, Object obj) { + mRingRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnCallRing(Handler h) { + mRingRegistrant.clear(); + } + + public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mVoicePrivacyOnRegistrants.add(r); + } + + public void unregisterForInCallVoicePrivacyOn(Handler h){ + mVoicePrivacyOnRegistrants.remove(h); + } + + public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mVoicePrivacyOffRegistrants.add(r); + } + + public void unregisterForInCallVoicePrivacyOff(Handler h){ + mVoicePrivacyOffRegistrants.remove(h); + } + + public void setOnRestrictedStateChanged(Handler h, int what, Object obj) { + mRestrictedStateRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnRestrictedStateChanged(Handler h) { + mRestrictedStateRegistrant.clear(); + } + + //***** Protected Methods + /** + * Store new RadioState and send notification based on the changes + * + * This function is called only by RIL.java when receiving unsolicited + * RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED + * + * RadioState has 5 values : RADIO_OFF, RADIO_UNAVAILABLE, SIM_NOT_READY, + * SIM_LOCKED_OR_ABSENT, and SIM_READY. + * + * @param newState new RadioState decoded from RIL_UNSOL_RADIO_STATE_CHANGED + */ + protected void setRadioState(RadioState newState) { + RadioState oldState; + + synchronized (mStateMonitor) { + if (Config.LOGV) { + Log.v(LOG_TAG, "setRadioState old: " + mState + + " new " + newState); + } + + oldState = mState; + mState = newState; + + if (oldState == mState) { + // no state transition + return; + } + + if (mContext != null && + newState == RadioState.RADIO_UNAVAILABLE && + oldState != RadioState.RADIO_OFF) { + Checkin.updateStats(mContext.getContentResolver(), + Checkin.Stats.Tag.PHONE_RADIO_RESETS, 1, 0.0); + } + + mRadioStateChangedRegistrants.notifyRegistrants(); + + if (mState.isAvailable() && !oldState.isAvailable()) { + Log.d(LOG_TAG,"Notifying: radio available"); + mAvailRegistrants.notifyRegistrants(); + onRadioAvailable(); + } + + if (!mState.isAvailable() && oldState.isAvailable()) { + Log.d(LOG_TAG,"Notifying: radio not available"); + mNotAvailRegistrants.notifyRegistrants(); + } + + if (mState.isSIMReady() && !oldState.isSIMReady()) { + Log.d(LOG_TAG,"Notifying: SIM ready"); + mSIMReadyRegistrants.notifyRegistrants(); + } + + if (mState == RadioState.SIM_LOCKED_OR_ABSENT) { + Log.d(LOG_TAG,"Notifying: SIM locked or absent"); + mSIMLockedRegistrants.notifyRegistrants(); + } + + if (mState.isRUIMReady() && !oldState.isRUIMReady()) { + Log.d(LOG_TAG,"Notifying: RUIM ready"); + mRUIMReadyRegistrants.notifyRegistrants(); + } + + if (mState == RadioState.RUIM_LOCKED_OR_ABSENT) { + Log.d(LOG_TAG,"Notifying: RUIM locked or absent"); + mRUIMLockedRegistrants.notifyRegistrants(); + } + if (mState.isNVReady() && !oldState.isNVReady()) { + Log.d(LOG_TAG,"Notifying: NV ready"); + mNVReadyRegistrants.notifyRegistrants(); + } + + if (mState.isOn() && !oldState.isOn()) { + Log.d(LOG_TAG,"Notifying: Radio On"); + mOnRegistrants.notifyRegistrants(); + } + + if ((!mState.isOn() || !mState.isAvailable()) + && !((!oldState.isOn() || !oldState.isAvailable())) + ) { + Log.d(LOG_TAG,"Notifying: radio off or not available"); + mOffOrNotAvailRegistrants.notifyRegistrants(); + } + + /* Radio Technology Change events + * NOTE: isGsm and isCdma have no common states in RADIO_OFF or RADIO_UNAVAILABLE; the + * current phone is determined by mPhoneType + * NOTE: at startup no phone have been created and the RIL determines the mPhoneType + * looking based on the networkMode set by the PhoneFactory in the constructor + */ + + if (mState.isGsm() && oldState.isCdma()) { + Log.d(LOG_TAG,"Notifying: radio technology change CDMA to GSM"); + mRadioTechnologyChangedRegistrants.notifyRegistrants(); + } + + if (mState.isGsm() && !oldState.isOn() && (mPhoneType == RILConstants.CDMA_PHONE)) { + Log.d(LOG_TAG,"Notifying: radio technology change CDMA OFF to GSM"); + mRadioTechnologyChangedRegistrants.notifyRegistrants(); + } + + if (mState.isCdma() && oldState.isGsm()) { + Log.d(LOG_TAG,"Notifying: radio technology change GSM to CDMA"); + mRadioTechnologyChangedRegistrants.notifyRegistrants(); + } + + if (mState.isCdma() && !oldState.isOn() && (mPhoneType == RILConstants.GSM_PHONE)) { + Log.d(LOG_TAG,"Notifying: radio technology change GSM OFF to CDMA"); + mRadioTechnologyChangedRegistrants.notifyRegistrants(); + } + } + } + + protected void onRadioAvailable() { + } +} diff --git a/telephony/java/com/android/internal/telephony/Call.java b/telephony/java/com/android/internal/telephony/Call.java index 82aeb25..70471b6 100644 --- a/telephony/java/com/android/internal/telephony/Call.java +++ b/telephony/java/com/android/internal/telephony/Call.java @@ -17,6 +17,7 @@ package com.android.internal.telephony; import java.util.List; + /** * {@hide} */ @@ -39,6 +40,13 @@ public abstract class Call { } } + + /* Instance Variables */ + + public State state = State.IDLE; + + + /* Instance Methods */ /** Do not modify the List result!!! This list is not yours to keep @@ -46,36 +54,46 @@ public abstract class Call { */ public abstract List<Connection> getConnections(); - public abstract State getState(); public abstract Phone getPhone(); + public abstract boolean isMultiparty(); + public abstract void hangup() throws CallStateException; + /** * hasConnection - * + * * @param c a Connection object * @return true if the call contains the connection object passed in */ public boolean hasConnection(Connection c) { return c.getCall() == this; } - + /** * hasConnections * @return true if the call contains one or more connections */ public boolean hasConnections() { List connections = getConnections(); - + if (connections == null) { return false; } - + return connections.size() > 0; } - + + /** + * getState + * @return state of class call + */ + public State getState() { + return state; + } + /** * isIdle - * + * * FIXME rename * @return true if the call contains only disconnected connections (if any) */ @@ -93,27 +111,27 @@ public abstract class Call { long time = Long.MAX_VALUE; Connection c; Connection earliest = null; - + l = getConnections(); - + if (l.size() == 0) { return null; } - + for (int i = 0, s = l.size() ; i < s ; i++) { c = (Connection) l.get(i); long t; - + t = c.getCreateTime(); - + if (t < time) { earliest = c; } } - + return earliest; } - + public long getEarliestCreateTime() { List l; @@ -160,9 +178,6 @@ public abstract class Call { return time; } - public abstract boolean isMultiparty(); - - public abstract void hangup() throws CallStateException; public boolean isDialingOrAlerting() { diff --git a/telephony/java/com/android/internal/telephony/gsm/CallForwardInfo.java b/telephony/java/com/android/internal/telephony/CallForwardInfo.java index bf31b13..8b853b0 100644 --- a/telephony/java/com/android/internal/telephony/gsm/CallForwardInfo.java +++ b/telephony/java/com/android/internal/telephony/CallForwardInfo.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.telephony.PhoneNumberUtils; @@ -23,8 +23,7 @@ import android.telephony.PhoneNumberUtils; * * {@hide} */ -public class CallForwardInfo -{ +public class CallForwardInfo { public int status; /*1 = active, 0 = not active */ public int reason; /* from TS 27.007 7.11 "reason" */ public int serviceClass; /* Sum of CommandsInterface.SERVICE_CLASS */ @@ -32,8 +31,7 @@ public class CallForwardInfo public String number; /* "number" from TS 27.007 7.11 */ public int timeSeconds; /* for CF no reply only */ - public String toString() - { + public String toString() { return super.toString() + (status == 0 ? " not active " : " active ") + " reason: " + reason + " serviceClass: " + serviceClass diff --git a/telephony/java/com/android/internal/telephony/CallTracker.java b/telephony/java/com/android/internal/telephony/CallTracker.java new file mode 100644 index 0000000..eb339f8 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/CallTracker.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +import com.android.internal.telephony.CommandException; + + +/** + * {@hide} + */ +public abstract class CallTracker extends Handler { + + private static final boolean DBG_POLL = false; + + //***** Constants + + static final int POLL_DELAY_MSEC = 250; + + protected int pendingOperations; + protected boolean needsPoll; + protected Message lastRelevantPoll; + + public CommandsInterface cm; + + + //***** 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 void pollCallsWhenSafe() { + needsPoll = true; + + if (checkNoOperationsPending()) { + lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); + cm.getCurrentCalls(lastRelevantPoll); + } + } + + protected void + pollCallsAfterDelay() { + Message msg = obtainMessage(); + + msg.what = EVENT_REPOLL_AFTER_DELAY; + sendMessageDelayed(msg, POLL_DELAY_MSEC); + } + + protected boolean + isCommandExceptionRadioNotAvailable(Throwable e) { + return e != null && e instanceof CommandException + && ((CommandException)e).getCommandError() + == CommandException.Error.RADIO_NOT_AVAILABLE; + } + + protected abstract void handlePollCalls(AsyncResult ar); + + protected void handleRadioAvailable() { + pollCallsWhenSafe(); + } + + /** + * Obtain a complete message that indicates that this operation + * does not require polling of getCurrentCalls(). However, if other + * operations that do need getCurrentCalls() are pending or are + * scheduled while this operation is pending, the invocation + * of getCurrentCalls() will be postponed until this + * operation is also complete. + */ + protected Message + obtainNoPollCompleteMessage(int what) { + pendingOperations++; + lastRelevantPoll = null; + return obtainMessage(what); + } + + /** + * @return true if we're idle or there's a call to getCurrentCalls() pending + * but nothing else + */ + private boolean + checkNoOperationsPending() { + if (DBG_POLL) log("checkNoOperationsPending: pendingOperations=" + + pendingOperations); + return pendingOperations == 0; + } + + + //***** Overridden from Handler + public abstract void handleMessage (Message msg); + + protected abstract void log(String msg); + +} diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java index 145e5d8..04da9f7 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java +++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java @@ -37,7 +37,7 @@ import android.util.Log; public class CallerInfoAsyncQuery { private static final boolean DBG = false; - private static final String LOG_TAG = "CallerInfoAsyncQuery"; + private static final String LOG_TAG = "PHONE"; private static final int EVENT_NEW_QUERY = 1; private static final int EVENT_ADD_LISTENER = 2; diff --git a/telephony/java/com/android/internal/telephony/gsm/CommandException.java b/telephony/java/com/android/internal/telephony/CommandException.java index 5cf48f3..a5d11cf 100644 --- a/telephony/java/com/android/internal/telephony/gsm/CommandException.java +++ b/telephony/java/com/android/internal/telephony/CommandException.java @@ -14,15 +14,16 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; + +import com.android.internal.telephony.RILConstants; import android.util.Log; /** * {@hide} */ -public class CommandException extends RuntimeException -{ +public class CommandException extends RuntimeException { private Error e; public enum Error { @@ -38,30 +39,28 @@ public class CommandException extends RuntimeException SMS_FAIL_RETRY, } - public CommandException(Error e) - { + public CommandException(Error e) { super(e.toString()); this.e = e; } public static CommandException - fromRilErrno(int ril_errno) - { + fromRilErrno(int ril_errno) { switch(ril_errno) { case RILConstants.SUCCESS: return null; - case RILConstants.RIL_ERRNO_INVALID_RESPONSE: + case RILConstants.RIL_ERRNO_INVALID_RESPONSE: return new CommandException(Error.INVALID_RESPONSE); - case RILConstants.RADIO_NOT_AVAILABLE: + case RILConstants.RADIO_NOT_AVAILABLE: return new CommandException(Error.RADIO_NOT_AVAILABLE); - case RILConstants.GENERIC_FAILURE: + case RILConstants.GENERIC_FAILURE: return new CommandException(Error.GENERIC_FAILURE); - case RILConstants.PASSWORD_INCORRECT: + case RILConstants.PASSWORD_INCORRECT: return new CommandException(Error.PASSWORD_INCORRECT); - case RILConstants.SIM_PIN2: + case RILConstants.SIM_PIN2: return new CommandException(Error.SIM_PIN2); - case RILConstants.SIM_PUK2: + case RILConstants.SIM_PUK2: return new CommandException(Error.SIM_PUK2); - case RILConstants.REQUEST_NOT_SUPPORTED: + case RILConstants.REQUEST_NOT_SUPPORTED: return new CommandException(Error.REQUEST_NOT_SUPPORTED); case RILConstants.OP_NOT_ALLOWED_DURING_VOICE_CALL: return new CommandException(Error.OP_NOT_ALLOWED_DURING_VOICE_CALL); @@ -75,8 +74,7 @@ public class CommandException extends RuntimeException } } - public Error getCommandError() - { + public Error getCommandError() { return e; } diff --git a/telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java index 7915798..aec7238 100644 --- a/telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java +++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java @@ -14,50 +14,79 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; -import com.android.internal.telephony.*; +package com.android.internal.telephony; + import android.os.Message; import android.os.Handler; + /** * {@hide} */ -public interface CommandsInterface -{ +public interface CommandsInterface { enum RadioState { RADIO_OFF, /* Radio explictly powered off (eg CFUN=0) */ RADIO_UNAVAILABLE, /* Radio unavailable (eg, resetting or not booted) */ SIM_NOT_READY, /* Radio is on, but the SIM interface is not ready */ - SIM_LOCKED_OR_ABSENT, /* SIM PIN locked, PUK required, network + SIM_LOCKED_OR_ABSENT, /* SIM PIN locked, PUK required, network personalization, or SIM absent */ - SIM_READY; /* Radio is on and SIM interface is available */ - - boolean isOn() /* and available...*/ - { + SIM_READY, /* Radio is on and SIM interface is available */ + RUIM_NOT_READY, /* Radio is on, but the RUIM interface is not ready */ + RUIM_READY, /* Radio is on and the RUIM interface is available */ + RUIM_LOCKED_OR_ABSENT, /* RUIM PIN locked, PUK required, network + personalization locked, or RUIM absent */ + NV_NOT_READY, /* Radio is on, but the NV interface is not available */ + NV_READY; /* Radio is on and the NV interface is available */ + + public boolean isOn() /* and available...*/ { return this == SIM_NOT_READY || this == SIM_LOCKED_OR_ABSENT - || this == SIM_READY; + || this == SIM_READY + || this == RUIM_NOT_READY + || this == RUIM_READY + || this == RUIM_LOCKED_OR_ABSENT + || this == NV_NOT_READY + || this == NV_READY; } - boolean isAvailable() - { + public boolean isAvailable() { return this != RADIO_UNAVAILABLE; } - boolean isSIMReady() - { - // if you add new states after SIM_READY, include them too + public boolean isSIMReady() { return this == SIM_READY; } + + public boolean isRUIMReady() { + return this == RUIM_READY; + } + + public boolean isNVReady() { + return this == NV_READY; + } + + public boolean isGsm() { + return this == SIM_NOT_READY + || this == SIM_LOCKED_OR_ABSENT + || this == SIM_READY; + } + + public boolean isCdma() { + return this == RUIM_NOT_READY + || this == RUIM_READY + || this == RUIM_LOCKED_OR_ABSENT + || this == NV_NOT_READY + || this == NV_READY; + } } - enum SimStatus { - SIM_ABSENT, - SIM_NOT_READY, - SIM_READY, - SIM_PIN, - SIM_PUK, - SIM_NETWORK_PERSONALIZATION + enum IccStatus { + ICC_ABSENT, + ICC_NOT_READY, + ICC_READY, + ICC_PIN, + ICC_PUK, + ICC_NETWORK_PERSONALIZATION } //***** Constants @@ -93,7 +122,7 @@ public interface CommandsInterface static final String CB_FACILITY_BA_MT = "AC"; static final String CB_FACILITY_BA_SIM = "SC"; static final String CB_FACILITY_BA_FD = "FD"; - + // Used for various supp services apis // See 27.007 +CCFC or +CLCK @@ -102,7 +131,7 @@ public interface CommandsInterface static final int SERVICE_CLASS_DATA = (1 << 1); //synoym for 16+32+64+128 static final int SERVICE_CLASS_FAX = (1 << 2); static final int SERVICE_CLASS_SMS = (1 << 3); - static final int SERVICE_CLASS_DATA_SYNC = (1 << 4); + static final int SERVICE_CLASS_DATA_SYNC = (1 << 4); static final int SERVICE_CLASS_DATA_ASYNC = (1 << 5); static final int SERVICE_CLASS_PACKET = (1 << 6); static final int SERVICE_CLASS_PAD = (1 << 7); @@ -122,8 +151,8 @@ public interface CommandsInterface RadioState getRadioState(); - /** - * Fires on any RadioState transition + /** + * Fires on any RadioState transition * Always fires immediately as well * * do not attempt to calculate transitions by storing getRadioState() values @@ -131,58 +160,85 @@ public interface CommandsInterface * registration methods */ void registerForRadioStateChanged(Handler h, int what, Object obj); + void unregisterForRadioStateChanged(Handler h); - /** - * Fires on any transition into RadioState.isOn() + /** + * Fires on any transition into RadioState.isOn() * Fires immediately if currently in that state * In general, actions should be idempotent. State may change * before event is received. */ void registerForOn(Handler h, int what, Object obj); + void unregisterForOn(Handler h); - /** - * Fires on any transition out of RadioState.isAvailable() + /** + * Fires on any transition out of RadioState.isAvailable() * Fires immediately if currently in that state * In general, actions should be idempotent. State may change * before event is received. */ void registerForAvailable(Handler h, int what, Object obj); - //void unregisterForAvailable(Handler h); - /** + void unregisterForAvailable(Handler h); + + /** * Fires on any transition into !RadioState.isAvailable() * Fires immediately if currently in that state * In general, actions should be idempotent. State may change * before event is received. */ void registerForNotAvailable(Handler h, int what, Object obj); - //void unregisterForNotAvailable(Handler h); - /** + void unregisterForNotAvailable(Handler h); + + /** * Fires on any transition into RADIO_OFF or !RadioState.isAvailable() * Fires immediately if currently in that state * In general, actions should be idempotent. State may change * before event is received. */ void registerForOffOrNotAvailable(Handler h, int what, Object obj); - //void unregisterForNotAvailable(Handler h); + void unregisterForOffOrNotAvailable(Handler h); - /** + /** * Fires on any transition into SIM_READY * Fires immediately if if currently in that state * In general, actions should be idempotent. State may change * before event is received. */ void registerForSIMReady(Handler h, int what, Object obj); - //void unregisterForSIMReady(Handler h); + void unregisterForSIMReady(Handler h); + /** Any transition into SIM_LOCKED_OR_ABSENT */ void registerForSIMLockedOrAbsent(Handler h, int what, Object obj); - //void unregisterForSIMLockedOrAbsent(Handler h); + void unregisterForSIMLockedOrAbsent(Handler h); void registerForCallStateChanged(Handler h, int what, Object obj); - //void unregisterForCallStateChanged(Handler h); + void unregisterForCallStateChanged(Handler h); void registerForNetworkStateChanged(Handler h, int what, Object obj); - //void unregisterForNetworkStateChanged(Handler h); - void registerForPDPStateChanged(Handler h, int what, Object obj); - //void unregisterForPDPStateChanged(Handler h); + void unregisterForNetworkStateChanged(Handler h); + void registerForDataStateChanged(Handler h, int what, Object obj); + void unregisterForDataStateChanged(Handler h); + + void registerForRadioTechnologyChanged(Handler h, int what, Object obj); + void unregisterForRadioTechnologyChanged(Handler h); + void registerForNVReady(Handler h, int what, Object obj); + void unregisterForNVReady(Handler h); + void registerForRUIMLockedOrAbsent(Handler h, int what, Object obj); + void unregisterForRUIMLockedOrAbsent(Handler h); + + /** InCall voice privacy notifications */ + void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj); + void unregisterForInCallVoicePrivacyOn(Handler h); + void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj); + void unregisterForInCallVoicePrivacyOff(Handler h); + + /** + * Fires on any transition into RUIM_READY + * Fires immediately if if currently in that state + * In general, actions should be idempotent. State may change + * before event is received. + */ + void registerForRUIMReady(Handler h, int what, Object obj); + void unregisterForRUIMReady(Handler h); /** * unlike the register* methods, there's only one new SMS handler @@ -192,21 +248,24 @@ public interface CommandsInterface * AsyncResult.result is a String containing the SMS PDU */ void setOnNewSMS(Handler h, int what, Object obj); + void unSetOnNewSMS(Handler h); /** - * Register for NEW_SMS_ON_SIM unsolicited message + * Register for NEW_SMS_ON_SIM unsolicited message * * AsyncResult.result is an int array containing the index of new SMS */ void setOnSmsOnSim(Handler h, int what, Object obj); + void unSetOnSmsOnSim(Handler h); /** - * Register for NEW_SMS_STATUS_REPORT unsolicited message + * Register for NEW_SMS_STATUS_REPORT unsolicited message * * AsyncResult.result is a String containing the status report PDU */ void setOnSmsStatus(Handler h, int what, Object obj); - + void unSetOnSmsStatus(Handler h); + /** * unlike the register* methods, there's only one NITZ time handler * @@ -220,13 +279,14 @@ public interface CommandsInterface * seconds on system startup */ void setOnNITZTime(Handler h, int what, Object obj); + void unSetOnNITZTime(Handler h); /** * unlike the register* methods, there's only one USSD notify handler * * Represents the arrival of a USSD "notify" message, which may * or may not have been triggered by a previous USSD send - * + * * AsyncResult.result is a String[] * ((String[])(AsyncResult.result))[0] contains status code * "0" USSD-Notify -- text in ((const char **)data)[1] @@ -241,26 +301,29 @@ public interface CommandsInterface */ void setOnUSSD(Handler h, int what, Object obj); + void unSetOnUSSD(Handler h); /** * unlike the register* methods, there's only one signal strength handler - * AsyncResult.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) + * AsyncResult.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) * as defined in TS 27.007 8.5 */ void setOnSignalStrengthUpdate(Handler h, int what, Object obj); + void unSetOnSignalStrengthUpdate(Handler h); /** - * Sets the handler for SIM SMS storage full unsolicited message. + * Sets the handler for SIM/RUIM SMS storage full unsolicited message. * 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 setOnSimSmsFull(Handler h, int what, Object obj); + void setOnIccSmsFull(Handler h, int what, Object obj); + void unSetOnIccSmsFull(Handler h); /** * Sets the handler for SIM Refresh notifications. @@ -270,8 +333,9 @@ public interface CommandsInterface * @param what User-defined message code. * @param obj User object. */ - void setOnSimRefresh(Handler h, int what, Object obj); - + void setOnIccRefresh(Handler h, int what, Object obj); + void unSetOnIccRefresh(Handler h); + /** * Sets the handler for RING notifications. * Unlike the register* methods, there's only one notification handler @@ -281,7 +345,8 @@ public interface CommandsInterface * @param obj User object. */ void setOnCallRing(Handler h, int what, Object obj); - + void unSetOnCallRing(Handler h); + /** * Sets the handler for RESTRICTED_STATE changed notification, * eg, for Domain Specific Access Control @@ -292,7 +357,8 @@ public interface CommandsInterface */ void setOnRestrictedStateChanged(Handler h, int what, Object obj); - + void unSetOnRestrictedStateChanged(Handler h); + /** * Sets the handler for Supplementary Service Notifications. * Unlike the register* methods, there's only one notification handler @@ -302,6 +368,7 @@ public interface CommandsInterface * @param obj User object. */ void setOnSuppServiceNotification(Handler h, int what, Object obj); + void unSetOnSuppServiceNotification(Handler h); /** * Sets the handler for Session End Notifications for STK. @@ -312,6 +379,7 @@ public interface CommandsInterface * @param obj User object. */ void setOnStkSessionEnd(Handler h, int what, Object obj); + void unSetOnStkSessionEnd(Handler h); /** * Sets the handler for Proactive Commands for STK. @@ -322,6 +390,7 @@ public interface CommandsInterface * @param obj User object. */ void setOnStkProactiveCmd(Handler h, int what, Object obj); + void unSetOnStkProactiveCmd(Handler h); /** * Sets the handler for Event Notifications for STK. @@ -332,6 +401,7 @@ public interface CommandsInterface * @param obj User object. */ void setOnStkEvent(Handler h, int what, Object obj); + void unSetOnStkEvent(Handler h); /** * Sets the handler for Call Set Up Notifications for STK. @@ -342,6 +412,7 @@ public interface CommandsInterface * @param obj User object. */ void setOnStkCallSetUp(Handler h, int what, Object obj); + void unSetOnStkCallSetUp(Handler h); /** * Enables/disbables supplementary service related notifications from @@ -351,19 +422,21 @@ public interface CommandsInterface * @param result Message to be posted when command completes. */ void setSuppServiceNotifications(boolean enable, Message result); + //void unSetSuppServiceNotifications(Handler h); + /** - * Returns current SIM status. + * Returns current ICC status. + * + * AsyncResult.result is IccStatus * - * AsyncResult.result is SimStatus - * */ - void getSimStatus(Message result); + void getIccStatus(Message result); /** - * Supply the SIM PIN to the SIM card - * + * Supply the ICC PIN to the ICC card + * * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -373,11 +446,11 @@ public interface CommandsInterface * ar.exception and ar.result are null on success */ - void supplySimPin(String pin, Message result); + void supplyIccPin(String pin, Message result); /** - * Supply the SIM PUK to the SIM card - * + * Supply the ICC PUK to the ICC card + * * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -387,13 +460,13 @@ public interface CommandsInterface * ar.exception and ar.result are null on success */ - void supplySimPuk(String puk, String newPin, Message result); + void supplyIccPuk(String puk, String newPin, Message result); /** - * Supply the SIM PIN2 to the SIM card - * Only called following operation where SIM_PIN2 was + * Supply the ICC PIN2 to the ICC card + * Only called following operation where ICC_PIN2 was * returned as a a failure from a previous operation - * + * * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -403,13 +476,13 @@ public interface CommandsInterface * ar.exception and ar.result are null on success */ - void supplySimPin2(String pin2, Message result); + void supplyIccPin2(String pin2, Message result); /** * Supply the SIM PUK2 to the SIM card * Only called following operation where SIM_PUK2 was * returned as a a failure from a previous operation - * + * * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -419,16 +492,16 @@ public interface CommandsInterface * ar.exception and ar.result are null on success */ - void supplySimPuk2(String puk2, String newPin2, Message result); + void supplyIccPuk2(String puk2, String newPin2, Message result); - void changeSimPin(String oldPin, String newPin, Message result); - void changeSimPin2(String oldPin2, String newPin2, Message result); + void changeIccPin(String oldPin, String newPin, Message result); + void changeIccPin2(String oldPin2, String newPin2, Message result); void changeBarringPassword(String facility, String oldPwd, String newPwd, Message result); void supplyNetworkDepersonalization(String netpin, Message result); - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -438,16 +511,26 @@ public interface CommandsInterface */ void getCurrentCalls (Message result); - /** + /** * returned message * 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 + * @deprecated */ void getPDPContextList(Message result); - /** + /** + * returned message + * 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 + */ + void getDataCallList(Message result); + + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -460,7 +543,7 @@ public interface CommandsInterface */ void dial (String address, int clirMode, Message result); - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -469,7 +552,7 @@ public interface CommandsInterface */ void getIMSI(Message result); - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -478,7 +561,7 @@ public interface CommandsInterface */ void getIMEI(Message result); - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -487,7 +570,7 @@ public interface CommandsInterface */ void getIMEISV(Message result); - /** + /** * Hang up one individual connection. * returned message * retMsg.obj = AsyncResult ar @@ -512,7 +595,7 @@ public interface CommandsInterface /** * 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 @@ -523,7 +606,7 @@ public interface CommandsInterface /** * 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 @@ -539,12 +622,27 @@ public interface CommandsInterface * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure - */ + */ void conference (Message result); /** + * Set preferred Voice Privacy (VP). + * + * @param enable true is enhanced and false is normal VP + * @param result is a callback message + */ + void setPreferredVoicePrivacy(boolean enable, Message result); + + /** + * Get currently set preferred Voice Privacy (VP) mode. + * + * @param result is a callback message + */ + void getPreferredVoicePrivacy(Message result); + + /** * 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." */ void separateConnection (int gsmIndex, Message result); @@ -554,15 +652,15 @@ public interface CommandsInterface * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure - */ + */ void acceptCall (Message result); - /** + /** * 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 - */ + */ void rejectCall (Message result); /** @@ -586,14 +684,21 @@ public interface CommandsInterface void getLastCallFailCause (Message result); - /** + /** * Reason for last PDP context deactivate or failure to activate * cause code returned as int[0] in Message.obj.response * returns an integer cause code defined in TS 24.008 * section 6.1.3.1.3 or close approximation + * @deprecated */ void getLastPdpFailCause (Message result); + /** + * The preferred new alternative to getLastPdpFailCause + * that is also CDMA-compatible. + */ + void getLastDataCallFailCause (Message result); + void setMute (boolean enableMute, Message response); void getMute (Message response); @@ -601,8 +706,8 @@ public interface CommandsInterface /** * 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 */ void getSignalStrength (Message response); @@ -612,21 +717,21 @@ public interface CommandsInterface * response.obj.result is an int[3] * response.obj.result[0] is registration state 0-5 from TS 27.007 7.2 * response.obj.result[1] is LAC if registered or -1 if not - * response.obj.result[2] is CID if registered or -1 if not + * response.obj.result[2] is CID if registered or -1 if not * valid LAC and CIDs are 0x0000 - 0xffff - * + * * Please note that registration state 4 ("unknown") is treated * as "out of service" above */ void getRegistrationState (Message response); - + /** * response.obj.result is an int[3] * response.obj.result[0] is registration state 0-5 from TS 27.007 7.2 * response.obj.result[1] is LAC if registered or -1 if not - * response.obj.result[2] is CID if registered or -1 if not + * response.obj.result[2] is CID if registered or -1 if not * valid LAC and CIDs are 0x0000 - 0xffff - * + * * Please note that registration state 4 ("unknown") is treated * as "out of service" above */ @@ -637,14 +742,14 @@ public interface CommandsInterface * 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 - */ + */ void getOperator(Message response); /** * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure - */ + */ void sendDtmf(char c, Message result); @@ -667,26 +772,40 @@ public interface CommandsInterface * 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 */ void sendSMS (String smscPDU, String pdu, Message response); /** + * @param pdu is CDMA-SMS in internal pseudo-PDU format + * @param response sent when operation completes + */ + void sendCdmaSms(byte[] pdu, Message response); + + /** * Deletes the specified SMS record from SIM memory (EF_SMS). - * + * * @param index index of the SMS record to delete * @param response sent when operation completes */ void deleteSmsOnSim(int index, Message response); /** + * Deletes the specified SMS record from RUIM memory (EF_SMS in DF_CDMA). + * + * @param index index of the SMS record to delete + * @param response sent when operation completes + */ + void deleteSmsOnRuim(int index, Message response); + + /** * Writes an SMS message to SIM memory (EF_SMS). - * + * * @param status status of message on SIM. One of: - * SmsManger.STATUS_ON_SIM_READ - * SmsManger.STATUS_ON_SIM_UNREAD - * SmsManger.STATUS_ON_SIM_SENT - * SmsManger.STATUS_ON_SIM_UNSENT + * SmsManger.STATUS_ON_ICC_READ + * SmsManger.STATUS_ON_ICC_UNREAD + * SmsManger.STATUS_ON_ICC_SENT + * SmsManger.STATUS_ON_ICC_UNSENT * @param pdu message PDU, as hex string * @param response sent when operation completes. * response.obj will be an AsyncResult, and will indicate @@ -694,89 +813,105 @@ public interface CommandsInterface */ void writeSmsToSim(int status, String smsc, String pdu, Message response); + void writeSmsToRuim(int status, String pdu, Message response); + + /** + * @deprecated + * @param apn + * @param user + * @param password + * @param response + */ void setupDefaultPDP(String apn, String user, String password, Message response); + /** + * @deprecated + * @param cid + * @param response + */ void deactivateDefaultPDP(int cid, Message response); void setRadioPower(boolean on, Message response); void acknowledgeLastIncomingSMS(boolean success, Message response); - /** - * parameters equivilient to 27.007 AT+CRSM command + void acknowledgeLastIncomingCdmaSms(boolean success, Message response); + + /** + * parameters equivilient to 27.007 AT+CRSM command * response.obj will be an AsyncResult - * response.obj.userObj will be a SimIoResult on success + * response.obj.userObj will be a IccIoResult on success */ - void simIO (int command, int fileid, String path, int p1, int p2, int p3, + void iccIO (int command, int fileid, String path, int p1, int p2, int p3, String data, String pin2, Message response); /** * (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 */ - + void queryCLIP(Message response); /** * 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 */ void getCLIR(Message response); - + /** * clirMode is one of the CLIR_* constants above * * response.obj is null */ - + void setCLIR(int clirMode, Message response); /** * (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 */ - + void queryCallWaiting(int serviceClass, Message response); - + /** * @param enable is true to enable, false to disable * @param serviceClass is a sum of SERVICE_CLASS_* * @param response is callback message */ - + void setCallWaiting(boolean enable, int serviceClass, Message response); /** * @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_* */ - void setCallForward(int action, int cfReason, int serviceClass, - String number, int timeSeconds, Message response); + void setCallForward(int action, int cfReason, int serviceClass, + String number, int timeSeconds, Message response); /** * cfReason is one of CF_REASON_* * * ((AsyncResult)response.obj).result will be an array of * CallForwardInfo's - * + * * An array of length 0 means "disabled for all codes" */ void queryCallForwardStatus(int cfReason, int serviceClass, @@ -815,7 +950,7 @@ public interface CommandsInterface * @param serviceClass is a sum of SERVICE_CLASS_* * @param response is callback message */ - + void queryFacilityLock (String facility, String password, int serviceClass, Message response); @@ -828,7 +963,7 @@ public interface CommandsInterface */ void setFacilityLock (String facility, boolean lockState, String password, int serviceClass, Message response); - + void sendUSSD (String ussdString, Message response); @@ -850,7 +985,7 @@ public interface CommandsInterface /** * Query the list of band mode supported by RF. - * + * * @param response is callback message * ((AsyncResult)response.obj).result is an int[] with every * element representing one avialable BM_*_BAND @@ -923,4 +1058,136 @@ public interface CommandsInterface * @param response Callback message */ public void handleCallSetupRequestFromSim(boolean accept, Message response); + + //***** new Methods for CDMA support + + /** + * Request the device ESN / MEID / IMEI / IMEISV. + * "response" is const char ** + * [0] is IMEI if GSM subscription is available + * [1] is IMEISV if GSM subscription is available + * [2] is ESN if CDMA subscription is available + * [3] is MEID if CDMA subscription is available + */ + public void getDeviceIdentity(Message response); + + /** + * Request the device IMSI_M / MDN / AH_SID / H_SID / H_NID. + * "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 + */ + public void getCDMASubscription(Message response); + + /** + * Send Flash Code. + * "response" is is NULL + * [0] is a FLASH string + */ + public void sendCDMAFeatureCode(String FeatureCode, Message response); + + /** Set the Phone type created */ + void setPhoneType(int phoneType); + /** + * Query the CDMA roaming preference setting + * + * @param response is callback message to report one of CDMA_RM_* + */ + void queryCdmaRoamingPreference(Message response); + + /** + * Requests to set the CDMA roaming preference + * @param cdmaRoamingType one of CDMA_RM_* + * @param response is callback message + */ + void setCdmaRoamingPreference(int cdmaRoamingType, Message response); + + /** + * Requests to set the CDMA subscription mode + * @param cdmaSubscriptionType one of CDMA_SUBSCRIPTION_* + * @param response is callback message + */ + void setCdmaSubscription(int cdmaSubscriptionType, Message response); + + /** + * Set the TTY mode for the CDMA phone + * + * @param enable is true to enable, false to disable + * @param response is callback message + */ + void setTTYModeEnabled(boolean enable, Message response); + + /** + * 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. + * + * @param response is callback message + */ + void queryTTYModeEnabled(Message response); + + /** + * Setup a packet data connection On successful completion, the result + * message will return the following: [0] indicating PDP CID, which is + * generated by RIL. This Connection ID is used in both GSM/UMTS and CDMA + * modes [1] indicating the network interface name for GSM/UMTS or CDMA [2] + * indicating the IP address for this interface for GSM/UMTS and NULL in the + * case of CDMA + * + * @param radioTechnology + * indicates whether to setup connection on radio technology CDMA + * (0) or GSM/UMTS (1) + * @param profile + * Profile Number or NULL to indicate default profile + * @param apn + * the APN to connect to if radio technology is GSM/UMTS. + * Otherwise null for CDMA. + * @param user + * the username for APN, or NULL + * @param password + * the password for APN, or NULL + * @param result + * Callback message + */ + public void setupDataCall(String radioTechnology, String profile, String apn, + String user, String password, Message result); + + /** + * Deactivate packet data connection + * + * @param cid + * The connection ID + * @param result + * Callback message is empty on completion + */ + public void deactivateDataCall(int cid, Message result); + + /** + * Activate or deactivate cell broadcast SMS. + * + * @param activate + * 0 = activate, 1 = deactivate + * @param result + * Callback message is empty on completion + */ + public void activateCdmaBroadcastSms(int activate, Message result); + + /** + * Configure cdma cell broadcast SMS. + * + * @param result + * Callback message is empty on completion + */ + public void setCdmaBroadcastConfig(int[] configValuesArray, Message result); + + /** + * Query the current configuration of cdma cell broadcast SMS. + * + * @param result + * Callback message contains the configuration from the modem on completion + */ + public void getCdmaBroadcastConfig(Message result); } diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java index ead49bf..86ceb89 100644 --- a/telephony/java/com/android/internal/telephony/Connection.java +++ b/telephony/java/com/android/internal/telephony/Connection.java @@ -19,8 +19,8 @@ package com.android.internal.telephony; /** * {@hide} */ -public abstract class Connection -{ +public abstract class Connection { + // Number presentation type for caller id display public static int PRESENTATION_ALLOWED = 1; // normal public static int PRESENTATION_RESTRICTED = 2; // block by user @@ -42,7 +42,7 @@ public abstract class Connection INCOMING_REJECTED, /* an incoming call that was rejected */ POWER_OFF, /* radio is turned off explicitly */ OUT_OF_SERVICE, /* out of service */ - SIM_ERROR, /* No SIM, SIM locked, or other SIM error */ + 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 */ @@ -54,7 +54,7 @@ public abstract class Connection /* Instance Methods */ - /** + /** * Gets address (e.g., phone number) associated with connection * TODO: distinguish reasons for unavailablity * @@ -92,7 +92,7 @@ public abstract class Connection public abstract long getDisconnectTime(); /** - * returns the number of milliseconds the call has been connected, + * returns the number of milliseconds the call has been connected, * or 0 if the call has never connected. * If the call is still connected, then returns the elapsed * time since connect @@ -113,8 +113,8 @@ public abstract class Connection public abstract DisconnectCause getDisconnectCause(); /** - * Returns true of this connection originated elsewhere - * ("MT" or mobile terminated; another party called this terminal) + * Returns true of this connection originated elsewhere + * ("MT" or mobile terminated; another party called this terminal) * or false if this call originated here (MO or mobile originated) */ public abstract boolean isIncoming(); @@ -122,32 +122,30 @@ public abstract class Connection /** * If this Connection is connected, then it is associated with * a Call. - * + * * Returns getCall().getState() or Call.State.IDLE if not * connected */ - public Call.State getState() - { + public Call.State getState() { Call c; c = getCall(); - if (c == null) { + if (c == null) { return Call.State.IDLE; } else { return c.getState(); } } - + /** * isAlive() - * + * * @return true if the connection isn't disconnected * (could be active, holding, ringing, dialing, etc) */ public boolean - isAlive() - { + isAlive() { return getState().isAlive(); } @@ -155,29 +153,26 @@ public abstract class Connection * Returns true if Connection is connected and is INCOMING or WAITING */ public boolean - isRinging() - { + isRinging() { return getState().isRinging(); } /** - * + * * @return the userdata set in setUserData() */ - public Object getUserData() - { + public Object getUserData() { return userData; } /** - * + * * @param userdata user can store an any userdata in the Connection object. */ - public void setUserData(Object userdata) - { + public void setUserData(Object userdata) { this.userData = userdata; } - + /** * Hangup individual Connection */ @@ -191,16 +186,16 @@ public abstract class Connection public abstract void separate() throws CallStateException; public enum PostDialState { - NOT_STARTED, /* The post dial string playback hasn't - been started, or this call is not yet + NOT_STARTED, /* The post dial string playback hasn't + been started, or this call is not yet connected, or this is an incoming call */ STARTED, /* The post dial string playback has begun */ - WAIT, /* The post dial string playback is waiting for a + WAIT, /* The post dial string playback is waiting for a call to proceedAfterWaitChar() */ - WILD, /* The post dial string playback is waiting for a + 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() */ } @@ -215,7 +210,7 @@ public abstract class Connection /** * See Phone.setOnPostDialWaitCharacter() */ - + public abstract void proceedAfterWaitChar(); /** @@ -232,5 +227,5 @@ public abstract class Connection * @return one of PRESENTATION_* */ public abstract int getNumberPresentation(); - + } diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java new file mode 100644 index 0000000..6e9d1ab --- /dev/null +++ b/telephony/java/com/android/internal/telephony/DataConnection.java @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +/** + * {@hide} + */ +public abstract class DataConnection extends Handler { + + // the inherited class + + public enum State { + ACTIVE, /* has active data connection */ + ACTIVATING, /* during connecting process */ + INACTIVE; /* has empty data connection */ + + public String toString() { + switch (this) { + case ACTIVE: + return "active"; + case ACTIVATING: + return "setting up"; + default: + return "inactive"; + } + } + + public boolean isActive() { + return this == ACTIVE; + } + + public boolean isInactive() { + return this == INACTIVE; + } + } + + public enum FailCause { + NONE, + BAD_APN, + BAD_PAP_SECRET, + BARRED, + USER_AUTHENTICATION, + SERVICE_OPTION_NOT_SUPPORTED, + SERVICE_OPTION_NOT_SUBSCRIBED, + SIM_LOCKED, + RADIO_OFF, + NO_SIGNAL, + NO_DATA_PLAN, + RADIO_NOT_AVAILABLE, + SUSPENED_TEMPORARY, + RADIO_ERROR_RETRY, + UNKNOWN; + + public boolean isPermanentFail() { + return (this == RADIO_OFF); + } + + 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"; + case USER_AUTHENTICATION: + return "error user autentication"; + case SERVICE_OPTION_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"; + case RADIO_NOT_AVAILABLE: + return "radio not available"; + case SUSPENED_TEMPORARY: + return "suspend temporary"; + case RADIO_ERROR_RETRY: + return "transient radio error"; + default: + return "unknown data error"; + } + } + } + + // ***** Event codes + protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = 1; + protected static final int EVENT_GET_LAST_FAIL_DONE = 2; + protected static final int EVENT_LINK_STATE_CHANGED = 3; + protected static final int EVENT_DEACTIVATE_DONE = 4; + protected static final int EVENT_FORCE_RETRY = 5; + + //***** Tag IDs for EventLog + protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100; + + + //***** Member Variables + protected PhoneBase phone; + protected Message onConnectCompleted; + protected Message onDisconnect; + protected int cid; + protected String interfaceName; + protected String ipAddress; + protected String gatewayAddress; + protected String[] dnsServers; + protected State state; + protected long createTime; + protected long lastFailTime; + protected FailCause lastFailCause; + protected static final String NULL_IP = "0.0.0.0"; + Object userData; + + // receivedDisconnectReq is set when disconnect during activation + protected boolean receivedDisconnectReq; + + /* Instance Methods */ + protected abstract void onSetupConnectionCompleted(AsyncResult ar); + + protected abstract void onDeactivated(AsyncResult ar); + + protected abstract void disconnect(Message msg); + + protected abstract void notifyFail(FailCause cause, Message onCompleted); + + protected abstract void notifyDisconnect(Message msg); + + protected abstract void onLinkStateChanged(DataLink.LinkState linkState); + + protected abstract FailCause getFailCauseFromRequest(int rilCause); + + public abstract String toString(); + + protected abstract void log(String s); + + + //***** Constructor + protected DataConnection(PhoneBase phone) { + super(); + this.phone = phone; + onConnectCompleted = null; + onDisconnect = null; + this.cid = -1; + receivedDisconnectReq = false; + this.dnsServers = new String[2]; + + clearSettings(); + } + + protected void setHttpProxy(String httpProxy, String httpPort) { + if (httpProxy == null || httpProxy.length() == 0) { + phone.setSystemProperty("net.gprs.http-proxy", null); + return; + } + + if (httpPort == null || httpPort.length() == 0) { + httpPort = "8080"; // Default to port 8080 + } + + phone.setSystemProperty("net.gprs.http-proxy", + "http://" + httpProxy + ":" + httpPort + "/"); + } + + public String getInterface() { + return interfaceName; + } + + public String getIpAddress() { + return ipAddress; + } + + public String getGatewayAddress() { + return gatewayAddress; + } + + public String[] getDnsServers() { + return dnsServers; + } + + public void clearSettings() { + log("DataConnection.clearSettings()"); + + this.state = State.INACTIVE; + this.createTime = -1; + this.lastFailTime = -1; + this.lastFailCause = FailCause.NONE; + + receivedDisconnectReq = false; + onConnectCompleted = null; + interfaceName = null; + ipAddress = null; + gatewayAddress = null; + dnsServers[0] = null; + dnsServers[1] = null; + } + + protected void onGetLastFailCompleted(AsyncResult ar) { + if (receivedDisconnectReq) { + // Don't bother reporting the error if there's already a + // pending disconnect request, since DataConnectionTracker + // has already updated its state. + notifyDisconnect(onDisconnect); + } else { + FailCause cause = FailCause.UNKNOWN; + + if (ar.exception == null) { + int rilFailCause = ((int[]) (ar.result))[0]; + cause = getFailCauseFromRequest(rilFailCause); + } + notifyFail(cause, onConnectCompleted); + } + } + + protected void onForceRetry() { + if (receivedDisconnectReq) { + notifyDisconnect(onDisconnect); + } else { + notifyFail(FailCause.RADIO_ERROR_RETRY, onConnectCompleted); + } + } + + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + + log("DataConnection.handleMessage()"); + + switch (msg.what) { + + case EVENT_SETUP_DATA_CONNECTION_DONE: + onSetupConnectionCompleted((AsyncResult) msg.obj); + break; + + case EVENT_FORCE_RETRY: + onForceRetry(); + break; + + case EVENT_GET_LAST_FAIL_DONE: + onGetLastFailCompleted((AsyncResult) msg.obj); + break; + + case EVENT_LINK_STATE_CHANGED: + ar = (AsyncResult) msg.obj; + DataLink.LinkState ls = (DataLink.LinkState) ar.result; + onLinkStateChanged(ls); + break; + + case EVENT_DEACTIVATE_DONE: + onDeactivated((AsyncResult) msg.obj); + break; + } + } + + public State getState() { + log("DataConnection.getState()"); + return state; + } + + public long getConnectionTime() { + log("DataConnection.getConnectionTime()"); + return createTime; + } + + public long getLastFailTime() { + log("DataConnection.getLastFailTime()"); + return lastFailTime; + } + + public FailCause getLastFailCause() { + log("DataConnection.getLastFailCause()"); + return lastFailCause; + } +} diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java new file mode 100644 index 0000000..5b826b2 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.app.PendingIntent; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.INetStatService; +import android.os.Message; +import android.os.RemoteException; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; +import android.util.Log; + +/** + * {@hide} + * + */ +public abstract class DataConnectionTracker extends Handler { + private static final boolean DBG = true; + + /** + * IDLE: ready to start data connection setup, default state + * INITING: state of issued setupDefaultPDP() but not finish yet + * CONNECTING: state of issued startPppd() but not finish yet + * SCANNING: data connection fails with one apn but other apns are available + * ready to start data connection on other apns (before INITING) + * CONNECTED: IP connection is setup + * DISCONNECTING: Connection.disconnect() has been called, but PDP + * context is not yet deactivated + * FAILED: data connection fail for all apns settings + * + * getDataConnectionState() maps State to DataState + * FAILED or IDLE : DISCONNECTED + * INITING or CONNECTING or SCANNING: CONNECTING + * CONNECTED : CONNECTED or DISCONNECTING + */ + public enum State { + IDLE, + INITING, + CONNECTING, + SCANNING, + CONNECTED, + DISCONNECTING, + FAILED + } + + public enum Activity { + NONE, + DATAIN, + DATAOUT, + DATAINANDOUT + } + + //***** Event Codes + protected static final int EVENT_DATA_SETUP_COMPLETE = 1; + protected static final int EVENT_RADIO_AVAILABLE = 3; + protected static final int EVENT_RECORDS_LOADED = 4; + protected static final int EVENT_TRY_SETUP_DATA = 5; + protected static final int EVENT_DATA_STATE_CHANGED = 6; + protected static final int EVENT_POLL_PDP = 7; + protected static final int EVENT_GET_PDP_LIST_COMPLETE = 11; + protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 12; + protected static final int EVENT_VOICE_CALL_STARTED = 14; + protected static final int EVENT_VOICE_CALL_ENDED = 15; + protected static final int EVENT_GPRS_DETACHED = 19; + protected static final int EVENT_LINK_STATE_CHANGED = 20; + protected static final int EVENT_ROAMING_ON = 21; + protected static final int EVENT_ROAMING_OFF = 22; + protected static final int EVENT_ENABLE_NEW_APN = 23; + protected static final int EVENT_RESTORE_DEFAULT_APN = 24; + protected static final int EVENT_DISCONNECT_DONE = 25; + protected static final int EVENT_GPRS_ATTACHED = 26; + protected static final int EVENT_START_NETSTAT_POLL = 27; + protected static final int EVENT_START_RECOVERY = 28; + protected static final int EVENT_APN_CHANGED = 29; + protected static final int EVENT_CDMA_DATA_DETACHED = 30; + 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; + + //***** 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; + + /** 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; + /** Default max failure count before attempting to network re-registration. */ + protected final int DEFAULT_MAX_PDP_RESET_FAIL = 3; + + /** + * After detecting a potential connection problem, this is the max number + * of subsequent polls before attempting a radio reset. At this point, + * poll interval is 5 seconds (POLL_NETSTAT_SLOW_MILLIS), so set this to + * poll for about 2 more minutes. + */ + protected static final int NO_RECV_POLL_LIMIT = 24; + + // 1 sec. default polling interval when screen is on. + protected static final int POLL_NETSTAT_MILLIS = 1000; + // 10 min. default polling interval when screen is off. + protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10; + // 2 min for round trip time + protected static final int POLL_LONGEST_RTT = 120 * 1000; + // 10 for packets without ack + protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10; + // how long to wait before switching back to default APN + protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000; + // system property that can override the above value + protected static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore"; + // represents an invalid IP address + protected static final String NULL_IP = "0.0.0.0"; + + + // member variables + protected PhoneBase phone; + protected Activity activity = Activity.NONE; + protected State state = State.IDLE; + protected Handler mDataConnectionTracker = null; + + + protected INetStatService netstat; + protected long txPkts, rxPkts, sentSinceLastRecv; + protected int netStatPollPeriod; + protected int mNoRecvPollCount = 0; + protected boolean netStatPollEnabled = false; + + // wifi connection status will be updated by sticky intent + protected boolean mIsWifiConnected = false; + + /** Intent sent when the reconnect alarm fires. */ + protected PendingIntent mReconnectIntent = null; + + /** CID of active data connection */ + protected int cidActive; + + /** + * Default constructor + */ + protected DataConnectionTracker(PhoneBase phone) { + super(); + this.phone = phone; + } + + public Activity getActivity() { + return activity; + } + + public State getState() { + return state; + } + + public String getStateInString() { + switch (state) { + case IDLE: return "IDLE"; + case INITING: return "INIT"; + case CONNECTING: return "CING"; + case SCANNING: return "SCAN"; + case CONNECTED: return "CNTD"; + case DISCONNECTING: return "DING"; + case FAILED: return "FAIL"; + default: return "ERRO"; + } + } + + /** + * The data connection is expected to be setup while device + * 1. has Icc card + * 2. registered for data service + * 3. user doesn't explicitly disable data service + * 4. wifi is not on + * + * @return false while no data connection if all above requirements are met. + */ + public abstract boolean isDataConnectionAsDesired(); + + //The data roaming setting is now located in the shared preferences. + // See if the requested preference value is the same as that stored in + // the shared values. If it is not, then update it. + public void setDataOnRoamingEnabled(boolean enabled) { + if (getDataOnRoamingEnabled() != enabled) { + Settings.Secure.putInt(phone.getContext().getContentResolver(), + Settings.Secure.DATA_ROAMING, enabled ? 1 : 0); + } + Message roamingMsg = phone.getServiceState().getRoaming() ? + obtainMessage(EVENT_ROAMING_ON) : obtainMessage(EVENT_ROAMING_OFF); + sendMessage(roamingMsg); + } + + //Retrieve the data roaming setting from the shared preferences. + public boolean getDataOnRoamingEnabled() { + try { + return Settings.Secure.getInt(phone.getContext().getContentResolver(), + Settings.Secure.DATA_ROAMING) > 0; + } catch (SettingNotFoundException snfe) { + return false; + } + } + + // abstract handler methods + protected abstract void onTrySetupData(); + protected abstract void onRoamingOff(); + protected abstract void onRoamingOn(); + protected abstract void onRadioAvailable(); + protected abstract void onRadioOffOrNotAvailable(); + protected abstract void onDataSetupComplete(AsyncResult ar); + protected abstract void onDisconnectDone(AsyncResult ar); + protected abstract void onVoiceCallStarted(); + protected abstract void onVoiceCallEnded(); + + //***** Overridden from Handler + public void handleMessage (Message msg) { + switch (msg.what) { + + case EVENT_TRY_SETUP_DATA: + onTrySetupData(); + break; + + case EVENT_ROAMING_OFF: + onRoamingOff(); + break; + + case EVENT_ROAMING_ON: + onRoamingOn(); + break; + + case EVENT_RADIO_AVAILABLE: + onRadioAvailable(); + break; + + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: + onRadioOffOrNotAvailable(); + break; + + case EVENT_DATA_SETUP_COMPLETE: + cidActive = msg.arg1; + onDataSetupComplete((AsyncResult) msg.obj); + break; + + case EVENT_DISCONNECT_DONE: + onDisconnectDone((AsyncResult) msg.obj); + break; + + case EVENT_VOICE_CALL_STARTED: + onVoiceCallStarted(); + break; + + case EVENT_VOICE_CALL_ENDED: + onVoiceCallEnded(); + break; + + default: + Log.e("DATA", "Unidentified event = " + msg.what); + break; + } + } + + /** + * 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. + */ + public abstract boolean getDataEnabled(); + + /** + * Report on whether data connectivity is enabled + * @return {@code false} if data connectivity has been explicitly disabled, + * {@code true} otherwise. + */ + public abstract boolean getAnyDataEnabled(); + + /** + * Prevent mobile data connections from being established, + * or once again allow mobile data connections. If the state + * toggles, then either tear down or set up data, as + * appropriate to match the new state. + * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data + * @return {@code true} if the operation succeeded + */ + public abstract boolean setDataEnabled(boolean enable); + + protected abstract void startNetStatPoll(); + + protected abstract void stopNetStatPoll(); + + protected abstract void restartRadio(); + + protected abstract void log(String s); +} diff --git a/telephony/java/com/android/internal/telephony/gsm/DataLink.java b/telephony/java/com/android/internal/telephony/DataLink.java index b822ab4..8132d91 100644 --- a/telephony/java/com/android/internal/telephony/gsm/DataLink.java +++ b/telephony/java/com/android/internal/telephony/DataLink.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.os.Handler; import android.os.Registrant; @@ -24,14 +24,13 @@ import android.os.Registrant; * * {@hide} */ -abstract class DataLink extends Handler implements DataLinkInterface { +public abstract class DataLink extends Handler implements DataLinkInterface { /** Registrant for link status change notifications. */ - Registrant mLinkChangeRegistrant; - + protected Registrant mLinkChangeRegistrant; protected DataConnectionTracker dataConnection; - DataLink(DataConnectionTracker dc) { + protected DataLink(DataConnectionTracker dc) { dataConnection = dc; } diff --git a/telephony/java/com/android/internal/telephony/gsm/DataLinkInterface.java b/telephony/java/com/android/internal/telephony/DataLinkInterface.java index bca63f2..e8148a8 100644 --- a/telephony/java/com/android/internal/telephony/gsm/DataLinkInterface.java +++ b/telephony/java/com/android/internal/telephony/DataLinkInterface.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.database.Cursor; import android.os.Handler; @@ -24,7 +24,7 @@ import android.os.Handler; * * {@hide} */ -interface DataLinkInterface { +public interface DataLinkInterface { /** * Link state enumeration. * @@ -35,21 +35,21 @@ interface DataLinkInterface { LINK_DOWN, LINK_EXITED } - + /** Normal exit */ final static int EXIT_OK = 0; /** Open failed */ final static int EXIT_OPEN_FAILED = 7; - + /** * Sets the handler for link state change events. - * + * * @param h Handler * @param what User-defined message code * @param obj User object */ void setOnLinkChange(Handler h, int what, Object obj); - + /** * Sets up the data link. */ @@ -59,14 +59,14 @@ interface DataLinkInterface { * Tears down the data link. */ void disconnect(); - + /** - * Returns the exit code for a data link failure. + * Returns the exit code for a data link failure. * * @return exit code */ int getLastLinkExitCode(); - + /** * Sets password information that may be required by the data link * (eg, PAP secrets). diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java index 81ef623..79b4afe 100644 --- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -33,7 +33,7 @@ public class DefaultPhoneNotifier implements PhoneNotifier { private static final boolean DBG = true; private ITelephonyRegistry mRegistry; - /*package*/ + /*package*/ DefaultPhoneNotifier() { mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( "telephony.registry")); @@ -94,7 +94,7 @@ public class DefaultPhoneNotifier implements PhoneNotifier { public void notifyDataConnection(Phone sender, String reason) { try { - mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()), + mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()), sender.isDataConnectivityPossible(), reason, sender.getActiveApn(), sender.getInterfaceName(null)); } catch (RemoteException ex) { @@ -119,7 +119,7 @@ public class DefaultPhoneNotifier implements PhoneNotifier { // system process is dead } } - + private void log(String s) { Log.d(LOG_TAG, "[PhoneNotifier] " + s); } diff --git a/telephony/java/com/android/internal/telephony/gsm/DriverCall.java b/telephony/java/com/android/internal/telephony/DriverCall.java index aab885a..6c4e71f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/DriverCall.java +++ b/telephony/java/com/android/internal/telephony/DriverCall.java @@ -14,9 +14,8 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; -import com.android.internal.telephony.*; - +package com.android.internal.telephony; +//import com.android.internal.telephony.*; import android.util.Log; import java.lang.Comparable; import android.telephony.PhoneNumberUtils; @@ -24,10 +23,9 @@ import android.telephony.PhoneNumberUtils; /** * {@hide} */ -public class DriverCall implements Comparable -{ - static final String LOG_TAG = "GSM"; - +public class DriverCall implements Comparable { + static final String LOG_TAG = "RILB"; + public enum State { ACTIVE, HOLDING, @@ -48,11 +46,10 @@ public class DriverCall implements Comparable public boolean isVoice; public int als; public int numberPresentation; - + /** returns null on error */ static DriverCall - fromCLCCLine(String line) - { + fromCLCCLine(String line) { DriverCall ret = new DriverCall(); //+CLCC: 1,0,2,0,0,\"+18005551212\",145 @@ -66,10 +63,10 @@ public class DriverCall implements Comparable ret.isVoice = (0 == p.nextInt()); ret.isMpty = p.nextBoolean(); - + // use ALLOWED as default presentation while parsing CLCC ret.numberPresentation = Connection.PRESENTATION_ALLOWED; - + if (p.hasMore()) { // Some lame implementations return strings // like "NOT AVAILABLE" in the CLCC line @@ -98,13 +95,11 @@ public class DriverCall implements Comparable } public - DriverCall() - { + DriverCall() { } public String - toString() - { + toString() { return "id=" + index + "," + (isMT ? "mt" : "mo") + "," + state + "," @@ -114,8 +109,7 @@ public class DriverCall implements Comparable } public static State - stateFromCLCC(int state) throws ATParseEx - { + stateFromCLCC(int state) throws ATParseEx { switch(state) { case 0: return State.ACTIVE; case 1: return State.HOLDING; @@ -127,7 +121,7 @@ public class DriverCall implements Comparable throw new ATParseEx("illegal call state " + state); } } - + public static int presentationFromCLIP(int cli) throws ATParseEx { @@ -141,12 +135,11 @@ public class DriverCall implements Comparable } } - //***** Comparable Implementation + //***** Comparable Implementation /** For sorting by index */ public int - compareTo (Object o) - { + compareTo (Object o) { DriverCall dc; dc = (DriverCall)o; diff --git a/telephony/java/com/android/internal/telephony/gsm/EncodeException.java b/telephony/java/com/android/internal/telephony/EncodeException.java index d546cef..0436ba0 100644 --- a/telephony/java/com/android/internal/telephony/gsm/EncodeException.java +++ b/telephony/java/com/android/internal/telephony/EncodeException.java @@ -14,25 +14,21 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * {@hide} */ -public class EncodeException extends Exception -{ - public EncodeException() - { +public class EncodeException extends Exception { + public EncodeException() { super(); } - - public EncodeException(String s) - { + + public EncodeException(String s) { super(s); } - public EncodeException(char c) - { + public EncodeException(char c) { super("Unencodable char: '" + c + "'"); } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java index df34897..8f4c69c 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java +++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; -import android.telephony.gsm.SmsMessage; +import android.telephony.SmsMessage; import android.util.SparseIntArray; import android.util.Log; @@ -28,16 +28,15 @@ import android.util.Log; * * {@hide} */ -public class GsmAlphabet -{ +public class GsmAlphabet { static final String LOG_TAG = "GSM"; - + //***** Constants /** - * This escapes extended characters, and when present indicates that the + * This escapes extended characters, and when present indicates that the * following character should * be looked up in the "extended" table * @@ -55,8 +54,7 @@ public class GsmAlphabet * should follow GSM_EXTENDED_ESCAPE in the GSM alphabet string */ public static int - charToGsm(char c) - { + charToGsm(char c) { try { return charToGsm(c, false); } catch (EncodeException ex) { @@ -67,7 +65,7 @@ public class GsmAlphabet /** * char to GSM alphabet char - * @param throwException If true, throws EncodeException on invalid char. + * @param throwException If true, throws EncodeException on invalid char. * If false, returns GSM alphabet ' ' char. * * Returns GSM_EXTENDED_ESCAPE if this character is in the extended table @@ -76,10 +74,9 @@ public class GsmAlphabet */ public static int - charToGsm(char c, boolean throwException) throws EncodeException - { + charToGsm(char c, boolean throwException) throws EncodeException { int ret; - + ret = charToGsm.get(c, -1); if (ret == -1) { @@ -99,7 +96,7 @@ public class GsmAlphabet return ret; } - + /** * char to extended GSM alphabet char @@ -110,10 +107,9 @@ public class GsmAlphabet * */ public static int - charToGsmExtended(char c) - { + charToGsmExtended(char c) { int ret; - + ret = charToGsmExtended.get(c, -1); if (ret == -1) { @@ -124,34 +120,32 @@ public class GsmAlphabet } /** - * Converts a character in the GSM alphabet into a char + * Converts a character in the GSM alphabet into a char * * if GSM_EXTENDED_ESCAPE is passed, 0xffff is returned. In this case, - * the following character in the stream should be decoded with + * the following character in the stream should be decoded with * gsmExtendedToChar() * * If an unmappable value is passed (one greater than 127), ' ' is returned */ public static char - gsmToChar(int gsmChar) - { + gsmToChar(int gsmChar) { return (char)gsmToChar.get(gsmChar, ' '); } - + /** - * Converts a character in the extended GSM alphabet into a char + * Converts a character in the extended GSM alphabet into a char * * if GSM_EXTENDED_ESCAPE is passed, ' ' is returned since no second * extension page has yet been defined (see Note 1 in table 6.2.1.1 of * TS 23.038 v7.00) - * + * * If an unmappable value is passed , ' ' is returned */ public static char - gsmExtendedToChar(int gsmChar) - { + gsmExtendedToChar(int gsmChar) { int ret; ret = gsmExtendedToChar.get(gsmChar, -1); @@ -205,7 +199,7 @@ public class GsmAlphabet } /** - * Converts a String into a byte array containing + * Converts a String into a byte array containing * the 7-bit packed GSM Alphabet representation of the string. * * Unencodable chars are encoded as spaces @@ -224,7 +218,7 @@ public class GsmAlphabet } /** - * Converts a String into a byte array containing + * Converts a String into a byte array containing * the 7-bit packed GSM Alphabet representation of the string. * * Byte 0 in the returned byte array is the count of septets used @@ -238,7 +232,7 @@ public class GsmAlphabet * enforced maximum. * @param startingBitOffset the number of padding bits to put before * the start of the first septet at the begining of the array - * @param throwException If true, throws EncodeException on invalid char. + * @param throwException If true, throws EncodeException on invalid char. * If false, replaces unencodable char with GSM alphabet space char. * * @throws EncodeException if String is too large to encode @@ -294,27 +288,26 @@ public class GsmAlphabet * @param bitOffset the bit offset that the septet should be packed at * (septet index * 7) */ - private static void - packSmsChar(byte[] packedChars, int bitOffset, int value) - { + private static void + packSmsChar(byte[] packedChars, int bitOffset, int value) { int byteOffset = bitOffset / 8; int shift = bitOffset % 8; packedChars[++byteOffset] |= value << shift; if (shift > 1) { - packedChars[++byteOffset] = (byte)(value >> (8 - shift)); - } + packedChars[++byteOffset] = (byte)(value >> (8 - shift)); + } } /** - * Convert a GSM alphabet 7 bit packed string (SMS string) into a + * Convert a GSM alphabet 7 bit packed string (SMS string) into a * {@link java.lang.String}. * * See TS 23.038 6.1.2.1 for SMS Character Packing * * @param pdu the raw data from the pdu - * @param offset the byte offset of + * @param offset the byte offset of * @param lengthSeptets string length in septets, not bytes * @return String representation or null on decoding exception */ @@ -324,27 +317,26 @@ public class GsmAlphabet } /** - * Convert a GSM alphabet 7 bit packed string (SMS string) into a + * Convert a GSM alphabet 7 bit packed string (SMS string) into a * {@link java.lang.String}. * * See TS 23.038 6.1.2.1 for SMS Character Packing * * @param pdu the raw data from the pdu - * @param offset the byte offset of + * @param offset the byte offset of * @param lengthSeptets string length in septets, not bytes * @param numPaddingBits the number of padding bits before the start of the * string in the first byte * @return String representation or null on decoding exception */ public static String gsm7BitPackedToString(byte[] pdu, int offset, - int lengthSeptets, int numPaddingBits) - { + int lengthSeptets, int numPaddingBits) { StringBuilder ret = new StringBuilder(lengthSeptets); boolean prevCharWasEscape; - + try { prevCharWasEscape = false; - + for (int i = 0 ; i < lengthSeptets ; i++) { int bitOffset = (7 * i) + numPaddingBits; @@ -381,15 +373,14 @@ public class GsmAlphabet /** - * Convert a GSM alphabet string that's stored in 8-bit unpacked + * Convert a GSM alphabet string that's stored in 8-bit unpacked * format (as it often appears in SIM records) into a String * * Field may be padded with trailing 0xff's. The decode stops * at the first 0xff encountered. */ public static String - gsm8BitUnpackedToString(byte[] data, int offset, int length) - { + gsm8BitUnpackedToString(byte[] data, int offset, int length) { boolean prevWasEscape; StringBuilder ret = new StringBuilder(length); @@ -420,8 +411,8 @@ public class GsmAlphabet prevWasEscape = false; } } - - return ret.toString(); + + return ret.toString(); } /** @@ -429,8 +420,7 @@ public class GsmAlphabet * array */ public static byte[] - stringToGsm8BitPacked(String s) - { + stringToGsm8BitPacked(String s) { byte[] ret; int septets = 0; @@ -452,15 +442,14 @@ public class GsmAlphabet * * Field is padded with 0xff's, string is truncated if necessary */ - + public static void - stringToGsm8BitUnpackedField(String s, byte dest[], int offset, int length) - { + stringToGsm8BitUnpackedField(String s, byte dest[], int offset, int length) { int outByteIndex = offset; // Septets are stored in byte-aligned octets for (int i = 0, sz = s.length() - ; i < sz && (outByteIndex - offset) < length + ; i < sz && (outByteIndex - offset) < length ; i++ ) { char c = s.charAt(i); @@ -475,7 +464,7 @@ public class GsmAlphabet dest[outByteIndex++] = GSM_EXTENDED_ESCAPE; - v = GsmAlphabet.charToGsmExtended(c); + v = GsmAlphabet.charToGsmExtended(c); } dest[outByteIndex++] = (byte)v; @@ -492,8 +481,7 @@ public class GsmAlphabet * needed to represent this character. Counts unencodable char as 1 septet. */ public static int - countGsmSeptets(char c) - { + countGsmSeptets(char c) { try { return countGsmSeptets(c, false); } catch (EncodeException ex) { @@ -509,21 +497,20 @@ public class GsmAlphabet * char. Otherwise, counts invalid char as 1 septet */ public static int - countGsmSeptets(char c, boolean throwsException) throws EncodeException - { - if (charToGsm.get(c, -1) != -1) { - return 1; - } - - if (charToGsmExtended.get(c, -1) != -1) { - return 2; - } + countGsmSeptets(char c, boolean throwsException) throws EncodeException { + if (charToGsm.get(c, -1) != -1) { + return 1; + } + + if (charToGsmExtended.get(c, -1) != -1) { + return 2; + } if (throwsException) { throw new EncodeException(c); - } else { - // count as a space char - return 1; + } else { + // count as a space char + return 1; } } @@ -532,8 +519,7 @@ public class GsmAlphabet * needed to represent this string. Counts unencodable char as 1 septet. */ public static int - countGsmSeptets(CharSequence s) - { + countGsmSeptets(CharSequence s) { try { return countGsmSeptets(s, false); } catch (EncodeException ex) { @@ -549,8 +535,7 @@ public class GsmAlphabet * char. Otherwise, counts invalid char as 1 septet */ public static int - countGsmSeptets(CharSequence s, boolean throwsException) throws EncodeException - { + countGsmSeptets(CharSequence s, boolean throwsException) throws EncodeException { int charIndex = 0; int sz = s.length(); int count = 0; @@ -559,9 +544,9 @@ public class GsmAlphabet count += countGsmSeptets(s.charAt(charIndex), throwsException); charIndex++; } - + return count; - } + } /** * Returns the index into <code>s</code> of the first character @@ -623,7 +608,7 @@ public class GsmAlphabet * @return index of first character that won't fit, or the length * of the entire string if everything fits */ - public static int + public static int findLimitIndex(String s, int start, int limit, int encodingType) throws EncodeException { if (encodingType == SmsMessage.ENCODING_7BIT) { return findGsmSeptetLimitIndex(s, start, limit); @@ -643,10 +628,10 @@ public class GsmAlphabet private static final SparseIntArray gsmToChar = new SparseIntArray(); private static final SparseIntArray charToGsmExtended = new SparseIntArray(); private static final SparseIntArray gsmExtendedToChar = new SparseIntArray(); - + static { int i = 0; - + charToGsm.put('@', i++); charToGsm.put('\u00a3', i++); charToGsm.put('$', i++); @@ -663,7 +648,7 @@ public class GsmAlphabet charToGsm.put('\r', i++); charToGsm.put('\u00c5', i++); charToGsm.put('\u00e5', i++); - + charToGsm.put('\u0394', i++); charToGsm.put('_', i++); charToGsm.put('\u03a6', i++); @@ -680,7 +665,7 @@ public class GsmAlphabet charToGsm.put('\u00e6', i++); charToGsm.put('\u00df', i++); charToGsm.put('\u00c9', i++); - + charToGsm.put(' ', i++); charToGsm.put('!', i++); charToGsm.put('"', i++); @@ -697,7 +682,7 @@ public class GsmAlphabet charToGsm.put('-', i++); charToGsm.put('.', i++); charToGsm.put('/', i++); - + charToGsm.put('0', i++); charToGsm.put('1', i++); charToGsm.put('2', i++); @@ -714,7 +699,7 @@ public class GsmAlphabet charToGsm.put('=', i++); charToGsm.put('>', i++); charToGsm.put('?', i++); - + charToGsm.put('\u00a1', i++); charToGsm.put('A', i++); charToGsm.put('B', i++); @@ -731,7 +716,7 @@ public class GsmAlphabet charToGsm.put('M', i++); charToGsm.put('N', i++); charToGsm.put('O', i++); - + charToGsm.put('P', i++); charToGsm.put('Q', i++); charToGsm.put('R', i++); @@ -748,7 +733,7 @@ public class GsmAlphabet charToGsm.put('\u0147', i++); charToGsm.put('\u00dc', i++); charToGsm.put('\u00a7', i++); - + charToGsm.put('\u00bf', i++); charToGsm.put('a', i++); charToGsm.put('b', i++); @@ -765,7 +750,7 @@ public class GsmAlphabet charToGsm.put('m', i++); charToGsm.put('n', i++); charToGsm.put('o', i++); - + charToGsm.put('p', i++); charToGsm.put('q', i++); charToGsm.put('r', i++); @@ -782,8 +767,8 @@ public class GsmAlphabet charToGsm.put('\u00f1', i++); charToGsm.put('\u00fc', i++); charToGsm.put('\u00e0', i++); - - + + charToGsmExtended.put('\f', 10); charToGsmExtended.put('^', 20); charToGsmExtended.put('{', 40); @@ -794,12 +779,12 @@ public class GsmAlphabet charToGsmExtended.put(']', 62); charToGsmExtended.put('|', 64); charToGsmExtended.put('\u20ac', 101); - + int size = charToGsm.size(); for (int j=0; j<size; j++) { gsmToChar.put(charToGsm.valueAt(j), charToGsm.keyAt(j)); } - + size = charToGsmExtended.size(); for (int j=0; j<size; j++) { gsmExtendedToChar.put(charToGsmExtended.valueAt(j), charToGsmExtended.keyAt(j)); @@ -808,6 +793,6 @@ public class GsmAlphabet sGsmSpaceChar = charToGsm.get(' '); } - + } diff --git a/telephony/java/com/android/internal/telephony/gsm/ISimPhoneBook.aidl b/telephony/java/com/android/internal/telephony/IIccPhoneBook.aidl index 77033a7..f700dfe 100644 --- a/telephony/java/com/android/internal/telephony/gsm/ISimPhoneBook.aidl +++ b/telephony/java/com/android/internal/telephony/IIccPhoneBook.aidl @@ -14,27 +14,27 @@ ** limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; -import com.android.internal.telephony.gsm.AdnRecord; +import com.android.internal.telephony.AdnRecord; -import java.util.List; -/** Interface for applications to access the SIM phone book. + +/** Interface for applications to access the ICC phone book. * * <p>The following code snippet demonstrates a static method to - * retrieve the ISimPhoneBook interface from Android:</p> - * <pre>private static ISimPhoneBook getSimPhoneBookInterface() + * retrieve the IIccPhoneBook interface from Android:</p> + * <pre>private static IIccPhoneBook getSimPhoneBookInterface() throws DeadObjectException { IServiceManager sm = ServiceManagerNative.getDefault(); - ISimPhoneBook spb; - spb = ISimPhoneBook.Stub.asInterface(sm.getService("simphonebook")); + IIccPhoneBook spb; + spb = IIccPhoneBook.Stub.asInterface(sm.getService("iccphonebook")); return spb; } * </pre> */ -interface ISimPhoneBook { +interface IIccPhoneBook { /** * Loads the AdnRecords in efid and returns them as a diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl index 00cbaf9..e74b9e4 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl @@ -39,9 +39,9 @@ interface IPhoneSubInfo { String getSubscriberId(); /** - * Retrieves the serial number of the SIM, if applicable. + * Retrieves the serial number of the ICC, if applicable. */ - String getSimSerialNumber(); + String getIccSerialNumber(); /** * Retrieves the phone number string for line 1. @@ -53,13 +53,13 @@ interface IPhoneSubInfo { */ String getLine1AlphaTag(); - /** - * Retrieves the voice mail number. - */ + /** + * Retrieves the voice mail number. + */ String getVoiceMailNumber(); - /** - * Retrieves the alpha identifier associated with the voice mail number. - */ + /** + * Retrieves the alpha identifier associated with the voice mail number. + */ String getVoiceMailAlphaTag(); } diff --git a/telephony/java/com/android/internal/telephony/gsm/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl index 904a54e..257f1e6 100644 --- a/telephony/java/com/android/internal/telephony/gsm/ISms.aidl +++ b/telephony/java/com/android/internal/telephony/ISms.aidl @@ -14,20 +14,20 @@ ** limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.app.PendingIntent; -import com.android.internal.telephony.gsm.SmsRawData; +import com.android.internal.telephony.SmsRawData; -/** Interface for applications to access the SIM phone book. +/** Interface for applications to access the ICC phone book. * * <p>The following code snippet demonstrates a static method to - * retrieve the ISimSms interface from Android:</p> - * <pre>private static ISimSms getSimSmsInterface() + * retrieve the ISms interface from Android:</p> + * <pre>private static ISms getSmsInterface() throws DeadObjectException { IServiceManager sm = ServiceManagerNative.getDefault(); - ISimSms ss; - ss = ISimSms.Stub.asInterface(sm.getService("isms")); + ISms ss; + ss = ISms.Stub.asInterface(sm.getService("isms")); return ss; } * </pre> @@ -35,45 +35,45 @@ import com.android.internal.telephony.gsm.SmsRawData; interface ISms { /** - * Retrieves all messages currently stored on SIM. + * Retrieves all messages currently stored on ICC. * - * @return list of SmsRawData of all sms on SIM + * @return list of SmsRawData of all sms on ICC */ - List<SmsRawData> getAllMessagesFromSimEf(); + List<SmsRawData> getAllMessagesFromIccEf(); /** - * Update the specified message on the SIM. + * Update the specified message on the ICC. * * @param messageIndex record index of message to update - * @param newStatus new message status (STATUS_ON_SIM_READ, - * STATUS_ON_SIM_UNREAD, STATUS_ON_SIM_SENT, - * STATUS_ON_SIM_UNSENT, STATUS_ON_SIM_FREE) + * @param newStatus new message status (STATUS_ON_ICC_READ, + * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, + * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) * @param pdu the raw PDU to store * @return success or not * */ - boolean updateMessageOnSimEf(int messageIndex, int newStatus, + boolean updateMessageOnIccEf(int messageIndex, int newStatus, in byte[] pdu); /** - * Copy a raw SMS PDU to the SIM. + * Copy a raw SMS PDU to the ICC. * * @param pdu the raw PDU to store - * @param status message status (STATUS_ON_SIM_READ, STATUS_ON_SIM_UNREAD, - * STATUS_ON_SIM_SENT, STATUS_ON_SIM_UNSENT) + * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, + * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) * @return success or not * */ - boolean copyMessageToSimEf(int status, in byte[] pdu, in byte[] smsc); + boolean copyMessageToIccEf(int status, in byte[] pdu, in byte[] smsc); /** * Send a SMS * * @param smsc the SMSC to send the message through, or NULL for the - * defatult SMSC + * default SMSC * @param pdu the raw PDU to send * @param sentIntent if not NULL this <code>Intent</code> is - * broadcast when the message is sucessfully sent, or failed. + * broadcast when the message is successfully sent, or failed. * The result code will be <code>Activity.RESULT_OK<code> for success, * or one of these errors: * <code>RESULT_ERROR_GENERIC_FAILURE</code> @@ -88,13 +88,13 @@ interface ISms { /** * Send a multi-part text based SMS. - * + * * @param destinationAddress the address to send the message to * @param scAddress is the service center address or null to use * the current default SMSC * @param parts an <code>ArrayList</code> of strings that, in order, * comprise the original message - * @param sentIntents if not null, an <code>ArrayList</code> of + * @param sentIntents if not null, an <code>ArrayList</code> of * <code>PendingIntent</code>s (one for each message part) that is * broadcast when the corresponding message part has been sent. * The result code will be <code>Activity.RESULT_OK<code> for success, @@ -102,7 +102,7 @@ interface ISms { * <code>RESULT_ERROR_GENERIC_FAILURE</code> * <code>RESULT_ERROR_RADIO_OFF</code> * <code>RESULT_ERROR_NULL_PDU</code>. - * @param deliveryIntents if not null, an <code>ArrayList</code> of + * @param deliveryIntents if not null, an <code>ArrayList</code> of * <code>PendingIntent</code>s (one for each message part) that is * broadcast when the corresponding message part has been delivered * to the recipient. The raw pdu of the status report is in the diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 2b4195b..bab0603 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -21,7 +21,7 @@ import java.util.List; import android.telephony.NeighboringCellInfo; /** - * Interface used to interact with the phone. Mostly this is used by the + * Interface used to interact with the phone. Mostly this is used by the * TelephonyManager class. A few places are still using this directly. * Please clean them up if possible and use TelephonyManager insteadl. * @@ -135,7 +135,7 @@ interface ITelephony { /** * Cancels the missed calls notification. */ - void cancelMissedCallsNotification(); + void cancelMissedCallsNotification(); /** * Supply a pin to unlock the SIM. Blocks until a result is determined. @@ -147,7 +147,7 @@ interface ITelephony { /** * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated * without SEND (so <code>dial</code> is not appropriate). - * + * * @param dialString the MMI command to be executed. * @return true if MMI command is executed. */ @@ -213,4 +213,13 @@ interface ITelephony { int getCallState(); int getDataActivity(); int getDataState(); + + /** + * Returns the current active phone type as integer. + * Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE + * and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE + */ + int getActivePhoneType(); + } + diff --git a/telephony/java/com/android/internal/telephony/SimCard.java b/telephony/java/com/android/internal/telephony/IccCard.java index 03b366f..d7ad492 100644 --- a/telephony/java/com/android/internal/telephony/SimCard.java +++ b/telephony/java/com/android/internal/telephony/IccCard.java @@ -22,35 +22,34 @@ import android.os.Handler; /** * {@hide} */ -public interface SimCard -{ - /* The extra data for broacasting intent INTENT_SIM_STATE_CHANGE */ - static public final String INTENT_KEY_SIM_STATE = "ss"; - /* NOT_READY means the SIM interface is not ready (eg, radio is off or powering on) */ - static public final String INTENT_VALUE_SIM_NOT_READY = "NOT_READY"; - /* ABSENT means SIM is missing */ - static public final String INTENT_VALUE_SIM_ABSENT = "ABSENT"; - /* LOCKED means SIM is locked by pin or by network */ - static public final String INTENT_VALUE_SIM_LOCKED = "LOCKED"; - /* READY means SIM is ready to access */ - static public final String INTENT_VALUE_SIM_READY = "READY"; - /* IMSI means SIM IMSI is ready in property */ - static public final String INTENT_VALUE_SIM_IMSI = "IMSI"; - /* LOADED means all SIM records, including IMSI, are loaded */ - static public final String INTENT_VALUE_SIM_LOADED = "LOADED"; - /* The extra data for broacasting intent INTENT_SIM_STATE_CHANGE */ +public interface IccCard { + /* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */ + static public final String INTENT_KEY_ICC_STATE = "ss"; + /* NOT_READY means the ICC interface is not ready (eg, radio is off or powering on) */ + static public final String INTENT_VALUE_ICC_NOT_READY = "NOT_READY"; + /* ABSENT means ICC is missing */ + static public final String INTENT_VALUE_ICC_ABSENT = "ABSENT"; + /* LOCKED means ICC is locked by pin or by network */ + static public final String INTENT_VALUE_ICC_LOCKED = "LOCKED"; + /* READY means ICC is ready to access */ + static public final String INTENT_VALUE_ICC_READY = "READY"; + /* IMSI means ICC IMSI is ready in property */ + static public final String INTENT_VALUE_ICC_IMSI = "IMSI"; + /* LOADED means all ICC records, including IMSI, are loaded */ + static public final String INTENT_VALUE_ICC_LOADED = "LOADED"; + /* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */ static public final String INTENT_KEY_LOCKED_REASON = "reason"; - /* PIN means SIM is locked on PIN1 */ + /* PIN means ICC is locked on PIN1 */ static public final String INTENT_VALUE_LOCKED_ON_PIN = "PIN"; - /* PUK means SIM is locked on PUK1 */ + /* PUK means ICC is locked on PUK1 */ static public final String INTENT_VALUE_LOCKED_ON_PUK = "PUK"; - /* NETWORK means SIM is locked on NETWORK PERSONALIZATION */ + /* NETWORK means ICC is locked on NETWORK PERSONALIZATION */ static public final String INTENT_VALUE_LOCKED_NETWORK = "NETWORK"; /* - UNKNOWN is a transient state, for example, after uesr inputs sim pin under - PIN_REQUIRED state, the query for sim status returns UNKNOWN before it + UNKNOWN is a transient state, for example, after uesr inputs ICC pin under + PIN_REQUIRED state, the query for ICC status returns UNKNOWN before it turns to READY */ public enum State { @@ -73,7 +72,7 @@ public interface SimCard * Notifies handler of any transition into State.ABSENT */ void registerForAbsent(Handler h, int what, Object obj); - void unregisterForAbsent(Handler h); + void unregisterForAbsent(Handler h); /** * Notifies handler of any transition into State.isPinLocked() @@ -88,7 +87,7 @@ public interface SimCard void unregisterForNetworkLocked(Handler h); /** - * Supply the SIM PIN to the SIM + * Supply the ICC PIN to the ICC * * When the operation is complete, onComplete will be sent to it's * Handler. @@ -100,11 +99,11 @@ public interface SimCard * * If the supplied PIN is incorrect: * ((AsyncResult)onComplete.obj).exception != null - * && ((AsyncResult)onComplete.obj).exception + * && ((AsyncResult)onComplete.obj).exception * instanceof com.android.internal.telephony.gsm.CommandException) * && ((CommandException)(((AsyncResult)onComplete.obj).exception)) * .getCommandError() == CommandException.Error.PASSWORD_INCORRECT - * + * * */ @@ -114,30 +113,30 @@ public interface SimCard void supplyPuk2 (String puk2, String newPin2, Message onComplete); /** - * Check whether sim pin lock is enabled + * Check whether ICC pin lock is enabled * This is a sync call which returns the cached pin enabled state * - * @return true for sim locked enabled - * false for sim locked disabled + * @return true for ICC locked enabled + * false for ICC locked disabled */ - boolean getSimLockEnabled (); + boolean getIccLockEnabled (); /** - * Set the sim pin lock enabled or disabled + * Set the ICC pin lock enabled or disabled * When the operation is complete, onComplete will be sent to its handler * * @param enabled "true" for locked "false" for unlocked. - * @param password needed to change the sim pin state, aka. Pin1 + * @param password needed to change the ICC pin state, aka. Pin1 * @param onComplete * onComplete.obj will be an AsyncResult * ((AsyncResult)onComplete.obj).exception == null on success * ((AsyncResult)onComplete.obj).exception != null on fail */ - void setSimLockEnabled(boolean enabled, String password, Message onComplete); + void setIccLockEnabled(boolean enabled, String password, Message onComplete); /** - * Change the sim password used in sim pin lock + * Change the ICC password used in ICC pin lock * When the operation is complete, onComplete will be sent to its handler * * @param oldPassword is the old password @@ -147,33 +146,33 @@ public interface SimCard * ((AsyncResult)onComplete.obj).exception == null on success * ((AsyncResult)onComplete.obj).exception != null on fail */ - void changeSimLockPassword(String oldPassword, String newPassword, + void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete); /** - * Check whether sim fdn (fixed dialing number) is enabled + * Check whether ICC fdn (fixed dialing number) is enabled * This is a sync call which returns the cached pin enabled state * - * @return true for sim fdn enabled - * false for sim fdn disabled + * @return true for ICC fdn enabled + * false for ICC fdn disabled */ - boolean getSimFdnEnabled (); + boolean getIccFdnEnabled (); /** - * Set the sim fdn enabled or disabled + * Set the ICC fdn enabled or disabled * When the operation is complete, onComplete will be sent to its handler * * @param enabled "true" for locked "false" for unlocked. - * @param password needed to change the sim fdn enable, aka Pin2 + * @param password needed to change the ICC fdn enable, aka Pin2 * @param onComplete * onComplete.obj will be an AsyncResult * ((AsyncResult)onComplete.obj).exception == null on success * ((AsyncResult)onComplete.obj).exception != null on fail */ - void setSimFdnEnabled(boolean enabled, String password, Message onComplete); + void setIccFdnEnabled(boolean enabled, String password, Message onComplete); /** - * Change the sim password used in sim fdn enable + * Change the ICC password used in ICC fdn enable * When the operation is complete, onComplete will be sent to its handler * * @param oldPassword is the old password @@ -183,13 +182,13 @@ public interface SimCard * ((AsyncResult)onComplete.obj).exception == null on success * ((AsyncResult)onComplete.obj).exception != null on fail */ - void changeSimFdnPassword(String oldPassword, String newPassword, + void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete); void supplyNetworkDepersonalization (String pin, Message onComplete); /** - * Returns service provider name stored in SIM card. + * Returns service provider name stored in ICC card. * If there is no service provider name associated or the record is not * yet available, null will be returned <p> * @@ -199,7 +198,7 @@ public interface SimCard * * Also available via Android property "gsm.sim.operator.alpha" * - * @return Service Provider Name stored in SIM card + * @return Service Provider Name stored in ICC card * null if no service provider name associated or the record is not * yet available * diff --git a/telephony/java/com/android/internal/telephony/IccCardApplication.java b/telephony/java/com/android/internal/telephony/IccCardApplication.java new file mode 100644 index 0000000..9f60a6c --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccCardApplication.java @@ -0,0 +1,178 @@ +/* + * 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; + + +/** + * See also RIL_AppStatus in include/telephony/ril.h + * + * {@hide} + */ +public class IccCardApplication { + public enum AppType{ + APPTYPE_UNKNOWN, + APPTYPE_SIM, + APPTYPE_USIM, + APPTYPE_RUIM, + APPTYPE_CSIM + }; + + public enum AppState{ + APPSTATE_UNKNOWN, + APPSTATE_DETECTED, + APPSTATE_PIN, + APPSTATE_PUK, + APPSTATE_SUBSCRIPTION_PERSO, + APPSTATE_READY; + + boolean isPinRequired() { + return this == APPSTATE_PIN; + } + + boolean isPukRequired() { + return this == APPSTATE_PUK; + } + + boolean isSubscriptionPersoEnabled() { + return this == APPSTATE_SUBSCRIPTION_PERSO; + } + + boolean isAppReady() { + return this == APPSTATE_READY; + } + + boolean isAppNotReady() { + return this == APPSTATE_UNKNOWN || + this == APPSTATE_DETECTED; + } + }; + + public enum PersoSubState{ + PERSOSUBSTATE_UNKNOWN, + PERSOSUBSTATE_IN_PROGRESS, + PERSOSUBSTATE_READY, + PERSOSUBSTATE_SIM_NETWORK, + PERSOSUBSTATE_SIM_NETWORK_SUBSET, + PERSOSUBSTATE_SIM_CORPORATE, + PERSOSUBSTATE_SIM_SERVICE_PROVIDER, + PERSOSUBSTATE_SIM_SIM, + PERSOSUBSTATE_SIM_NETWORK_PUK, + PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK, + PERSOSUBSTATE_SIM_CORPORATE_PUK, + PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK, + PERSOSUBSTATE_SIM_SIM_PUK, + PERSOSUBSTATE_RUIM_NETWORK1, + PERSOSUBSTATE_RUIM_NETWORK2, + PERSOSUBSTATE_RUIM_HRPD, + PERSOSUBSTATE_RUIM_CORPORATE, + PERSOSUBSTATE_RUIM_SERVICE_PROVIDER, + PERSOSUBSTATE_RUIM_RUIM, + PERSOSUBSTATE_RUIM_NETWORK1_PUK, + PERSOSUBSTATE_RUIM_NETWORK2_PUK, + PERSOSUBSTATE_RUIM_HRPD_PUK, + PERSOSUBSTATE_RUIM_CORPORATE_PUK, + PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK, + PERSOSUBSTATE_RUIM_RUIM_PUK; + + boolean isPersoSubStateUnknown() { + return this == PERSOSUBSTATE_UNKNOWN; + } + }; + + public AppType app_type; + public AppState app_state; + // applicable only if app_state == RIL_APPSTATE_SUBSCRIPTION_PERSO + public PersoSubState perso_substate; + // null terminated string, e.g., from 0xA0, 0x00 -> 0x41, 0x30, 0x30, 0x30 */ + public String aid; + // null terminated string + public String app_label; + // applicable to USIM and CSIM + public int pin1_replaced; + public int pin1; + public int pin2; + + AppType AppTypeFromRILInt(int type) { + AppType newType; + /* RIL_AppType ril.h */ + switch(type) { + case 0: newType = AppType.APPTYPE_UNKNOWN; break; + case 1: newType = AppType.APPTYPE_SIM; break; + case 2: newType = AppType.APPTYPE_USIM; break; + case 3: newType = AppType.APPTYPE_RUIM; break; + case 4: newType = AppType.APPTYPE_CSIM; break; + default: + throw new RuntimeException( + "Unrecognized RIL_AppType: " +type); + } + return newType; + } + + AppState AppStateFromRILInt(int state) { + AppState newState; + /* RIL_AppState ril.h */ + switch(state) { + case 0: newState = AppState.APPSTATE_UNKNOWN; break; + case 1: newState = AppState.APPSTATE_DETECTED; break; + case 2: newState = AppState.APPSTATE_PIN; break; + case 3: newState = AppState.APPSTATE_PUK; break; + case 4: newState = AppState.APPSTATE_SUBSCRIPTION_PERSO; break; + case 5: newState = AppState.APPSTATE_READY; break; + default: + throw new RuntimeException( + "Unrecognized RIL_AppState: " +state); + } + return newState; + } + + PersoSubState PersoSubstateFromRILInt(int substate) { + PersoSubState newSubState; + /* RIL_PeroSubstate ril.h */ + switch(substate) { + case 0: newSubState = PersoSubState.PERSOSUBSTATE_UNKNOWN; break; + case 1: newSubState = PersoSubState.PERSOSUBSTATE_IN_PROGRESS; break; + case 2: newSubState = PersoSubState.PERSOSUBSTATE_READY; break; + case 3: newSubState = PersoSubState.PERSOSUBSTATE_SIM_NETWORK; break; + case 4: newSubState = PersoSubState.PERSOSUBSTATE_SIM_NETWORK_SUBSET; break; + case 5: newSubState = PersoSubState.PERSOSUBSTATE_SIM_CORPORATE; break; + case 6: newSubState = PersoSubState.PERSOSUBSTATE_SIM_SERVICE_PROVIDER; break; + case 7: newSubState = PersoSubState.PERSOSUBSTATE_SIM_SIM; break; + case 8: newSubState = PersoSubState.PERSOSUBSTATE_SIM_NETWORK_PUK; break; + case 9: newSubState = PersoSubState.PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK; break; + case 10: newSubState = PersoSubState.PERSOSUBSTATE_SIM_CORPORATE_PUK; break; + case 11: newSubState = PersoSubState.PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK; break; + case 12: newSubState = PersoSubState.PERSOSUBSTATE_SIM_SIM_PUK; break; + case 13: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK1; break; + case 14: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK2; break; + case 15: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_HRPD; break; + case 16: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_CORPORATE; break; + case 17: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_SERVICE_PROVIDER; break; + case 18: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_RUIM; break; + case 19: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK1_PUK; break; + case 20: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK2_PUK; break; + case 21: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_HRPD_PUK ; break; + case 22: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_CORPORATE_PUK; break; + case 23: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK; break; + case 24: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_RUIM_PUK; break; + default: + throw new RuntimeException( + "Unrecognized RIL_PersoSubstate: " +substate); + } + return newSubState; + } + +} diff --git a/telephony/java/com/android/internal/telephony/IccCardStatus.java b/telephony/java/com/android/internal/telephony/IccCardStatus.java new file mode 100644 index 0000000..b602b1c --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccCardStatus.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import java.util.ArrayList; + +/** + * See also RIL_CardStatus in include/telephony/ril.h + * + * {@hide} + */ +public class IccCardStatus { + static final int CARD_MAX_APPS = 8; + + public enum CardState { + CARDSTATE_ABSENT, + CARDSTATE_PRESENT, + CARDSTATE_ERROR; + + boolean isCardPresent() { + return this == CARDSTATE_PRESENT; + } + }; + + public enum PinState { + PINSTATE_UNKNOWN, + PINSTATE_ENABLED_NOT_VERIFIED, + PINSTATE_ENABLED_VERIFIED, + PINSTATE_DISABLED, + PINSTATE_ENABLED_BLOCKED, + PINSTATE_ENABLED_PERM_BLOCKED + }; + + public CardState card_state; + public PinState universal_pin_state; + public int gsm_umts_subscription_app_index; + public int cdma_subscription_app_index; + public int num_applications; + + ArrayList<IccCardApplication> application = new ArrayList<IccCardApplication>(CARD_MAX_APPS); + + CardState CardStateFromRILInt(int state) { + CardState newState; + /* RIL_CardState ril.h */ + switch(state) { + case 0: newState = CardState.CARDSTATE_ABSENT; break; + case 1: newState = CardState.CARDSTATE_PRESENT; break; + case 2: newState = CardState.CARDSTATE_ERROR; break; + default: + throw new RuntimeException( + "Unrecognized RIL_CardState: " +state); + } + return newState; + } + + PinState PinStateFromRILInt(int state) { + PinState newState; + /* RIL_PinState ril.h */ + switch(state) { + case 0: newState = PinState.PINSTATE_UNKNOWN; break; + case 1: newState = PinState.PINSTATE_ENABLED_NOT_VERIFIED; break; + case 2: newState = PinState.PINSTATE_ENABLED_VERIFIED; break; + case 3: newState = PinState.PINSTATE_DISABLED; break; + case 4: newState = PinState.PINSTATE_ENABLED_BLOCKED; break; + case 5: newState = PinState.PINSTATE_ENABLED_PERM_BLOCKED; break; + default: + throw new RuntimeException( + "Unrecognized RIL_PinState: " +state); + } + return newState; + } +} diff --git a/telephony/java/com/android/internal/telephony/gsm/SimConstants.java b/telephony/java/com/android/internal/telephony/IccConstants.java index a7e3bbc..59ce5bb 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimConstants.java +++ b/telephony/java/com/android/internal/telephony/IccConstants.java @@ -14,13 +14,13 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * {@hide} */ -public interface SimConstants { - // SIM file ids from TS 51.011 +public interface IccConstants { + // GSM SIM file ids from TS 51.011 public static final int EF_ADN = 0x6F3A; public static final int EF_FDN = 0x6F3B; public static final int EF_SDN = 0x6F49; @@ -42,7 +42,7 @@ public interface SimConstants { public static final int EF_CFIS = 0x6FCB; public static final int EF_IMG = 0x4f20; - // SIM file ids from CPHS (phase 2, version 4.2) CPHS4_2.WW6 + // GSM SIM file ids from CPHS (phase 2, version 4.2) CPHS4_2.WW6 public static final int EF_MAILBOX_CPHS = 0x6F17; public static final int EF_VOICE_MAIL_INDICATOR_CPHS = 0x6F11; public static final int EF_CFF_CPHS = 0x6F13; @@ -50,6 +50,10 @@ public interface SimConstants { public static final int EF_SPN_SHORT_CPHS = 0x6f18; public static final int EF_INFO_CPHS = 0x6f16; + // CDMA RUIM file ids from 3GPP2 C.S0023-0 + public static final int EF_CST = 0x6f32; + public static final int EF_RUIM_SPN =0x6F41; + // SMS record length from TS 51.011 10.5.3 static public final int SMS_RECORD_LENGTH = 176; } diff --git a/telephony/java/com/android/internal/telephony/gsm/SimFileTypeMismatch.java b/telephony/java/com/android/internal/telephony/IccException.java index 72790d0..1659a4e 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimFileTypeMismatch.java +++ b/telephony/java/com/android/internal/telephony/IccException.java @@ -14,20 +14,17 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * {@hide} */ -public class SimFileTypeMismatch extends SimException -{ - SimFileTypeMismatch() - { +public class IccException extends Exception { + public IccException() { } - SimFileTypeMismatch(String s) - { + public IccException(String s) { super(s); } } diff --git a/telephony/java/com/android/internal/telephony/IccFileHandler.java b/telephony/java/com/android/internal/telephony/IccFileHandler.java new file mode 100644 index 0000000..e751c5e --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccFileHandler.java @@ -0,0 +1,513 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.os.*; +import android.util.Log; +import java.util.ArrayList; + +/** + * {@hide} + */ +public abstract class IccFileHandler extends Handler { + + //from TS 11.11 9.1 or elsewhere + static protected final int COMMAND_READ_BINARY = 0xb0; + static protected final int COMMAND_UPDATE_BINARY = 0xd6; + static protected final int COMMAND_READ_RECORD = 0xb2; + static protected final int COMMAND_UPDATE_RECORD = 0xdc; + static protected final int COMMAND_SEEK = 0xa2; + static protected final int COMMAND_GET_RESPONSE = 0xc0; + + // from TS 11.11 9.2.5 + static protected final int READ_RECORD_MODE_ABSOLUTE = 4; + + //***** types of files TS 11.11 9.3 + static protected final int EF_TYPE_TRANSPARENT = 0; + static protected final int EF_TYPE_LINEAR_FIXED = 1; + static protected final int EF_TYPE_CYCLIC = 3; + + //***** types of files TS 11.11 9.3 + static protected final int TYPE_RFU = 0; + static protected final int TYPE_MF = 1; + static protected final int TYPE_DF = 2; + static protected final int TYPE_EF = 4; + + // size of GET_RESPONSE for EF's + static protected final int GET_RESPONSE_EF_SIZE_BYTES = 15; + static protected final int GET_RESPONSE_EF_IMG_SIZE_BYTES = 10; + + // Byte order received in response to COMMAND_GET_RESPONSE + // Refer TS 51.011 Section 9.2.1 + static protected final int RESPONSE_DATA_RFU_1 = 0; + static protected final int RESPONSE_DATA_RFU_2 = 1; + + static protected final int RESPONSE_DATA_FILE_SIZE_1 = 2; + static protected final int RESPONSE_DATA_FILE_SIZE_2 = 3; + + static protected final int RESPONSE_DATA_FILE_ID_1 = 4; + static protected final int RESPONSE_DATA_FILE_ID_2 = 5; + static protected final int RESPONSE_DATA_FILE_TYPE = 6; + static protected final int RESPONSE_DATA_RFU_3 = 7; + static protected final int RESPONSE_DATA_ACCESS_CONDITION_1 = 8; + static protected final int RESPONSE_DATA_ACCESS_CONDITION_2 = 9; + static protected final int RESPONSE_DATA_ACCESS_CONDITION_3 = 10; + static protected final int RESPONSE_DATA_FILE_STATUS = 11; + static protected final int RESPONSE_DATA_LENGTH = 12; + static protected final int RESPONSE_DATA_STRUCTURE = 13; + static protected final int RESPONSE_DATA_RECORD_LENGTH = 14; + + + //***** Events + + /** Finished retrieving size of transparent EF; start loading. */ + static protected final int EVENT_GET_BINARY_SIZE_DONE = 4; + /** Finished loading contents of transparent EF; post result. */ + static protected final int EVENT_READ_BINARY_DONE = 5; + /** Finished retrieving size of records for linear-fixed EF; now load. */ + static protected final int EVENT_GET_RECORD_SIZE_DONE = 6; + /** Finished loading single record from a linear-fixed EF; post result. */ + static protected final int EVENT_READ_RECORD_DONE = 7; + /** Finished retrieving record size; post result. */ + static protected final int EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE = 8; + /** Finished retrieving image instance record; post result. */ + static protected final int EVENT_READ_IMG_DONE = 9; + /** Finished retrieving icon data; post result. */ + static protected final int EVENT_READ_ICON_DONE = 10; + + // member variables + protected PhoneBase phone; + + static class LoadLinearFixedContext { + + int efid; + int recordNum, recordSize, countRecords; + boolean loadAll; + + Message onLoaded; + + ArrayList<byte[]> results; + + LoadLinearFixedContext(int efid, int recordNum, Message onLoaded) { + this.efid = efid; + this.recordNum = recordNum; + this.onLoaded = onLoaded; + this.loadAll = false; + } + + LoadLinearFixedContext(int efid, Message onLoaded) { + this.efid = efid; + this.recordNum = 1; + this.loadAll = true; + this.onLoaded = onLoaded; + } + } + + /** + * Default constructor + */ + protected IccFileHandler(PhoneBase phone) { + super(); + this.phone = phone; + } + + public void dispose() { + } + + //***** Public Methods + + /** + * Load a record from a SIM Linear Fixed EF + * + * @param fileid EF id + * @param recordNum 1-based (not 0-based) record number + * @param onLoaded + * + * ((AsyncResult)(onLoaded.obj)).result is the byte[] + * + */ + public void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded) { + Message response + = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, + new LoadLinearFixedContext(fileid, recordNum, onLoaded)); + + phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null, + 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + } + + /** + * Load a image instance record from a SIM Linear Fixed EF-IMG + * + * @param recordNum 1-based (not 0-based) record number + * @param onLoaded + * + * ((AsyncResult)(onLoaded.obj)).result is the byte[] + * + */ + public void loadEFImgLinearFixed(int recordNum, Message onLoaded) { + Message response = obtainMessage(EVENT_READ_IMG_DONE, + new LoadLinearFixedContext(IccConstants.EF_IMG, recordNum, + onLoaded)); + + phone.mCM.iccIO(COMMAND_GET_RESPONSE, IccConstants.EF_IMG, "img", + recordNum, READ_RECORD_MODE_ABSOLUTE, + GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null, response); + } + + /** + * get record size for a linear fixed EF + * + * @param fileid EF id + * @param onLoaded ((AsnyncResult)(onLoaded.obj)).result is the recordSize[] + * int[0] is the record length int[1] is the total length of the EF + * file int[3] is the number of records in the EF file So int[0] * + * int[3] = int[1] + */ + public void getEFLinearRecordSize(int fileid, Message onLoaded) { + Message response + = obtainMessage(EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE, + new LoadLinearFixedContext(fileid, onLoaded)); + phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null, + 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + } + + /** + * Load all records from a SIM Linear Fixed EF + * + * @param fileid EF id + * @param onLoaded + * + * ((AsyncResult)(onLoaded.obj)).result is an ArrayList<byte[]> + * + */ + public void loadEFLinearFixedAll(int fileid, Message onLoaded) { + Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, + new LoadLinearFixedContext(fileid,onLoaded)); + + phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null, + 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + } + + /** + * Load a SIM Transparent EF + * + * @param fileid EF id + * @param onLoaded + * + * ((AsyncResult)(onLoaded.obj)).result is the byte[] + * + */ + + public void loadEFTransparent(int fileid, Message onLoaded) { + Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE, + fileid, 0, onLoaded); + + phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null, + 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + } + + /** + * Load a SIM Transparent EF-IMG. Used right after loadEFImgLinearFixed to + * retrive STK's icon data. + * + * @param fileid EF id + * @param onLoaded + * + * ((AsyncResult)(onLoaded.obj)).result is the byte[] + * + */ + public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset, + int length, Message onLoaded) { + Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0, + onLoaded); + + phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, "img", highOffset, lowOffset, + length, null, null, response); + } + + /** + * Update a record in a linear fixed EF + * @param fileid EF id + * @param recordNum 1-based (not 0-based) record number + * @param data must be exactly as long as the record in the EF + * @param pin2 for CHV2 operations, otherwist must be null + * @param onComplete onComplete.obj will be an AsyncResult + * onComplete.obj.userObj will be a IccIoResult on success + */ + public void updateEFLinearFixed(int fileid, int recordNum, byte[] data, + String pin2, Message onComplete) { + phone.mCM.iccIO(COMMAND_UPDATE_RECORD, fileid, null, + recordNum, READ_RECORD_MODE_ABSOLUTE, data.length, + IccUtils.bytesToHexString(data), pin2, onComplete); + } + + /** + * Update a transparent EF + * @param fileid EF id + * @param data must be exactly as long as the EF + */ + public void updateEFTransparent(int fileid, byte[] data, Message onComplete) { + phone.mCM.iccIO(COMMAND_UPDATE_BINARY, fileid, null, + 0, 0, data.length, + IccUtils.bytesToHexString(data), null, onComplete); + } + + + //***** Abstract Methods + + + //***** Private Methods + + private void sendResult(Message response, Object result, Throwable ex) { + if (response == null) { + return; + } + + AsyncResult.forMessage(response, result, ex); + + response.sendToTarget(); + } + + //***** Overridden from Handler + + public void handleMessage(Message msg) { + AsyncResult ar; + IccIoResult result; + Message response = null; + String str; + LoadLinearFixedContext lc; + + IccException iccException; + byte data[]; + int size; + int fileid; + int recordNum; + int recordSize[]; + + try { + switch (msg.what) { + case EVENT_READ_IMG_DONE: + ar = (AsyncResult) msg.obj; + lc = (LoadLinearFixedContext) ar.userObj; + result = (IccIoResult) ar.result; + response = lc.onLoaded; + + iccException = result.getException(); + if (iccException != null) { + sendResult(response, result.payload, ar.exception); + } + break; + case EVENT_READ_ICON_DONE: + ar = (AsyncResult) msg.obj; + response = (Message) ar.userObj; + result = (IccIoResult) ar.result; + + iccException = result.getException(); + if (iccException != null) { + sendResult(response, result.payload, ar.exception); + } + break; + case EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE: + ar = (AsyncResult)msg.obj; + lc = (LoadLinearFixedContext) ar.userObj; + result = (IccIoResult) ar.result; + response = lc.onLoaded; + + if (ar.exception != null) { + sendResult(response, null, ar.exception); + break; + } + + iccException = result.getException(); + if (iccException != null) { + sendResult(response, null, iccException); + break; + } + + data = result.payload; + + if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] || + EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { + throw new IccFileTypeMismatch(); + } + + recordSize = new int[3]; + recordSize[0] = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; + recordSize[1] = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) + + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); + recordSize[2] = recordSize[1] / recordSize[0]; + + sendResult(response, recordSize, null); + break; + case EVENT_GET_RECORD_SIZE_DONE: + ar = (AsyncResult)msg.obj; + lc = (LoadLinearFixedContext) ar.userObj; + result = (IccIoResult) ar.result; + response = lc.onLoaded; + + if (ar.exception != null) { + sendResult(response, null, ar.exception); + break; + } + + iccException = result.getException(); + + if (iccException != null) { + sendResult(response, null, iccException); + break; + } + + data = result.payload; + fileid = lc.efid; + recordNum = lc.recordNum; + + if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { + throw new IccFileTypeMismatch(); + } + + if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { + throw new IccFileTypeMismatch(); + } + + lc.recordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; + + size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) + + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); + + lc.countRecords = size / lc.recordSize; + + if (lc.loadAll) { + lc.results = new ArrayList<byte[]>(lc.countRecords); + } + + phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, null, + lc.recordNum, + READ_RECORD_MODE_ABSOLUTE, + lc.recordSize, null, null, + obtainMessage(EVENT_READ_RECORD_DONE, lc)); + break; + case EVENT_GET_BINARY_SIZE_DONE: + ar = (AsyncResult)msg.obj; + response = (Message) ar.userObj; + result = (IccIoResult) ar.result; + + if (ar.exception != null) { + sendResult(response, null, ar.exception); + break; + } + + iccException = result.getException(); + + if (iccException != null) { + sendResult(response, null, iccException); + break; + } + + data = result.payload; + + fileid = msg.arg1; + + if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { + throw new IccFileTypeMismatch(); + } + + if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) { + throw new IccFileTypeMismatch(); + } + + size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) + + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); + + phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, null, + 0, 0, size, null, null, + obtainMessage(EVENT_READ_BINARY_DONE, + fileid, 0, response)); + break; + + case EVENT_READ_RECORD_DONE: + + ar = (AsyncResult)msg.obj; + lc = (LoadLinearFixedContext) ar.userObj; + result = (IccIoResult) ar.result; + response = lc.onLoaded; + + if (ar.exception != null) { + sendResult(response, null, ar.exception); + break; + } + + iccException = result.getException(); + + if (iccException != null) { + sendResult(response, null, iccException); + break; + } + + if (!lc.loadAll) { + sendResult(response, result.payload, null); + } else { + lc.results.add(result.payload); + + lc.recordNum++; + + if (lc.recordNum > lc.countRecords) { + sendResult(response, lc.results, null); + } else { + phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, null, + lc.recordNum, + READ_RECORD_MODE_ABSOLUTE, + lc.recordSize, null, null, + obtainMessage(EVENT_READ_RECORD_DONE, lc)); + } + } + + break; + + case EVENT_READ_BINARY_DONE: + ar = (AsyncResult)msg.obj; + response = (Message) ar.userObj; + result = (IccIoResult) ar.result; + + if (ar.exception != null) { + sendResult(response, null, ar.exception); + break; + } + + iccException = result.getException(); + + if (iccException != null) { + sendResult(response, null, iccException); + break; + } + + sendResult(response, result.payload, null); + break; + + }} catch (Exception exc) { + if (response != null) { + sendResult(response, null, exc); + } else { + loge("uncaught exception" + exc); + } + } + } + + protected abstract void logd(String s); + + protected abstract void loge(String s); + +} diff --git a/telephony/java/com/android/internal/telephony/gsm/SimFileNotFound.java b/telephony/java/com/android/internal/telephony/IccFileNotFound.java index 982e2fd..915cea6 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimFileNotFound.java +++ b/telephony/java/com/android/internal/telephony/IccFileNotFound.java @@ -14,25 +14,21 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * {@hide} */ -public class SimFileNotFound extends SimException -{ - SimFileNotFound() - { +public class IccFileNotFound extends IccException { + IccFileNotFound() { } - SimFileNotFound(String s) - { + IccFileNotFound(String s) { super(s); } - SimFileNotFound(int ef) - { - super("SIM EF Not Found 0x" + Integer.toHexString(ef)); + IccFileNotFound(int ef) { + super("ICC EF Not Found 0x" + Integer.toHexString(ef)); } } diff --git a/telephony/java/com/android/internal/telephony/gsm/SimException.java b/telephony/java/com/android/internal/telephony/IccFileTypeMismatch.java index 1c0daba..66fcfa9 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimException.java +++ b/telephony/java/com/android/internal/telephony/IccFileTypeMismatch.java @@ -14,45 +14,17 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * {@hide} */ -public class SimException extends Exception -{ - SimException() - { +public class IccFileTypeMismatch extends IccException { + public IccFileTypeMismatch() { } - SimException(String s) - { + public IccFileTypeMismatch(String s) { super(s); } } - -final class SimVmFixedException extends SimException { - SimVmFixedException() - { - - } - - SimVmFixedException(String s) - { - super(s); - } -} - -final class SimVmNotSupportedException extends SimException { - SimVmNotSupportedException() - { - - } - - SimVmNotSupportedException(String s) - { - super(s); - } -} - diff --git a/telephony/java/com/android/internal/telephony/gsm/SimIoResult.java b/telephony/java/com/android/internal/telephony/IccIoResult.java index 2c4da83..a6e0ec3 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimIoResult.java +++ b/telephony/java/com/android/internal/telephony/IccIoResult.java @@ -14,33 +14,30 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * {@hide} */ public class -SimIoResult -{ +IccIoResult { int sw1; int sw2; - byte[] payload; - public SimIoResult(int sw1, int sw2, byte[] payload) - { + public byte[] payload; + + public IccIoResult(int sw1, int sw2, byte[] payload) { this.sw1 = sw1; this.sw2 = sw2; this.payload = payload; } - public SimIoResult(int sw1, int sw2, String hexString) - { - this(sw1, sw2, SimUtils.hexStringToBytes(hexString)); + public IccIoResult(int sw1, int sw2, String hexString) { + this(sw1, sw2, IccUtils.hexStringToBytes(hexString)); } - public String toString() - { - return "SimIoResponse sw1:0x" + Integer.toHexString(sw1) + " sw2:0x" + public String toString() { + return "IccIoResponse sw1:0x" + Integer.toHexString(sw1) + " sw2:0x" + Integer.toHexString(sw2); } @@ -49,27 +46,25 @@ SimIoResult * See GSM 11.11 Section 9.4 * (the fun stuff is absent in 51.011) */ - public boolean success() - { + public boolean success() { return sw1 == 0x90 || sw1 == 0x91 || sw1 == 0x9e || sw1 == 0x9f; } /** * Returns exception on error or null if success */ - public SimException getException() - { + public IccException getException() { if (success()) return null; - + switch (sw1) { case 0x94: if (sw2 == 0x08) { - return new SimFileTypeMismatch(); + return new IccFileTypeMismatch(); } else { - return new SimFileNotFound(); + return new IccFileNotFound(); } default: - return new SimException("sw1:" + sw1 + " sw2:" + sw2); + return new IccException("sw1:" + sw1 + " sw2:" + sw2); } } } diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java new file mode 100644 index 0000000..0bcaaa6 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.content.pm.PackageManager; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.ServiceManager; +import android.telephony.PhoneNumberUtils; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * SimPhoneBookInterfaceManager to provide an inter-process communication to + * access ADN-like SIM records. + */ +public abstract class IccPhoneBookInterfaceManager extends IIccPhoneBook.Stub { + protected static final boolean DBG = true; + + protected PhoneBase phone; + protected AdnRecordCache adnCache; + protected Object mLock = new Object(); + protected int recordSize[]; + protected boolean success; + protected List<AdnRecord> records; + + protected static final boolean ALLOW_SIM_OP_IN_UI_THREAD = false; + + protected static final int EVENT_GET_SIZE_DONE = 1; + protected static final int EVENT_LOAD_DONE = 2; + protected static final int EVENT_UPDATE_DONE = 3; + + protected Handler mBaseHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + + switch (msg.what) { + case EVENT_GET_SIZE_DONE: + ar = (AsyncResult) msg.obj; + synchronized (mLock) { + if (ar.exception == null) { + recordSize = (int[])ar.result; + // recordSize[0] is the record length + // recordSize[1] is the total length of the EF file + // recordSize[2] is the number of records in the EF file + logd("GET_RECORD_SIZE Size " + recordSize[0] + + " total " + recordSize[1] + + " #record " + recordSize[2]); + mLock.notifyAll(); + } + } + break; + case EVENT_UPDATE_DONE: + ar = (AsyncResult) msg.obj; + synchronized (mLock) { + success = (ar.exception == null); + mLock.notifyAll(); + } + break; + case EVENT_LOAD_DONE: + ar = (AsyncResult)msg.obj; + synchronized (mLock) { + if (ar.exception == null) { + records = (List<AdnRecord>) + ((ArrayList<AdnRecord>) ar.result); + } else { + if(DBG) logd("Cannot load ADN records"); + if (records != null) { + records.clear(); + } + } + mLock.notifyAll(); + } + break; + } + } + }; + + public IccPhoneBookInterfaceManager(PhoneBase phone) { + this.phone = phone; + } + + public void dispose() { + } + + protected void publish() { + //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy + ServiceManager.addService("simphonebook", this); + } + + protected abstract void logd(String msg); + + protected abstract void loge(String msg); + + /** + * Replace oldAdn with newAdn in ADN-like record in EF + * + * getAdnRecordsInEf must be called at least once before this function, + * otherwise an error will be returned + * throws SecurityException if no WRITE_CONTACTS permission + * + * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN + * @param oldTag adn tag to be replaced + * @param oldPhoneNumber adn number to be replaced + * Set both oldTag and oldPhoneNubmer to "" means to replace an + * empty record, aka, insert new record + * @param newTag adn tag to be stored + * @param newPhoneNumber adn number ot be stored + * Set both newTag and newPhoneNubmer to "" means to replace the old + * record with empty one, aka, delete old record + * @param pin2 required to update EF_FDN, otherwise must be null + * @return true for success + */ + public boolean + updateAdnRecordsInEfBySearch (int efid, + String oldTag, String oldPhoneNumber, + String newTag, String newPhoneNumber, String pin2) { + + + if (phone.getContext().checkCallingOrSelfPermission( + android.Manifest.permission.WRITE_CONTACTS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Requires android.permission.WRITE_CONTACTS permission"); + } + + + if (DBG) logd("updateAdnRecordsInEfBySearch: efid=" + efid + + " ("+ oldTag + "," + oldPhoneNumber + ")"+ "==>" + + " ("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2); + synchronized(mLock) { + checkThread(); + success = false; + Message response = mBaseHandler.obtainMessage(EVENT_UPDATE_DONE); + AdnRecord oldAdn = new AdnRecord(oldTag, oldPhoneNumber); + AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber); + adnCache.updateAdnBySearch(efid, oldAdn, newAdn, pin2, response); + try { + mLock.wait(); + } catch (InterruptedException e) { + logd("interrupted while trying to update by search"); + } + } + return success; + } + + /** + * Update an ADN-like EF record by record index + * + * This is useful for iteration the whole ADN file, such as write the whole + * phone book or erase/format the whole phonebook + * throws SecurityException if no WRITE_CONTACTS permission + * + * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN + * @param newTag adn tag to be stored + * @param newPhoneNumber adn number to be stored + * Set both newTag and newPhoneNubmer to "" means to replace the old + * record with empty one, aka, delete old record + * @param index is 1-based adn record index to be updated + * @param pin2 required to update EF_FDN, otherwise must be null + * @return true for success + */ + public boolean + updateAdnRecordsInEfByIndex(int efid, String newTag, + String newPhoneNumber, int index, String pin2) { + + if (phone.getContext().checkCallingOrSelfPermission( + android.Manifest.permission.WRITE_CONTACTS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Requires android.permission.WRITE_CONTACTS permission"); + } + + if (DBG) logd("updateAdnRecordsInEfByIndex: efid=" + efid + + " Index=" + index + " ==> " + + "("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2); + synchronized(mLock) { + checkThread(); + success = false; + Message response = mBaseHandler.obtainMessage(EVENT_UPDATE_DONE); + AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber); + adnCache.updateAdnByIndex(efid, newAdn, index, pin2, response); + try { + mLock.wait(); + } catch (InterruptedException e) { + logd("interrupted while trying to update by index"); + } + } + return success; + } + + /** + * Get the capacity of records in efid + * + * @param efid the EF id of a ADN-like ICC + * @return int[3] array + * recordSizes[0] is the single record length + * recordSizes[1] is the total length of the EF file + * recordSizes[2] is the number of records in the EF file + */ + public abstract int[] getAdnRecordsSize(int efid); + + /** + * Loads the AdnRecords in efid and returns them as a + * List of AdnRecords + * + * throws SecurityException if no READ_CONTACTS permission + * + * @param efid the EF id of a ADN-like ICC + * @return List of AdnRecord + */ + public List<AdnRecord> getAdnRecordsInEf(int efid) { + + if (phone.getContext().checkCallingOrSelfPermission( + android.Manifest.permission.READ_CONTACTS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Requires android.permission.READ_CONTACTS permission"); + } + + if (DBG) logd("getAdnRecordsInEF: efid=" + efid); + + synchronized(mLock) { + checkThread(); + Message response = mBaseHandler.obtainMessage(EVENT_LOAD_DONE); + adnCache.requestLoadAllAdnLike(efid, response); + try { + mLock.wait(); + } catch (InterruptedException e) { + logd("interrupted while trying to load from the SIM"); + } + } + return records; + } + + protected void checkThread() { + if (!ALLOW_SIM_OP_IN_UI_THREAD) { + // Make sure this isn't the UI thread, since it will block + if (mBaseHandler.getLooper().equals(Looper.myLooper())) { + loge("query() called on the main UI thread!"); + throw new IllegalStateException( + "You cannot call query on this provder from the main UI thread."); + } + } + } +} + diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManagerProxy.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManagerProxy.java new file mode 100644 index 0000000..1c0fc52 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManagerProxy.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.content.pm.PackageManager; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.ServiceManager; +import android.telephony.PhoneNumberUtils; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + + +/** + * SimPhoneBookInterfaceManager to provide an inter-process communication to + * access ADN-like SIM records. + */ +public class IccPhoneBookInterfaceManagerProxy extends IIccPhoneBook.Stub { + private IccPhoneBookInterfaceManager mIccPhoneBookInterfaceManager; + + public IccPhoneBookInterfaceManagerProxy(IccPhoneBookInterfaceManager + iccPhoneBookInterfaceManager) { + mIccPhoneBookInterfaceManager = iccPhoneBookInterfaceManager; + if(ServiceManager.getService("simphonebook") == null) { + ServiceManager.addService("simphonebook", this); + } + } + + public void setmIccPhoneBookInterfaceManager( + IccPhoneBookInterfaceManager iccPhoneBookInterfaceManager) { + this.mIccPhoneBookInterfaceManager = iccPhoneBookInterfaceManager; + } + + public boolean + updateAdnRecordsInEfBySearch (int efid, + String oldTag, String oldPhoneNumber, + String newTag, String newPhoneNumber, + String pin2) throws android.os.RemoteException { + return mIccPhoneBookInterfaceManager.updateAdnRecordsInEfBySearch( + efid, oldTag, oldPhoneNumber, newTag, newPhoneNumber, pin2); + } + + public boolean + updateAdnRecordsInEfByIndex(int efid, String newTag, + String newPhoneNumber, int index, String pin2) throws android.os.RemoteException { + return mIccPhoneBookInterfaceManager.updateAdnRecordsInEfByIndex(efid, + newTag, newPhoneNumber, index, pin2); + } + + public int[] getAdnRecordsSize(int efid) throws android.os.RemoteException { + return mIccPhoneBookInterfaceManager.getAdnRecordsSize(efid); + } + + public List<AdnRecord> getAdnRecordsInEf(int efid) throws android.os.RemoteException { + return mIccPhoneBookInterfaceManager.getAdnRecordsInEf(efid); + } +} diff --git a/telephony/java/com/android/internal/telephony/gsm/SimProvider.java b/telephony/java/com/android/internal/telephony/IccProvider.java index cece4ba..4cbd779 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimProvider.java +++ b/telephony/java/com/android/internal/telephony/IccProvider.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.content.ContentProvider; import android.content.UriMatcher; @@ -31,11 +31,16 @@ import android.util.Log; import java.util.ArrayList; import java.util.List; +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.AdnRecord; +import com.android.internal.telephony.IIccPhoneBook; + + /** * {@hide} */ -public class SimProvider extends ContentProvider { - private static final String TAG = "SimProvider"; +public class IccProvider extends ContentProvider { + private static final String TAG = "IccProvider"; private static final boolean DBG = false; @@ -56,9 +61,9 @@ public class SimProvider extends ContentProvider { new UriMatcher(UriMatcher.NO_MATCH); static { - URL_MATCHER.addURI("sim", "adn", ADN); - URL_MATCHER.addURI("sim", "fdn", FDN); - URL_MATCHER.addURI("sim", "sdn", SDN); + URL_MATCHER.addURI("icc", "adn", ADN); + URL_MATCHER.addURI("icc", "fdn", FDN); + URL_MATCHER.addURI("icc", "sdn", SDN); } @@ -81,21 +86,21 @@ public class SimProvider extends ContentProvider { public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, String sort) { ArrayList<ArrayList> results; - + if (!mSimulator) { switch (URL_MATCHER.match(url)) { case ADN: - results = loadFromEf(SimConstants.EF_ADN); + results = loadFromEf(IccConstants.EF_ADN); break; - + case FDN: - results = loadFromEf(SimConstants.EF_FDN); + results = loadFromEf(IccConstants.EF_FDN); break; - + case SDN: - results = loadFromEf(SimConstants.EF_SDN); + results = loadFromEf(IccConstants.EF_SDN); break; - + default: throw new IllegalArgumentException("Unknown URL " + url); } @@ -152,11 +157,11 @@ public class SimProvider extends ContentProvider { int match = URL_MATCHER.match(url); switch (match) { case ADN: - efType = SimConstants.EF_ADN; + efType = IccConstants.EF_ADN; break; case FDN: - efType = SimConstants.EF_FDN; + efType = IccConstants.EF_FDN; pin2 = initialValues.getAsString("pin2"); break; @@ -167,7 +172,7 @@ public class SimProvider extends ContentProvider { String tag = initialValues.getAsString("tag"); String number = initialValues.getAsString("number"); - boolean success = addSimRecordToEf(efType, tag, number, pin2); + boolean success = addIccRecordToEf(efType, tag, number, pin2); if (!success) { return null; @@ -183,7 +188,7 @@ public class SimProvider extends ContentProvider { buf.append("fdn/"); break; } - + // TODO: we need to find out the rowId for the newly added record buf.append(0); @@ -218,11 +223,11 @@ public class SimProvider extends ContentProvider { int match = URL_MATCHER.match(url); switch (match) { case ADN: - efType = SimConstants.EF_ADN; + efType = IccConstants.EF_ADN; break; case FDN: - efType = SimConstants.EF_FDN; + efType = IccConstants.EF_FDN; break; default: @@ -269,7 +274,7 @@ public class SimProvider extends ContentProvider { return 0; } - boolean success = deleteSimRecordFromEf(efType, tag, number, pin2); + boolean success = deleteIccRecordFromEf(efType, tag, number, pin2); if (!success) { return 0; } @@ -287,11 +292,11 @@ public class SimProvider extends ContentProvider { int match = URL_MATCHER.match(url); switch (match) { case ADN: - efType = SimConstants.EF_ADN; + efType = IccConstants.EF_ADN; break; case FDN: - efType = SimConstants.EF_FDN; + efType = IccConstants.EF_FDN; pin2 = values.getAsString("pin2"); break; @@ -305,7 +310,7 @@ public class SimProvider extends ContentProvider { String newTag = values.getAsString("newTag"); String newNumber = values.getAsString("newNumber"); - boolean success = updateSimRecordInEf(efType, tag, number, + boolean success = updateIccRecordInEf(efType, tag, number, newTag, newNumber, pin2); if (!success) { @@ -322,17 +327,16 @@ public class SimProvider extends ContentProvider { if (DBG) log("loadFromEf: efType=" + efType); try { - ISimPhoneBook simIpb = ISimPhoneBook.Stub.asInterface( + IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface( ServiceManager.getService("simphonebook")); - if (simIpb != null) { - adnRecords = simIpb.getAdnRecordsInEf(efType); + if (iccIpb != null) { + adnRecords = iccIpb.getAdnRecordsInEf(efType); } } catch (RemoteException ex) { // ignore it } catch (SecurityException ex) { if (DBG) log(ex.toString()); } - if (adnRecords != null) { // Load the results @@ -351,8 +355,8 @@ public class SimProvider extends ContentProvider { } private boolean - addSimRecordToEf(int efType, String name, String number, String pin2) { - if (DBG) log("addSimRecordToEf: efType=" + efType + ", name=" + name + + addIccRecordToEf(int efType, String name, String number, String pin2) { + if (DBG) log("addIccRecordToEf: efType=" + efType + ", name=" + name + ", number=" + number); boolean success = false; @@ -361,11 +365,12 @@ public class SimProvider extends ContentProvider { // updateAdnRecordsInEfBySearch()? In any case, we will leave // the UI level logic to fill that prereq if necessary. But // hopefully, we can remove this requirement. + try { - ISimPhoneBook simIpb = ISimPhoneBook.Stub.asInterface( + IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface( ServiceManager.getService("simphonebook")); - if (simIpb != null) { - success = simIpb.updateAdnRecordsInEfBySearch(efType, "", "", + if (iccIpb != null) { + success = iccIpb.updateAdnRecordsInEfBySearch(efType, "", "", name, number, pin2); } } catch (RemoteException ex) { @@ -373,23 +378,23 @@ public class SimProvider extends ContentProvider { } catch (SecurityException ex) { if (DBG) log(ex.toString()); } - if (DBG) log("addSimRecordToEf: " + success); + if (DBG) log("addIccRecordToEf: " + success); return success; } private boolean - updateSimRecordInEf(int efType, String oldName, String oldNumber, + updateIccRecordInEf(int efType, String oldName, String oldNumber, String newName, String newNumber,String pin2) { - if (DBG) log("updateSimRecordInEf: efType=" + efType + + if (DBG) log("updateIccRecordInEf: efType=" + efType + ", oldname=" + oldName + ", oldnumber=" + oldNumber + ", newname=" + newName + ", newnumber=" + newNumber); boolean success = false; try { - ISimPhoneBook simIpb = ISimPhoneBook.Stub.asInterface( + IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface( ServiceManager.getService("simphonebook")); - if (simIpb != null) { - success = simIpb.updateAdnRecordsInEfBySearch(efType, + if (iccIpb != null) { + success = iccIpb.updateAdnRecordsInEfBySearch(efType, oldName, oldNumber, newName, newNumber, pin2); } } catch (RemoteException ex) { @@ -397,34 +402,30 @@ public class SimProvider extends ContentProvider { } catch (SecurityException ex) { if (DBG) log(ex.toString()); } - - if (DBG) log("updateSimRecordInEf: " + success); + if (DBG) log("updateIccRecordInEf: " + success); return success; } - private boolean deleteSimRecordFromEf(int efType, - String name, String number, - String pin2) { - if (DBG) log("deleteSimRecordFromEf: efType=" + efType + + private boolean deleteIccRecordFromEf(int efType, String name, String number, String pin2) { + if (DBG) log("deleteIccRecordFromEf: efType=" + efType + ", name=" + name + ", number=" + number + ", pin2=" + pin2); boolean success = false; try { - ISimPhoneBook simIpb = ISimPhoneBook.Stub.asInterface( + IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface( ServiceManager.getService("simphonebook")); - if (simIpb != null) { - success = simIpb.updateAdnRecordsInEfBySearch(efType, - name, number, "", "", pin2); + if (iccIpb != null) { + success = iccIpb.updateAdnRecordsInEfBySearch(efType, + name, number, "", "", pin2); } } catch (RemoteException ex) { // ignore it } catch (SecurityException ex) { if (DBG) log(ex.toString()); } - - if (DBG) log("deleteSimRecordFromEf: " + success); + if (DBG) log("deleteIccRecordFromEf: " + success); return success; } @@ -449,7 +450,7 @@ public class SimProvider extends ContentProvider { } private void log(String msg) { - Log.d(TAG, "[SimProvider] " + msg); + Log.d(TAG, "[IccProvider] " + msg); } } diff --git a/telephony/java/com/android/internal/telephony/IccRecords.java b/telephony/java/com/android/internal/telephony/IccRecords.java new file mode 100644 index 0000000..114094b --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccRecords.java @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.Registrant; +import android.os.RegistrantList; +import android.util.Log; + +import java.util.ArrayList; + +/** + * {@hide} + */ +public abstract class IccRecords extends Handler implements IccConstants { + + protected static final boolean DBG = true; + //***** Instance Variables + + protected PhoneBase phone; + protected RegistrantList recordsLoadedRegistrants = new RegistrantList(); + + protected int recordsToLoad; // number of pending load requests + + protected AdnRecordCache adnCache; + + //***** Cached SIM State; cleared on channel close + + protected boolean recordsRequested = false; // true if we've made requests for the sim records + + public String iccid; + protected String msisdn = null; // My mobile number + protected String msisdnTag = null; + protected String voiceMailNum = null; + protected String voiceMailTag = null; + protected String newVoiceMailNum = null; + protected String newVoiceMailTag = null; + protected boolean isVoiceMailFixed = false; + protected int countVoiceMessages = 0; + + protected int mncLength = 0; // 0 is used to indicate that the value + // is not initialized + protected int mailboxIndex = 0; // 0 is no mailbox dailing number associated + + protected String spn; + protected int spnDisplayCondition; + + //***** Constants + + // Bitmasks for SPN display rules. + protected static final int SPN_RULE_SHOW_SPN = 0x01; + protected static final int SPN_RULE_SHOW_PLMN = 0x02; + + //***** Event Constants + protected static final int EVENT_SET_MSISDN_DONE = 30; + + //***** Constructor + + public IccRecords(PhoneBase p) { + this.phone = p; + } + + protected abstract void onRadioOffOrNotAvailable(); + + //***** Public Methods + public AdnRecordCache getAdnCache() { + return adnCache; + } + + public void registerForRecordsLoaded(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + recordsLoadedRegistrants.add(r); + + if (recordsToLoad == 0 && recordsRequested == true) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + + public void unregisterForRecordsLoaded(Handler h) { + recordsLoadedRegistrants.remove(h); + } + + public String getMsisdnNumber() { + return msisdn; + } + + /** + * Set subscriber number to SIM record + * + * The subscriber number is stored in EF_MSISDN (TS 51.011) + * + * When the operation is complete, onComplete will be sent to its handler + * + * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters) + * @param number dailing nubmer (up to 20 digits) + * if the number starts with '+', then set to international TOA + * @param onComplete + * onComplete.obj will be an AsyncResult + * ((AsyncResult)onComplete.obj).exception == null on success + * ((AsyncResult)onComplete.obj).exception != null on fail + */ + public void setMsisdnNumber(String alphaTag, String number, + Message onComplete) { + + msisdn = number; + msisdnTag = alphaTag; + + if(DBG) log("Set MSISDN: " + msisdnTag +" " + msisdn); + + + AdnRecord adn = new AdnRecord(msisdnTag, msisdn); + + new AdnRecordLoader(phone).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null, + obtainMessage(EVENT_SET_MSISDN_DONE, onComplete)); + } + + public String getMsisdnAlphaTag() { + return msisdnTag; + } + + public String getVoiceMailNumber() { + return voiceMailNum; + } + + /** + * Return Service Provider Name stored in SIM (EF_SPN=0x6F46) or in RUIM (EF_RUIM_SPN=0x6F41) + * @return null if SIM is not yet ready or no RUIM entry + */ + public String getServiceProviderName() { + return spn; + } + + /** + * Set voice mail number to SIM record + * + * The voice mail number can be stored either in EF_MBDN (TS 51.011) or + * EF_MAILBOX_CPHS (CPHS 4.2) + * + * If EF_MBDN is available, store the voice mail number to EF_MBDN + * + * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS + * + * So the voice mail number will be stored in both EFs if both are available + * + * Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail. + * + * When the operation is complete, onComplete will be sent to its handler + * + * @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters) + * @param voiceNumber dailing nubmer (upto 20 digits) + * if the number is start with '+', then set to international TOA + * @param onComplete + * onComplete.obj will be an AsyncResult + * ((AsyncResult)onComplete.obj).exception == null on success + * ((AsyncResult)onComplete.obj).exception != null on fail + */ + public abstract void setVoiceMailNumber(String alphaTag, String voiceNumber, + Message onComplete); + + public String getVoiceMailAlphaTag() { + return voiceMailTag; + } + + /** + * Sets the SIM voice message waiting indicator records + * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported + * @param countWaiting The number of messages waiting, if known. Use + * -1 to indicate that an unknown number of + * messages are waiting + */ + public abstract void setVoiceMessageWaiting(int line, int countWaiting); + + /** @return true if there are messages waiting, false otherwise. */ + public boolean getVoiceMessageWaiting() { + return countVoiceMessages != 0; + } + + /** + * Returns number of voice messages waiting, if available + * If not available (eg, on an older CPHS SIM) -1 is returned if + * getVoiceMessageWaiting() is true + */ + public int getCountVoiceMessages() { + return countVoiceMessages; + } + + /** + * Called by STK Service when REFRESH is received. + * @param fileChanged indicates whether any files changed + * @param fileList if non-null, a list of EF files that changed + */ + public abstract void onRefresh(boolean fileChanged, int[] fileList); + + + public boolean getRecordsLoaded() { + if (recordsToLoad == 0 && recordsRequested == true) { + return true; + } else { + return false; + } + } + + //***** Overridden from Handler + public abstract void handleMessage(Message msg); + + protected abstract void onRecordLoaded(); + + protected abstract void onAllRecordsLoaded(); + + /** + * Returns the SpnDisplayRule based on settings on the SIM and the + * specified plmn (currently-registered PLMN). See TS 22.101 Annex A + * and TS 51.011 10.3.11 for details. + * + * If the SPN is not found on the SIM, the rule is always PLMN_ONLY. + */ + protected abstract int getDisplayRule(String plmn); + + protected abstract void log(String s); +} + diff --git a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java new file mode 100644 index 0000000..620f2de --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.app.PendingIntent; +import android.content.Context; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +import static android.telephony.SmsManager.STATUS_ON_ICC_FREE; + +/** + * IccSmsInterfaceManager to provide an inter-process communication to + * access Sms in Icc. + */ +public abstract class IccSmsInterfaceManager extends ISms.Stub { + static final boolean DBG = true; + + protected PhoneBase mPhone; + protected Context mContext; + protected SMSDispatcher mDispatcher; + + protected IccSmsInterfaceManager(PhoneBase phone){ + mPhone = phone; + mContext = phone.getContext(); + } + + protected void enforceReceiveAndSend(String message) { + mContext.enforceCallingPermission( + "android.permission.RECEIVE_SMS", message); + mContext.enforceCallingPermission( + "android.permission.SEND_SMS", message); + } + + /** + * Send a Raw PDU SMS + * + * @param smsc the SMSC to send the message through, or NULL for the + * defatult SMSC + * @param pdu the raw PDU to send + * @param sentIntent if not NULL this <code>Intent</code> is + * broadcast when the message is sucessfully sent, or failed. + * The result code will be <code>Activity.RESULT_OK<code> for success, + * or one of these errors: + * <code>RESULT_ERROR_GENERIC_FAILURE</code> + * <code>RESULT_ERROR_RADIO_OFF</code> + * <code>RESULT_ERROR_NULL_PDU</code>. + * @param deliveryIntent if not NULL this <code>Intent</code> is + * broadcast when the message is delivered to the recipient. The + * raw pdu of the status report is in the extended data ("pdu"). + */ + public void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, + PendingIntent deliveryIntent) { + Context context = mPhone.getContext(); + + context.enforceCallingPermission( + "android.permission.SEND_SMS", + "Sending SMS message"); + if (DBG) log("sendRawPdu: smsc=" + smsc + + " pdu="+ pdu + " sentIntent" + sentIntent + + " deliveryIntent" + deliveryIntent); + mDispatcher.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); + } + + /** + * Send a multi-part text based SMS. + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param parts an <code>ArrayList</code> of strings that, in order, + * comprise the original message + * @param sentIntents if not null, an <code>ArrayList</code> of + * <code>PendingIntent</code>s (one for each message part) that is + * broadcast when the corresponding message part has been sent. + * The result code will be <code>Activity.RESULT_OK<code> for success, + * or one of these errors: + * <code>RESULT_ERROR_GENERIC_FAILURE</code> + * <code>RESULT_ERROR_RADIO_OFF</code> + * <code>RESULT_ERROR_NULL_PDU</code>. + * @param deliveryIntents if not null, an <code>ArrayList</code> of + * <code>PendingIntent</code>s (one for each message part) that is + * broadcast when the corresponding message part has been delivered + * to the recipient. The raw pdu of the status report is in the + * extended data ("pdu"). + */ + public void sendMultipartText(String destinationAddress, String scAddress, List<String> parts, + List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) { + Context context = mPhone.getContext(); + + context.enforceCallingPermission( + "android.permission.SEND_SMS", + "Sending SMS message"); + if (DBG) log("sendMultipartText"); + mDispatcher.sendMultipartText(destinationAddress, scAddress, (ArrayList<String>) parts, + (ArrayList<PendingIntent>) sentIntents, (ArrayList<PendingIntent>) deliveryIntents); + } + + /** + * create SmsRawData lists from all sms record byte[] + * Use null to indicate "free" record + * + * @param messages List of message records from EF_SMS. + * @return SmsRawData list of all in-used records + */ + protected ArrayList<SmsRawData> buildValidRawData(ArrayList<byte[]> messages) { + int count = messages.size(); + ArrayList<SmsRawData> ret; + + ret = new ArrayList<SmsRawData>(count); + + for (int i = 0; i < count; i++) { + byte[] ba = messages.get(i); + if (ba[0] == STATUS_ON_ICC_FREE) { + ret.add(null); + } else { + ret.add(new SmsRawData(messages.get(i))); + } + } + + return ret; + } + + /** + * Generates an EF_SMS record from status and raw PDU. + * + * @param status Message status. See TS 51.011 10.5.3. + * @param pdu Raw message PDU. + * @return byte array for the record. + */ + protected byte[] makeSmsRecordData(int status, byte[] pdu) { + byte[] data = new byte[IccConstants.SMS_RECORD_LENGTH]; + + // Status bits for this record. See TS 51.011 10.5.3 + data[0] = (byte)(status & 7); + + System.arraycopy(pdu, 0, data, 1, pdu.length); + + // Pad out with 0xFF's. + for (int j = pdu.length+1; j < IccConstants.SMS_RECORD_LENGTH; j++) { + data[j] = -1; + } + + return data; + } + + protected abstract void log(String msg); + +} + diff --git a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java new file mode 100644 index 0000000..a51d074 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.app.PendingIntent; +import android.os.ServiceManager; + +import java.util.List; + +public class IccSmsInterfaceManagerProxy extends ISms.Stub { + private IccSmsInterfaceManager mIccSmsInterfaceManager; + + public IccSmsInterfaceManagerProxy(IccSmsInterfaceManager + iccSmsInterfaceManager) { + this.mIccSmsInterfaceManager = iccSmsInterfaceManager; + if(ServiceManager.getService("isms") == null) { + ServiceManager.addService("isms", this); + } + } + + public void setmIccSmsInterfaceManager(IccSmsInterfaceManager iccSmsInterfaceManager) { + this.mIccSmsInterfaceManager = iccSmsInterfaceManager; + } + + public boolean + updateMessageOnIccEf(int index, int status, byte[] pdu) throws android.os.RemoteException { + return mIccSmsInterfaceManager.updateMessageOnIccEf(index, status, pdu); + } + + public boolean copyMessageToIccEf(int status, byte[] pdu, + byte[] smsc) throws android.os.RemoteException { + return mIccSmsInterfaceManager.copyMessageToIccEf(status, pdu, smsc); + } + + public List<SmsRawData> getAllMessagesFromIccEf() throws android.os.RemoteException { + return mIccSmsInterfaceManager.getAllMessagesFromIccEf(); + } + + public void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, + PendingIntent deliveryIntent) throws android.os.RemoteException { + mIccSmsInterfaceManager.sendRawPdu(smsc, pdu, sentIntent, + deliveryIntent); + } + + public void sendMultipartText(String destinationAddress, String scAddress, + List<String> parts, List<PendingIntent> sentIntents, + List<PendingIntent> deliveryIntents) throws android.os.RemoteException { + mIccSmsInterfaceManager.sendMultipartText(destinationAddress, scAddress, + parts, sentIntents, deliveryIntents); + } + +} diff --git a/telephony/java/com/android/internal/telephony/gsm/SimUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java index 2eecdba..881ed2d 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimUtils.java +++ b/telephony/java/com/android/internal/telephony/IccUtils.java @@ -14,48 +14,48 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; - -import java.io.UnsupportedEncodingException; +package com.android.internal.telephony; import android.graphics.Bitmap; import android.graphics.Color; import android.util.Log; +import com.android.internal.telephony.GsmAlphabet; + +import java.io.UnsupportedEncodingException; + /** * Various methods, useful for dealing with SIM data. */ -public class SimUtils -{ - static final String LOG_TAG="GSM"; +public class IccUtils { + static final String LOG_TAG="IccUtils"; /** * Many fields in GSM SIM's are stored as nibble-swizzled BCD * - * Assumes left-justified field that may be padded right with 0xf + * Assumes left-justified field that may be padded right with 0xf * values. * * Stops on invalid BCD value, returning string so far */ public static String - bcdToString(byte[] data, int offset, int length) - { + bcdToString(byte[] data, int offset, int length) { StringBuilder ret = new StringBuilder(length*2); - + for (int i = offset ; i < offset + length ; i++) { byte b; int v; - + v = data[i] & 0xf; if (v > 9) break; ret.append((char)('0' + v)); v = (data[i] >> 4) & 0xf; if (v > 9) break; - ret.append((char)('0' + v)); + ret.append((char)('0' + v)); } - - return ret.toString(); + + return ret.toString(); } @@ -66,7 +66,7 @@ public class SimUtils * significant nibble. * * Out-of-range digits are treated as 0 for the sake of the time stamp, - * because of this: + * because of this: * * TS 23.040 section 9.2.3.11 * "if the MS receives a non-integer value in the SCTS, it shall @@ -74,13 +74,12 @@ public class SimUtils * exactly as received" */ public static int - bcdByteToInt(byte b) - { + bcdByteToInt(byte b) { int ret = 0; // treat out-of-range BCD values as 0 if ((b & 0xf0) <= 0x90) { - ret = (b >> 4) & 0xf; + ret = (b >> 4) & 0xf; } if ((b & 0x0f) <= 0x09) { @@ -90,6 +89,24 @@ public class SimUtils return ret; } + /** Decodes BCD byte like {@link bcdByteToInt}, but the most significant BCD + * digit is expected in the most significant nibble. + */ + public static int + beBcdByteToInt(byte b) { + int ret = 0; + + // treat out-of-range BCD values as 0 + if ((b & 0xf0) <= 0x90) { + ret = ((b >> 4) & 0xf) * 10; + } + + if ((b & 0x0f) <= 0x09) { + ret += (b & 0xf); + } + + return ret; + } /** * Decodes a string field that's formatted like the EF[ADN] alpha @@ -97,11 +114,11 @@ public class SimUtils * * From TS 51.011 10.5.1: * Coding: - * this alpha tagging shall use either - * - the SMS default 7 bit coded alphabet as defined in - * TS 23.038 [12] with bit 8 set to 0. The alpha identifier + * this alpha tagging shall use either + * - the SMS default 7 bit coded alphabet as defined in + * TS 23.038 [12] with bit 8 set to 0. The alpha identifier * shall be left justified. Unused bytes shall be set to 'FF'; or - * - one of the UCS2 coded options as defined in annex B. + * - one of the UCS2 coded options as defined in annex B. * * Annex B from TS 11.11 V8.13.0: * 1) If the first octet in the alpha string is '80', then the @@ -109,7 +126,7 @@ public class SimUtils * 2) if the first octet in the alpha string is '81', then the * second octet contains a value indicating the number of * characters in the string, and the third octet contains an - * 8 bit number which defines bits 15 to 8 of a 16 bit + * 8 bit number which defines bits 15 to 8 of a 16 bit * base pointer, where bit 16 is set to zero and bits 7 to 1 * are also set to zero. These sixteen bits constitute a * base pointer to a "half page" in the UCS2 code space, to be @@ -127,8 +144,7 @@ public class SimUtils * base pointer to a "half page" in the UCS2 code space... */ public static String - adnStringFieldToString(byte[] data, int offset, int length) - { + adnStringFieldToString(byte[] data, int offset, int length) { if (length >= 1) { if (data[offset] == (byte) 0x80) { int ucslen = (length - 1) / 2; @@ -208,8 +224,7 @@ public class SimUtils } static int - hexCharToInt(char c) - { + hexCharToInt(char c) { if (c >= '0' && c <= '9') return (c - '0'); if (c >= 'A' && c <= 'F') return (c - 'A' + 10); if (c >= 'a' && c <= 'f') return (c - 'a' + 10); @@ -219,17 +234,16 @@ public class SimUtils /** * Converts a hex String to a byte array. - * + * * @param s A string of hexadecimal characters, must be an even number of * chars long * * @return byte array representation - * + * * @throws RuntimeException on invalid format */ public static byte[] - hexStringToBytes(String s) - { + hexStringToBytes(String s) { byte[] ret; if (s == null) return null; @@ -239,10 +253,10 @@ public class SimUtils ret = new byte[sz/2]; for (int i=0 ; i <sz ; i+=2) { - ret[i/2] = (byte) ((hexCharToInt(s.charAt(i)) << 4) + ret[i/2] = (byte) ((hexCharToInt(s.charAt(i)) << 4) | hexCharToInt(s.charAt(i+1))); } - + return ret; } @@ -253,10 +267,9 @@ public class SimUtils * null returns null */ public static String - bytesToHexString(byte[] bytes) - { + bytesToHexString(byte[] bytes) { if (bytes == null) return null; - + StringBuilder ret = new StringBuilder(2*bytes.length); for (int i = 0 ; i < bytes.length ; i++) { @@ -281,10 +294,9 @@ public class SimUtils * empty string returned on decode error */ public static String - networkNameToString(byte[] data, int offset, int length) - { + networkNameToString(byte[] data, int offset, int length) { String ret; - + if ((data[offset] & 0x80) != 0x80 || length < 1) { return ""; } @@ -295,13 +307,12 @@ public class SimUtils int countSeptets; int unusedBits = data[offset] & 7; countSeptets = (((length - 1) * 8) - unusedBits) / 7 ; - ret = GsmAlphabet.gsm7BitPackedToString( - data, offset + 1, countSeptets); + ret = GsmAlphabet.gsm7BitPackedToString(data, offset + 1, countSeptets); break; case 1: // UCS2 try { - ret = new String(data, + ret = new String(data, offset + 1, length - 1, "utf-16"); } catch (UnsupportedEncodingException ex) { ret = ""; @@ -332,7 +343,7 @@ public class SimUtils * @param data The raw data * @param length The length of image body * @return The bitmap - */ + */ public static Bitmap parseToBnW(byte[] data, int length){ int valueIndex = 0; int width = data[valueIndex++] & 0xFF; @@ -369,7 +380,7 @@ public class SimUtils /** * a TS 131.102 image instance of code scheme '11' into color Bitmap - * + * * @param data The raw data * @param length the length of image body * @param transparency with or without transparency diff --git a/telephony/java/com/android/internal/telephony/IccVmFixedException.java b/telephony/java/com/android/internal/telephony/IccVmFixedException.java new file mode 100644 index 0000000..45679c1 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccVmFixedException.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +/** + * {@hide} + */ +public final class IccVmFixedException extends IccException { + IccVmFixedException() + { + + } + + 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 new file mode 100644 index 0000000..7e90d24 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccVmNotSupportedException.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +/** + * {@hide} + */ +public final class IccVmNotSupportedException extends IccException { + IccVmNotSupportedException() + { + + } + + public IccVmNotSupportedException(String s) + { + super(s); + } +} diff --git a/telephony/java/com/android/internal/telephony/MmiCode.java b/telephony/java/com/android/internal/telephony/MmiCode.java index 925b06f..c71ff77 100644 --- a/telephony/java/com/android/internal/telephony/MmiCode.java +++ b/telephony/java/com/android/internal/telephony/MmiCode.java @@ -41,14 +41,14 @@ public interface MmiCode * @return Localized message for UI display, valid only in COMPLETE * or FAILED states. null otherwise */ - + public CharSequence getMessage(); /** * Cancels pending MMI request. * State becomes CANCELLED unless already COMPLETE or FAILED */ - public void cancel(); + public void cancel(); /** * @return true if the network response is a REQUEST for more user input. diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java index 05e61f2..ed90d32 100644 --- a/telephony/java/com/android/internal/telephony/Phone.java +++ b/telephony/java/com/android/internal/telephony/Phone.java @@ -17,10 +17,14 @@ package com.android.internal.telephony; import android.content.Context; +import android.content.SharedPreferences; import android.os.Handler; import android.os.Message; +import android.preference.PreferenceManager; import android.telephony.CellLocation; import android.telephony.ServiceState; + +import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.gsm.NetworkInfo; import com.android.internal.telephony.gsm.PdpConnection; import com.android.internal.telephony.test.SimulatedRadioControl; @@ -38,13 +42,13 @@ public interface Phone { /** used to enable additional debug messages */ static final boolean DEBUG_PHONE = true; - - /** + + /** * The phone state. One of the following:<p> * <ul> * <li>IDLE = no phone activity</li> - * <li>RINGING = a phone call is ringing or call waiting. + * <li>RINGING = a phone call is ringing or call waiting. * In the latter case, another call is active as well</li> * <li>OFFHOOK = The phone is off hook. At least one call * exists that is dialing, active or holding and no calls are @@ -70,7 +74,7 @@ public interface Phone { CONNECTED, CONNECTING, DISCONNECTED, SUSPENDED; }; - enum DataActivityState { + public enum DataActivityState { /** * The state of a data activity. * <ul> @@ -131,6 +135,8 @@ public interface Phone { static final String REASON_DATA_ENABLED = "dataEnabled"; static final String REASON_GPRS_ATTACHED = "gprsAttached"; static final String REASON_GPRS_DETACHED = "gprsDetached"; + static final String REASON_CDMA_DATA_ATTACHED = "cdmaDataAttached"; + static final String REASON_CDMA_DATA_DETACHED = "cdmaDataDetached"; static final String REASON_APN_CHANGED = "apnChanged"; static final String REASON_APN_SWITCHED = "apnSwitched"; static final String REASON_RESTORE_DEFAULT_APN = "restoreDefaultApn"; @@ -152,12 +158,32 @@ public interface Phone { static final int BM_BOUNDARY = 6; // upper band boundary // Used for preferred network type - static final int NT_AUTO_TYPE = 0; // WCDMA preferred (auto mode) - static final int NT_GSM_TYPE = 1; // GSM only - static final int NT_WCDMA_TYPE = 2; // WCDMA only - - /** - * Get the current ServiceState. Use + // 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_GLOBAL; + + + // 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 + + // 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 + + /** + * Get the current ServiceState. Use * <code>registerForServiceStateChanged</code> to be informed of * updates. */ @@ -167,11 +193,12 @@ public interface Phone { * Get the current CellLocation. */ CellLocation getCellLocation(); - + /** * Get the current DataState. No change notification exists at this - * interface -- use - * {@link com.android.internal.telephony.PhoneStateIntentReceiver PhoneStateIntentReceiver} instead. + * interface -- use + * {@link com.android.internal.telephony.PhoneStateIntentReceiver PhoneStateIntentReceiver} + * instead. */ DataState getDataConnectionState(); @@ -181,58 +208,70 @@ public interface Phone { * {@link TelephonyManager} instead. */ DataActivityState getDataActivityState(); - + /** * Gets the context for the phone, as set at initialization time. */ Context getContext(); - /** + /** + * Disables the DNS check (i.e., allows "0.0.0.0"). + * Useful for lab testing environment. + * @param b true disables the check, false enables. + */ + void disableDnsCheck(boolean b); + + /** + * Returns true if the DNS check is currently disabled. + */ + boolean isDnsCheckDisabled(); + + /** * Get current coarse-grained voice call state. - * Use {@link #registerForPhoneStateChanged(Handler, int, Object) + * Use {@link #registerForPhoneStateChanged(Handler, int, Object) * registerForPhoneStateChanged()} for change notification. <p> * If the phone has an active call and call waiting occurs, * then the phone state is RINGING not OFFHOOK - * <strong>Note:</strong> + * <strong>Note:</strong> * This registration point provides notification of finer-grained * changes.<p> * */ State getState(); - /** + /** * Returns a string identifier for this phone interface for parties * outside the phone app process. * @return The string name. */ String getPhoneName(); - /** + /** * Returns an array of string identifiers for the APN types serviced by the * currently active or last connected APN. * @return The string array. */ String[] getActiveApnTypes(); - - /** + + /** * Returns a string identifier for currently active or last connected APN. * @return The string name. */ String getActiveApn(); - - /** + + /** * Get current signal strength. No change notification available on this * interface. Use <code>PhoneStateNotifier</code> or an equivalent. - * An ASU is 0-31 or -1 if unknown (for GSM, dBm = -113 - 2 * asu). + * An ASU is 0-31 or -1 if unknown (for GSM, dBm = -113 - 2 * asu). * The following special values are defined:</p> * <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. */ int getSignalStrengthASU(); - - /** + + /** * Notifies when a previously untracked non-ringing/waiting connection has appeared. * This is likely due to some other entity (eg, SIM card application) initiating a call. */ @@ -243,7 +282,7 @@ public interface Phone { */ void unregisterForUnknownConnection(Handler h); - /** + /** * Notifies when any aspect of the voice call state changes. * Resulting events will have an AsyncResult in <code>Message.obj</code>. * AsyncResult.userData will be set to the obj argument here. @@ -252,13 +291,13 @@ public interface Phone { void registerForPhoneStateChanged(Handler h, int what, Object obj); /** - * Unregisters for voice call state change notifications. + * Unregisters for voice call state change notifications. * Extraneous calls are tolerated silently. */ void unregisterForPhoneStateChanged(Handler h); - /** + /** * Notifies when a new ringing or waiting connection has appeared.<p> * * Messages received from this: @@ -267,19 +306,19 @@ public interface Phone { * AsyncResult.result = a Connection. <p> * Please check Connection.isRinging() to make sure the Connection * has not dropped since this message was posted. - * If Connection.isRinging() is true, then + * If Connection.isRinging() is true, then * Connection.getCall() == Phone.getRingingCall() */ void registerForNewRingingConnection(Handler h, int what, Object obj); /** - * Unregisters for new ringing connection notification. + * Unregisters for new ringing connection notification. * Extraneous calls are tolerated silently */ void unregisterForNewRingingConnection(Handler h); - /** + /** * Notifies when an incoming call rings.<p> * * Messages received from this: @@ -288,29 +327,29 @@ public interface Phone { * AsyncResult.result = a Connection. <p> */ void registerForIncomingRing(Handler h, int what, Object obj); - + /** - * Unregisters for ring notification. + * Unregisters for ring notification. * Extraneous calls are tolerated silently */ - + void unregisterForIncomingRing(Handler h); - - - /** + + + /** * Notifies when a voice connection has disconnected, either due to local * or remote hangup or error. - * + * * Messages received from this will have the following members:<p> * <ul><li>Message.obj will be an AsyncResult</li> * <li>AsyncResult.userObj = obj</li> - * <li>AsyncResult.result = a Connection object that is + * <li>AsyncResult.result = a Connection object that is * no longer connected.</li></ul> */ void registerForDisconnect(Handler h, int what, Object obj); /** - * Unregisters for voice disconnection notification. + * Unregisters for voice disconnection notification. * Extraneous calls are tolerated silently */ void unregisterForDisconnect(Handler h); @@ -330,7 +369,7 @@ public interface Phone { void registerForMmiInitiate(Handler h, int what, Object obj); /** - * Unregisters for new MMI initiate notification. + * Unregisters for new MMI initiate notification. * Extraneous calls are tolerated silently */ void unregisterForMmiInitiate(Handler h); @@ -346,7 +385,7 @@ public interface Phone { void registerForMmiComplete(Handler h, int what, Object obj); /** - * Unregisters for MMI complete notification. + * Unregisters for MMI complete notification. * Extraneous calls are tolerated silently */ void unregisterForMmiComplete(Handler h); @@ -355,7 +394,7 @@ public interface Phone { * Returns a list of MMI codes that are pending. (They have initiated * but have not yet completed). * Presently there is only ever one. - * Use <code>registerForMmiInitiate</code> + * Use <code>registerForMmiInitiate</code> * and <code>registerForMmiComplete</code> for change notification. */ public List<? extends MmiCode> getPendingMmiCodes(); @@ -370,14 +409,14 @@ public interface Phone { public void sendUssdResponse(String ussdMessge); /** - * Register for ServiceState changed. + * Register for ServiceState changed. * Message.obj will contain an AsyncResult. * AsyncResult.result will be a ServiceState instance */ void registerForServiceStateChanged(Handler h, int what, Object obj); /** - * Unregisters for ServiceStateChange notification. + * Unregisters for ServiceStateChange notification. * Extraneous calls are tolerated silently */ void unregisterForServiceStateChanged(Handler h); @@ -394,9 +433,9 @@ public interface Phone { void registerForSuppServiceNotification(Handler h, int what, Object obj); /** - * Unregisters for Supplementary Service notifications. + * Unregisters for Supplementary Service notifications. * Extraneous calls are tolerated silently - * + * * @param h Handler to be removed from the registrant list. */ void unregisterForSuppServiceNotification(Handler h); @@ -414,53 +453,85 @@ public interface Phone { /** * Unregister for notifications when a supplementary service attempt fails. * Extraneous calls are tolerated silently - * + * * @param h Handler to be removed from the registrant list. */ void unregisterForSuppServiceFailed(Handler h); - /** - * Returns SIM record load state. Use + /** + * Register for notifications when a sInCall VoicePrivacy is enabled + * + * @param h Handler that receives the notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj); + + /** + * Unegister for notifications when a sInCall VoicePrivacy is enabled + * + * @param h Handler to be removed from the registrant list. + */ + void unregisterForInCallVoicePrivacyOn(Handler h); + + /** + * Register for notifications when a sInCall VoicePrivacy is disabled + * + * @param h Handler that receives the notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj); + + /** + * Unegister for notifications when a sInCall VoicePrivacy is disabled + * + * @param h Handler to be removed from the registrant list. + */ + void unregisterForInCallVoicePrivacyOff(Handler h); + + /** + * Returns SIM record load state. Use * <code>getSimCard().registerForReady()</code> for change notification. * - * @return true if records from the SIM have been loaded and are + * @return true if records from the SIM have been loaded and are * available (if applicable). If not applicable to the underlying * technology, returns true as well. */ - boolean getSimRecordsLoaded(); + boolean getIccRecordsLoaded(); /** - * Returns the SIM card interface for this phone, or null + * Returns the ICC card interface for this phone, or null * if not applicable to underlying technology. */ - SimCard getSimCard(); + IccCard getIccCard(); /** - * Answers a ringing or waiting call. Active calls, if any, go on hold. + * Answers a ringing or waiting call. Active calls, if any, go on hold. * Answering occurs asynchronously, and final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. * * @exception CallStateException when no call is ringing or waiting */ void acceptCall() throws CallStateException; - /** - * Reject (ignore) a ringing call. In GSM, this means UDUB - * (User Determined User Busy). Reject occurs asynchronously, - * and final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + /** + * Reject (ignore) a ringing call. In GSM, this means UDUB + * (User Determined User Busy). Reject occurs asynchronously, + * and final notification occurs via + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. * * @exception CallStateException when no call is ringing or waiting */ void rejectCall() throws CallStateException; - /** + /** * Places any active calls on hold, and makes any held calls * active. Switch occurs asynchronously and may fail. - * Final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * Final notification occurs via + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. * * @exception CallStateException if a call is ringing, waiting, or @@ -469,24 +540,40 @@ public interface Phone { void switchHoldingAndActive() throws CallStateException; /** - * Whether or not the phone can conference in the current phone + * Whether or not the phone can conference in the current phone * state--that is, one call holding and one call active. - * @return true if the phone can conference; false otherwise. + * @return true if the phone can conference; false otherwise. */ boolean canConference(); /** - * Conferences holding and active. Conference occurs asynchronously - * and may fail. Final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()}. - * + * Conferences holding and active. Conference occurs asynchronously + * and may fail. Final notification occurs via + * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPhoneStateChanged()}. + * * @exception CallStateException if canConference() would return false. * In these cases, this operation may not be performed. */ void conference() throws CallStateException; /** + * Enable or disable enhanced Voice Privacy (VP). If enhanced VP is + * disabled, normal VP is enabled. + * + * @param enable whether true or false to enable or disable. + * @param onComplete a callback message when the action is completed. + */ + void enableEnhancedVoicePrivacy(boolean enable, Message onComplete); + + /** + * Get the currently set Voice Privacy (VP) mode. + * + * @param onComplete a callback message when the action is completed. + */ + void getEnhancedVoicePrivacy(Message onComplete); + + /** * Whether or not the phone can do explicit call transfer in the current * phone state--that is, one call holding and one call active. * @return true if the phone can do explicit call transfer; false otherwise. @@ -513,65 +600,65 @@ public interface Phone { void clearDisconnected(); - /** - * Gets the foreground call object, which represents all connections that - * are dialing or active (all connections + /** + * Gets the foreground call object, which represents all connections that + * are dialing or active (all connections * that have their audio path connected).<p> * * The foreground call is a singleton object. It is constant for the life * of this phone. It is never null.<p> - * + * * The foreground call will only ever be in one of these states: - * IDLE, ACTIVE, DIALING, ALERTING, or DISCONNECTED. + * IDLE, ACTIVE, DIALING, ALERTING, or DISCONNECTED. * * State change notification is available via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. */ Call getForegroundCall(); - /** + /** * Gets the background call object, which represents all connections that * are holding (all connections that have been accepted or connected, but * do not have their audio path connected). <p> * * The background call is a singleton object. It is constant for the life * of this phone object . It is never null.<p> - * + * * The background call will only ever be in one of these states: * IDLE, HOLDING or DISCONNECTED. * * State change notification is available via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. */ Call getBackgroundCall(); - /** - * Gets the ringing call object, which represents an incoming + /** + * Gets the ringing call object, which represents an incoming * connection (if present) that is pending answer/accept. (This connection * may be RINGING or WAITING, and there may be only one.)<p> * The ringing call is a singleton object. It is constant for the life * of this phone. It is never null.<p> - * + * * The ringing call will only ever be in one of these states: * IDLE, INCOMING, WAITING or DISCONNECTED. * * State change notification is available via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. */ Call getRingingCall(); - /** + /** * Initiate a new voice connection. This happens asynchronously, so you * cannot assume the audio path is connected (or a call index has been * assigned) until PhoneStateChanged notification has occurred. * * @exception CallStateException if a new outgoing call is not currently - * possible because no more call slots exist or a call exists that is - * dialing, alerting, ringing, or waiting. Other errors are + * possible because no more call slots exist or a call exists that is + * dialing, alerting, ringing, or waiting. Other errors are * handled asynchronously. */ Connection dial(String dialString) throws CallStateException; @@ -579,7 +666,7 @@ public interface Phone { /** * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated * without SEND (so <code>dial</code> is not appropriate). - * + * * @param dialString the MMI command to be executed. * @return true if MMI command is executed. */ @@ -597,7 +684,7 @@ public interface Phone { boolean handleInCallMmiCommands(String command) throws CallStateException; /** - * Play a DTMF tone on the active call. Ignored if there is no active call. + * Play a DTMF tone on the active call. Ignored if there is no active call. * @param c should be one of 0-9, '*' or '#'. Other values will be * silently ignored. */ @@ -619,20 +706,20 @@ public interface Phone { /** - * Sets the radio power on/off state (off is sometimes - * called "airplane mode"). Current state can be gotten via - * {@link #getServiceState()}.{@link + * Sets the radio power on/off state (off is sometimes + * called "airplane mode"). Current state can be gotten via + * {@link #getServiceState()}.{@link * android.telephony.ServiceState#getState() getState()}. - * <strong>Note: </strong>This request is asynchronous. + * <strong>Note: </strong>This request is asynchronous. * getServiceState().getState() will not change immediately after this call. - * registerForServiceStateChanged() to find out when the + * registerForServiceStateChanged() to find out when the * request is complete. * - * @param power true means "on", false means "off". + * @param power true means "on", false means "off". */ void setRadioPower(boolean power); - /** + /** * Get voice message waiting indicator status. No change notification * available on this interface. Use PhoneStateNotifier or similar instead. * @@ -674,8 +761,8 @@ public interface Phone { void setLine1Number(String alphaTag, String number, Message onComplete); /** - * Get the voice mail access phone number. Typically dialed when the - * user holds the "1" key in the phone app. May return null if not + * Get the voice mail access phone number. Typically dialed when the + * user holds the "1" key in the phone app. May return null if not * available or the SIM is not ready.<p> */ String getVoiceMailNumber(); @@ -684,8 +771,8 @@ public interface Phone { * 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> - * - * Please use this value instead of some other localized string when + * + * Please use this value instead of some other localized string when * showing a name for this number in the UI. For example, call log * entries should show this alpha tag. <p> * @@ -708,29 +795,29 @@ public interface Phone { /** * getCallForwardingOptions - * gets a call forwarding option. The return value of - * ((AsyncResult)onComplete.obj) is an array of CallForwardInfo. - * - * @param commandInterfaceCFReason is one of the valid call forwarding - * CF_REASONS, as defined in - * <code>com.android.internal.telephony.gsm.CommandsInterface</code> + * gets a call forwarding option. The return value of + * ((AsyncResult)onComplete.obj) is an array of CallForwardInfo. + * + * @param commandInterfaceCFReason is one of the valid call forwarding + * CF_REASONS, as defined in + * <code>com.android.internal.telephony.CommandsInterface./code> * @param onComplete a callback message when the action is completed. - * @see com.android.internal.telephony.gsm.CallForwardInfo for details. + * @see com.android.internal.telephony.CallForwardInfo for details. */ void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete); - + /** * setCallForwardingOptions * sets a call forwarding option. - * - * @param commandInterfaceCFReason is one of the valid call forwarding - * CF_REASONS, as defined in - * <code>com.android.internal.telephony.gsm.CommandsInterface</code> - * @param commandInterfaceCFAction is one of the valid call forwarding - * CF_ACTIONS, as defined in - * <code>com.android.internal.telephony.gsm.CommandsInterface</code> - * @param dialingNumber is the target phone number to forward calls to + * + * @param commandInterfaceCFReason is one of the valid call forwarding + * CF_REASONS, as defined in + * <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> + * @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. * @param onComplete a callback message when the action is completed. @@ -740,83 +827,83 @@ public interface Phone { String dialingNumber, int timerSeconds, Message onComplete); - + /** * getOutgoingCallerIdDisplay - * gets outgoing caller id display. The return value of + * gets outgoing caller id display. The return value of * ((AsyncResult)onComplete.obj) is an array of int, with a length of 2. - * + * * @param onComplete a callback message when the action is completed. - * @see com.android.internal.telephony.gsm.CommandsInterface.getCLIR for details. + * @see com.android.internal.telephony.CommandsInterface.getCLIR for details. */ void getOutgoingCallerIdDisplay(Message onComplete); - + /** * setOutgoingCallerIdDisplay - * sets a call forwarding option. - * - * @param commandInterfaceCLIRMode is one of the valid call CLIR - * modes, as defined in - * <code>com.android.internal.telephony.gsm.CommandsInterface</code> + * sets a call forwarding option. + * + * @param commandInterfaceCLIRMode is one of the valid call CLIR + * modes, as defined in + * <code>com.android.internal.telephony.CommandsInterface./code> * @param onComplete a callback message when the action is completed. */ void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete); - + /** * getCallWaiting - * gets call waiting activation state. The return value of + * gets call waiting activation state. The return value of * ((AsyncResult)onComplete.obj) is an array of int, with a length of 1. - * + * * @param onComplete a callback message when the action is completed. - * @see com.android.internal.telephony.gsm.CommandsInterface.queryCallWaiting for details. + * @see com.android.internal.telephony.CommandsInterface.queryCallWaiting for details. */ void getCallWaiting(Message onComplete); - + /** * setCallWaiting - * sets a call forwarding option. - * - * @param enable is a boolean representing the state that you are + * sets a call forwarding 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 setCallWaiting(boolean enable, Message onComplete); - + /** * Scan available networks. This method is asynchronous; . * On completion, <code>response.obj</code> is set to an AsyncResult with * one of the following members:.<p> *<ul> - * <li><code>response.obj.result</code> will be a <code>List</code> of - * <code>com.android.internal.telephony.gsm.NetworkInfo</code> objects, or</li> - * <li><code>response.obj.exception</code> will be set with an exception + * <li><code>response.obj.result</code> will be a <code>List</code> of + * <code>com.android.internal.telephony.gsm.NetworkInfo</code> objects, or</li> + * <li><code>response.obj.exception</code> will be set with an exception * on failure.</li> * </ul> */ - void getAvailableNetworks(Message response); + void getAvailableNetworks(Message response); /** * Switches network selection mode to "automatic", re-scanning and * re-selecting a network if appropriate. - * - * @param response The message to dispatch when the network selection + * + * @param response The message to dispatch when the network selection * is complete. - * - * @see #selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo, + * + * @see #selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo, * android.os.Message ) */ void setNetworkSelectionModeAutomatic(Message response); /** - * Manually selects a network. <code>response</code> is + * Manually selects a network. <code>response</code> is * dispatched when this is complete. <code>response.obj</code> will be * an AsyncResult, and <code>response.obj.exception</code> will be non-null * on failure. - * + * * @see #setNetworkSelectionModeAutomatic(Message) */ - void selectNetworkManually(NetworkInfo network, + void selectNetworkManually(NetworkInfo network, Message response); /** @@ -843,7 +930,7 @@ public interface Phone { * of available cell IDs. Cell IDs are in hexadecimal format. * * @param response callback message that is dispatched when the query - * completes. + * completes. */ void getNeighboringCids(Message response); @@ -856,28 +943,28 @@ public interface Phone { * <code>AsyncResult</code>. <code>Message.obj.result</code> will be * a Connection object.<p> * - * Message.arg1 will be the post dial character being processed, + * Message.arg1 will be the post dial character being processed, * or 0 ('\0') if end of string.<p> * - * If Connection.getPostDialState() == WAIT, - * the application must call - * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar() - * Connection.proceedAfterWaitChar()} or - * {@link com.android.internal.telephony.Connection#cancelPostDial() + * If Connection.getPostDialState() == WAIT, + * the application must call + * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar() + * Connection.proceedAfterWaitChar()} or + * {@link com.android.internal.telephony.Connection#cancelPostDial() * Connection.cancelPostDial()} - * for the telephony system to continue playing the post-dial + * for the telephony system to continue playing the post-dial * DTMF sequence.<p> * - * If Connection.getPostDialState() == WILD, - * the application must call + * If Connection.getPostDialState() == WILD, + * the application must call * {@link com.android.internal.telephony.Connection#proceedAfterWildChar * Connection.proceedAfterWildChar()} - * or - * {@link com.android.internal.telephony.Connection#cancelPostDial() + * or + * {@link com.android.internal.telephony.Connection#cancelPostDial() * Connection.cancelPostDial()} - * for the telephony system to continue playing the + * for the telephony system to continue playing the * post-dial DTMF sequence.<p> - * + * * Only one post dial character handler may be set. <p> * Calling this method with "h" equal to null unsets this handler.<p> */ @@ -885,19 +972,19 @@ public interface Phone { /** - * Mutes or unmutes the microphone for the active call. The microphone - * is automatically unmuted if a call is answered, dialed, or resumed + * Mutes or unmutes the microphone for the active call. The microphone + * is automatically unmuted if a call is answered, dialed, or resumed * from a holding state. - * - * @param muted true to mute the microphone, + * + * @param muted true to mute the microphone, * false to activate the microphone. */ void setMute(boolean muted); /** - * Gets current mute status. Use - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * Gets current mute status. Use + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()} * as a change notifcation, although presently phone state changed is not * fired when setMute() is called. @@ -908,12 +995,12 @@ public interface Phone { /** * Invokes RIL_REQUEST_OEM_HOOK_RAW on RIL implementation. - * + * * @param data The data for the request. - * @param response <strong>On success</strong>, + * @param response <strong>On success</strong>, * (byte[])(((AsyncResult)response.obj).result) - * <strong>On failure</strong>, - * (((AsyncResult)response.obj).result) == null and + * <strong>On failure</strong>, + * (((AsyncResult)response.obj).result) == null and * (((AsyncResult)response.obj).exception) being an instance of * com.android.internal.telephony.gsm.CommandException * @@ -923,13 +1010,13 @@ public interface Phone { /** * Invokes RIL_REQUEST_OEM_HOOK_Strings on RIL implementation. - * + * * @param strings The strings to make available as the request data. - * @param response <strong>On success</strong>, "response" bytes is + * @param response <strong>On success</strong>, "response" bytes is * made available as: * (String[])(((AsyncResult)response.obj).result). - * <strong>On failure</strong>, - * (((AsyncResult)response.obj).result) == null and + * <strong>On failure</strong>, + * (((AsyncResult)response.obj).result) == null and * (((AsyncResult)response.obj).exception) being an instance of * com.android.internal.telephony.gsm.CommandException * @@ -940,6 +1027,7 @@ public interface Phone { /** * Get the current active PDP context list * + * @deprecated * @param response <strong>On success</strong>, "response" bytes is * made available as: * (String[])(((AsyncResult)response.obj).result). @@ -951,13 +1039,34 @@ public interface Phone { void getPdpContextList(Message response); /** + * Get the current active Data Call list, substitutes getPdpContextList + * + * @param response <strong>On success</strong>, "response" bytes is + * made available as: + * (String[])(((AsyncResult)response.obj).result). + * <strong>On failure</strong>, + * (((AsyncResult)response.obj).result) == null and + * (((AsyncResult)response.obj).exception) being an instance of + * com.android.internal.telephony.gsm.CommandException + */ + void getDataCallList(Message response); + + /** * Get current mutiple PDP link status - * + * + * @deprecated * @return list of pdp link connections */ List<PdpConnection> getCurrentPdpList (); /** + * Get current mutiple data connection status + * + * @return list of data connections + */ + List<DataConnection> getCurrentDataConnectionList (); + + /** * Udpate LAC and CID in service state for currnet GSM netowrk registration * * If get different LAC and/or CID, notifyServiceState will be sent @@ -981,11 +1090,11 @@ public interface Phone { void disableLocationUpdates(); /** - * For unit tests; don't send notifications to "Phone" + * For unit tests; don't send notifications to "Phone" * mailbox registrants if true. */ void setUnitTestMode(boolean f); - + /** * @return true If unit test mode is enabled */ @@ -1019,8 +1128,29 @@ public interface Phone { void setDataRoamingEnabled(boolean enable); /** + * Query the CDMA roaming preference setting + * + * @param response is callback message to report one of CDMA_RM_* + */ + void queryCdmaRoamingPreference(Message response); + + /** + * Requests to set the CDMA roaming preference + * @param cdmaRoamingType one of CDMA_RM_* + * @param response is callback message + */ + void setCdmaRoamingPreference(int cdmaRoamingType, Message response); + + /** + * Requests to set the CDMA subscription mode + * @param cdmaSubscriptionType one of CDMA_SUBSCRIPTION_* + * @param response is callback message + */ + void setCdmaSubscription(int cdmaSubscriptionType, Message response); + + /** * If this is a simulated phone interface, returns a SimulatedRadioControl. - * @ return A SimulatedRadioControl if this is a simulated interface; + * @ return A SimulatedRadioControl if this is a simulated interface; * otherwise, null. */ SimulatedRadioControl getSimulatedRadioControl(); @@ -1109,7 +1239,7 @@ public interface Phone { public String[] getDnsServers(String apnType); /** - * Retrieves the unique device ID, e.g., IMEI for GSM phones. + * Retrieves the unique device ID, e.g., IMEI for GSM phones and MEID for CDMA phones. */ String getDeviceId(); @@ -1125,7 +1255,81 @@ public interface Phone { String getSubscriberId(); /** - * Retrieves the serial number of the SIM, if applicable. + * Retrieves the serial number of the ICC, if applicable. + */ + String getIccSerialNumber(); + + //***** CDMA support methods + + + /** + * Retrieves the ESN for CDMA phones. */ - String getSimSerialNumber(); + String getEsn(); + + /** + * Retrieves MEID for CDMA phones. + */ + String getMeid(); + + /** + * Retrieves the PhoneSubInfo of the Phone + */ + public PhoneSubInfo getPhoneSubInfo(); + + /** + * Retrieves the IccSmsInterfaceManager of the Phone + */ + public IccSmsInterfaceManager getIccSmsInterfaceManager(); + + /** + * Retrieves the IccPhoneBookInterfaceManager of the Phone + */ + public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(); + + /** + * setTTYModeEnabled + * 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); + + /** + * queryTTYModeEnabled + * query the status of the TTY mode + * + * @param onComplete a callback message when the action is completed. + */ + void queryTTYModeEnabled(Message onComplete); + + /** + * Activate or deactivate cell broadcast SMS. + * + * @param activate + * 0 = activate, 1 = deactivate + * @param response + * Callback message is empty on completion + */ + void activateCellBroadcastSms(int activate, Message response); + + /** + * Query the current configuration of cdma cell broadcast SMS. + * + * @param response + * Callback message is empty on completion + */ + void getCellBroadcastSmsConfig(Message response); + + /** + * Configure cell broadcast SMS. + * + * @param response + * Callback message is empty on completion + */ + public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response); + + public void notifyDataActivity(); } diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index 4fb5f61..259de62 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -20,23 +20,30 @@ import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.content.Context; import android.content.res.Configuration; +import android.content.SharedPreferences; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; +import android.os.Message; import android.os.RegistrantList; import android.os.SystemProperties; +import android.preference.PreferenceManager; import android.telephony.ServiceState; +import android.text.TextUtils; import android.util.Log; + import com.android.internal.R; +import com.android.internal.telephony.gsm.PdpConnection; import com.android.internal.telephony.test.SimulatedRadioControl; import java.util.List; import java.util.Locale; + /** - * (<em>Not for SDK use</em>) + * (<em>Not for SDK use</em>) * A base implementation for the com.android.internal.telephony.Phone interface. - * + * * Note that implementations of Phone.java are expected to be used * from a single application thread. This should be the same thread that * originally called PhoneFactory to obtain the interface. @@ -46,42 +53,101 @@ import java.util.Locale; */ public abstract class PhoneBase implements Phone { - private static final String LOG_TAG = "GSM"; + private static final String LOG_TAG = "PHONE"; + private static final boolean LOCAL_DEBUG = true; + + // Key used to read and write the saved network selection value + public static final String NETWORK_SELECTION_KEY = "network_selection_key"; + + // Key used to read/write "disable data connection on boot" pref (used for testing) + public static final String DATA_DISABLED_ON_BOOT_KEY = "disabled_on_boot_key"; + + //***** Event Constants + protected static final int EVENT_RADIO_AVAILABLE = 1; + /** Supplementary Service Notification received. */ + protected static final int EVENT_SSN = 2; + protected static final int EVENT_SIM_RECORDS_LOADED = 3; + protected static final int EVENT_MMI_DONE = 4; + protected static final int EVENT_RADIO_ON = 5; + protected static final int EVENT_GET_BASEBAND_VERSION_DONE = 6; + protected static final int EVENT_USSD = 7; + protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 8; + protected static final int EVENT_GET_IMEI_DONE = 9; + protected static final int EVENT_GET_IMEISV_DONE = 10; + protected static final int EVENT_GET_SIM_STATUS_DONE = 11; + protected static final int EVENT_SET_CALL_FORWARD_DONE = 12; + protected static final int EVENT_GET_CALL_FORWARD_DONE = 13; + protected static final int EVENT_CALL_RING = 14; + // Used to intercept the carrier selection calls so that + // we can save the values. + protected static final int EVENT_SET_NETWORK_MANUAL_COMPLETE = 15; + protected static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 16; + protected static final int EVENT_SET_CLIR_COMPLETE = 17; + protected static final int EVENT_REGISTERED_TO_NETWORK = 18; + protected static final int EVENT_SET_VM_NUMBER_DONE = 19; + // Events for CDMA support + protected static final int EVENT_GET_DEVICE_IDENTITY_DONE = 20; + protected static final int EVENT_RUIM_RECORDS_LOADED = 21; + protected static final int EVENT_NV_READY = 22; + protected static final int EVENT_SET_ENHANCED_VP = 23; + + // Key used to read/write current CLIR setting + public static final String CLIR_KEY = "clir_key"; + + // Key used to read/write "disable DNS server check" pref (used for testing) + public static final String DNS_SERVER_CHECK_DISABLED_KEY = "dns_server_check_disabled_key"; + + //***** Instance Variables + public CommandsInterface mCM; + protected IccFileHandler mIccFileHandler; + boolean mDnsCheckDisabled = false; + + /** + * Set a system property, unless we're in unit test mode + */ + public void + setSystemProperty(String property, String value) { + if(getUnitTestMode()) { + return; + } + SystemProperties.set(property, value); + } - protected final RegistrantList mPhoneStateRegistrants + + protected final RegistrantList mPhoneStateRegistrants = new RegistrantList(); - protected final RegistrantList mNewRingingConnectionRegistrants + protected final RegistrantList mNewRingingConnectionRegistrants = new RegistrantList(); - protected final RegistrantList mIncomingRingRegistrants + protected final RegistrantList mIncomingRingRegistrants = new RegistrantList(); - - protected final RegistrantList mDisconnectRegistrants + + protected final RegistrantList mDisconnectRegistrants = new RegistrantList(); - protected final RegistrantList mServiceStateRegistrants + protected final RegistrantList mServiceStateRegistrants = new RegistrantList(); - - protected final RegistrantList mMmiCompleteRegistrants + + protected final RegistrantList mMmiCompleteRegistrants = new RegistrantList(); - protected final RegistrantList mMmiRegistrants + protected final RegistrantList mMmiRegistrants = new RegistrantList(); - protected final RegistrantList mUnknownConnectionRegistrants + protected final RegistrantList mUnknownConnectionRegistrants = new RegistrantList(); - - protected final RegistrantList mSuppServiceFailedRegistrants + + protected final RegistrantList mSuppServiceFailedRegistrants = new RegistrantList(); - + protected Looper mLooper; /* to insure registrants are in correct thread*/ protected Context mContext; - /** - * PhoneNotifier is an abstraction for all system-wide - * state change notification. DefaultPhoneNotifier is + /** + * PhoneNotifier is an abstraction for all system-wide + * state change notification. DefaultPhoneNotifier is * used here unless running we're inside a unit test. */ protected PhoneNotifier mNotifier; @@ -94,7 +160,7 @@ public abstract class PhoneBase implements Phone { * Constructs a PhoneBase in normal (non-unit test) mode. * * @param context Context object from hosting application - * @param notifier An instance of DefaultPhoneNotifier, + * @param notifier An instance of DefaultPhoneNotifier, * unless unit testing. */ protected PhoneBase(PhoneNotifier notifier, Context context) { @@ -105,13 +171,13 @@ public abstract class PhoneBase implements Phone { * Constructs a PhoneBase in normal (non-unit test) mode. * * @param context Context object from hosting application - * @param notifier An instance of DefaultPhoneNotifier, + * @param notifier An instance of DefaultPhoneNotifier, * unless unit testing. - * @param unitTestMode when true, prevents notifications + * @param unitTestMode when true, prevents notifications * of state change events */ - protected PhoneBase(PhoneNotifier notifier, Context context, - boolean unitTestMode) { + protected PhoneBase(PhoneNotifier notifier, Context context, + boolean unitTestMode) { this.mNotifier = notifier; this.mContext = context; mLooper = Looper.myLooper(); @@ -119,6 +185,9 @@ public abstract class PhoneBase implements Phone { setLocaleByCarrier(); setUnitTestMode(unitTestMode); + + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false); } // Inherited documentation suffices. @@ -126,6 +195,26 @@ public abstract class PhoneBase implements Phone { return mContext; } + /** + * Disables the DNS check (i.e., allows "0.0.0.0"). + * Useful for lab testing environment. + * @param b true disables the check, false enables. + */ + public void disableDnsCheck(boolean b) { + mDnsCheckDisabled = b; + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); + SharedPreferences.Editor editor = sp.edit(); + editor.putBoolean(DNS_SERVER_CHECK_DISABLED_KEY, b); + editor.commit(); + } + + /** + * Returns true if the DNS check is currently disabled. + */ + public boolean isDnsCheckDisabled() { + return mDnsCheckDisabled; + } + // Inherited documentation suffices. public void registerForPhoneStateChanged(Handler h, int what, Object obj) { checkCorrectThread(h); @@ -137,29 +226,29 @@ public abstract class PhoneBase implements Phone { public void unregisterForPhoneStateChanged(Handler h) { mPhoneStateRegistrants.remove(h); } - + /** * Notify registrants of a PhoneStateChanged. - * Subclasses of Phone probably want to replace this with a + * Subclasses of Phone probably want to replace this with a * version scoped to their packages */ protected void notifyCallStateChangedP() { AsyncResult ar = new AsyncResult(null, this, null); mPhoneStateRegistrants.notifyRegistrants(ar); } - + // Inherited documentation suffices. public void registerForUnknownConnection(Handler h, int what, Object obj) { checkCorrectThread(h); - + mUnknownConnectionRegistrants.addUnique(h, what, obj); } - + // Inherited documentation suffices. public void unregisterForUnknownConnection(Handler h) { mUnknownConnectionRegistrants.remove(h); } - + // Inherited documentation suffices. public void registerForNewRingingConnection( Handler h, int what, Object obj) { @@ -173,12 +262,33 @@ public abstract class PhoneBase implements Phone { mNewRingingConnectionRegistrants.remove(h); } + // Inherited documentation suffices. + public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){ + mCM.registerForInCallVoicePrivacyOn(h,what,obj); + } + + // Inherited documentation suffices. + public void unregisterForInCallVoicePrivacyOn(Handler h){ + mCM.unregisterForInCallVoicePrivacyOn(h); + } + + // Inherited documentation suffices. + public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){ + mCM.registerForInCallVoicePrivacyOff(h,what,obj); + } + + // Inherited documentation suffices. + public void unregisterForInCallVoicePrivacyOff(Handler h){ + mCM.unregisterForInCallVoicePrivacyOff(h); + } + + /** * Notifiy registrants of a new ringing Connection. - * Subclasses of Phone probably want to replace this with a + * Subclasses of Phone probably want to replace this with a * version scoped to their packages */ - protected void notifyNewRingingConnectionP(Connection cn) { + protected void notifyNewRingingConnectionP(Connection cn) { AsyncResult ar = new AsyncResult(null, cn, null); mNewRingingConnectionRegistrants.notifyRegistrants(ar); } @@ -187,15 +297,15 @@ public abstract class PhoneBase implements Phone { public void registerForIncomingRing( Handler h, int what, Object obj) { checkCorrectThread(h); - + mIncomingRingRegistrants.addUnique(h, what, obj); } - + // Inherited documentation suffices. public void unregisterForIncomingRing(Handler h) { mIncomingRingRegistrants.remove(h); } - + // Inherited documentation suffices. public void registerForDisconnect(Handler h, int what, Object obj) { checkCorrectThread(h); @@ -211,15 +321,15 @@ public abstract class PhoneBase implements Phone { // Inherited documentation suffices. public void registerForSuppServiceFailed(Handler h, int what, Object obj) { checkCorrectThread(h); - + mSuppServiceFailedRegistrants.addUnique(h, what, obj); } - + // Inherited documentation suffices. public void unregisterForSuppServiceFailed(Handler h) { mSuppServiceFailedRegistrants.remove(h); } - + // Inherited documentation suffices. public void registerForMmiInitiate(Handler h, int what, Object obj) { checkCorrectThread(h); @@ -231,7 +341,7 @@ public abstract class PhoneBase implements Phone { public void unregisterForMmiInitiate(Handler h) { mMmiRegistrants.remove(h); } - + // Inherited documentation suffices. public void registerForMmiComplete(Handler h, int what, Object obj) { checkCorrectThread(h); @@ -247,10 +357,31 @@ public abstract class PhoneBase implements Phone { } /** - * Subclasses should override this. See documentation in superclass. + * Method to retrieve the saved operator id from the Shared Preferences */ - public abstract List getPendingMmiCodes(); - + private String getSavedNetworkSelection() { + // open the shared preferences and search with our key. + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); + return sp.getString(NETWORK_SELECTION_KEY, ""); + } + + /** + * Method to restore the previously saved operator id, or reset to + * automatic selection, all depending upon the value in the shared + * preferences. + */ + public void restoreSavedNetworkSelection(Message response) { + // retrieve the operator id + String networkSelection = getSavedNetworkSelection(); + + // set to auto if the id is empty, otherwise select the network. + if (TextUtils.isEmpty(networkSelection)) { + mCM.setNetworkSelectionModeAutomatic(response); + } else { + mCM.setNetworkSelectionModeManual(networkSelection, response); + } + } + // Inherited documentation suffices. public void setUnitTestMode(boolean f) { mUnitTestMode = f; @@ -260,11 +391,11 @@ public abstract class PhoneBase implements Phone { public boolean getUnitTestMode() { return mUnitTestMode; } - + /** * To be invoked when a voice call Connection disconnects. * - * Subclasses of Phone probably want to replace this with a + * Subclasses of Phone probably want to replace this with a * version scoped to their packages */ protected void notifyDisconnectP(Connection cn) { @@ -286,7 +417,7 @@ public abstract class PhoneBase implements Phone { } /** - * Subclasses of Phone probably want to replace this with a + * Subclasses of Phone probably want to replace this with a * version scoped to their packages */ protected void notifyServiceStateChangedP(ServiceState ss) { @@ -312,7 +443,7 @@ public abstract class PhoneBase implements Phone { private void checkCorrectThread(Handler h) { if (h.getLooper() != mLooper) { throw new RuntimeException( - "com.android.internal.telephony.Phone must be used from within one thread"); + "com.android.internal.telephony.Phone must be used from within one thread"); } } @@ -401,4 +532,107 @@ public abstract class PhoneBase implements Phone { } } } + + /* + * Retrieves the Handler of the Phone instance + */ + public abstract Handler getHandler(); + + /** + * Retrieves the IccFileHandler of the Phone instance + */ + public abstract IccFileHandler getIccFileHandler(); + + + /** + * Query the status of the CDMA roaming preference + */ + public void queryCdmaRoamingPreference(Message response) { + mCM.queryCdmaRoamingPreference(response); + } + + /** + * Set the status of the CDMA roaming preference + */ + public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { + mCM.setCdmaRoamingPreference(cdmaRoamingType, response); + } + + /** + * Set the status of the CDMA subscription mode + */ + public void setCdmaSubscription(int cdmaSubscriptionType, Message response) { + mCM.setCdmaSubscription(cdmaSubscriptionType, response); + } + + /** + * Set the preferred Network Type: Global, CDMA only or GSM/UMTS only + */ + public void setPreferredNetworkType(int networkType, Message response) { + 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); + } + + public void setTTYModeEnabled(boolean enable, Message onComplete) { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + } + + public void queryTTYModeEnabled(Message onComplete) { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + } + + /** + * This should only be called in GSM mode. + * Only here for some backward compatibility + * issues concerning the GSMPhone class. + * @deprecated + */ + public List<PdpConnection> getCurrentPdpList() { + return null; + } + + public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + } + + public void getEnhancedVoicePrivacy(Message onComplete) { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + } + + public void setBandMode(int bandMode, Message response) { + mCM.setBandMode(bandMode, response); + } + + public void queryAvailableBandMode(Message response) { + mCM.queryAvailableBandMode(response); + } + + public void invokeOemRilRequestRaw(byte[] data, Message response) { + mCM.invokeOemRilRequestRaw(data, response); + } + + public void invokeOemRilRequestStrings(String[] strings, Message response) { + mCM.invokeOemRilRequestStrings(strings, response); + } + + public void notifyDataActivity() { + mNotifier.notifyDataActivity(this); + } + + public void notifyDataConnection(String reason) { + mNotifier.notifyDataConnection(this, reason); + } + + public abstract String getPhoneName(); + } diff --git a/telephony/java/com/android/internal/telephony/PhoneFactory.java b/telephony/java/com/android/internal/telephony/PhoneFactory.java index 0ca5f45..3db0499 100644 --- a/telephony/java/com/android/internal/telephony/PhoneFactory.java +++ b/telephony/java/com/android/internal/telephony/PhoneFactory.java @@ -16,80 +16,55 @@ package com.android.internal.telephony; -import java.util.ArrayList; -import java.util.List; -import java.io.IOException; -import java.net.InetSocketAddress; - -import java.util.Collections; - -import android.util.Log; -import com.android.internal.telephony.gsm.GSMPhone; -import com.android.internal.telephony.gsm.RIL; -import com.android.internal.telephony.test.ModelInterpreter; -import com.android.internal.telephony.test.SimulatedCommands; -import android.os.Looper; -import android.os.SystemProperties; import android.content.Context; -import android.content.Intent; import android.net.LocalServerSocket; -import android.app.ActivityManagerNative; +import android.os.Looper; +import android.provider.Settings; +import android.util.Log; + +import com.android.internal.telephony.cdma.CDMAPhone; +import com.android.internal.telephony.gsm.GSMPhone; /** * {@hide} */ -public class PhoneFactory -{ - static final String LOG_TAG="GSM"; - +public class PhoneFactory { + static final String LOG_TAG = "PHONE"; static final int SOCKET_OPEN_RETRY_MILLIS = 2 * 1000; static final int SOCKET_OPEN_MAX_RETRY = 3; - //***** Class Variables + //***** Class Variables - static private ArrayList<Phone> sPhones = new ArrayList<Phone>(); + static private Phone sProxyPhone = null; + static private CommandsInterface sCommandsInterface = null; static private boolean sMadeDefaults = false; static private PhoneNotifier sPhoneNotifier; static private Looper sLooper; + static private Context sContext; - static private Object testMailbox; - - //***** Class Methods + static final int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE; - private static void - useNewRIL(Context context) - { - ModelInterpreter mi = null; - GSMPhone phone; + static final int preferredCdmaSubscription = RILConstants.PREFERRED_CDMA_SUBSCRIPTION; - try { - if (false) { - mi = new ModelInterpreter(new InetSocketAddress("127.0.0.1", 6502)); - } - - phone = new GSMPhone(context, new RIL(context), sPhoneNotifier); + //***** Class Methods - registerPhone (phone); - } catch (IOException ex) { - Log.e(LOG_TAG, "Error creating ModelInterpreter", ex); - } + public static void makeDefaultPhones(Context context) { + makeDefaultPhone(context); } - /** * FIXME replace this with some other way of making these * instances */ - public static void - makeDefaultPhones(Context context) - { - synchronized(Phone.class) { - if (!sMadeDefaults) { + public static void makeDefaultPhone(Context context) { + synchronized(Phone.class) { + if (!sMadeDefaults) { sLooper = Looper.myLooper(); + sContext = context; if (sLooper == null) { throw new RuntimeException( - "PhoneFactory.makeDefaultPhones must be called from Looper thread"); + "PhoneFactory.makeDefaultPhone must be called from Looper thread"); } int retryCount = 0; @@ -109,7 +84,7 @@ public class PhoneFactory break; } else if (retryCount > SOCKET_OPEN_MAX_RETRY) { throw new RuntimeException("PhoneFactory probably already running"); - }else { + } else { try { Thread.sleep(SOCKET_OPEN_RETRY_MILLIS); } catch (InterruptedException er) { @@ -119,44 +94,71 @@ public class PhoneFactory sPhoneNotifier = new DefaultPhoneNotifier(); - if ((SystemProperties.get("ro.radio.noril","")).equals("")) { - useNewRIL(context); - } else { - GSMPhone phone; - phone = new GSMPhone(context, new SimulatedCommands(), sPhoneNotifier); - registerPhone (phone); + //Get preferredNetworkMode from Settings.System + int networkMode = Settings.Secure.getInt(context.getContentResolver(), + Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode); + Log.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkMode)); + + //Get preferredNetworkMode from Settings.System + int cdmaSubscription = Settings.Secure.getInt(context.getContentResolver(), + Settings.Secure.PREFERRED_CDMA_SUBSCRIPTION, preferredCdmaSubscription); + Log.i(LOG_TAG, "Cdma Subscription set to " + Integer.toString(cdmaSubscription)); + + //reads the system properties and makes commandsinterface + sCommandsInterface = new RIL(context, networkMode, cdmaSubscription); + + 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: + sProxyPhone = new PhoneProxy(new GSMPhone(context, + sCommandsInterface, sPhoneNotifier)); + Log.i(LOG_TAG, "Creating GSMPhone"); + break; + case RILConstants.NETWORK_MODE_CDMA: + case RILConstants.NETWORK_MODE_CDMA_NO_EVDO: + case RILConstants.NETWORK_MODE_EVDO_NO_CDMA: + sProxyPhone = new PhoneProxy(new CDMAPhone(context, + sCommandsInterface, sPhoneNotifier)); + Log.i(LOG_TAG, "Creating CDMAPhone"); + break; + case RILConstants.NETWORK_MODE_GLOBAL: + default: + sProxyPhone = new PhoneProxy(new CDMAPhone(context, + sCommandsInterface, sPhoneNotifier)); + Log.i(LOG_TAG, "Creating CDMAPhone"); } - sMadeDefaults = true; } } } - public static Phone getDefaultPhone() - { - if (!sMadeDefaults) { - throw new IllegalStateException("Default phones haven't been made yet!"); - } - + public static Phone getDefaultPhone() { if (sLooper != Looper.myLooper()) { throw new RuntimeException( "PhoneFactory.getDefaultPhone must be called from Looper thread"); } - synchronized (sPhones) { - return sPhones.isEmpty() ? null : sPhones.get(0); + if (!sMadeDefaults) { + throw new IllegalStateException("Default phones haven't been made yet!"); } + return sProxyPhone; } - - public static void registerPhone(Phone p) - { - if (sLooper != Looper.myLooper()) { - throw new RuntimeException( - "PhoneFactory.getDefaultPhone must be called from Looper thread"); + + public static Phone getCdmaPhone() { + synchronized(PhoneProxy.lockForRadioTechnologyChange) { + Phone phone = new CDMAPhone(sContext, sCommandsInterface, sPhoneNotifier); + return phone; } - synchronized (sPhones) { - sPhones.add(p); + } + + public static Phone getGsmPhone() { + synchronized(PhoneProxy.lockForRadioTechnologyChange) { + Phone phone = new GSMPhone(sContext, sCommandsInterface, sPhoneNotifier); + return phone; } } } + diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java new file mode 100644 index 0000000..dd36f0b --- /dev/null +++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java @@ -0,0 +1,675 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + + +import android.app.ActivityManagerNative; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Handler; +import android.os.Message; +import android.preference.PreferenceManager; +import android.telephony.CellLocation; +import android.telephony.ServiceState; +import android.util.Log; + +import com.android.internal.telephony.cdma.CDMAPhone; +import com.android.internal.telephony.gsm.GSMPhone; +import com.android.internal.telephony.gsm.NetworkInfo; +import com.android.internal.telephony.gsm.PdpConnection; +import com.android.internal.telephony.test.SimulatedRadioControl; + +import java.util.List; + +public class PhoneProxy extends Handler implements Phone { + public final static Object lockForRadioTechnologyChange = new Object(); +// private static boolean radioTechnologyChangeGsmToCdma = false; +// private static boolean radioTechnologyChangeCdmaToGsm = false; + + private Phone mActivePhone; + private String mOutgoingPhone; + private CommandsInterface mCommandsInterface; + private IccSmsInterfaceManagerProxy mIccSmsInterfaceManagerProxy; + private IccPhoneBookInterfaceManagerProxy mIccPhoneBookInterfaceManagerProxy; + private PhoneSubInfoProxy mPhoneSubInfoProxy; + + private static final int EVENT_RADIO_TECHNOLOGY_CHANGED = 1; + private static final String LOG_TAG = "PHONE"; + + //***** Class Methods + public PhoneProxy(Phone phone) { + mActivePhone = phone; + mIccSmsInterfaceManagerProxy = new IccSmsInterfaceManagerProxy( + phone.getIccSmsInterfaceManager()); + mIccPhoneBookInterfaceManagerProxy = new IccPhoneBookInterfaceManagerProxy( + phone.getIccPhoneBookInterfaceManager()); + mPhoneSubInfoProxy = new PhoneSubInfoProxy(phone.getPhoneSubInfo()); + mCommandsInterface = ((PhoneBase)mActivePhone).mCM; + mCommandsInterface.registerForRadioTechnologyChanged( + this, EVENT_RADIO_TECHNOLOGY_CHANGED, null); + } + + @Override + public void handleMessage(Message msg) { + switch(msg.what) { + case EVENT_RADIO_TECHNOLOGY_CHANGED: + //switch Phone from CDMA to GSM or vice versa + mOutgoingPhone = ((PhoneBase)mActivePhone).getPhoneName(); + logd("Switching phone from " + mOutgoingPhone + "Phone to " + + (mOutgoingPhone.equals("GSM") ? "CDMAPhone" : "GSMPhone") ); + boolean oldPowerState = false; //old power state to off + if (mCommandsInterface.getRadioState().isOn()) { + oldPowerState = true; + logd("Setting Radio Power to Off"); + mCommandsInterface.setRadioPower(false, null); + } + if(mOutgoingPhone.equals("GSM")) { + logd("Make a new CDMAPhone and destroy the old GSMPhone."); + + ((GSMPhone)mActivePhone).dispose(); + Phone oldPhone = mActivePhone; + + //Give the garbage collector a hint to start the garbage collection asap + // NOTE this has been disabled since radio technology change could happen during + // e.g. a multimedia playing and could slow the system. Tests needs to be done + // to see the effects of the GC call here when system is busy. + //System.gc(); + + mActivePhone = PhoneFactory.getCdmaPhone(); + logd("Resetting Radio"); + mCommandsInterface.setRadioPower(oldPowerState, null); + ((GSMPhone)oldPhone).removeReferences(); + oldPhone = null; + } else { + logd("Make a new GSMPhone and destroy the old CDMAPhone."); + + ((CDMAPhone)mActivePhone).dispose(); + //mActivePhone = null; + Phone oldPhone = mActivePhone; + + // Give the GC a hint to start the garbage collection asap + // NOTE this has been disabled since radio technology change could happen during + // e.g. a multimedia playing and could slow the system. Tests needs to be done + // to see the effects of the GC call here when system is busy. + //System.gc(); + + mActivePhone = PhoneFactory.getGsmPhone(); + logd("Resetting Radio:"); + mCommandsInterface.setRadioPower(oldPowerState, null); + ((CDMAPhone)oldPhone).removeReferences(); + oldPhone = null; + } + + //Set the new interfaces in the proxy's + mIccSmsInterfaceManagerProxy.setmIccSmsInterfaceManager( + mActivePhone.getIccSmsInterfaceManager()); + mIccPhoneBookInterfaceManagerProxy.setmIccPhoneBookInterfaceManager( + mActivePhone.getIccPhoneBookInterfaceManager()); + mPhoneSubInfoProxy.setmPhoneSubInfo(this.mActivePhone.getPhoneSubInfo()); + mCommandsInterface = ((PhoneBase)mActivePhone).mCM; + + //Send an Intent to the PhoneApp that we had a radio technology change + 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: " + + msg.what); + break; + } + super.handleMessage(msg); + } + + private void logv(String msg) { + Log.v(LOG_TAG, "[PhoneProxy] " + msg); + } + + private void logd(String msg) { + Log.d(LOG_TAG, "[PhoneProxy] " + msg); + } + + private void logw(String msg) { + Log.w(LOG_TAG, "[PhoneProxy] " + msg); + } + + private void loge(String msg) { + Log.e(LOG_TAG, "[PhoneProxy] " + msg); + } + + + public ServiceState getServiceState() { + return mActivePhone.getServiceState(); + } + + public CellLocation getCellLocation() { + return mActivePhone.getCellLocation(); + } + + public DataState getDataConnectionState() { + return mActivePhone.getDataConnectionState(); + } + + public DataActivityState getDataActivityState() { + return mActivePhone.getDataActivityState(); + } + + public Context getContext() { + return mActivePhone.getContext(); + } + + public void disableDnsCheck(boolean b) { + mActivePhone.disableDnsCheck(b); + } + + public boolean isDnsCheckDisabled() { + return mActivePhone.isDnsCheckDisabled(); + } + + public State getState() { + return mActivePhone.getState(); + } + + public String getPhoneName() { + return mActivePhone.getPhoneName(); + } + + public String[] getActiveApnTypes() { + return mActivePhone.getActiveApnTypes(); + } + + public String getActiveApn() { + return mActivePhone.getActiveApn(); + } + + public int getSignalStrengthASU() { + return mActivePhone.getSignalStrengthASU(); + } + + public void registerForUnknownConnection(Handler h, int what, Object obj) { + mActivePhone.registerForUnknownConnection(h, what, obj); + } + + public void unregisterForUnknownConnection(Handler h) { + mActivePhone.unregisterForUnknownConnection(h); + } + + public void registerForPhoneStateChanged(Handler h, int what, Object obj) { + mActivePhone.registerForPhoneStateChanged(h, what, obj); + } + + public void unregisterForPhoneStateChanged(Handler h) { + mActivePhone.unregisterForPhoneStateChanged(h); + } + + public void registerForNewRingingConnection(Handler h, int what, Object obj) { + mActivePhone.registerForNewRingingConnection(h, what, obj); + } + + public void unregisterForNewRingingConnection(Handler h) { + mActivePhone.unregisterForNewRingingConnection(h); + } + + public void registerForIncomingRing(Handler h, int what, Object obj) { + mActivePhone.registerForIncomingRing(h, what, obj); + } + + public void unregisterForIncomingRing(Handler h) { + mActivePhone.unregisterForIncomingRing(h); + } + + public void registerForDisconnect(Handler h, int what, Object obj) { + mActivePhone.registerForDisconnect(h, what, obj); + } + + public void unregisterForDisconnect(Handler h) { + mActivePhone.unregisterForDisconnect(h); + } + + public void registerForMmiInitiate(Handler h, int what, Object obj) { + mActivePhone.registerForMmiInitiate(h, what, obj); + } + + public void unregisterForMmiInitiate(Handler h) { + mActivePhone.unregisterForMmiInitiate(h); + } + + public void registerForMmiComplete(Handler h, int what, Object obj) { + mActivePhone.registerForMmiComplete(h, what, obj); + } + + public void unregisterForMmiComplete(Handler h) { + mActivePhone.unregisterForMmiComplete(h); + } + + public List<? extends MmiCode> getPendingMmiCodes() { + return mActivePhone.getPendingMmiCodes(); + } + + public void sendUssdResponse(String ussdMessge) { + mActivePhone.sendUssdResponse(ussdMessge); + } + + public void registerForServiceStateChanged(Handler h, int what, Object obj) { + mActivePhone.registerForServiceStateChanged(h, what, obj); + } + + public void unregisterForServiceStateChanged(Handler h) { + mActivePhone.unregisterForServiceStateChanged(h); + } + + public void registerForSuppServiceNotification(Handler h, int what, Object obj) { + mActivePhone.registerForSuppServiceNotification(h, what, obj); + } + + public void unregisterForSuppServiceNotification(Handler h) { + mActivePhone.unregisterForSuppServiceNotification(h); + } + + public void registerForSuppServiceFailed(Handler h, int what, Object obj) { + mActivePhone.registerForSuppServiceFailed(h, what, obj); + } + + public void unregisterForSuppServiceFailed(Handler h) { + mActivePhone.unregisterForSuppServiceFailed(h); + } + + public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){ + mActivePhone.registerForInCallVoicePrivacyOn(h,what,obj); + } + + public void unregisterForInCallVoicePrivacyOn(Handler h){ + mActivePhone.unregisterForInCallVoicePrivacyOn(h); + } + + public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){ + mActivePhone.registerForInCallVoicePrivacyOff(h,what,obj); + } + + public void unregisterForInCallVoicePrivacyOff(Handler h){ + mActivePhone.unregisterForInCallVoicePrivacyOff(h); + } + + public boolean getIccRecordsLoaded() { + return mActivePhone.getIccRecordsLoaded(); + } + + public IccCard getIccCard() { + return mActivePhone.getIccCard(); + } + + public void acceptCall() throws CallStateException { + mActivePhone.acceptCall(); + } + + public void rejectCall() throws CallStateException { + mActivePhone.rejectCall(); + } + + public void switchHoldingAndActive() throws CallStateException { + mActivePhone.switchHoldingAndActive(); + } + + public boolean canConference() { + return mActivePhone.canConference(); + } + + public void conference() throws CallStateException { + mActivePhone.conference(); + } + + public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) { + mActivePhone.enableEnhancedVoicePrivacy(enable, onComplete); + } + + public void getEnhancedVoicePrivacy(Message onComplete) { + mActivePhone.getEnhancedVoicePrivacy(onComplete); + } + + public boolean canTransfer() { + return mActivePhone.canTransfer(); + } + + public void explicitCallTransfer() throws CallStateException { + mActivePhone.explicitCallTransfer(); + } + + public void clearDisconnected() { + mActivePhone.clearDisconnected(); + } + + public Call getForegroundCall() { + return mActivePhone.getForegroundCall(); + } + + public Call getBackgroundCall() { + return mActivePhone.getBackgroundCall(); + } + + public Call getRingingCall() { + return mActivePhone.getRingingCall(); + } + + public Connection dial(String dialString) throws CallStateException { + return mActivePhone.dial(dialString); + } + + public boolean handlePinMmi(String dialString) { + return mActivePhone.handlePinMmi(dialString); + } + + public boolean handleInCallMmiCommands(String command) throws CallStateException { + return mActivePhone.handleInCallMmiCommands(command); + } + + public void sendDtmf(char c) { + mActivePhone.sendDtmf(c); + } + + public void startDtmf(char c) { + mActivePhone.startDtmf(c); + } + + public void stopDtmf() { + mActivePhone.stopDtmf(); + } + + public void setRadioPower(boolean power) { + mActivePhone.setRadioPower(power); + } + + public boolean getMessageWaitingIndicator() { + return mActivePhone.getMessageWaitingIndicator(); + } + + public boolean getCallForwardingIndicator() { + return mActivePhone.getCallForwardingIndicator(); + } + + public String getLine1Number() { + return mActivePhone.getLine1Number(); + } + + public String getLine1AlphaTag() { + return mActivePhone.getLine1AlphaTag(); + } + + public void setLine1Number(String alphaTag, String number, Message onComplete) { + mActivePhone.setLine1Number(alphaTag, number, onComplete); + } + + public String getVoiceMailNumber() { + return mActivePhone.getVoiceMailNumber(); + } + + public String getVoiceMailAlphaTag() { + return mActivePhone.getVoiceMailAlphaTag(); + } + + public void setVoiceMailNumber(String alphaTag,String voiceMailNumber, + Message onComplete) { + mActivePhone.setVoiceMailNumber(alphaTag, voiceMailNumber, onComplete); + } + + public void getCallForwardingOption(int commandInterfaceCFReason, + Message onComplete) { + mActivePhone.getCallForwardingOption(commandInterfaceCFReason, + onComplete); + } + + public void setCallForwardingOption(int commandInterfaceCFReason, + int commandInterfaceCFAction, String dialingNumber, + int timerSeconds, Message onComplete) { + mActivePhone.setCallForwardingOption(commandInterfaceCFReason, + commandInterfaceCFAction, dialingNumber, timerSeconds, onComplete); + } + + public void getOutgoingCallerIdDisplay(Message onComplete) { + mActivePhone.getOutgoingCallerIdDisplay(onComplete); + } + + public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, + Message onComplete) { + mActivePhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, + onComplete); + } + + public void getCallWaiting(Message onComplete) { + mActivePhone.getCallWaiting(onComplete); + } + + public void setCallWaiting(boolean enable, Message onComplete) { + mActivePhone.setCallWaiting(enable, onComplete); + } + + public void getAvailableNetworks(Message response) { + mActivePhone.getAvailableNetworks(response); + } + + public void setNetworkSelectionModeAutomatic(Message response) { + mActivePhone.setNetworkSelectionModeAutomatic(response); + } + + public void selectNetworkManually(NetworkInfo network, Message response) { + mActivePhone.selectNetworkManually(network, response); + } + + public void setPreferredNetworkType(int networkType, Message response) { + mActivePhone.setPreferredNetworkType(networkType, response); + } + + public void getPreferredNetworkType(Message response) { + mActivePhone.getPreferredNetworkType(response); + } + + public void getNeighboringCids(Message response) { + mActivePhone.getNeighboringCids(response); + } + + public void setOnPostDialCharacter(Handler h, int what, Object obj) { + mActivePhone.setOnPostDialCharacter(h, what, obj); + } + + public void setMute(boolean muted) { + mActivePhone.setMute(muted); + } + + public boolean getMute() { + return mActivePhone.getMute(); + } + + public void invokeOemRilRequestRaw(byte[] data, Message response) { + mActivePhone.invokeOemRilRequestRaw(data, response); + } + + public void invokeOemRilRequestStrings(String[] strings, Message response) { + mActivePhone.invokeOemRilRequestStrings(strings, response); + } + + /** + * @deprecated + */ + public void getPdpContextList(Message response) { + mActivePhone.getPdpContextList(response); + } + + public void getDataCallList(Message response) { + mActivePhone.getDataCallList(response); + } + + /** + * @deprecated + */ + public List<PdpConnection> getCurrentPdpList() { + return mActivePhone.getCurrentPdpList(); + } + + public List<DataConnection> getCurrentDataConnectionList() { + return mActivePhone.getCurrentDataConnectionList(); + } + + public void updateServiceLocation(Message response) { + mActivePhone.updateServiceLocation(response); + } + + public void enableLocationUpdates() { + mActivePhone.enableLocationUpdates(); + } + + public void disableLocationUpdates() { + mActivePhone.disableLocationUpdates(); + } + + public void setUnitTestMode(boolean f) { + mActivePhone.setUnitTestMode(f); + } + + public boolean getUnitTestMode() { + return mActivePhone.getUnitTestMode(); + } + + public void setBandMode(int bandMode, Message response) { + mActivePhone.setBandMode(bandMode, response); + } + + public void queryAvailableBandMode(Message response) { + mActivePhone.queryAvailableBandMode(response); + } + + public boolean getDataRoamingEnabled() { + return mActivePhone.getDataRoamingEnabled(); + } + + public void setDataRoamingEnabled(boolean enable) { + mActivePhone.setDataRoamingEnabled(enable); + } + + public void queryCdmaRoamingPreference(Message response) { + mActivePhone.queryCdmaRoamingPreference(response); + } + + public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { + mActivePhone.setCdmaRoamingPreference(cdmaRoamingType, response); + } + + public void setCdmaSubscription(int cdmaSubscriptionType, Message response) { + mActivePhone.setCdmaSubscription(cdmaSubscriptionType, response); + } + + public SimulatedRadioControl getSimulatedRadioControl() { + return mActivePhone.getSimulatedRadioControl(); + } + + public boolean enableDataConnectivity() { + return mActivePhone.enableDataConnectivity(); + } + + public boolean disableDataConnectivity() { + return mActivePhone.disableDataConnectivity(); + } + + public int enableApnType(String type) { + return mActivePhone.enableApnType(type); + } + + public int disableApnType(String type) { + return mActivePhone.disableApnType(type); + } + + public boolean isDataConnectivityPossible() { + return mActivePhone.isDataConnectivityPossible(); + } + + public String getInterfaceName(String apnType) { + return mActivePhone.getInterfaceName(apnType); + } + + public String getIpAddress(String apnType) { + return mActivePhone.getIpAddress(apnType); + } + + public String getGateway(String apnType) { + return mActivePhone.getGateway(apnType); + } + + public String[] getDnsServers(String apnType) { + return mActivePhone.getDnsServers(apnType); + } + + public String getDeviceId() { + return mActivePhone.getDeviceId(); + } + + public String getDeviceSvn() { + return mActivePhone.getDeviceSvn(); + } + + public String getSubscriberId() { + return mActivePhone.getSubscriberId(); + } + + public String getIccSerialNumber() { + return mActivePhone.getIccSerialNumber(); + } + + public String getEsn() { + return mActivePhone.getEsn(); + } + + public String getMeid() { + return mActivePhone.getMeid(); + } + + public PhoneSubInfo getPhoneSubInfo(){ + return mActivePhone.getPhoneSubInfo(); + } + + public IccSmsInterfaceManager getIccSmsInterfaceManager(){ + return mActivePhone.getIccSmsInterfaceManager(); + } + + public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){ + return mActivePhone.getIccPhoneBookInterfaceManager(); + } + + public void setTTYModeEnabled(boolean enable, Message onComplete) { + mActivePhone.setTTYModeEnabled(enable, onComplete); + } + + public void queryTTYModeEnabled(Message onComplete) { + mActivePhone.queryTTYModeEnabled(onComplete); + } + + public void activateCellBroadcastSms(int activate, Message response) { + mActivePhone.activateCellBroadcastSms(activate, response); + } + + public void getCellBroadcastSmsConfig(Message response) { + mActivePhone.getCellBroadcastSmsConfig(response); + } + + public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) { + mActivePhone.setCellBroadcastSmsConfig(configValuesArray, response); + } + + public void notifyDataActivity() { + mActivePhone.notifyDataActivity(); + } +} + diff --git a/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java b/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java index 61d4c9f..fd822cd 100644 --- a/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java +++ b/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java @@ -32,11 +32,11 @@ import android.util.Log; * * Use android.telephony.TelephonyManager and PhoneStateListener instead. * - * + * */ @Deprecated public final class PhoneStateIntentReceiver extends BroadcastReceiver { - private static final String LOG_TAG = "PhoneStateIntRecv"; + private static final String LOG_TAG = "PHONE"; private static final boolean DBG = false; public static final String INTENT_KEY_ASU = "asu"; @@ -182,7 +182,7 @@ public final class PhoneStateIntentReceiver extends BroadcastReceiver { 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); - + if (mTarget != null && getNotifySignalStrength()) { Message message = Message.obtain(mTarget, mAsuEventWhat); mTarget.sendMessage(message); diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java index 644d1f4..4d1f7e5 100644 --- a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java +++ b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java @@ -1,10 +1,25 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.android.internal.telephony; import android.content.Context; -import android.os.ServiceManager; -import com.android.internal.telephony.*; +import android.util.Log; public class PhoneSubInfo extends IPhoneSubInfo.Stub { + static final String LOG_TAG = "PHONE"; private Phone mPhone; private Context mContext; private static final String READ_PHONE_STATE = @@ -13,10 +28,17 @@ public class PhoneSubInfo extends IPhoneSubInfo.Stub { public PhoneSubInfo(Phone phone) { mPhone = phone; mContext = phone.getContext(); - ServiceManager.addService("iphonesubinfo", this); } + + public void dispose() { + } + + protected void finalize() { + Log.d(LOG_TAG, "PhoneSubInfo finalized"); + } + /** - * Retrieves the unique device ID, e.g., IMEI for GSM phones. + * Retrieves the unique device ID, e.g., IMEI for GSM phones and MEID for CDMA phones. */ public String getDeviceId() { mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE"); @@ -41,11 +63,11 @@ public class PhoneSubInfo extends IPhoneSubInfo.Stub { } /** - * Retrieves the serial number of the SIM, if applicable. + * Retrieves the serial number of the ICC, if applicable. */ - public String getSimSerialNumber() { + public String getIccSerialNumber() { mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE"); - return mPhone.getSimSerialNumber(); + return mPhone.getIccSerialNumber(); } /** diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java new file mode 100644 index 0000000..450b3a7 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.os.ServiceManager; + + +public class PhoneSubInfoProxy extends IPhoneSubInfo.Stub { + private PhoneSubInfo mPhoneSubInfo; + + public PhoneSubInfoProxy(PhoneSubInfo phoneSubInfo) { + mPhoneSubInfo = phoneSubInfo; + if(ServiceManager.getService("iphonesubinfo") == null) { + ServiceManager.addService("iphonesubinfo", this); + } + } + + public void setmPhoneSubInfo(PhoneSubInfo phoneSubInfo) { + this.mPhoneSubInfo = phoneSubInfo; + } + + public String getDeviceId() { + return mPhoneSubInfo.getDeviceId(); + } + + public String getDeviceSvn() { + return mPhoneSubInfo.getDeviceSvn(); + } + + /** + * Retrieves the unique sbuscriber ID, e.g., IMSI for GSM phones. + */ + public String getSubscriberId() { + return mPhoneSubInfo.getSubscriberId(); + } + + /** + * Retrieves the serial number of the ICC, if applicable. + */ + public String getIccSerialNumber() { + return mPhoneSubInfo.getIccSerialNumber(); + } + + /** + * Retrieves the phone number string for line 1. + */ + public String getLine1Number() { + return mPhoneSubInfo.getLine1Number(); + } + + /** + * Retrieves the alpha identifier for line 1. + */ + public String getLine1AlphaTag() { + return mPhoneSubInfo.getLine1AlphaTag(); + } + + /** + * Retrieves the voice mail number. + */ + public String getVoiceMailNumber() { + return mPhoneSubInfo.getVoiceMailNumber(); + } + + /** + * Retrieves the alpha identifier associated with the voice mail number. + */ + public String getVoiceMailAlphaTag() { + return mPhoneSubInfo.getVoiceMailAlphaTag(); + } +} diff --git a/telephony/java/com/android/internal/telephony/gsm/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java index e2d0f72..f5d3b32 100644 --- a/telephony/java/com/android/internal/telephony/gsm/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -14,9 +14,8 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; -import static com.android.internal.telephony.gsm.RILConstants.*; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -32,22 +31,36 @@ import android.os.Parcel; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.telephony.PhoneNumberUtils; -import android.telephony.gsm.SmsManager; -import android.telephony.gsm.SmsMessage; import android.telephony.NeighboringCellInfo; -import android.util.Config; +import android.telephony.SmsManager; +import android.telephony.SmsMessage; import android.util.Log; +import android.util.Config; -import java.io.IOException; +import static com.android.internal.telephony.RILConstants.*; + +import com.android.internal.telephony.CallForwardInfo; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.gsm.NetworkInfo; +import com.android.internal.telephony.gsm.PDPContextState; +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 java.io.ByteArrayInputStream; +import java.io.DataInputStream; import java.io.InputStream; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; /** * {@hide} */ -class RILRequest -{ +class RILRequest { static final String LOG_TAG = "RILJ"; //***** Class Variables @@ -67,14 +80,14 @@ class RILRequest /** * Retrieves a new RILRequest instance from the pool. - * + * * @param request RIL_REQUEST_* * @param result sent when operation completes * @return a RILRequest instance from the pool. */ static RILRequest obtain(int request, Message result) { RILRequest rr = null; - + synchronized(sPoolSync) { if (sPool != null) { rr = sPool; @@ -83,7 +96,7 @@ class RILRequest sPoolSize--; } } - + if (rr == null) { rr = new RILRequest(); } @@ -108,7 +121,7 @@ class RILRequest /** * Returns a RILRequest instance to the pool. - * + * * Note: This should only be called once per use. */ void release() { @@ -121,21 +134,18 @@ class RILRequest } } - private RILRequest() - { + private RILRequest() { } static void - resetSerial() - { + resetSerial() { synchronized(sSerialMonitor) { sNextSerial = 0; } } String - serialString() - { + serialString() { //Cheesy way to do %04d StringBuilder sb = new StringBuilder(8); String sn; @@ -154,14 +164,13 @@ class RILRequest } void - onError(int error) - { + onError(int error) { CommandException ex; ex = CommandException.fromRilErrno(error); if (RIL.RILJ_LOGD) Log.d(LOG_TAG, serialString() + "< " - + RIL.requestToString(mRequest) + + RIL.requestToString(mRequest) + " error: " + ex); if (mResult != null) { @@ -180,11 +189,10 @@ class RILRequest /** * RIL implementation of the CommandsInterface. * FIXME public only for testing - * + * * {@hide} */ -public final class RIL extends BaseCommands implements CommandsInterface -{ +public final class RIL extends BaseCommands implements CommandsInterface { static final String LOG_TAG = "RILJ"; private static final boolean DBG = false; static final boolean RILJ_LOGD = Config.LOGD; @@ -194,20 +202,20 @@ public final class RIL extends BaseCommands implements CommandsInterface //***** Instance Variables LocalSocket mSocket; - HandlerThread mSenderThread; + HandlerThread mSenderThread; RILSender mSender; Thread mReceiverThread; RILReceiver mReceiver; private Context mContext; WakeLock mWakeLock; int mRequestMessagesPending; - + // Is this the first radio state change? private boolean mInitialRadioStateChange = true; //I'd rather this be LinkedList or something ArrayList<RILRequest> mRequestsList = new ArrayList<RILRequest>(); - + Object mLastNITZTimeInfo; //***** Events @@ -238,20 +246,18 @@ public final class RIL extends BaseCommands implements CommandsInterface } } }; - - class RILSender extends Handler implements Runnable - { + + class RILSender extends Handler implements Runnable { public RILSender(Looper looper) { super(looper); } - + // Only allocated once byte[] dataLength = new byte[4]; //***** Runnable implementation public void - run() - { + run() { //setup if needed } @@ -259,11 +265,10 @@ public final class RIL extends BaseCommands implements CommandsInterface //***** Handler implemementation public void - handleMessage(Message msg) - { + handleMessage(Message msg) { RILRequest rr = (RILRequest)(msg.obj); RILRequest req = null; - + switch (msg.what) { case EVENT_SEND: /** @@ -300,7 +305,7 @@ public final class RIL extends BaseCommands implements CommandsInterface if (data.length > RIL_MAX_COMMAND_BYTES) { throw new RuntimeException( - "Parcel larger than max bytes allowed! " + "Parcel larger than max bytes allowed! " + data.length); } @@ -311,7 +316,7 @@ public final class RIL extends BaseCommands implements CommandsInterface //Log.v(LOG_TAG, "writing packet: " + data.length + " bytes"); - s.getOutputStream().write(dataLength); + s.getOutputStream().write(dataLength); s.getOutputStream().write(data); } catch (IOException ex) { Log.e(LOG_TAG, "IOException", ex); @@ -351,12 +356,12 @@ public final class RIL extends BaseCommands implements CommandsInterface Log.d(LOG_TAG, "WAKE_LOCK_TIMEOUT " + " mReqPending=" + mRequestMessagesPending + " mRequestList=" + count); - + for (int i = 0; i < count; i++) { rr = mRequestsList.get(i); Log.d(LOG_TAG, i + ": [" + rr.mSerial + "] " + requestToString(rr.mRequest)); - + } } } @@ -383,8 +388,7 @@ public final class RIL extends BaseCommands implements CommandsInterface * @throws IOException */ private static int readRilMessage(InputStream is, byte[] buffer) - throws IOException - { + throws IOException { int countRead; int offset; int remaining; @@ -429,20 +433,17 @@ public final class RIL extends BaseCommands implements CommandsInterface return messageLength; } - class RILReceiver implements Runnable - { + class RILReceiver implements Runnable { byte[] buffer; - RILReceiver() - { + RILReceiver() { buffer = new byte[RIL_MAX_COMMAND_BYTES]; } public void - run() - { + run() { int retryCount = 0; - + try {for (;;) { LocalSocket s = null; LocalSocketAddress l; @@ -460,23 +461,23 @@ public final class RIL extends BaseCommands implements CommandsInterface } catch (IOException ex2) { //ignore failure to close after failure to connect } - + // don't print an error message after the the first time // or after the 8th time if (retryCount == 8) { - Log.e (LOG_TAG, + Log.e (LOG_TAG, "Couldn't find '" + SOCKET_NAME_RIL + "' socket after " + retryCount + " times, continuing to retry silently"); } else if (retryCount > 0 && retryCount < 8) { - Log.i (LOG_TAG, + Log.i (LOG_TAG, "Couldn't find '" + SOCKET_NAME_RIL + "' socket; retrying after timeout"); } try { - Thread.sleep(SOCKET_OPEN_RETRY_MILLIS); + Thread.sleep(SOCKET_OPEN_RETRY_MILLIS); } catch (InterruptedException er) { } @@ -492,7 +493,7 @@ public final class RIL extends BaseCommands implements CommandsInterface int length = 0; try { InputStream is = mSocket.getInputStream(); - + for (;;) { Parcel p; @@ -524,9 +525,9 @@ public final class RIL extends BaseCommands implements CommandsInterface + "' socket"); setRadioState (RadioState.RADIO_UNAVAILABLE); - + try { - mSocket.close(); + mSocket.close(); } catch (IOException ex) { } @@ -551,15 +552,39 @@ public final class RIL extends BaseCommands implements CommandsInterface - //***** Constructor - + //***** Constructors public - RIL(Context context) - { + RIL(Context context) { + this(context, RILConstants.PREFERRED_NETWORK_MODE, + RILConstants.PREFERRED_CDMA_SUBSCRIPTION); + } + + public RIL(Context context, int networkMode, int cdmaSubscription) { super(context); + mCdmaSubscription = cdmaSubscription; + 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; + default: + mPhoneType = RILConstants.CDMA_PHONE; + } PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); mWakeLock.setReferenceCounted(false); mRequestMessagesPending = 0; @@ -583,9 +608,8 @@ public final class RIL extends BaseCommands implements CommandsInterface //***** CommandsInterface implementation - @Override public void - setOnNITZTime(Handler h, int what, Object obj) - { + @Override public void + setOnNITZTime(Handler h, int what, Object obj) { super.setOnNITZTime(h, what, obj); // Send the last NITZ time if we have it @@ -597,9 +621,10 @@ public final class RIL extends BaseCommands implements CommandsInterface } } - public void - getSimStatus(Message result) - { + public void + getIccStatus(Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -607,9 +632,10 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - supplySimPin(String pin, Message result) - { + public void + supplyIccPin(String pin, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PIN, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -620,9 +646,10 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - supplySimPuk(String puk, String newPin, Message result) - { + public void + supplyIccPuk(String puk, String newPin, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PUK, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -634,9 +661,10 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - supplySimPin2(String pin, Message result) - { + public void + supplyIccPin2(String pin, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PIN2, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -647,9 +675,10 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - supplySimPuk2(String puk, String newPin2, Message result) - { + public void + supplyIccPuk2(String puk, String newPin2, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PUK2, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -662,8 +691,9 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - changeSimPin(String oldPin, String newPin, Message result) - { + changeIccPin(String oldPin, String newPin, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -676,8 +706,9 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - changeSimPin2(String oldPin2, String newPin2, Message result) - { + changeIccPin2(String oldPin2, String newPin2, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN2, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -690,8 +721,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - changeBarringPassword(String facility, String oldPwd, String newPwd, Message result) - { + changeBarringPassword(String facility, String oldPwd, String newPwd, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_BARRING_PASSWORD, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -704,9 +734,8 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - supplyNetworkDepersonalization(String netpin, Message result) - { + public void + supplyNetworkDepersonalization(String netpin, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -716,10 +745,9 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - - public void - getCurrentCalls (Message result) - { + + public void + getCurrentCalls (Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -727,19 +755,22 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - getPDPContextList(Message result) - { - RILRequest rr = RILRequest.obtain(RIL_REQUEST_PDP_CONTEXT_LIST, result); + public void + getPDPContextList(Message result) { + getDataCallList(result); + } + + public void + getDataCallList(Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_DATA_CALL_LIST, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } - public void - dial (String address, int clirMode, Message result) - { + public void + dial (String address, int clirMode, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result); rr.mp.writeString(address); @@ -750,19 +781,20 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - getIMSI(Message result) - { + public void + getIMSI(Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMSI, result); - if (RILJ_LOGD) riljLog(rr.serialString() + "> getIMSI:RIL_REQUEST_GET_IMSI " + RIL_REQUEST_GET_IMSI + " " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + + "> getIMSI:RIL_REQUEST_GET_IMSI " + + RIL_REQUEST_GET_IMSI + + " " + requestToString(rr.mRequest)); send(rr); } public void - getIMEI(Message result) - { + getIMEI(Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMEI, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -771,8 +803,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - getIMEISV(Message result) - { + getIMEISV(Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMEISV, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -781,14 +812,14 @@ public final class RIL extends BaseCommands implements CommandsInterface } - public void - hangupConnection (int gsmIndex, Message result) - { + public void + hangupConnection (int gsmIndex, Message result) { if (RILJ_LOGD) riljLog("hangupConnection: gsmIndex=" + gsmIndex); RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP, result); - if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + gsmIndex); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + + gsmIndex); rr.mp.writeInt(1); rr.mp.writeInt(gsmIndex); @@ -796,10 +827,9 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - hangupWaitingOrBackground (Message result) - { - RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, + public void + hangupWaitingOrBackground (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -808,11 +838,10 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - hangupForegroundResumeBackground (Message result) - { - RILRequest rr + hangupForegroundResumeBackground (Message result) { + RILRequest rr = RILRequest.obtain( - RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, + RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -820,11 +849,10 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - switchWaitingOrHoldingAndActive (Message result) - { - RILRequest rr + switchWaitingOrHoldingAndActive (Message result) { + RILRequest rr = RILRequest.obtain( - RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, + RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -832,9 +860,8 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - conference (Message result) - { - RILRequest rr + conference (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CONFERENCE, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -843,10 +870,25 @@ public final class RIL extends BaseCommands implements CommandsInterface } + public void setPreferredVoicePrivacy(boolean enable, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE, + result); + + rr.mp.writeInt(1); + rr.mp.writeInt(enable ? 1:0); + + send(rr); + } + + public void getPreferredVoicePrivacy(Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE, + result); + send(rr); + } + public void - separateConnection (int gsmIndex, Message result) - { - RILRequest rr + separateConnection (int gsmIndex, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SEPARATE_CONNECTION, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) @@ -859,9 +901,8 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - acceptCall (Message result) - { - RILRequest rr + acceptCall (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_ANSWER, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -869,10 +910,9 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - rejectCall (Message result) - { - RILRequest rr + public void + rejectCall (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_UDUB, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -881,8 +921,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - explicitCallTransfer (Message result) - { + explicitCallTransfer (Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_EXPLICIT_CALL_TRANSFER, result); @@ -892,9 +931,8 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - getLastCallFailCause (Message result) - { - RILRequest rr + getLastCallFailCause (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_LAST_CALL_FAIL_CAUSE, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -902,11 +940,21 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - getLastPdpFailCause (Message result) - { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_LAST_PDP_FAIL_CAUSE, result); + /** + * @deprecated + */ + public void + getLastPdpFailCause (Message result) { + getLastDataCallFailCause (result); + } + + /** + * The preferred new alternative to getLastPdpFailCause + */ + public void + getLastDataCallFailCause (Message result) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -914,9 +962,8 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - setMute (boolean enableMute, Message response) - { - RILRequest rr + setMute (boolean enableMute, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_MUTE, response); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) @@ -929,9 +976,8 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - getMute (Message response) - { - RILRequest rr + getMute (Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_MUTE, response); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -940,9 +986,8 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - getSignalStrength (Message result) - { - RILRequest rr + getSignalStrength (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SIGNAL_STRENGTH, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -950,10 +995,9 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - getRegistrationState (Message result) - { - RILRequest rr + public void + getRegistrationState (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_REGISTRATION_STATE, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -961,10 +1005,9 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - getGPRSRegistrationState (Message result) - { - RILRequest rr + public void + getGPRSRegistrationState (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_GPRS_REGISTRATION_STATE, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -972,10 +1015,9 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - getOperator(Message result) - { - RILRequest rr + public void + getOperator(Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_OPERATOR, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -983,14 +1025,13 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - sendDtmf(char c, Message result) - { - RILRequest rr + public void + sendDtmf(char c, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_DTMF, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + rr.mp.writeString(Character.toString(c)); send(rr); @@ -1020,9 +1061,8 @@ public final class RIL extends BaseCommands implements CommandsInterface public void - sendSMS (String smscPDU, String pdu, Message result) - { - RILRequest rr + sendSMS (String smscPDU, String pdu, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SEND_SMS, result); rr.mp.writeInt(2); @@ -1030,19 +1070,82 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeString(pdu); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + + send(rr); + } + + public void + sendCdmaSms(byte[] pdu, Message result) { + int address_nbr_of_digits; + int subaddr_nbr_of_digits; + int bearerDataLength; + ByteArrayInputStream bais = new ByteArrayInputStream(pdu); + DataInputStream dis = new DataInputStream(bais); + + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_CDMA_SEND_SMS, result); + + try { + rr.mp.writeInt(dis.readInt()); //teleServiceId + rr.mp.writeByte((byte) dis.readInt()); //servicePresent + rr.mp.writeInt(dis.readInt()); //serviceCategory + rr.mp.writeInt(dis.read()); //address_digit_mode + rr.mp.writeInt(dis.read()); //address_nbr_mode + rr.mp.writeInt(dis.read()); //address_ton + rr.mp.writeInt(dis.read()); //address_nbr_plan + address_nbr_of_digits = (byte) dis.read(); + rr.mp.writeByte((byte) address_nbr_of_digits); + for(int i=0; i < address_nbr_of_digits; i++){ + rr.mp.writeByte(dis.readByte()); // address_orig_bytes[i] + } + rr.mp.writeInt(dis.read()); //subaddressType + rr.mp.writeByte((byte) dis.read()); //subaddr_odd + subaddr_nbr_of_digits = (byte) dis.read(); + rr.mp.writeByte((byte) subaddr_nbr_of_digits); + for(int i=0; i < subaddr_nbr_of_digits; i++){ + rr.mp.writeByte(dis.readByte()); //subaddr_orig_bytes[i] + } + + bearerDataLength = dis.read(); + rr.mp.writeInt(bearerDataLength); + for(int i=0; i < bearerDataLength; i++){ + rr.mp.writeByte(dis.readByte()); //bearerData[i] + } + }catch (IOException ex){ + if (RILJ_LOGD) riljLog("sendSmsCdma: conversion from input stream to object failed: " + + ex); + } + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + send(rr); } public void deleteSmsOnSim(int index, Message response) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_DELETE_SMS_ON_SIM, response); - + rr.mp.writeInt(1); rr.mp.writeInt(index); - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + if (Config.LOGD) { + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + + requestToString(rr.mRequest) + + " " + index); + } + + send(rr); + } + + public void deleteSmsOnRuim(int index, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, + response); + + rr.mp.writeInt(1); + rr.mp.writeInt(index); + + if (Config.LOGD) { + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + index); } @@ -1052,17 +1155,35 @@ public final class RIL extends BaseCommands implements CommandsInterface public void writeSmsToSim(int status, String smsc, String pdu, Message response) { status = translateStatus(status); - + RILRequest rr = RILRequest.obtain(RIL_REQUEST_WRITE_SMS_TO_SIM, response); - + rr.mp.writeInt(status); rr.mp.writeString(pdu); rr.mp.writeString(smsc); - - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " - + requestToString(rr.mRequest) + + if (Config.LOGD) { + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + + requestToString(rr.mRequest) + + " " + status); + } + + send(rr); + } + + public void writeSmsToRuim(int status, String pdu, Message response) { + status = translateStatus(status); + + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM, + response); + + rr.mp.writeInt(status); + rr.mp.writeString(pdu); + + if (Config.LOGD) { + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + + requestToString(rr.mRequest) + " " + status); } @@ -1075,101 +1196,166 @@ public final class RIL extends BaseCommands implements CommandsInterface */ private int translateStatus(int status) { switch(status & 0x7) { - case SmsManager.STATUS_ON_SIM_READ: + case SmsManager.STATUS_ON_ICC_READ: return 1; - case SmsManager.STATUS_ON_SIM_UNREAD: + case SmsManager.STATUS_ON_ICC_UNREAD: return 0; - case SmsManager.STATUS_ON_SIM_SENT: + case SmsManager.STATUS_ON_ICC_SENT: return 3; - case SmsManager.STATUS_ON_SIM_UNSENT: + case SmsManager.STATUS_ON_ICC_UNSENT: return 2; } - + // Default to READ. return 1; } - public void - setupDefaultPDP(String apn, String user, String password, Message result) - { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_SETUP_DEFAULT_PDP, result); + /** + * @deprecated + */ + public void + setupDefaultPDP(String apn, String user, String password, Message result) { + String radioTechnology = "1"; //0 for CDMA, 1 for GSM/UMTS + String profile = ""; //profile number, NULL for GSM/UMTS + setupDataCall(radioTechnology, profile, apn, user, + password, result); - rr.mp.writeInt(3); + } + + /** + * @deprecated + */ + public void + deactivateDefaultPDP(int cid, Message result) { + deactivateDataCall(cid, result); + } + + /** + * The preferred new alternative to setupDefaultPDP that is + * CDMA-compatible. + * + */ + public void + setupDataCall(String radioTechnology, String profile, String apn, + String user, String password, Message result) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result); + + rr.mp.writeInt(5); + + rr.mp.writeString(radioTechnology); + rr.mp.writeString(profile); rr.mp.writeString(apn); rr.mp.writeString(user); rr.mp.writeString(password); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + apn); - + send(rr); } public void - deactivateDefaultPDP(int cid, Message result) - { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_DEACTIVATE_DEFAULT_PDP, result); + deactivateDataCall(int cid, Message result) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_DEACTIVATE_DATA_CALL, result); rr.mp.writeInt(1); rr.mp.writeString(Integer.toString(cid)); - if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + cid); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + + requestToString(rr.mRequest) + " " + cid); + send(rr); } public void - setRadioPower(boolean on, Message result) - { - RILRequest rr + setRadioPower(boolean on, Message result) { + //if radio is OFF set preferred NW type and cmda subscription + if(mInitialRadioStateChange) { + synchronized (mStateMonitor) { + if (!mState.isOn()) { + RILRequest rrPnt = RILRequest.obtain( + RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, null); + + rrPnt.mp.writeInt(1); + rrPnt.mp.writeInt(mNetworkMode); + if (RILJ_LOGD) riljLog(rrPnt.serialString() + "> " + + requestToString(rrPnt.mRequest) + " : " + mNetworkMode); + + send(rrPnt); + + RILRequest rrCs = RILRequest.obtain( + RIL_REQUEST_CDMA_SET_SUBSCRIPTION, null); + rrCs.mp.writeInt(1); + rrCs.mp.writeInt(mCdmaSubscription); + if (RILJ_LOGD) riljLog(rrCs.serialString() + "> " + + requestToString(rrCs.mRequest) + " : " + mCdmaSubscription); + send(rrCs); + } + } + } + RILRequest rr = RILRequest.obtain(RIL_REQUEST_RADIO_POWER, result); rr.mp.writeInt(1); rr.mp.writeInt(on ? 1 : 0); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } public void - setSuppServiceNotifications(boolean enable, Message result) - { - RILRequest rr + setSuppServiceNotifications(boolean enable, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, result); rr.mp.writeInt(1); rr.mp.writeInt(enable ? 1 : 0); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " - + requestToString(rr.mRequest)); + + requestToString(rr.mRequest)); send(rr); } - public void - acknowledgeLastIncomingSMS(boolean success, Message result) - { - RILRequest rr + public void + acknowledgeLastIncomingSMS(boolean success, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SMS_ACKNOWLEDGE, result); rr.mp.writeInt(1); rr.mp.writeInt(success ? 1 : 0); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } - + public void - simIO (int command, int fileid, String path, int p1, int p2, int p3, - String data, String pin2, Message result) - { - RILRequest rr + acknowledgeLastIncomingCdmaSms(boolean success, 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. + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + + public void + iccIO (int command, int fileid, String path, int p1, int p2, int p3, + String data, String pin2, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SIM_IO, result); - + rr.mp.writeInt(command); rr.mp.writeInt(fileid); rr.mp.writeString(path); @@ -1179,51 +1365,48 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeString(data); rr.mp.writeString(pin2); - if (RILJ_LOGD) riljLog(rr.serialString() + "> simIO: " + requestToString(rr.mRequest) - + " 0x" + Integer.toHexString(command) - + " 0x" + Integer.toHexString(fileid) + " " + if (RILJ_LOGD) riljLog(rr.serialString() + "> iccIO: " + requestToString(rr.mRequest) + + " 0x" + Integer.toHexString(command) + + " 0x" + Integer.toHexString(fileid) + " " + p1 + "," + p2 + "," + p3); - + send(rr); } - + public void - getCLIR(Message result) - { - RILRequest rr + getCLIR(Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CLIR, result); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } public void - setCLIR(int clirMode, Message result) - { - RILRequest rr + setCLIR(int clirMode, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_CLIR, result); // count ints rr.mp.writeInt(1); rr.mp.writeInt(clirMode); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + clirMode); - + send(rr); } public void - queryCallWaiting(int serviceClass, Message response) - { - RILRequest rr + queryCallWaiting(int serviceClass, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_CALL_WAITING, response); rr.mp.writeInt(1); rr.mp.writeInt(serviceClass); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + serviceClass); @@ -1231,77 +1414,71 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - setCallWaiting(boolean enable, int serviceClass, Message response) - { - RILRequest rr + setCallWaiting(boolean enable, int serviceClass, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_CALL_WAITING, response); - + rr.mp.writeInt(2); rr.mp.writeInt(enable ? 1 : 0); rr.mp.writeInt(serviceClass); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + enable + ", " + serviceClass); - + send(rr); } public void - setNetworkSelectionModeAutomatic(Message response) - { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, + setNetworkSelectionModeAutomatic(Message response) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, response); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } - public void - setNetworkSelectionModeManual(String operatorNumeric, Message response) - { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, + public void + setNetworkSelectionModeManual(String operatorNumeric, Message response) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, response); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + operatorNumeric); rr.mp.writeString(operatorNumeric); - + send(rr); } - public void - getNetworkSelectionMode(Message response) - { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, + public void + getNetworkSelectionMode(Message response) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, response); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } - public void - getAvailableNetworks(Message response) - { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_QUERY_AVAILABLE_NETWORKS, + public void + getAvailableNetworks(Message response) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_QUERY_AVAILABLE_NETWORKS, response); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } public void - setCallForward(int action, int cfReason, int serviceClass, - String number, int timeSeconds, Message response) - { - RILRequest rr + setCallForward(int action, int cfReason, int serviceClass, + String number, int timeSeconds, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_CALL_FORWARD, response); rr.mp.writeInt(action); @@ -1310,19 +1487,18 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeInt(PhoneNumberUtils.toaFromString(number)); rr.mp.writeString(number); rr.mp.writeInt (timeSeconds); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) - + " " + action + " " + cfReason + " " + serviceClass + + " " + action + " " + cfReason + " " + serviceClass + timeSeconds); - + send(rr); } public void queryCallForwardStatus(int cfReason, int serviceClass, - String number, Message response) - { - RILRequest rr + String number, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_CALL_FORWARD_STATUS, response); rr.mp.writeInt(2); // 2 is for query action, not in used anyway @@ -1331,7 +1507,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeInt(PhoneNumberUtils.toaFromString(number)); rr.mp.writeString(number); rr.mp.writeInt (0); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + cfReason + " " + serviceClass); @@ -1339,8 +1515,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - queryCLIP(Message response) - { + queryCLIP(Message response) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_CLIP, response); @@ -1351,11 +1526,10 @@ public final class RIL extends BaseCommands implements CommandsInterface public void - getBasebandVersion (Message response) - { - RILRequest rr + getBasebandVersion (Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_BASEBAND_VERSION, response); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); @@ -1363,14 +1537,13 @@ public final class RIL extends BaseCommands implements CommandsInterface public void queryFacilityLock (String facility, String password, int serviceClass, - Message response) - { + Message response) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_FACILITY_LOCK, response); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); // count strings - rr.mp.writeInt(3); + rr.mp.writeInt(3); rr.mp.writeString(facility); rr.mp.writeString(password); @@ -1382,8 +1555,7 @@ public final class RIL extends BaseCommands implements CommandsInterface public void setFacilityLock (String facility, boolean lockState, String password, - int serviceClass, Message response) - { + int serviceClass, Message response) { String lockString; RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_FACILITY_LOCK, response); @@ -1402,11 +1574,10 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - + public void - sendUSSD (String ussdString, Message response) - { - RILRequest rr + sendUSSD (String ussdString, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SEND_USSD, response); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) @@ -1429,9 +1600,8 @@ public final class RIL extends BaseCommands implements CommandsInterface } - public void resetRadio(Message result) - { - RILRequest rr + public void resetRadio(Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_RESET_RADIO, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -1439,13 +1609,12 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void invokeOemRilRequestRaw(byte[] data, Message response) - { - RILRequest rr + public void invokeOemRilRequestRaw(byte[] data, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_OEM_HOOK_RAW, response); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) - + "[" + SimUtils.bytesToHexString(data) + "]"); + + "[" + IccUtils.bytesToHexString(data) + "]"); rr.mp.writeByteArray(data); @@ -1453,9 +1622,8 @@ public final class RIL extends BaseCommands implements CommandsInterface } - public void invokeOemRilRequestStrings(String[] strings, Message response) - { - RILRequest rr + public void invokeOemRilRequestStrings(String[] strings, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_OEM_HOOK_STRINGS, response); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -1592,29 +1760,27 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_LOCATION_UPDATES, response); rr.mp.writeInt(1); rr.mp.writeInt(enable ? 1 : 0); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + ": " + enable); - + send(rr); } //***** Private Methods - private void sendScreenState(boolean on) - { + private void sendScreenState(boolean on) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_SCREEN_STATE, null); rr.mp.writeInt(1); rr.mp.writeInt(on ? 1 : 0); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + ": " + on); - + send(rr); } - + protected void - onRadioAvailable() - { + onRadioAvailable() { // In case screen state was lost (due to process crash), // this ensures that the RIL knows the correct screen state. @@ -1633,13 +1799,18 @@ public final class RIL extends BaseCommands implements CommandsInterface case 2: newState = RadioState.SIM_NOT_READY; break; case 3: newState = RadioState.SIM_LOCKED_OR_ABSENT; break; case 4: newState = RadioState.SIM_READY; break; - default: + case 5: newState = RadioState.RUIM_NOT_READY; break; + case 6: newState = RadioState.RUIM_READY; break; + case 7: newState = RadioState.RUIM_LOCKED_OR_ABSENT; break; + case 8: newState = RadioState.NV_NOT_READY; break; + case 9: newState = RadioState.NV_READY; break; + + default: throw new RuntimeException( "Unrecognized RIL_RadioState: " +state); } if (mInitialRadioStateChange) { - mInitialRadioStateChange = false; if (newState.isOn()) { /* If this is our first notification, make sure the radio * is powered off. This gets the radio into a known state, @@ -1648,12 +1819,15 @@ 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); - return; + setRadioPower(false, null); + } else { + if (DBG) Log.d(LOG_TAG, "Radio OFF @ init"); + setRadioState(newState); } + mInitialRadioStateChange = false; + } else { + setRadioState(newState); } - - setRadioState(newState); } /** @@ -1661,13 +1835,12 @@ public final class RIL extends BaseCommands implements CommandsInterface * a) There is outstanding RIL request sent to RIL deamon and no replied * b) There is a request waiting to be sent out. * - * There is a WAKE_LOCK_TIMEOUT to release the lock, though it shouldn't + * There is a WAKE_LOCK_TIMEOUT to release the lock, though it shouldn't * happen often. */ private void - acquireWakeLock() - { + acquireWakeLock() { synchronized (mWakeLock) { mWakeLock.acquire(); mRequestMessagesPending++; @@ -1679,8 +1852,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } private void - releaseWakeLockIfDone() - { + releaseWakeLockIfDone() { synchronized (mWakeLock) { if (mWakeLock.isHeld() && (mRequestMessagesPending == 0) && @@ -1692,8 +1864,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } private void - send(RILRequest rr) - { + send(RILRequest rr) { Message msg; msg = mSender.obtainMessage(EVENT_SEND, rr); @@ -1704,8 +1875,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } private void - processResponse (Parcel p) - { + processResponse (Parcel p) { int type; type = p.readInt(); @@ -1714,15 +1884,12 @@ public final class RIL extends BaseCommands implements CommandsInterface processUnsolicited (p); } else if (type == RESPONSE_SOLICITED) { processSolicited (p); - } + } releaseWakeLockIfDone(); } - - - private RILRequest findAndRemoveRequestFromList(int serial) - { + private RILRequest findAndRemoveRequestFromList(int serial) { synchronized (mRequestsList) { for (int i = 0, s = mRequestsList.size() ; i < s ; i++) { RILRequest rr = mRequestsList.get(i); @@ -1738,8 +1905,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } private void - processSolicited (Parcel p) - { + processSolicited (Parcel p) { int serial, error; boolean found = false; @@ -1751,7 +1917,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr = findAndRemoveRequestFromList(serial); if (rr == null) { - Log.w(LOG_TAG, "Unexpected solicited response! sn: " + Log.w(LOG_TAG, "Unexpected solicited response! sn: " + serial + " error: " + error); return; } @@ -1763,14 +1929,14 @@ public final class RIL extends BaseCommands implements CommandsInterface } Object ret; - + 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 = responseSimStatus(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; @@ -1796,8 +1962,8 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_REQUEST_DTMF: ret = responseVoid(p); break; case RIL_REQUEST_SEND_SMS: ret = responseSMS(p); break; case RIL_REQUEST_SEND_SMS_EXPECT_MORE: ret = responseSMS(p); break; - case RIL_REQUEST_SETUP_DEFAULT_PDP: ret = responseStrings(p); break; - case RIL_REQUEST_SIM_IO: ret = responseSIM_IO(p); break; + case RIL_REQUEST_SETUP_DATA_CALL: ret = responseStrings(p); break; + case RIL_REQUEST_SIM_IO: ret = responseICC_IO(p); break; case RIL_REQUEST_SEND_USSD: ret = responseVoid(p); break; case RIL_REQUEST_CANCEL_USSD: ret = responseVoid(p); break; case RIL_REQUEST_GET_CLIR: ret = responseInts(p); break; @@ -1810,7 +1976,7 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_REQUEST_GET_IMEI: ret = responseString(p); break; case RIL_REQUEST_GET_IMEISV: ret = responseString(p); break; case RIL_REQUEST_ANSWER: ret = responseVoid(p); break; - case RIL_REQUEST_DEACTIVATE_DEFAULT_PDP: 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_CHANGE_BARRING_PASSWORD: ret = responseVoid(p); break; @@ -1822,39 +1988,61 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_REQUEST_DTMF_STOP: ret = responseVoid(p); break; case RIL_REQUEST_BASEBAND_VERSION: ret = responseString(p); break; case RIL_REQUEST_SEPARATE_CONNECTION: ret = responseVoid(p); break; - case RIL_REQUEST_SET_MUTE: ret =responseVoid(p); break; - case RIL_REQUEST_GET_MUTE: ret = responseInts(p); break; - case RIL_REQUEST_QUERY_CLIP: ret = responseInts(p); break; - case RIL_REQUEST_LAST_PDP_FAIL_CAUSE: ret = responseInts(p); break; - case RIL_REQUEST_PDP_CONTEXT_LIST: ret = responseContextList(p); break; - case RIL_REQUEST_RESET_RADIO: ret = responseVoid(p); break; - case RIL_REQUEST_OEM_HOOK_RAW: ret = responseRaw(p); break; - case RIL_REQUEST_OEM_HOOK_STRINGS: ret = responseStrings(p); break; + case RIL_REQUEST_SET_MUTE: ret = responseVoid(p); break; + case RIL_REQUEST_GET_MUTE: ret = responseInts(p); break; + case RIL_REQUEST_QUERY_CLIP: ret = responseInts(p); break; + case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: ret = responseInts(p); break; + case RIL_REQUEST_DATA_CALL_LIST: ret = responseDataCallList(p); break; + case RIL_REQUEST_RESET_RADIO: ret = responseVoid(p); break; + case RIL_REQUEST_OEM_HOOK_RAW: ret = responseRaw(p); break; + case RIL_REQUEST_OEM_HOOK_STRINGS: ret = responseStrings(p); break; case RIL_REQUEST_SCREEN_STATE: ret = responseVoid(p); break; - case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION: ret = responseVoid(p); break; - case RIL_REQUEST_WRITE_SMS_TO_SIM: ret = responseInts(p); break; - case RIL_REQUEST_DELETE_SMS_ON_SIM: ret = responseVoid(p); break; - case RIL_REQUEST_SET_BAND_MODE: ret = responseVoid(p); break; - case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: ret = responseInts(p); break; - case RIL_REQUEST_STK_GET_PROFILE: ret = responseString(p); break; - case RIL_REQUEST_STK_SET_PROFILE: ret = responseVoid(p); break; - case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: ret = responseString(p); break; - case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: ret = responseVoid(p); break; - case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: ret = responseInts(p); break; - case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: ret = responseVoid(p); break; - case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: ret = responseVoid(p); break; - case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: ret = responseInts(p); break; + case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION: ret = responseVoid(p); break; + case RIL_REQUEST_WRITE_SMS_TO_SIM: ret = responseInts(p); break; + case RIL_REQUEST_DELETE_SMS_ON_SIM: ret = responseVoid(p); break; + case RIL_REQUEST_SET_BAND_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: ret = responseInts(p); break; + case RIL_REQUEST_STK_GET_PROFILE: ret = responseString(p); break; + case RIL_REQUEST_STK_SET_PROFILE: ret = responseVoid(p); break; + case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: ret = responseString(p); break; + case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: ret = responseVoid(p); break; + case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: ret = responseInts(p); break; + case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: ret = responseVoid(p); break; + case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: ret = responseVoid(p); break; + case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: ret = responseInts(p); break; case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: ret = responseCellList(p); break; - case RIL_REQUEST_SET_LOCATION_UPDATES: ret = responseVoid(p); break; - + case RIL_REQUEST_SET_LOCATION_UPDATES: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SET_SUBSCRIPTION: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE: ret = responseInts(p); break; + case RIL_REQUEST_SET_TTY_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_TTY_MODE: ret = responseInts(p); break; + case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE: ret = responseInts(p); break; + case RIL_REQUEST_CDMA_FLASH: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_BURST_DTMF: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SEND_SMS: ret = responseVoid(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_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_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; default: - throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest); + throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest); //break; }} 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); @@ -1866,18 +2054,17 @@ public final class RIL extends BaseCommands implements CommandsInterface if (RILJ_LOGD) riljLog(rr.serialString() + "< " + requestToString(rr.mRequest) + " " + retToString(rr.mRequest, ret)); - + if (rr.mResult != null) { AsyncResult.forMessage(rr.mResult, ret, null); rr.mResult.sendToTarget(); } - + rr.release(); } private String - retToString(int req, Object ret) - { + retToString(int req, Object ret) { if (ret == null) return ""; switch (req) { // Don't log these return values, for privacy's sake. @@ -1938,8 +2125,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } private void - processUnsolicited (Parcel p) - { + processUnsolicited (Parcel p) { int response; Object ret; @@ -1961,7 +2147,7 @@ public final class RIL extends BaseCommands implements CommandsInterface 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_PDP_CONTEXT_LIST_CHANGED: ret = responseContextList(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; case RIL_UNSOL_STK_PROACTIVE_COMMAND: ret = responseString(p); break; @@ -1971,8 +2157,12 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_UNSOL_SIM_REFRESH: ret = responseInts(p); break; case RIL_UNSOL_CALL_RING: ret = responseVoid(p); break; case RIL_UNSOL_RESTRICTED_STATE_CHANGED: ret = responseInts(p); break; - default: - throw new RuntimeException("Unrecognized unsol response: " + response); + 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; + default: + throw new RuntimeException("Unrecognized unsol response: " + response); //break; (implied) }} catch (Throwable tr) { Log.e(LOG_TAG, "Exception processing unsol response: " + response + @@ -1984,7 +2174,7 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: /* has bonus radio state int */ setRadioStateFromRILInt(p.readInt()); - + if (RILJ_LOGD) unsljLogMore(response, mState.toString()); break; case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: @@ -2009,7 +2199,7 @@ public final class RIL extends BaseCommands implements CommandsInterface SmsMessage sms; - sms = SmsMessage.newFromCMT(a); + sms = SmsMessage.newFromCMT(a); if (mSMSRegistrant != null) { mSMSRegistrant .notifyRegistrant(new AsyncResult(null, sms, null)); @@ -2041,7 +2231,7 @@ public final class RIL extends BaseCommands implements CommandsInterface break; case RIL_UNSOL_ON_USSD: String[] resp = (String[])ret; - + if (resp.length < 2) { resp = new String[2]; resp[0] = ((String[])ret)[0]; @@ -2053,7 +2243,7 @@ public final class RIL extends BaseCommands implements CommandsInterface new AsyncResult (null, resp, null)); } break; - case RIL_UNSOL_NITZ_TIME_RECEIVED: + case RIL_UNSOL_NITZ_TIME_RECEIVED: if (RILJ_LOGD) unsljLogRet(response, ret); // has bonus long containing milliseconds since boot that the NITZ @@ -2066,7 +2256,7 @@ public final class RIL extends BaseCommands implements CommandsInterface result[1] = Long.valueOf(nitzReceiveTime); if (mNITZTimeRegistrant != null) { - + mNITZTimeRegistrant .notifyRegistrant(new AsyncResult (null, result, null)); } else { @@ -2074,22 +2264,21 @@ public final class RIL extends BaseCommands implements CommandsInterface mLastNITZTimeInfo = result; } break; - + case RIL_UNSOL_SIGNAL_STRENGTH: // Note this is set to "verbose" because it happens // frequently if (RILJ_LOGV) unsljLogvRet(response, ret); - + if (mSignalStrengthRegistrant != null) { mSignalStrengthRegistrant.notifyRegistrant( new AsyncResult (null, ret, null)); } break; - case RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED: + case RIL_UNSOL_DATA_CALL_LIST_CHANGED: if (RILJ_LOGD) unsljLogRet(response, ret); - mPDPRegistrants - .notifyRegistrants(new AsyncResult(null, ret, null)); + mDataConnectionRegistrants.notifyRegistrants(new AsyncResult(null, ret, null)); break; case RIL_UNSOL_SUPP_SVC_NOTIFICATION: @@ -2140,21 +2329,21 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_UNSOL_SIM_SMS_STORAGE_FULL: if (RILJ_LOGD) unsljLog(response); - if (mSimSmsFullRegistrant != null) { - mSimSmsFullRegistrant.notifyRegistrant(); + if (mIccSmsFullRegistrant != null) { + mIccSmsFullRegistrant.notifyRegistrant(); } break; - case RIL_UNSOL_SIM_REFRESH: + case RIL_UNSOL_SIM_REFRESH: if (RILJ_LOGD) unsljLogRet(response, ret); - if (mSimRefreshRegistrant != null) { - mSimRefreshRegistrant.notifyRegistrant( + if (mIccRefreshRegistrant != null) { + mIccRefreshRegistrant.notifyRegistrant( new AsyncResult (null, ret, null)); } break; - - case RIL_UNSOL_CALL_RING: + + case RIL_UNSOL_CALL_RING: if (RILJ_LOGD) unsljLog(response); if (mRingRegistrant != null) { @@ -2168,12 +2357,40 @@ public final class RIL extends BaseCommands implements CommandsInterface mRestrictedStateRegistrant.notifyRegistrant( new AsyncResult (null, ret, null)); } + + case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: + if (mIccStatusChangedRegistrants != null) { + mIccStatusChangedRegistrants.notifyRegistrants(); + } + break; + + case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS: + SmsMessage sms = (SmsMessage) ret; + + if (mSMSRegistrant != null) { + mSMSRegistrant + .notifyRegistrant(new AsyncResult(null, sms, null)); + } + break; + + case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: + // TODO T: waiting for SMS BC feature + break; + + case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL: + if (Config.LOGD) { + if (RILJ_LOGD) riljLog("[UNSL]< RUIM_SMS_STORAGE_FULL"); + } + + if (mIccSmsFullRegistrant != null) { + mIccSmsFullRegistrant.notifyRegistrant(); + } + break; } } private Object - responseInts(Parcel p) - { + responseInts(Parcel p) { int numInts; int response[]; @@ -2190,14 +2407,12 @@ public final class RIL extends BaseCommands implements CommandsInterface private Object - responseVoid(Parcel p) - { + responseVoid(Parcel p) { return null; } private Object - responseCallForward(Parcel p) - { + responseCallForward(Parcel p) { int numInfos; CallForwardInfo infos[]; @@ -2220,22 +2435,28 @@ public final class RIL extends BaseCommands implements CommandsInterface } private Object - responseSuppServiceNotification(Parcel p) - { + responseSuppServiceNotification(Parcel p) { SuppServiceNotification notification = new SuppServiceNotification(); - + notification.notificationType = p.readInt(); notification.code = p.readInt(); notification.index = p.readInt(); notification.type = p.readInt(); notification.number = p.readString(); - + return notification; } - + private Object - responseString(Parcel p) - { + responseCdmaSms(Parcel p) { + SmsMessage sms; + sms = SmsMessage.newFromParcel(p); + + return sms; + } + + private Object + responseString(Parcel p) { String response; response = p.readString(); @@ -2244,8 +2465,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } private Object - responseStrings(Parcel p) - { + responseStrings(Parcel p) { int num; String response[]; @@ -2259,13 +2479,12 @@ public final class RIL extends BaseCommands implements CommandsInterface response[i] = p.readString(); } } - + return response; } private Object - responseRaw(Parcel p) - { + responseRaw(Parcel p) { int num; byte response[]; @@ -2275,8 +2494,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } private Object - responseSMS(Parcel p) - { + responseSMS(Parcel p) { int messageRef; String ackPDU; @@ -2290,46 +2508,110 @@ public final class RIL extends BaseCommands implements CommandsInterface private Object - responseSIM_IO(Parcel p) - { + responseICC_IO(Parcel p) { int sw1, sw2; byte data[] = null; Message ret; - + sw1 = p.readInt(); sw2 = p.readInt(); String s = p.readString(); - return new SimIoResult(sw1, sw2, s); + return new IccIoResult(sw1, sw2, s); } private Object - responseSimStatus(Parcel p) - { - int status; - - status = ((int[])responseInts(p))[0]; - switch (status){ - case RIL_SIM_ABSENT: return SimStatus.SIM_ABSENT; - case RIL_SIM_NOT_READY: return SimStatus.SIM_NOT_READY; - case RIL_SIM_READY: return SimStatus.SIM_READY; - case RIL_SIM_PIN: return SimStatus.SIM_PIN; - case RIL_SIM_PUK: return SimStatus.SIM_PUK; - case RIL_SIM_NETWORK_PERSONALIZATION: - return SimStatus.SIM_NETWORK_PERSONALIZATION; - default: - // Unrecognized SIM status. Treat it like a missing SIM. - Log.e(LOG_TAG, "Unrecognized RIL_REQUEST_GET_SIM_STATUS result: " + status); - return SimStatus.SIM_ABSENT; + responseIccCardStatus(Parcel p) { + RadioState currentRadioState; + IccCardApplication ca; + + currentRadioState = getRadioState(); + + IccCardStatus status = new IccCardStatus(); + status.card_state = status.CardStateFromRILInt(p.readInt()); + status.universal_pin_state = status.PinStateFromRILInt(p.readInt()); + status.gsm_umts_subscription_app_index = p.readInt(); + status.cdma_subscription_app_index = p.readInt(); + status.num_applications = p.readInt(); + + // limit to maximum allowed applications + if (status.num_applications > IccCardStatus.CARD_MAX_APPS) { + status.num_applications = IccCardStatus.CARD_MAX_APPS; } - } + for (int i = 0 ; i < status.num_applications ; i++) { + ca = new IccCardApplication(); + ca.app_type = ca.AppTypeFromRILInt(p.readInt()); + ca.app_state = ca.AppStateFromRILInt(p.readInt()); + ca.perso_substate = ca.PersoSubstateFromRILInt(p.readInt()); + ca.aid = p.readString(); + ca.app_label = p.readString(); + ca.pin1_replaced = p.readInt(); + ca.pin1 = p.readInt(); + ca.pin2 = p.readInt(); + status.application.add(ca); + } + + // this is common for all radio technologies + if (!status.card_state.isCardPresent()) { + return IccStatus.ICC_ABSENT; + } + + // check radio technology + if( currentRadioState == RadioState.RADIO_OFF || + currentRadioState == RadioState.RADIO_UNAVAILABLE || + currentRadioState == RadioState.SIM_NOT_READY || + currentRadioState == RadioState.RUIM_NOT_READY || + currentRadioState == RadioState.NV_NOT_READY || + currentRadioState == RadioState.NV_READY ) { + return IccStatus.ICC_NOT_READY; + } + + if( currentRadioState == RadioState.SIM_LOCKED_OR_ABSENT || + currentRadioState == RadioState.SIM_READY || + currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT || + currentRadioState == RadioState.RUIM_READY) { + + int index; + + // check for CDMA radio technology + if (currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT || + currentRadioState == RadioState.RUIM_READY) { + index = status.cdma_subscription_app_index; + } + else { + index = status.gsm_umts_subscription_app_index; + } + + // check if PIN required + if (status.application.get(index).app_state.isPinRequired()) { + return IccStatus.ICC_PIN; + } + if (status.application.get(index).app_state.isPukRequired()) { + return IccStatus.ICC_PUK; + } + if (status.application.get(index).app_state.isSubscriptionPersoEnabled()) { + return IccStatus.ICC_NETWORK_PERSONALIZATION; + } + if (status.application.get(index).app_state.isAppReady()) { + return IccStatus.ICC_READY; + } + if (status.application.get(index).app_state.isAppNotReady()) { + return IccStatus.ICC_NOT_READY; + } + return IccStatus.ICC_NOT_READY; + } + + // Unrecognized ICC status. Treat it like a missing ICC. + Log.e(LOG_TAG, "Unrecognized RIL_REQUEST_GET_SIM_STATUS result: " + status); + return IccStatus.ICC_ABSENT; + } private Object - responseCallList(Parcel p) - { + responseCallList(Parcel p) { int num; + int voiceSettings; ArrayList<DriverCall> response; DriverCall dc; @@ -2338,17 +2620,18 @@ public final class RIL extends BaseCommands implements CommandsInterface for (int i = 0 ; i < num ; i++) { dc = new DriverCall(); - + dc.state = DriverCall.stateFromCLCC(p.readInt()); dc.index = p.readInt(); dc.TOA = p.readInt(); dc.isMpty = (0 != p.readInt()); dc.isMT = (0 != p.readInt()); dc.als = p.readInt(); - dc.isVoice = (0 == p.readInt()) ? false : true; + voiceSettings = p.readInt(); + dc.isVoice = (0 == voiceSettings) ? false : true; dc.number = p.readString(); dc.numberPresentation = DriverCall.presentationFromCLIP(p.readInt()); - + // Make sure there's a leading + on addresses with a TOA // of 145 @@ -2356,6 +2639,16 @@ public final class RIL extends BaseCommands implements CommandsInterface dc.number, dc.TOA); response.add(dc); + + if ( RILConstants.CDMA_VOICE_PRIVACY == voiceSettings ) { + mVoicePrivacyOnRegistrants.notifyRegistrants(); + Log.d(LOG_TAG, "InCall VoicePrivacy is enabled: " + + Integer.toString(voiceSettings)); + } else { + mVoicePrivacyOffRegistrants.notifyRegistrants(); + Log.d(LOG_TAG, "InCall VoicePrivacy is disabled: " + + Integer.toString(voiceSettings)); + } } Collections.sort(response); @@ -2364,8 +2657,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } private Object - responseContextList(Parcel p) - { + responseDataCallList(Parcel p) { int num; ArrayList<PDPContextState> response; @@ -2388,14 +2680,13 @@ public final class RIL extends BaseCommands implements CommandsInterface } private Object - responseNetworkInfos(Parcel p) - { + responseNetworkInfos(Parcel p) { String strings[] = (String [])responseStrings(p); ArrayList<NetworkInfo> ret; if (strings.length % 4 != 0) { throw new RuntimeException( - "RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: invalid response. Got " + "RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: invalid response. Got " + strings.length + " strings, expected multible of 4"); } @@ -2409,37 +2700,57 @@ public final class RIL extends BaseCommands implements CommandsInterface strings[i+2], strings[i+3])); } - + return ret; } + private Object + responseCellList(Parcel p) { + int num; + ArrayList<NeighboringCellInfo> response; + NeighboringCellInfo cell; + + num = p.readInt(); + 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) { + } + } + + return response; + } + private Object - responseCellList(Parcel p) - { - int num; - ArrayList<NeighboringCellInfo> response; - NeighboringCellInfo cell; + responseBR_SMS_CNF(Parcel p) { + // TODO + return null; + } - num = p.readInt(); - response = new ArrayList<NeighboringCellInfo>(num); + private Object + responseCDMA_BR_CNF(Parcel p) { + int numInts; + int response[]; - 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) { - } + numInts = p.readInt(); + + response = new int[numInts]; + + response[0] = numInts; + for (int i = 1 ; i < numInts; i++) { + response[i] = p.readInt(); } return response; } - static String - requestToString(int request) - { + requestToString(int request) { /* cat libs/telephony/ril_commands.h \ | egrep "^ *{RIL_" \ @@ -2472,7 +2783,7 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_REQUEST_DTMF: return "DTMF"; case RIL_REQUEST_SEND_SMS: return "SEND_SMS"; case RIL_REQUEST_SEND_SMS_EXPECT_MORE: return "SEND_SMS_EXPECT_MORE"; - case RIL_REQUEST_SETUP_DEFAULT_PDP: return "SETUP_DEFAULT_PDP"; + case RIL_REQUEST_SETUP_DATA_CALL: return "SETUP_DATA_CALL"; case RIL_REQUEST_SIM_IO: return "SIM_IO"; case RIL_REQUEST_SEND_USSD: return "SEND_USSD"; case RIL_REQUEST_CANCEL_USSD: return "CANCEL_USSD"; @@ -2486,7 +2797,7 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_REQUEST_GET_IMEI: return "GET_IMEI"; case RIL_REQUEST_GET_IMEISV: return "GET_IMEISV"; case RIL_REQUEST_ANSWER: return "ANSWER"; - case RIL_REQUEST_DEACTIVATE_DEFAULT_PDP: return "DEACTIVATE_DEFAULT_PDP"; + case RIL_REQUEST_DEACTIVATE_DATA_CALL: return "DEACTIVATE_DATA_CALL"; case RIL_REQUEST_QUERY_FACILITY_LOCK: return "QUERY_FACILITY_LOCK"; case RIL_REQUEST_SET_FACILITY_LOCK: return "SET_FACILITY_LOCK"; case RIL_REQUEST_CHANGE_BARRING_PASSWORD: return "CHANGE_BARRING_PASSWORD"; @@ -2501,8 +2812,8 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_REQUEST_SET_MUTE: return "SET_MUTE"; case RIL_REQUEST_GET_MUTE: return "GET_MUTE"; case RIL_REQUEST_QUERY_CLIP: return "QUERY_CLIP"; - case RIL_REQUEST_LAST_PDP_FAIL_CAUSE: return "LAST_PDP_FAIL_CAUSE"; - case RIL_REQUEST_PDP_CONTEXT_LIST: return "PDP_CONTEXT_LIST"; + case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: return "LAST_DATA_CALL_FAIL_CAUSE"; + case RIL_REQUEST_DATA_CALL_LIST: return "DATA_CALL_LIST"; case RIL_REQUEST_RESET_RADIO: return "RESET_RADIO"; case RIL_REQUEST_OEM_HOOK_RAW: return "OEM_HOOK_RAW"; case RIL_REQUEST_OEM_HOOK_STRINGS: return "OEM_HOOK_STRINGS"; @@ -2522,6 +2833,28 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: return "REQUEST_GET_PREFERRED_NETWORK_TYPE"; case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: return "REQUEST_GET_NEIGHBORING_CELL_IDS"; case RIL_REQUEST_SET_LOCATION_UPDATES: return "REQUEST_SET_LOCATION_UPDATES"; + case RIL_REQUEST_CDMA_SET_SUBSCRIPTION: return "RIL_REQUEST_CDMA_SET_SUBSCRIPTION"; + case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE: return "RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE"; + case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE: return "RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE"; + case RIL_REQUEST_SET_TTY_MODE: return "RIL_REQUEST_SET_TTY_MODE"; + case RIL_REQUEST_QUERY_TTY_MODE: return "RIL_REQUEST_QUERY_TTY_MODE"; + case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE: return "RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE"; + case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE: return "RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE"; + case RIL_REQUEST_CDMA_FLASH: return "RIL_REQUEST_CDMA_FLASH"; + 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_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_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"; + case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: return "RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM"; + case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: return "RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM"; + case RIL_REQUEST_DEVICE_IDENTITY: return "RIL_REQUEST_DEVICE_IDENTITY"; default: return "<unknown request>"; } } @@ -2545,7 +2878,7 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_UNSOL_ON_USSD_REQUEST: return "UNSOL_ON_USSD_REQUEST"; case RIL_UNSOL_NITZ_TIME_RECEIVED: return "UNSOL_NITZ_TIME_RECEIVED"; case RIL_UNSOL_SIGNAL_STRENGTH: return "UNSOL_SIGNAL_STRENGTH"; - case RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED: return "UNSOL_PDP_CONTEXT_LIST_CHANGED"; + case RIL_UNSOL_DATA_CALL_LIST_CHANGED: return "UNSOL_DATA_CALL_LIST_CHANGED"; case RIL_UNSOL_SUPP_SVC_NOTIFICATION: return "UNSOL_SUPP_SVC_NOTIFICATION"; case RIL_UNSOL_STK_SESSION_END: return "UNSOL_STK_SESSION_END"; case RIL_UNSOL_STK_PROACTIVE_COMMAND: return "UNSOL_STK_PROACTIVE_COMMAND"; @@ -2554,7 +2887,7 @@ 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_RESTRICTED_STATE_CHANGED: return "RIL_UNSOL_RESTRICTED_STATE_CHANGED"; default: return "<unknown reponse>"; } } @@ -2583,4 +2916,135 @@ public final class RIL extends BaseCommands implements CommandsInterface riljLogv("[UNSL]< " + responseToString(response) + " " + retToString(response, ret)); } + + // ***** Methods for CDMA support + public void + getDeviceIdentity(Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_DEVICE_IDENTITY, response); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + public void + getCDMASubscription(Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_SUBSCRIPTION, response); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + public void setPhoneType(int phoneType) { //Set by CDMAPhone and GSMPhone constructor + mPhoneType = phoneType; + } + + /** + * {@inheritDoc} + */ + public void queryCdmaRoamingPreference(Message response) { + RILRequest rr = RILRequest.obtain( + RILConstants.RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE, response); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { + RILRequest rr = RILRequest.obtain( + RILConstants.RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE, response); + + rr.mp.writeInt(1); + rr.mp.writeInt(cdmaRoamingType); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " : " + cdmaRoamingType); + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void setCdmaSubscription(int cdmaSubscription , Message response) { + RILRequest rr = RILRequest.obtain( + RILConstants.RIL_REQUEST_CDMA_SET_SUBSCRIPTION, response); + + rr.mp.writeInt(1); + rr.mp.writeInt(cdmaSubscription); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " : " + cdmaSubscription); + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void queryTTYModeEnabled(Message response) { + RILRequest rr = RILRequest.obtain( + RILConstants.RIL_REQUEST_QUERY_TTY_MODE, response); + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void setTTYModeEnabled(boolean enable, Message response) { + RILRequest rr = RILRequest.obtain( + RILConstants.RIL_REQUEST_SET_TTY_MODE, response); + + rr.mp.writeInt(1); + rr.mp.writeInt(enable ? 1 : 0); + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void + 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) + + " : " + FeatureCode); + + send(rr); + } + + public void getCdmaBroadcastConfig(Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG, response); + + send(rr); + } + + public void setCdmaBroadcastConfig(int[] configValuesArray, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG, response); + + for(int i = 0; i < configValuesArray.length; i++) { + rr.mp.writeInt(configValuesArray[i]); + } + + send(rr); + } + + public void activateCdmaBroadcastSms(int activate, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_BROADCAST_ACTIVATION, response); + + rr.mp.writeInt(1); + rr.mp.writeInt(activate); + + send(rr); + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index 4463b20..ba3b754 100644 --- a/telephony/java/com/android/internal/telephony/gsm/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -14,29 +14,62 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * {@hide} */ -interface RILConstants -{ +public interface RILConstants { // From the top of ril.cpp int RIL_ERRNO_INVALID_RESPONSE = -1; // from RIL_Errno int SUCCESS = 0; - int RADIO_NOT_AVAILABLE = 1; /* If radio did not start or is resetting */ + int RADIO_NOT_AVAILABLE = 1; /* If radio did not start or is resetting */ int GENERIC_FAILURE = 2; - int PASSWORD_INCORRECT = 3; /* for PIN/PIN2 methods only! */ - int SIM_PIN2 = 4; /* Operation requires SIM PIN2 to be entered */ - int SIM_PUK2 = 5; /* Operation requires SIM PIN2 to be entered */ + int PASSWORD_INCORRECT = 3; /* for PIN/PIN2 methods only! */ + int SIM_PIN2 = 4; /* Operation requires SIM PIN2 to be entered */ + int SIM_PUK2 = 5; /* Operation requires SIM PIN2 to be entered */ int REQUEST_NOT_SUPPORTED = 6; int REQUEST_CANCELLED = 7; - int OP_NOT_ALLOWED_DURING_VOICE_CALL = 8; /* data operation is not allowed during voice call in class C */ - int OP_NOT_ALLOWED_BEFORE_REG_NW = 9; /* request is not allowed before device registers to network */ - int SMS_SEND_FAIL_RETRY = 10; /* send sms fail and need retry */ + int OP_NOT_ALLOWED_DURING_VOICE_CALL = 8; /* data operation is not allowed during voice call in + class C */ + int OP_NOT_ALLOWED_BEFORE_REG_NW = 9; /* request is not allowed before device registers to + network */ + int SMS_SEND_FAIL_RETRY = 10; /* send sms fail and need retry */ + + /* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */ + int NETWORK_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */ + int NETWORK_MODE_GSM_ONLY = 1; /* GSM only */ + int NETWORK_MODE_WCDMA_ONLY = 2; /* WCDMA only */ + int NETWORK_MODE_GSM_UMTS = 3; /* GSM/WCDMA (auto mode, according to PRL) + AVAILABLE Application Settings menu*/ + int NETWORK_MODE_CDMA = 4; /* CDMA and EvDo (auto mode, according to PRL) + AVAILABLE Application Settings menu*/ + int NETWORK_MODE_CDMA_NO_EVDO = 5; /* CDMA only */ + 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_GLOBAL; + + /* CDMA subscription source. See ril.h RIL_REQUEST_CDMA_SET_SUBSCRIPTION */ + int SUBSCRIPTION_FROM_RUIM = 0; /* CDMA subscription from RUIM when available */ + int SUBSCRIPTION_FROM_NV = 1; /* CDMA subscription from NV */ + int PREFERRED_CDMA_SUBSCRIPTION = SUBSCRIPTION_FROM_NV; + + int CDMA_CELL_BROADCAST_SMS_DISABLED = 1; + int CDMA_CELL_BROADCAST_SMS_ENABLED = 0; + + int CDMA_PHONE = 0; + int GSM_PHONE = 1; + + 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 */ + /* cat include/telephony/ril.h | \ egrep '^#define' | \ @@ -76,7 +109,7 @@ cat include/telephony/ril.h | \ * Block packet data access due to restriction. */ int RIL_RESTRICTED_STATE_PS_ALL = 0x10; - + int RIL_REQUEST_GET_SIM_STATUS = 1; int RIL_REQUEST_ENTER_SIM_PIN = 2; int RIL_REQUEST_ENTER_SIM_PUK = 3; @@ -103,7 +136,7 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_DTMF = 24; int RIL_REQUEST_SEND_SMS = 25; int RIL_REQUEST_SEND_SMS_EXPECT_MORE = 26; - int RIL_REQUEST_SETUP_DEFAULT_PDP = 27; + int RIL_REQUEST_SETUP_DATA_CALL = 27; int RIL_REQUEST_SIM_IO = 28; int RIL_REQUEST_SEND_USSD = 29; int RIL_REQUEST_CANCEL_USSD = 30; @@ -117,7 +150,7 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_GET_IMEI = 38; int RIL_REQUEST_GET_IMEISV = 39; int RIL_REQUEST_ANSWER = 40; - int RIL_REQUEST_DEACTIVATE_DEFAULT_PDP = 41; + int RIL_REQUEST_DEACTIVATE_DATA_CALL = 41; int RIL_REQUEST_QUERY_FACILITY_LOCK = 42; int RIL_REQUEST_SET_FACILITY_LOCK = 43; int RIL_REQUEST_CHANGE_BARRING_PASSWORD = 44; @@ -132,8 +165,8 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_SET_MUTE = 53; int RIL_REQUEST_GET_MUTE = 54; int RIL_REQUEST_QUERY_CLIP = 55; - int RIL_REQUEST_LAST_PDP_FAIL_CAUSE = 56; - int RIL_REQUEST_PDP_CONTEXT_LIST = 57; + int RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE = 56; + int RIL_REQUEST_DATA_CALL_LIST = 57; int RIL_REQUEST_RESET_RADIO = 58; int RIL_REQUEST_OEM_HOOK_RAW = 59; int RIL_REQUEST_OEM_HOOK_STRINGS = 60; @@ -153,6 +186,28 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE = 74; int RIL_REQUEST_GET_NEIGHBORING_CELL_IDS = 75; int RIL_REQUEST_SET_LOCATION_UPDATES = 76; + int RIL_REQUEST_CDMA_SET_SUBSCRIPTION = 77; + int RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE = 78; + int RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE = 79; + int RIL_REQUEST_SET_TTY_MODE = 80; + int RIL_REQUEST_QUERY_TTY_MODE = 81; + int RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE = 82; + int RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE = 83; + int RIL_REQUEST_CDMA_FLASH = 84; + int RIL_REQUEST_CDMA_BURST_DTMF = 85; + 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_CDMA_GET_BROADCAST_CONFIG = 92; + int RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG = 93; + int RIL_REQUEST_CDMA_BROADCAST_ACTIVATION = 94; + int RIL_REQUEST_CDMA_SUBSCRIPTION = 99; + int RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM = 100; + int RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM = 101; + int RIL_REQUEST_DEVICE_IDENTITY = 102; int RIL_UNSOL_RESPONSE_BASE = 1000; int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000; int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001; @@ -164,7 +219,7 @@ cat include/telephony/ril.h | \ int RIL_UNSOL_ON_USSD_REQUEST = 1007; int RIL_UNSOL_NITZ_TIME_RECEIVED = 1008; int RIL_UNSOL_SIGNAL_STRENGTH = 1009; - int RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED = 1010; + int RIL_UNSOL_DATA_CALL_LIST_CHANGED = 1010; int RIL_UNSOL_SUPP_SVC_NOTIFICATION = 1011; int RIL_UNSOL_STK_SESSION_END = 1012; int RIL_UNSOL_STK_PROACTIVE_COMMAND = 1013; @@ -173,5 +228,9 @@ cat include/telephony/ril.h | \ int RIL_UNSOL_SIM_SMS_STORAGE_FULL = 1016; int RIL_UNSOL_SIM_REFRESH = 1017; int RIL_UNSOL_CALL_RING = 1018; + int RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED = 1019; + int RIL_UNSOL_RESPONSE_CDMA_NEW_SMS = 1020; + int RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS = 1021; + int RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL = 1022; int RIL_UNSOL_RESTRICTED_STATE_CHANGED = 1023; } diff --git a/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java index 5585524..f2bd361 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.app.Activity; import android.app.PendingIntent; @@ -32,19 +32,21 @@ 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.Settings; import android.provider.Telephony.Sms.Intents; -import android.telephony.gsm.SmsMessage; -import android.telephony.gsm.SmsManager; -import com.android.internal.telephony.WapPushOverSms; +import android.provider.Settings; +import android.telephony.SmsMessage; import android.telephony.ServiceState; import android.util.Config; -import com.android.internal.util.HexDump; import android.util.Log; import android.view.WindowManager; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.SmsResponse; +import com.android.internal.telephony.WapPushOverSms; +import com.android.internal.util.HexDump; + import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.HashMap; @@ -52,58 +54,61 @@ import java.util.Random; import com.android.internal.R; -final class SMSDispatcher extends Handler { - private static final String TAG = "GSM"; +import static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE; +import static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE; +import static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU; +import static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF; + + +public abstract class SMSDispatcher extends Handler { + private static final String TAG = "SMS"; - /** Default checking period for SMS sent without uesr permit */ + /** Default checking period for SMS sent without user permit */ private static final int DEFAULT_SMS_CHECK_PERIOD = 3600000; - /** Default number of SMS sent in checking period without uesr permit */ + /** Default number of SMS sent in checking period without user permit */ private static final int DEFAULT_SMS_MAX_COUNT = 100; /** Default timeout for SMS sent query */ private static final int DEFAULT_SMS_TIMOUEOUT = 6000; - private static final String[] RAW_PROJECTION = new String[] { + protected static final String[] RAW_PROJECTION = new String[] { "pdu", "sequence", }; static final int MAIL_SEND_SMS = 1; - static final int EVENT_NEW_SMS = 1; + static final protected int EVENT_NEW_SMS = 1; - static final int EVENT_SEND_SMS_COMPLETE = 2; + static final protected int EVENT_SEND_SMS_COMPLETE = 2; /** Retry sending a previously failed SMS message */ - static final int EVENT_SEND_RETRY = 3; + static final protected int EVENT_SEND_RETRY = 3; /** Status report received */ - static final int EVENT_NEW_SMS_STATUS_REPORT = 5; + static final protected int EVENT_NEW_SMS_STATUS_REPORT = 5; - /** SIM storage is full */ - static final int EVENT_SIM_FULL = 6; + /** SIM/RUIM storage is full */ + static final protected int EVENT_ICC_FULL = 6; /** SMS confirm required */ - static final int EVENT_POST_ALERT = 7; + static final protected int EVENT_POST_ALERT = 7; /** Send the user confirmed SMS */ - static final int EVENT_SEND_CONFIRMED_SMS = 8; + static final protected int EVENT_SEND_CONFIRMED_SMS = 8; /** Alert is timeout */ - static final int EVENT_ALERT_TIMEOUT = 9; + static final protected int EVENT_ALERT_TIMEOUT = 9; - private final GSMPhone mPhone; + protected Phone mPhone; + protected Context mContext; + protected ContentResolver mResolver; + protected CommandsInterface mCm; - private final WapPushOverSms mWapPush; + protected final WapPushOverSms mWapPush; - private final Context mContext; - - private final ContentResolver mResolver; - - private final CommandsInterface mCm; - - private final Uri mRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw"); + protected final Uri mRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw"); /** Maximum number of times to retry sending a failed SMS. */ private static final int MAX_SEND_RETRIES = 3; @@ -117,20 +122,15 @@ final class SMSDispatcher extends Handler { * CONCATENATED_16_BIT_REFERENCE message set. Should be * incremented for each set of concatenated messages. */ - private static int sConcatenatedRef; + protected 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; /** * Implement the per-application based SMS control, which only allows @@ -177,6 +177,7 @@ final class SMSDispatcher extends Handler { while (sent.size() > 0 && (ct - sent.get(0)) > mCheckPeriod ) { sent.remove(0); } + if ( (sent.size() + smsWaiting) <= mMaxAllowed) { for (int i = 0; i < smsWaiting; i++ ) { @@ -188,7 +189,7 @@ final class SMSDispatcher extends Handler { } } - SMSDispatcher(GSMPhone phone) { + protected SMSDispatcher(PhoneBase phone) { mPhone = phone; mWapPush = new WapPushOverSms(phone); mContext = phone.getContext(); @@ -196,8 +197,6 @@ final class SMSDispatcher extends Handler { mCm = phone.mCM; mSTracker = null; - createWakelock(); - int check_period = Settings.Gservices.getInt(mResolver, Settings.Gservices.SMS_OUTGOING_CEHCK_INTERVAL_MS, DEFAULT_SMS_CHECK_PERIOD); @@ -208,19 +207,30 @@ final class SMSDispatcher extends Handler { mCm.setOnNewSMS(this, EVENT_NEW_SMS, null); mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null); - mCm.setOnSimSmsFull(this, EVENT_SIM_FULL, null); + mCm.setOnIccSmsFull(this, EVENT_ICC_FULL, null); // Don't always start message ref at 0. sConcatenatedRef = new Random().nextInt(256); } + public void dispose() { + mCm.unSetOnNewSMS(this); + mCm.unSetOnSmsStatus(this); + mCm.unSetOnIccSmsFull(this); + } + + protected void finalize() { + Log.d(TAG, "SMSDispatcher finalized"); + } + + /* TODO: Need to figure out how to keep track of status report routing in a * persistent manner. If the phone process restarts (reboot or crash), * we will lose this list and any status reports that come in after * will be dropped. */ /** Sent messages awaiting a delivery status report. */ - private final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>(); + protected final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>(); /** * Handles events coming from the phone stack. Overridden from handler. @@ -242,11 +252,8 @@ final class SMSDispatcher extends Handler { ar = (AsyncResult) msg.obj; - // FIXME unit test leaves cm == null. this should change - if (mCm != null) { // FIXME only acknowledge on store - mCm.acknowledgeLastIncomingSMS(true, null); - } + acknowledgeLastIncomingSms(true, null); if (ar.exception != null) { Log.e(TAG, "Exception processing incoming SMS. Exception:" + ar.exception); @@ -254,12 +261,12 @@ final class SMSDispatcher extends Handler { } sms = (SmsMessage) ar.result; - dispatchMessage(sms); + dispatchMessage(sms.mWrappedSmsMessage); break; case EVENT_SEND_SMS_COMPLETE: - // An outbound SMS has been sucessfully transferred, or failed. + // An outbound SMS has been successfully transferred, or failed. handleSendComplete((AsyncResult) msg.obj); break; @@ -271,8 +278,8 @@ final class SMSDispatcher extends Handler { handleStatusReport((AsyncResult)msg.obj); break; - case EVENT_SIM_FULL: - handleSimFull(); + case EVENT_ICC_FULL: + handleIccFull(); break; case EVENT_POST_ALERT: @@ -298,27 +305,14 @@ final class SMSDispatcher extends Handler { } } - private void createWakelock() { - PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SMSDispatcher"); - 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); - } - /** * Called when SIM_FULL message is received from the RIL. Notifies interested * parties that SIM storage for SMS messages is full. */ - private void handleSimFull() { + private void handleIccFull(){ // broadcast SIM_FULL intent Intent intent = new Intent(Intents.SIM_FULL_ACTION); - sendBroadcast(intent, "android.permission.RECEIVE_SMS"); + mPhone.getContext().sendBroadcast(intent, "android.permission.RECEIVE_SMS"); } /** @@ -328,34 +322,7 @@ final class SMSDispatcher extends Handler { * @param ar AsyncResult passed into the message handler. ar.result should * be a String representing the status report PDU, as ASCII hex. */ - private void handleStatusReport(AsyncResult ar) { - String pduString = (String) ar.result; - SmsMessage sms = SmsMessage.newFromCDS(pduString); - - if (sms != null) { - int messageRef = sms.messageRef; - for (int i = 0, count = deliveryPendingList.size(); i < count; i++) { - SmsTracker tracker = deliveryPendingList.get(i); - if (tracker.mMessageRef == messageRef) { - // Found it. Remove from list and broadcast. - deliveryPendingList.remove(i); - PendingIntent intent = tracker.mDeliveryIntent; - Intent fillIn = new Intent(); - fillIn.putExtra("pdu", SimUtils.hexStringToBytes(pduString)); - try { - intent.send(mContext, Activity.RESULT_OK, fillIn); - } catch (CanceledException ex) {} - - // Only expect to see one tracker matching this messageref - break; - } - } - } - - if (mCm != null) { - mCm.acknowledgeLastIncomingSMS(true, null); - } - } + protected abstract void handleStatusReport(AsyncResult ar); /** * Called when SMS send completes. Broadcasts a sentIntent on success. @@ -366,7 +333,7 @@ final class SMSDispatcher extends Handler { * an SmsResponse instance if send was successful. ar.userObj * should be an SmsTracker instance. */ - private void handleSendComplete(AsyncResult ar) { + protected void handleSendComplete(AsyncResult ar) { SmsTracker tracker = (SmsTracker) ar.userObj; PendingIntent sentIntent = tracker.mSentIntent; @@ -414,7 +381,7 @@ final class SMSDispatcher extends Handler { } else if (tracker.mSentIntent != null) { // Done retrying; return an error to the app. try { - tracker.mSentIntent.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE); + tracker.mSentIntent.send(RESULT_ERROR_GENERIC_FAILURE); } catch (CanceledException ex) {} } } @@ -429,13 +396,13 @@ final class SMSDispatcher extends Handler { * POWER_OFF * @param tracker An SmsTracker for the current message. */ - private void handleNotInService(int ss, SmsTracker tracker) { + protected void handleNotInService(int ss, SmsTracker tracker) { if (tracker.mSentIntent != null) { try { if (ss == ServiceState.STATE_POWER_OFF) { - tracker.mSentIntent.send(SmsManager.RESULT_ERROR_RADIO_OFF); + tracker.mSentIntent.send(RESULT_ERROR_RADIO_OFF); } else { - tracker.mSentIntent.send(SmsManager.RESULT_ERROR_NO_SERVICE); + tracker.mSentIntent.send(RESULT_ERROR_NO_SERVICE); } } catch (CanceledException ex) {} } @@ -446,130 +413,14 @@ final class SMSDispatcher extends Handler { * * @param sms the incoming message from the phone */ - /* package */ void dispatchMessage(SmsMessage sms) { - - // If sms is null, means there was a parsing error. - // TODO: Should NAK this. - if (sms == null) { - return; - } - - boolean handled = false; - - // Special case the message waiting indicator messages - if (sms.isMWISetMessage()) { - 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()) { - mPhone.updateMessageWaitingIndicator(false); - - if (sms.isMwiDontStore()) { - handled = true; - } + protected abstract void dispatchMessage(SmsMessageBase sms); - if (Config.LOGD) { - Log.d(TAG, - "Received voice mail indicator clear SMS shouldStore=" - + !handled); - } - } - - if (handled) { - return; - } - - // 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 - byte[][] pdus = new byte[1][]; - pdus[0] = sms.getPdu(); - - if (destPort != -1) { - if (destPort == SmsHeader.PORT_WAP_PUSH) { - mWapPush.dispatchWapPdu(sms.getUserData()); - } - // The message was sent to a port, so concoct a URI for it - dispatchPortAddressedPdus(pdus, destPort); - } else { - // It's a normal message, dispatch it - dispatchPdus(pdus); - } - } else { - // Process the message part - processMessagePart(sms, referenceNumber, sequence, count, destPort); - } - } /** * If this is the last part send the parts out to the application, otherwise * the part is stored for later processing. */ - private void processMessagePart(SmsMessage sms, int referenceNumber, + protected void processMessagePart(SmsMessageBase sms, int referenceNumber, int sequence, int count, int destinationPort) { // Lookup all other related parts StringBuilder where = new StringBuilder("reference_number ="); @@ -655,10 +506,11 @@ final class SMSDispatcher extends Handler { * * @param pdus The raw PDUs making up the message */ - private void dispatchPdus(byte[][] pdus) { + protected void dispatchPdus(byte[][] pdus) { Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION); intent.putExtra("pdus", pdus); - sendBroadcast(intent, "android.permission.RECEIVE_SMS"); + mPhone.getContext().sendBroadcast( + intent, "android.permission.RECEIVE_SMS"); } /** @@ -667,11 +519,12 @@ final class SMSDispatcher extends Handler { * @param pdus The raw PDUs making up the message * @param port The destination port of the messages */ - private void dispatchPortAddressedPdus(byte[][] pdus, int port) { + protected void dispatchPortAddressedPdus(byte[][] pdus, int port) { Uri uri = Uri.parse("sms://localhost:" + port); Intent intent = new Intent(Intents.DATA_SMS_RECEIVED_ACTION, uri); intent.putExtra("pdus", pdus); - sendBroadcast(intent, "android.permission.RECEIVE_SMS"); + mPhone.getContext().sendBroadcast( + intent, "android.permission.RECEIVE_SMS"); } @@ -700,114 +553,9 @@ final class SMSDispatcher extends Handler { * to the recipient. The raw pdu of the status report is in the * extended data ("pdu"). */ - void sendMultipartText(String destinationAddress, String scAddress, ArrayList<String> parts, - ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { - - PendingIntent sentIntent = null; - - - int ss = mPhone.getServiceState().getState(); - - if (ss == ServiceState.STATE_IN_SERVICE) { - // Only check SMS sending limit while in service - if (sentIntents != null && sentIntents.size() > 0) { - sentIntent = sentIntents.get(0); - } - String appName = getAppNameByIntent(sentIntent); - if ( !mCounter.check(appName, parts.size())) { - HashMap<String, Object> map = new HashMap<String, Object>(); - map.put("destination", destinationAddress); - map.put("scaddress", scAddress); - map.put("parts", parts); - map.put("sentIntents", sentIntents); - map.put("deliveryIntents", deliveryIntents); - - SmsTracker multipartParameter = new SmsTracker(map, null, null); - - sendMessage(obtainMessage(EVENT_POST_ALERT, multipartParameter)); - return; - } - } - - sendMultipartTextWithPermit(destinationAddress, - scAddress, parts, sentIntents, deliveryIntents); - } - - /** - * 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 - * @param parts an <code>ArrayList</code> of strings that, in order, - * comprise the original message - * @param sentIntents if not null, an <code>ArrayList</code> of - * <code>PendingIntent</code>s (one for each message part) that is - * broadcast when the corresponding message part has been sent. - * The result code will be <code>Activity.RESULT_OK<code> for success, - * or one of these errors: - * <code>RESULT_ERROR_GENERIC_FAILURE</code> - * <code>RESULT_ERROR_RADIO_OFF</code> - * <code>RESULT_ERROR_NULL_PDU</code>. - * @param deliveryIntents if not null, an <code>ArrayList</code> of - * <code>PendingIntent</code>s (one for each message part) that is - * broadcast when the corresponding message part has been delivered - * to the recipient. The raw pdu of the status report is in the - * extended data ("pdu"). - */ - private void sendMultipartTextWithPermit(String destinationAddress, - String scAddress, ArrayList<String> parts, - 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++) { - if (sentIntents != null && sentIntents.size() > i) { - sentIntent = sentIntents.get(i); - } - SmsTracker tracker = new SmsTracker(null, sentIntent, null); - handleNotInService(ss, tracker); - } - 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)); - - if (sentIntents != null && sentIntents.size() > i) { - sentIntent = sentIntents.get(i); - } - if (deliveryIntents != null && deliveryIntents.size() > i) { - deliveryIntent = deliveryIntents.get(i); - } - - SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, - parts.get(i), deliveryIntent != null, header.toByteArray()); - - HashMap<String, Object> map = new HashMap<String, Object>(); - map.put("smsc", pdus.encodedScAddress); - map.put("pdu", pdus.encodedMessage); - - SmsTracker tracker = new SmsTracker(map, sentIntent, - deliveryIntent); - sendSms(tracker); - } - } + protected abstract void sendMultipartText(String destinationAddress, String scAddress, + ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, + ArrayList<PendingIntent> deliveryIntents); /** * Send a SMS @@ -829,12 +577,12 @@ final class SMSDispatcher extends Handler { * broadcast when the message is delivered to the recipient. The * raw pdu of the status report is in the extended data ("pdu"). */ - void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, + protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, PendingIntent deliveryIntent) { if (pdu == null) { if (sentIntent != null) { try { - sentIntent.send(SmsManager.RESULT_ERROR_NULL_PDU); + sentIntent.send(RESULT_ERROR_NULL_PDU); } catch (CanceledException ex) {} } return; @@ -865,7 +613,7 @@ final class SMSDispatcher extends Handler { * * An SmsTracker for the current message. */ - private void handleReachSentLimit(SmsTracker tracker) { + protected void handleReachSentLimit(SmsTracker tracker) { Resources r = Resources.getSystem(); @@ -886,7 +634,7 @@ final class SMSDispatcher extends Handler { DEFAULT_SMS_TIMOUEOUT); } - private String getAppNameByIntent(PendingIntent intent) { + protected String getAppNameByIntent(PendingIntent intent) { Resources r = Resources.getSystem(); return (intent != null) ? intent.getTargetPackage() : r.getString(R.string.sms_control_default_app_name); @@ -897,41 +645,53 @@ final class SMSDispatcher extends Handler { * * @param tracker holds the SMS message to send */ - private void sendSms(SmsTracker tracker) { - HashMap map = tracker.mData; - - byte smsc[] = (byte[]) map.get("smsc"); - byte pdu[] = (byte[]) map.get("pdu"); - - Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); - mCm.sendSMS(SimUtils.bytesToHexString(smsc), - SimUtils.bytesToHexString(pdu), reply); - } + protected abstract void sendSms(SmsTracker tracker); /** * Send the multi-part SMS based on multipart Sms tracker * * @param tracker holds the multipart Sms tracker ready to be sent */ - private 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, - scAddress, parts, sentIntents, deliveryIntents); + protected abstract void sendMultipartSms (SmsTracker tracker); + + /** + * Activate or deactivate cell broadcast SMS. + * + * @param activate + * 0 = activate, 1 = deactivate + * @param response + * Callback message is empty on completion + */ + protected abstract void activateCellBroadcastSms(int activate, Message response); + + /** + * Query the current configuration of cell broadcast SMS. + * + * @param response + * Callback message contains the configuration from the modem on completion + * @see #setCellBroadcastConfig + */ + protected abstract void getCellBroadcastSmsConfig(Message response); + + /** + * Configure cell broadcast SMS. + * + * @param configValuesArray + * The first element defines the number of triples that follow. + * A triple is made up of the service category, the language identifier + * and a boolean that specifies whether the category is set active. + * @param response + * Callback message is empty on completion + */ + protected abstract void setCellBroadcastConfig(int[] configValuesArray, Message response); + + /** + * Send an acknowledge message. + * @param success indicates that last message was successfully received. + * @param response callback message sent when operation completes. + */ + protected abstract void acknowledgeLastIncomingSms(boolean success, Message response); - } - /** * Check if a SmsTracker holds multi-part Sms * @@ -942,19 +702,20 @@ final class SMSDispatcher extends Handler { HashMap map = tracker.mData; return ( map.get("parts") != null); } - + /** * Keeps track of an SMS that has been sent to the RIL, until it it has * successfully been sent, or we're done trying. * */ - static class SmsTracker { - HashMap mData; - int mRetryCount; - int mMessageRef; + static protected class SmsTracker { + // fields need to be public for derived SmsDispatchers + public HashMap mData; + public int mRetryCount; + public int mMessageRef; - PendingIntent mSentIntent; - PendingIntent mDeliveryIntent; + public PendingIntent mSentIntent; + public PendingIntent mDeliveryIntent; SmsTracker(HashMap data, PendingIntent sentIntent, PendingIntent deliveryIntent) { @@ -963,17 +724,21 @@ final class SMSDispatcher extends Handler { mDeliveryIntent = deliveryIntent; mRetryCount = 0; } - + } + + protected SmsTracker SmsTrackerFactory(HashMap data, PendingIntent sentIntent, + PendingIntent deliveryIntent) { + return new SmsTracker(data, sentIntent, deliveryIntent); } private DialogInterface.OnClickListener mListener = - new DialogInterface.OnClickListener() { + new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - if (which == DialogInterface.BUTTON_POSITIVE) { - Log.d(TAG, "click YES to send out sms"); - sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS)); - } + public void onClick(DialogInterface dialog, int which) { + if (which == DialogInterface.BUTTON_POSITIVE) { + Log.d(TAG, "click YES to send out sms"); + sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS)); } - }; + } + }; } diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java new file mode 100644 index 0000000..a4bf0dd --- /dev/null +++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.Registrant; +import android.os.RegistrantList; +import android.telephony.ServiceState; + +/** + * {@hide} + */ +public abstract class ServiceStateTracker extends Handler { + /** + * The access technology currently in use: + * 0 = unknown + * 1 = GPRS only + * 2 = EDGE + * 3 = UMTS + */ + protected static final int DATA_ACCESS_UNKNOWN = 0; + protected static final int DATA_ACCESS_GPRS = 1; + protected static final int DATA_ACCESS_EDGE = 2; + protected static final int DATA_ACCESS_UMTS = 3; + protected static final int DATA_ACCESS_CDMA_IS95A = 4; + protected static final int DATA_ACCESS_CDMA_IS95B = 5; + protected static final int DATA_ACCESS_CDMA_1xRTT = 6; + protected static final int DATA_ACCESS_CDMA_EvDo_0 = 7; + protected static final int DATA_ACCESS_CDMA_EvDo_A = 8; + //***** Instance Variables + + protected CommandsInterface cm; + + public ServiceState ss; + protected ServiceState newSS; + + // 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 + protected int[] pollingContext; + protected boolean mDesiredPowerState; + + protected boolean dontPollSignalStrength = false; // Default is to poll strength + // If we're getting unsolicited signal strength updates from the radio, + // set value to true and don't bother polling any more + + protected RegistrantList networkAttachedRegistrants = new RegistrantList(); + protected RegistrantList roamingOnRegistrants = new RegistrantList(); + protected RegistrantList roamingOffRegistrants = new RegistrantList(); + + //***** Constants + + protected static final boolean DBG = true; + + // signal strength poll rate + protected static final int POLL_PERIOD_MILLIS = 20 * 1000; + + // waiting period before recheck gprs and voice registration + public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000; + + public static final int MAX_NUM_DATA_STATE_READS = 15; + public static final int DATA_STATE_POLL_SLEEP_MS = 100; + + //*****GSM events + protected static final int EVENT_RADIO_STATE_CHANGED = 1; + protected static final int EVENT_NETWORK_STATE_CHANGED = 2; + protected static final int EVENT_GET_SIGNAL_STRENGTH = 3; + protected static final int EVENT_POLL_STATE_REGISTRATION = 4; + protected static final int EVENT_POLL_STATE_GPRS = 5; + protected static final int EVENT_POLL_STATE_OPERATOR = 6; + protected static final int EVENT_POLL_SIGNAL_STRENGTH = 10; + protected static final int EVENT_NITZ_TIME = 11; + protected static final int EVENT_SIGNAL_STRENGTH_UPDATE = 12; + protected static final int EVENT_RADIO_AVAILABLE = 13; + protected static final int EVENT_POLL_STATE_NETWORK_SELECTION_MODE = 14; + protected static final int EVENT_GET_LOC_DONE = 15; + protected static final int EVENT_SIM_RECORDS_LOADED = 16; + protected static final int EVENT_SIM_READY = 17; + protected static final int EVENT_LOCATION_UPDATES_ENABLED = 18; + protected static final int EVENT_GET_PREFERRED_NETWORK_TYPE = 19; + protected static final int EVENT_SET_PREFERRED_NETWORK_TYPE = 20; + protected static final int EVENT_RESET_PREFERRED_NETWORK_TYPE = 21; + protected static final int EVENT_CHECK_REPORT_GPRS = 22; + protected static final int EVENT_RESTRICTED_STATE_CHANGED = 23; + + //*****CDMA events: + protected static final int EVENT_POLL_STATE_REGISTRATION_CDMA = 24; + 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; + + // Event Log Tags + protected static final int EVENT_LOG_CGREG_FAIL = 50107; + protected static final int EVENT_DATA_STATE_RADIO_OFF = 50108; + + //***** Time Zones + protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; + + // List of ISO codes for countries that can have an offset of GMT+0 + // when not in daylight savings time. This ignores some small places + // such as the Canary Islands (Spain) and Danmarkshavn (Denmark). + // The list must be sorted by code. + protected static final String[] GMT_COUNTRY_CODES = { + "bf", // Burkina Faso + "ci", // Cote d'Ivoire + "eh", // Western Sahara + "fo", // Faroe Islands, Denmark + "gh", // Ghana + "gm", // Gambia + "gn", // Guinea + "gw", // Guinea Bissau + "ie", // Ireland + "lr", // Liberia + "is", // Iceland + "ma", // Morocco + "ml", // Mali + "mr", // Mauritania + "pt", // Portugal + "sl", // Sierra Leone + "sn", // Senegal + "st", // Sao Tome and Principe + "tg", // Togo + "uk", // U.K + }; + + + //***** Constructors + public ServiceStateTracker() { + + } + + + /** + * Registration point for combined roaming on + * combined roaming is true when roaming is true and ONS differs SPN + * + * @param h handler to notify + * @param what what code of message when delivered + * @param obj placed in Message.obj + */ + public void registerForRoamingOn(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + roamingOnRegistrants.add(r); + + if (ss.getRoaming()) { + r.notifyRegistrant(); + } + } + + public void unregisterForRoamingOn(Handler h) { + roamingOnRegistrants.remove(h); + } + + /** + * Registration point for combined roaming off + * combined roaming is true when roaming is true and ONS differs SPN + * + * @param h handler to notify + * @param what what code of message when delivered + * @param obj placed in Message.obj + */ + public void registerForRoamingOff(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + roamingOffRegistrants.add(r); + + if (!ss.getRoaming()) { + r.notifyRegistrant(); + } + } + + public void unregisterForRoamingOff(Handler h) { + roamingOffRegistrants.remove(h); + } + + /** + * Reregister network through toggle perferred network type + * This is a work aorund to deregister and register network since there is + * no ril api to set COPS=2 (deregister) only. + * + * @param onComplete is dispatched when this is complete. it will be + * an AsyncResult, and onComplete.obj.exception will be non-null + * on failure. + */ + public void reRegisterNetwork(Message onComplete) { + cm.getPreferredNetworkType( + obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE, onComplete)); + } + + + //***** Called from Phone + public void + setRadioPower(boolean power) { + mDesiredPowerState = power; + + setPowerStateToDesired(); + } + + + public void enableLocationUpdates() { + cm.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED)); + } + + public void disableLocationUpdates() { + cm.setLocationUpdates(false, null); + } + + //***** Overridden from Handler + public abstract void handleMessage(Message msg); + + //***** Protected abstract Methods + protected abstract void handlePollStateResult(int what, AsyncResult ar); + protected abstract void updateSpnDisplay(); + protected abstract void setPowerStateToDesired(); + + /** Cancel a pending (if any) pollState() operation */ + protected void cancelPollState() { + // This will effectively cancel the rest of the poll requests + pollingContext = new int[1]; + } +} + diff --git a/telephony/java/com/android/internal/telephony/SmsAddress.java b/telephony/java/com/android/internal/telephony/SmsAddress.java new file mode 100644 index 0000000..b3892cb --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SmsAddress.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +public abstract class SmsAddress { + // From TS 23.040 9.1.2.5 and TS 24.008 table 10.5.118 + // and C.S0005-D table 2.7.1.3.2.4-2 + public static final int TON_UNKNOWN = 0; + public static final int TON_INTERNATIONAL = 1; + public static final int TON_NATIONAL = 2; + public static final int TON_NETWORK = 3; + public static final int TON_SUBSCRIBER = 4; + public static final int TON_ALPHANUMERIC = 5; + public static final int TON_ABBREVIATED = 6; + + public int ton; + public String address; + public byte[] origBytes; + + /** + * Returns the address of the SMS message in String form or null if unavailable + */ + public String getAddressString() { + return address; + } + + /** + * Returns true if this is an alphanumeric address + */ + public boolean isAlphanumeric() { + return ton == TON_ALPHANUMERIC; + } + + /** + * Returns true if this is a network address + */ + public boolean isNetworkSpecific() { + return ton == TON_NETWORK; + } + + public boolean couldBeEmailGateway() { + // Some carriers seems to send email gateway messages in this form: + // from: an UNKNOWN TON, 3 or 4 digits long, beginning with a 5 + // PID: 0x00, Data coding scheme 0x03 + // So we just attempt to treat any message from an address length <= 4 + // as an email gateway + + return address.length() <= 4; + } + +} diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsHeader.java b/telephony/java/com/android/internal/telephony/SmsHeader.java index 22366ec..64b884e 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsHeader.java +++ b/telephony/java/com/android/internal/telephony/SmsHeader.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import com.android.internal.util.HexDump; @@ -24,8 +24,7 @@ import java.util.ArrayList; * This class represents a SMS user data header. * */ -public class SmsHeader -{ +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. */ @@ -42,6 +41,7 @@ public class SmsHeader 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. @@ -49,36 +49,33 @@ public class SmsHeader * @param data is user data header bytes * @return an SmsHeader object */ - public static SmsHeader parse(byte[] data) - { + public static SmsHeader parse(byte[] data) { SmsHeader header = new SmsHeader(); header.m_data = data; int index = 0; - while (index < data.length) - { + 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++; } return header; } - public SmsHeader() - { - } + public SmsHeader() { } /** * Returns the list of SmsHeader Elements that make up the header. * * @return the list of SmsHeader Elements. */ - public ArrayList<Element> getElements() - { + public ArrayList<Element> getElements() { return m_elements; } @@ -87,14 +84,12 @@ public class SmsHeader * * @param element to add. */ - public void add(Element element) - { + public void add(Element element) { m_elements.add(element); } @Override - public String toString() - { + public String toString() { StringBuilder builder = new StringBuilder(); builder.append("UDH LENGTH: " + m_data.length + " octets"); @@ -104,40 +99,56 @@ public class SmsHeader for (Element e : getElements()) { builder.append(" 0x" + HexDump.toHexString((byte)e.getID()) + " - "); - switch (e.getID()) - { - case CONCATENATED_8_BIT_REFERENCE: - { + 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(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: - { + 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(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_16_BIT: + 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"); + builder.append(HexDump.toHexString((byte)data.length) + + ") Bytes - Information Element\n"); int source = (data[0] & 0xff) << 8; source |= (data[1] & 0xff); @@ -149,8 +160,7 @@ public class SmsHeader break; } - default: - { + default: { builder.append("Unknown element\n"); break; } @@ -202,13 +212,11 @@ public class SmsHeader * See TS 23.040 9.2.3.24. * */ - public static class Element - { + public static class Element { private byte[] m_data; private int m_id; - public Element(int id, byte[] data) - { + public Element(int id, byte[] data) { m_id = id; m_data = data; } @@ -218,8 +226,7 @@ public class SmsHeader * * @return the IE identifier. */ - public int getID() - { + public int getID() { return m_id; } @@ -228,8 +235,7 @@ public class SmsHeader * * @return element data. */ - public byte[] getData() - { + public byte[] getData() { return m_data; } } diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java new file mode 100644 index 0000000..7c32451 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.util.Log; +import com.android.internal.telephony.SmsHeader; +import java.util.Arrays; + +import static android.telephony.SmsMessage.ENCODING_7BIT; +import static android.telephony.SmsMessage.ENCODING_16BIT; +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; +import static android.telephony.SmsMessage.MessageClass; +import static com.android.internal.telephony.SmsAddress.TON_ABBREVIATED; +import static com.android.internal.telephony.SmsAddress.TON_ALPHANUMERIC; +import static com.android.internal.telephony.SmsAddress.TON_INTERNATIONAL; +import static com.android.internal.telephony.SmsAddress.TON_NATIONAL; +import static com.android.internal.telephony.SmsAddress.TON_NETWORK; +import static com.android.internal.telephony.SmsAddress.TON_SUBSCRIBER; +import static com.android.internal.telephony.SmsAddress.TON_UNKNOWN; + +/** + * Base class declaring the specific methods and members for SmsMessage. + * {@hide} + */ +public abstract class SmsMessageBase { + private static final String LOG_TAG = "SMS"; + + /** {@hide} The address of the SMSC. May be null */ + protected String scAddress; + + /** {@hide} The address of the sender */ + protected SmsAddress originatingAddress; + + /** {@hide} The message body as a string. May be null if the message isn't text */ + protected String messageBody; + + /** {@hide} */ + protected String pseudoSubject; + + /** {@hide} Non-null if this is an email gateway message */ + protected String emailFrom; + + /** {@hide} Non-null if this is an email gateway message */ + protected String emailBody; + + /** {@hide} */ + protected boolean isEmail; + + /** {@hide} */ + protected long scTimeMillis; + + /** {@hide} The raw PDU of the message */ + protected byte[] mPdu; + + /** {@hide} The raw bytes for the user data section of the message */ + protected byte[] userData; + + /** {@hide} */ + protected SmsHeader userDataHeader; + + // "Message Waiting Indication Group" + // 23.038 Section 4 + /** {@hide} */ + protected boolean isMwi; + + /** {@hide} */ + protected boolean mwiSense; + + /** {@hide} */ + protected boolean mwiDontStore; + + /** + * Indicates status for messages stored on the ICC. + */ + protected int statusOnIcc = -1; + + /** + * Record index of message in the EF. + */ + protected int indexOnIcc = -1; + + /** TP-Message-Reference - Message Reference of sent message. @hide */ + public int messageRef; + + public static abstract class SubmitPduBase { + public byte[] encodedScAddress; // Null if not applicable. + public byte[] encodedMessage; + + public String toString() { + return "SubmitPdu: encodedScAddress = " + + Arrays.toString(encodedScAddress) + + ", encodedMessage = " + + Arrays.toString(encodedMessage); + } + } + + /** + * Returns the address of the SMS service center that relayed this message + * or null if there is none. + */ + public String getServiceCenterAddress() { + return scAddress; + } + + /** + * Returns the originating address (sender) of this SMS message in String + * form or null if unavailable + */ + public String getOriginatingAddress() { + if (originatingAddress == null) { + return null; + } + + return originatingAddress.getAddressString(); + } + + /** + * Returns the originating address, or email from address if this message + * was from an email gateway. Returns null if originating address + * unavailable. + */ + public String getDisplayOriginatingAddress() { + if (isEmail) { + return emailFrom; + } else { + return getOriginatingAddress(); + } + } + + /** + * Returns the message body as a String, if it exists and is text based. + * @return message body is there is one, otherwise null + */ + public String getMessageBody() { + return messageBody; + } + + /** + * Returns the class of this message. + */ + public abstract MessageClass getMessageClass(); + + /** + * Returns the message body, or email message body if this message was from + * an email gateway. Returns null if message body unavailable. + */ + public String getDisplayMessageBody() { + if (isEmail) { + return emailBody; + } else { + return getMessageBody(); + } + } + + /** + * Unofficial convention of a subject line enclosed in parens empty string + * if not present + */ + public String getPseudoSubject() { + return pseudoSubject == null ? "" : pseudoSubject; + } + + /** + * Returns the service centre timestamp in currentTimeMillis() format + */ + public long getTimestampMillis() { + return scTimeMillis; + } + + /** + * Returns true if message is an email. + * + * @return true if this message came through an email gateway and email + * sender / subject / parsed body are available + */ + public boolean isEmail() { + return isEmail; + } + + /** + * @return if isEmail() is true, body of the email sent through the gateway. + * null otherwise + */ + public String getEmailBody() { + return emailBody; + } + + /** + * @return if isEmail() is true, email from address of email sent through + * the gateway. null otherwise + */ + public String getEmailFrom() { + return emailFrom; + } + + /** + * Get protocol identifier. + */ + public abstract int getProtocolIdentifier(); + + /** + * See TS 23.040 9.2.3.9 returns true if this is a "replace short message" + * SMS + */ + public abstract boolean isReplace(); + + /** + * Returns true for CPHS MWI toggle message. + * + * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section + * B.4.2 + */ + public abstract boolean isCphsMwiMessage(); + + /** + * returns true if this message is a CPHS voicemail / message waiting + * indicator (MWI) clear message + */ + public abstract boolean isMWIClearMessage(); + + /** + * returns true if this message is a CPHS voicemail / message waiting + * indicator (MWI) set message + */ + public abstract boolean isMWISetMessage(); + + /** + * returns true if this message is a "Message Waiting Indication Group: + * Discard Message" notification and should not be stored. + */ + public abstract boolean isMwiDontStore(); + + /** + * returns the user data section minus the user data header if one was + * present. + */ + public byte[] getUserData() { + return userData; + } + + /** + * Returns an object representing the user data header + * + * @return an object representing the user data header + * + * {@hide} + */ + public SmsHeader getUserDataHeader() { + return userDataHeader; + } + + /** + * Returns the raw PDU for the message. + * + * @return the raw PDU for the message. + */ + public byte[] getPdu() { + return mPdu; + } + + /** + * For an SMS-STATUS-REPORT message, this returns the status field from + * the status report. This field indicates the status of a previously + * submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a + * description of values. + * + * @return 0 indicates the previously sent message was received. + * See TS 23.040, 9.9.2.3.15 for a description of other possible + * values. + */ + public abstract int getStatus(); + + /** + * Return true iff the message is a SMS-STATUS-REPORT message. + */ + public abstract boolean isStatusReportMessage(); + + /** + * Returns true iff the <code>TP-Reply-Path</code> bit is set in + * this message. + */ + public abstract boolean isReplyPathPresent(); + + /** + * Returns the status of the message on the ICC (read, unread, sent, unsent). + * + * @return the status of the message on the ICC. These are: + * SmsManager.STATUS_ON_ICC_FREE + * SmsManager.STATUS_ON_ICC_READ + * SmsManager.STATUS_ON_ICC_UNREAD + * SmsManager.STATUS_ON_ICC_SEND + * SmsManager.STATUS_ON_ICC_UNSENT + */ + public int getStatusOnIcc() { + return statusOnIcc; + } + + /** + * Returns the record index of the message on the ICC (1-based index). + * @return the record index of the message on the ICC, or -1 if this + * SmsMessage was not created from a ICC SMS EF record. + */ + public int getIndexOnIcc() { + return indexOnIcc; + } + + protected void parseMessageBody() { + if (originatingAddress.couldBeEmailGateway()) { + extractEmailAddressFromMessageBody(); + } + } + + /** + * Try to parse this message as an email gateway message -> Neither + * of the standard ways are currently supported: There are two ways + * specified in TS 23.040 Section 3.8 (not supported via this mechanism) - + * SMS message "may have its TP-PID set for internet electronic mail - MT + * SMS format: [<from-address><space>]<message> - "Depending on the + * nature of the gateway, the destination/origination address is either + * derived from the content of the SMS TP-OA or TP-DA field, or the + * TP-OA/TP-DA field contains a generic gateway address and the to/from + * address is added at the beginning as shown above." - multiple addreses + * separated by commas, no spaces - subject field delimited by '()' or '##' + * and '#' Section 9.2.3.24.11 + */ + protected void extractEmailAddressFromMessageBody() { + + /* + * a little guesswork here. I haven't found doc for this. + * the format could be either + * + * 1. [x@y][ ]/[subject][ ]/[body] + * -or- + * 2. [x@y][ ]/[body] + */ + int slash = 0, slash2 = 0, atSymbol = 0; + + try { + slash = messageBody.indexOf(" /"); + if (slash == -1) { + return; + } + + atSymbol = messageBody.indexOf('@'); + if (atSymbol == -1 || atSymbol > slash) { + return; + } + + emailFrom = messageBody.substring(0, slash); + + slash2 = messageBody.indexOf(" /", slash + 2); + + if (slash2 == -1) { + pseudoSubject = null; + emailBody = messageBody.substring(slash + 2); + } else { + pseudoSubject = messageBody.substring(slash + 2, slash2); + emailBody = messageBody.substring(slash2 + 2); + } + + isEmail = true; + } catch (Exception ex) { + Log.w(LOG_TAG, + "extractEmailAddressFromMessageBody: exception slash=" + + slash + ", atSymbol=" + atSymbol + ", slash2=" + + slash2, ex); + } + } + +} + diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsRawData.aidl b/telephony/java/com/android/internal/telephony/SmsRawData.aidl index 6f1a46d..b0b3e4f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsRawData.aidl +++ b/telephony/java/com/android/internal/telephony/SmsRawData.aidl @@ -14,6 +14,6 @@ ** limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; parcelable SmsRawData; diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsRawData.java b/telephony/java/com/android/internal/telephony/SmsRawData.java index a029d5c..891d942 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsRawData.java +++ b/telephony/java/com/android/internal/telephony/SmsRawData.java @@ -15,10 +15,10 @@ */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; /** * A parcelable holder class of byte[] for ISms aidl implementation @@ -50,7 +50,7 @@ public class SmsRawData implements Parcelable { public byte[] getBytes() { return data; } - + public int describeContents() { return 0; } diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsResponse.java b/telephony/java/com/android/internal/telephony/SmsResponse.java index c005b5f..3c4df56 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsResponse.java +++ b/telephony/java/com/android/internal/telephony/SmsResponse.java @@ -14,20 +14,20 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * Object returned by the RIL upon successful completion of sendSMS. * Contains message reference and ackPdu. * */ -class SmsResponse { +public class SmsResponse { /** Message reference of the just-sent SMS. */ int messageRef; /** ackPdu for the just-sent SMS. */ String ackPdu; - SmsResponse(int messageRef, String ackPdu) { + public SmsResponse(int messageRef, String ackPdu) { this.messageRef = messageRef; this.ackPdu = ackPdu; } diff --git a/telephony/java/com/android/internal/telephony/gsm/TelephonyEventLog.java b/telephony/java/com/android/internal/telephony/TelephonyEventLog.java index 1e583f0..1ef3c6c 100644 --- a/telephony/java/com/android/internal/telephony/gsm/TelephonyEventLog.java +++ b/telephony/java/com/android/internal/telephony/TelephonyEventLog.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /* This class contains the details related to Telephony Event Logging */ public final class TelephonyEventLog { diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index 9219e7a..c342233 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -35,6 +35,24 @@ public class TelephonyIntents { */ public static final String ACTION_SERVICE_STATE_CHANGED = "android.intent.action.SERVICE_STATE"; + /** + * <p>Broadcast Action: The radio technology has changed. The intent will have the following + * extra values:</p> + * <ul> + * <li><em>phoneName</em> - A string version of the new phone name.</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_RADIO_TECHNOLOGY_CHANGED + = "android.intent.action.RADIO_TECHNOLOGY"; /** * Broadcast Action: The phone's signal strength has changed. The intent will have the @@ -47,7 +65,7 @@ public class TelephonyIntents { * <ul><li>0 means "-113 dBm or less".</li><li>31 means "-51 dBm or greater".</li></ul> * </li> * </ul> - * + * * <p class="note"> * You can <em>not</em> receive this through components declared * in manifests, only by exlicitly registering for it with diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java index 6aa90f1..396b42d 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java +++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java @@ -26,8 +26,11 @@ public interface TelephonyProperties { //****** Baseband and Radio Interface version - /** - * Baseband version + //TODO T: property strings do not have to be gsm specific + // change gsm.*operator.*" properties to "operator.*" properties + + /** + * Baseband version * Availability: property is available any time radio is on */ static final String PROPERTY_BASEBAND_VERSION = "gsm.version.baseband"; @@ -47,6 +50,12 @@ public interface TelephonyProperties */ static final String PROPERTY_OPERATOR_NUMERIC = "gsm.operator.numeric"; + /** 'true' if the device is on a manually selected network + * + * Availability: when registered to a network + */ + static final String PROPERTY_OPERATOR_ISMANUAL = "operator.ismanual"; + /** 'true' if the device is considered roaming on this network for GSM * purposes. * Availability: when registered to a network @@ -60,7 +69,7 @@ public interface TelephonyProperties static final String PROPERTY_OPERATOR_ISO_COUNTRY = "gsm.operator.iso-country"; //****** SIM Card - /** + /** * One of <code>"UNKNOWN"</code> <code>"ABSENT"</code> <code>"PIN_REQUIRED"</code> * <code>"PUK_REQUIRED"</code> <code>"NETWORK_LOCKED"</code> or <code>"READY"</code> */ @@ -70,15 +79,15 @@ public interface TelephonyProperties * provider of the SIM. 5 or 6 decimal digits. * Availablity: SIM state must be "READY" */ - static String PROPERTY_SIM_OPERATOR_NUMERIC = "gsm.sim.operator.numeric"; + static String PROPERTY_ICC_OPERATOR_NUMERIC = "gsm.sim.operator.numeric"; - /** PROPERTY_SIM_OPERATOR_ALPHA is also known as the SPN, or Service Provider Name. + /** PROPERTY_ICC_OPERATOR_ALPHA is also known as the SPN, or Service Provider Name. * Availablity: SIM state must be "READY" */ - static String PROPERTY_SIM_OPERATOR_ALPHA = "gsm.sim.operator.alpha"; + static String PROPERTY_ICC_OPERATOR_ALPHA = "gsm.sim.operator.alpha"; /** ISO country code equivalent for the SIM provider's country code*/ - static String PROPERTY_SIM_OPERATOR_ISO_COUNTRY = "gsm.sim.operator.iso-country"; + static String PROPERTY_ICC_OPERATOR_ISO_COUNTRY = "gsm.sim.operator.iso-country"; /** * Indicates the available radio technology. Values include: <code>"unknown"</code>, diff --git a/telephony/java/com/android/internal/telephony/WapPushOverSms.java b/telephony/java/com/android/internal/telephony/WapPushOverSms.java index 2b70162..98899c9 100644 --- a/telephony/java/com/android/internal/telephony/WapPushOverSms.java +++ b/telephony/java/com/android/internal/telephony/WapPushOverSms.java @@ -22,7 +22,6 @@ import android.os.PowerManager; import android.provider.Telephony.Sms.Intents; import android.util.Config; import android.util.Log; -import com.android.internal.telephony.gsm.SimUtils; /** @@ -44,6 +43,7 @@ public class WapPushOverSms { private final int WAKE_LOCK_TIMEOUT = 5000; public WapPushOverSms(Phone phone) { + mContext = phone.getContext(); createWakelock(); } @@ -56,7 +56,7 @@ public class WapPushOverSms { */ public void dispatchWapPdu(byte[] pdu) { - if (Config.LOGD) Log.d(LOG_TAG, "Rx: " + SimUtils.bytesToHexString(pdu)); + if (Config.LOGD) Log.d(LOG_TAG, "Rx: " + IccUtils.bytesToHexString(pdu)); int index = 0; int transactionId = pdu[index++] & 0xFF; @@ -225,3 +225,4 @@ public class WapPushOverSms { mContext.sendBroadcast(intent, permission); } } + diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java new file mode 100644 index 0000000..ef2f548 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java @@ -0,0 +1,916 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma; + +import android.content.Context; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.Registrant; +import android.os.RegistrantList; +import android.os.SystemProperties; +import android.provider.Settings; +import android.telephony.CellLocation; +import android.telephony.PhoneNumberUtils; +import android.telephony.ServiceState; +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.CommandsInterface; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.DataConnection; +import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.IccFileHandler; +import com.android.internal.telephony.IccPhoneBookInterfaceManager; +import com.android.internal.telephony.IccSmsInterfaceManager; +import com.android.internal.telephony.MmiCode; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneBase; +import com.android.internal.telephony.PhoneNotifier; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.PhoneSubInfo; +import com.android.internal.telephony.RILConstants; + +import java.util.ArrayList; +import java.util.List; + +/** + * {@hide} + */ +public class CDMAPhone extends PhoneBase { + static final String LOG_TAG = "CDMA"; + private static final boolean LOCAL_DEBUG = true; + + //***** Instance Variables + CdmaCallTracker mCT; + CdmaSMSDispatcher mSMS; + CdmaServiceStateTracker mSST; + CdmaDataConnectionTracker mDataConnection; + RuimFileHandler mRuimFileHandler; + RuimRecords mRuimRecords; + RuimCard mRuimCard; + MyHandler h; + ArrayList <FeatureCode> mPendingMMIs = new ArrayList<FeatureCode>(); + RuimPhoneBookInterfaceManager mRuimPhoneBookInterfaceManager; + RuimSmsInterfaceManager mRuimSmsInterfaceManager; + PhoneSubInfo mSubInfo; + + protected RegistrantList mNvLoadedRegistrants = new RegistrantList(); + private String mEsn; + private String mMeid; + + Registrant mPostDialHandler; + + + //***** Constructors + public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) { + this(context,ci,notifier, false); + } + + public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, + boolean unitTestMode) { + super(notifier, context, unitTestMode); + + h = new MyHandler(); + mCM = ci; + + mCM.setPhoneType(RILConstants.CDMA_PHONE); + mCT = new CdmaCallTracker(this); + mSST = new CdmaServiceStateTracker (this); + mSMS = new CdmaSMSDispatcher(this); + mIccFileHandler = new RuimFileHandler(this); + mRuimRecords = new RuimRecords(this); + mDataConnection = new CdmaDataConnectionTracker (this); + mRuimCard = new RuimCard(this); + mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this); + mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this); + mSubInfo = new PhoneSubInfo(this); + + mCM.registerForAvailable(h, EVENT_RADIO_AVAILABLE, null); + mRuimRecords.registerForRecordsLoaded(h, EVENT_RUIM_RECORDS_LOADED, null); + mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + mCM.registerForOn(h, EVENT_RADIO_ON, null); + mCM.setOnSuppServiceNotification(h, EVENT_SSN, null); + mCM.setOnCallRing(h, EVENT_CALL_RING, null); + mSST.registerForNetworkAttach(h, EVENT_REGISTERED_TO_NETWORK, null); + mCM.registerForNVReady(h, EVENT_NV_READY, null); + + //Change the system setting + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.CURRENT_ACTIVE_PHONE, RILConstants.CDMA_PHONE); + } + + public void dispose() { + synchronized(PhoneProxy.lockForRadioTechnologyChange) { + + //Unregister from all former registered events + mRuimRecords.unregisterForRecordsLoaded(h); //EVENT_RUIM_RECORDS_LOADED + mCM.unregisterForAvailable(h); //EVENT_RADIO_AVAILABLE + mCM.unregisterForOffOrNotAvailable(h); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE + mCM.unregisterForOn(h); //EVENT_RADIO_ON + mCM.unregisterForNVReady(h); //EVENT_NV_READY + mSST.unregisterForNetworkAttach(h); //EVENT_REGISTERED_TO_NETWORK + mCM.unSetOnSuppServiceNotification(h); + mCM.unSetOnCallRing(h); + + //Force all referenced classes to unregister their former registered events + mCT.dispose(); + mDataConnection.dispose(); + mSST.dispose(); + mSMS.dispose(); + mIccFileHandler.dispose(); // instance of RuimFileHandler + mRuimRecords.dispose(); + mRuimCard.dispose(); + mRuimPhoneBookInterfaceManager.dispose(); + mRuimSmsInterfaceManager.dispose(); + mSubInfo.dispose(); + } + } + + public void removeReferences() { + this.mRuimPhoneBookInterfaceManager = null; + this.mRuimSmsInterfaceManager = null; + this.mSMS = null; + this.mSubInfo = null; + this.mRuimRecords = null; + this.mIccFileHandler = null; + this.mRuimCard = null; + this.mDataConnection = null; + this.mCT = null; + this.mSST = null; + } + + protected void finalize() { + if(LOCAL_DEBUG) Log.d(LOG_TAG, "CDMAPhone finalized"); + } + + + //***** Overridden from Phone + public ServiceState getServiceState() { + return mSST.ss; + } + + public Phone.State + getState() { + return mCT.state; + } + + public String + getPhoneName() { + return "CDMA"; + } + + public boolean canTransfer() { + Log.e(LOG_TAG, "canTransfer: not possible in CDMA"); + return false; + } + + public CdmaCall + getRingingCall() { + return mCT.ringingCall; + } + + public void setMute(boolean muted) { + mCT.setMute(muted); + } + + public boolean getMute() { + return mCT.getMute(); + } + + public void conference() throws CallStateException { + // three way calls in CDMA will be handled by feature codes + Log.e(LOG_TAG, "conference: not possible in CDMA"); + } + + public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) { + this.mCM.setPreferredVoicePrivacy(enable, onComplete); + } + + public void getEnhancedVoicePrivacy(Message onComplete) { + this.mCM.getPreferredVoicePrivacy(onComplete); + } + + public void clearDisconnected() { + mCT.clearDisconnected(); + } + + public DataActivityState getDataActivityState() { + DataActivityState ret = DataActivityState.NONE; + + if (mSST.getCurrentCdmaDataConnectionState() != ServiceState.RADIO_TECHNOLOGY_UNKNOWN) { + + switch (mDataConnection.getActivity()) { + case DATAIN: + ret = DataActivityState.DATAIN; + break; + + case DATAOUT: + ret = DataActivityState.DATAOUT; + break; + + case DATAINANDOUT: + ret = DataActivityState.DATAINANDOUT; + break; + } + } + return ret; + } + + /*package*/ void + notifySignalStrength() { + mNotifier.notifySignalStrength(this); + } + + public Connection + dial (String dialString) throws CallStateException { + // Need to make sure dialString gets parsed properly + String newDialString = PhoneNumberUtils.stripSeparators(dialString); + + FeatureCode fc = FeatureCode.newFromDialString(newDialString, this); + if (LOCAL_DEBUG) Log.d(LOG_TAG, + "dialing w/ fc '" + fc + "'..."); + // check for feature code + if (fc == null) { + // check if call in progress + if (!mCT.foregroundCall.isIdle()) { + FeatureCode digits = new FeatureCode(this); + // use dial number as poundString + digits.poundString = newDialString; + mPendingMMIs.add(fc); + mMmiRegistrants.notifyRegistrants(new AsyncResult(null, fc, null)); + digits.processCode(); + return null; + } else { + return mCT.dial(newDialString); + } + } else { + mPendingMMIs.add(fc); + mMmiRegistrants.notifyRegistrants(new AsyncResult(null, fc, null)); + fc.processCode(); + + // FIXME should this return null or something else? + return null; + } + } + + public int getSignalStrengthASU() { + return mSST.rssi == 99 ? -1 : mSST.rssi; + } + + public boolean + getMessageWaitingIndicator() { + Log.e(LOG_TAG, "method getMessageWaitingIndicator is NOT supported in CDMA!"); + return false; + } + + public List<? extends MmiCode> + getPendingMmiCodes() { + Log.e(LOG_TAG, "method getPendingMmiCodes is NOT supported in CDMA!"); + return null; + } + + public void registerForSuppServiceNotification( + Handler h, int what, Object obj) { + Log.e(LOG_TAG, "method registerForSuppServiceNotification is NOT supported in CDMA!"); + } + + public CdmaCall getBackgroundCall() { + return mCT.backgroundCall; + } + + public String getGateway(String apnType) { + return mDataConnection.getGateway(); + } + + public boolean handleInCallMmiCommands(String dialString) { + Log.e(LOG_TAG, "method handleInCallMmiCommands is NOT supported in CDMA!"); + return false; + } + + public int enableApnType(String type) { + // This request is mainly used to enable MMS APN + // In CDMA there is no need to enable/disable a different APN for MMS + Log.d(LOG_TAG, "Request to enableApnType("+type+")"); + if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { + return Phone.APN_ALREADY_ACTIVE; + } else { + return Phone.APN_REQUEST_FAILED; + } + } + + public int disableApnType(String type) { + // This request is mainly used to disable MMS APN + // In CDMA there is no need to enable/disable a different APN for MMS + Log.d(LOG_TAG, "Request to disableApnType("+type+")"); + if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { + return Phone.APN_REQUEST_STARTED; + } else { + return Phone.APN_REQUEST_FAILED; + } + } + + public String getActiveApn() { + Log.d(LOG_TAG, "Request to getActiveApn()"); + return null; + } + + public void + setNetworkSelectionModeAutomatic(Message response) { + Log.e(LOG_TAG, "method setNetworkSelectionModeAutomatic is NOT supported in CDMA!"); + } + + public void unregisterForSuppServiceNotification(Handler h) { + Log.e(LOG_TAG, "method unregisterForSuppServiceNotification is NOT supported in CDMA!"); + } + + public void + acceptCall() throws CallStateException { + mCT.acceptCall(); + } + + public void + rejectCall() throws CallStateException { + mCT.rejectCall(); + } + + public void + switchHoldingAndActive() throws CallStateException { + mCT.switchWaitingOrHoldingAndActive(); + } + + public String getLine1Number() { + return mRuimRecords.getMdnNumber(); + } + + public void getCallWaiting(Message onComplete) { + mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete); + } + + public void + setRadioPower(boolean power) { + mSST.setRadioPower(power); + } + + public String getEsn() { + return mEsn; + } + + public String getMeid() { + return mMeid; + } + + //returns MEID in CDMA + public String getDeviceId() { + return getMeid(); + } + + public String getDeviceSvn() { + Log.d(LOG_TAG, "getDeviceSvn(): return 0"); + return "0"; + } + + public String getSubscriberId() { + Log.e(LOG_TAG, "method getSubscriberId for IMSI is NOT supported in CDMA!"); + return null; + } + + public boolean canConference() { + Log.e(LOG_TAG, "canConference: not possible in CDMA"); + return false; + } + + public String getInterfaceName(String apnType) { + return mDataConnection.getInterfaceName(); + } + + public CellLocation getCellLocation() { + return mSST.cellLoc; + } + + public boolean disableDataConnectivity() { + return mDataConnection.setDataEnabled(false); + } + + public CdmaCall getForegroundCall() { + return mCT.foregroundCall; + } + + public void + selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo network, + Message response) { + Log.e(LOG_TAG, "selectNetworkManually: not possible in CDMA"); + } + + public void setOnPostDialCharacter(Handler h, int what, Object obj) { + Log.e(LOG_TAG, "setOnPostDialCharacter: not possible in CDMA"); + } + + public boolean handlePinMmi(String dialString) { + Log.e(LOG_TAG, "method handlePinMmi is NOT supported in CDMA!"); + return false; + } + + public boolean isDataConnectivityPossible() { + boolean noData = mDataConnection.getDataEnabled() && + getDataConnectionState() == DataState.DISCONNECTED; + return !noData && getIccCard().getState() == IccCard.State.READY && + getServiceState().getState() == ServiceState.STATE_IN_SERVICE && + (mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming()); + } + + public void setLine1Number(String alphaTag, String number, Message onComplete) { + Log.e(LOG_TAG, "setLine1Number: not possible in CDMA"); + } + + public String[] getDnsServers(String apnType) { + return mDataConnection.getDnsServers(); + } + + public IccCard getIccCard() { + return mRuimCard; + } + + public String getIccSerialNumber() { + return mRuimRecords.iccid; + } + + public void setCallWaiting(boolean enable, Message onComplete) { + Log.e(LOG_TAG, "method setCallWaiting is NOT supported in CDMA!"); + } + + public void updateServiceLocation(Message response) { + mSST.getLacAndCid(response); + } + + public void setDataRoamingEnabled(boolean enable) { + mDataConnection.setDataOnRoamingEnabled(enable); + } + + public String getIpAddress(String apnType) { + return mDataConnection.getIpAddress(); + } + + public void + getNeighboringCids(Message response) { + // WINK:TODO: implement after Cupcake merge + mCM.getNeighboringCids(response); // workaround. + } + + public DataState getDataConnectionState() { + DataState ret = DataState.DISCONNECTED; + + if ((SystemProperties.get("adb.connected", "").length() > 0) + && (SystemProperties.get("android.net.use-adb-networking", "") + .length() > 0)) { + // We're connected to an ADB host and we have USB networking + // turned on. No matter what the radio state is, + // we report data connected + + ret = DataState.CONNECTED; + } else if (mSST.getCurrentCdmaDataConnectionState() + == ServiceState.RADIO_TECHNOLOGY_UNKNOWN) { + // If we're out of service, open TCP sockets may still work + // but no data will flow + ret = DataState.DISCONNECTED; + } else { + switch (mDataConnection.getState()) { + case FAILED: + case IDLE: + ret = DataState.DISCONNECTED; + break; + + case CONNECTED: + case DISCONNECTING: + if ( mCT.state != Phone.State.IDLE + && !mSST.isConcurrentVoiceAndData()) { + ret = DataState.SUSPENDED; + } else { + ret = DataState.CONNECTED; + } + break; + + case INITING: + case CONNECTING: + case SCANNING: + ret = DataState.CONNECTING; + break; + } + } + + return ret; + } + + public void sendUssdResponse(String ussdMessge) { + Log.e(LOG_TAG, "sendUssdResponse: not possible in CDMA"); + } + + public void sendDtmf(char c) { + if (!PhoneNumberUtils.is12Key(c)) { + Log.e(LOG_TAG, + "sendDtmf called with invalid character '" + c + "'"); + } else { + if (mCT.state == Phone.State.OFFHOOK) { + mCM.sendDtmf(c, null); + } + } + } + + public void startDtmf(char c) { + if (!PhoneNumberUtils.is12Key(c)) { + Log.e(LOG_TAG, + "startDtmf called with invalid character '" + c + "'"); + } else { + mCM.startDtmf(c, null); + } + } + + public void stopDtmf() { + mCM.stopDtmf(null); + } + + public void getAvailableNetworks(Message response) { + Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA"); + } + + public String[] getActiveApnTypes() { + String[] result; + Log.d(LOG_TAG, "Request to getActiveApn()"); + result = new String[1]; + result[0] = Phone.APN_TYPE_DEFAULT; + return result; + } + + public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) { + Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA"); + } + + public void enableLocationUpdates() { + mSST.enableLocationUpdates(); + } + + /** + * @deprecated + */ + public void getPdpContextList(Message response) { + getDataCallList(response); + } + + public void getDataCallList(Message response) { + mCM.getDataCallList(response); + } + + public boolean getDataRoamingEnabled() { + return mDataConnection.getDataOnRoamingEnabled(); + } + + public List<DataConnection> getCurrentDataConnectionList () { + return mDataConnection.getAllDataConnections(); + } + + 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 + } + + public String getVoiceMailNumber() { + //TODO: Where can we get this value has to be clarified with QC + //return mSIMRecords.getVoiceMailNumber(); +// throw new RuntimeException(); + return "12345"; + } + + public String getVoiceMailAlphaTag() { + // TODO: Where can we get this value has to be clarified with QC. + String ret = "";//TODO: Remove = "", if we know where to get this value. + + //ret = mSIMRecords.getVoiceMailAlphaTag(); + + if (ret == null || ret.length() == 0) { + return mContext.getText( + com.android.internal.R.string.defaultVoiceMailAlphaTag).toString(); + } + + return ret; + } + + public boolean enableDataConnectivity() { + return mDataConnection.setDataEnabled(true); + } + + public void disableLocationUpdates() { + mSST.disableLocationUpdates(); + } + + public boolean getIccRecordsLoaded() { + return mRuimRecords.getRecordsLoaded(); + } + + public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) { + Log.e(LOG_TAG, "getCallForwardingOption: not possible in CDMA"); + } + + public void setCallForwardingOption(int commandInterfaceCFAction, + int commandInterfaceCFReason, + String dialingNumber, + int timerSeconds, + Message onComplete) { + Log.e(LOG_TAG, "setCallForwardingOption: not possible in CDMA"); + } + + public void + getOutgoingCallerIdDisplay(Message onComplete) { + Log.e(LOG_TAG, "getOutgoingCallerIdDisplay: not possible in CDMA"); + } + + public boolean + getCallForwardingIndicator() { + Log.e(LOG_TAG, "getCallForwardingIndicator: not possible in CDMA"); + return false; + } + + public void explicitCallTransfer() { + Log.e(LOG_TAG, "explicitCallTransfer: not possible in CDMA"); + } + + public String getLine1AlphaTag() { + Log.e(LOG_TAG, "getLine1AlphaTag: not possible in CDMA"); + return null; + } + + /** + * Notify any interested party of a Phone state change. + */ + /*package*/ void notifyPhoneStateChanged() { + mNotifier.notifyPhoneState(this); + } + + /** + * Notifies registrants (ie, activities in the Phone app) about + * changes to call state (including Phone and Connection changes). + */ + /*package*/ void notifyCallStateChanged() { + /* we'd love it if this was package-scoped*/ + super.notifyCallStateChangedP(); + } + + void notifyServiceStateChanged(ServiceState ss) { + super.notifyServiceStateChangedP(ss); + } + + void notifyLocationChanged() { + mNotifier.notifyCellLocation(this); + } + + /*package*/ void notifyNewRingingConnection(Connection c) { + /* we'd love it if this was package-scoped*/ + super.notifyNewRingingConnectionP(c); + } + + /** + * Notifiy registrants of a RING event. + */ + void notifyIncomingRing() { + AsyncResult ar = new AsyncResult(null, this, null); + mIncomingRingRegistrants.notifyRegistrants(ar); + } + + /*package*/ void notifyDisconnect(Connection cn) { + mDisconnectRegistrants.notifyResult(cn); + } + + void notifyUnknownConnection() { + mUnknownConnectionRegistrants.notifyResult(this); + } + + /*package*/ void + updateMessageWaitingIndicator(boolean mwi) { + // this also calls notifyMessageWaitingIndicator() + mRuimRecords.setVoiceMessageWaiting(1, mwi ? -1 : 0); + } + + + /** + * Removes the given FC from the pending list and notifies + * registrants that it is complete. + * @param fc FC that is done + */ + /*package*/ void onMMIDone(FeatureCode fc) { + /* Only notify complete if it's on the pending list. + * Otherwise, it's already been handled (eg, previously canceled). + * The exception is cancellation of an incoming USSD-REQUEST, which is + * not on the list. + */ + if (mPendingMMIs.remove(fc)) { + mMmiCompleteRegistrants.notifyRegistrants( + new AsyncResult(null, fc, null)); + } + } + + //***** Inner Classes + class MyHandler extends Handler { + MyHandler() { + } + + MyHandler(Looper l) { + super(l); + } + + public void handleMessage(Message msg) { + AsyncResult ar; + Message onComplete; + + switch(msg.what) { + case EVENT_RADIO_AVAILABLE: { + mCM.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE)); + + mCM.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE)); + } + break; + + case EVENT_GET_BASEBAND_VERSION_DONE:{ + ar = (AsyncResult)msg.obj; + + if (ar.exception != null) { + break; + } + + if (LOCAL_DEBUG) Log.d(LOG_TAG, "Baseband version: " + ar.result); + setSystemProperty(PROPERTY_BASEBAND_VERSION, (String)ar.result); + } + break; + + case EVENT_GET_DEVICE_IDENTITY_DONE:{ + ar = (AsyncResult)msg.obj; + + if (ar.exception != null) { + break; + } + String[] respId = (String[])ar.result; + mEsn = respId[2]; + mMeid = respId[3]; + } + break; + + case EVENT_RUIM_RECORDS_LOADED:{ + Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received"); + } + break; + + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:{ + Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received"); + } + break; + + case EVENT_RADIO_ON:{ + Log.d(LOG_TAG, "Event EVENT_RADIO_ON Received"); + } + break; + + case EVENT_SSN:{ + Log.d(LOG_TAG, "Event EVENT_SSN Received"); + } + break; + + case EVENT_CALL_RING:{ + Log.d(LOG_TAG, "Event EVENT_CALL_RING Received"); + } + break; + + case EVENT_REGISTERED_TO_NETWORK:{ + Log.d(LOG_TAG, "Event EVENT_REGISTERED_TO_NETWORK Received"); + } + break; + + case EVENT_NV_READY:{ + Log.d(LOG_TAG, "Event EVENT_NV_READY Received"); + //Inform the Service State Tracker + mNvLoadedRegistrants.notifyRegistrants(); + } + break; + + default:{ + throw new RuntimeException("unexpected event not handled"); + } + } + } + } + + /** + * Retrieves the PhoneSubInfo of the CDMAPhone + */ + public PhoneSubInfo getPhoneSubInfo(){ + return mSubInfo; + } + + /** + * Retrieves the IccSmsInterfaceManager of the CDMAPhone + */ + public IccSmsInterfaceManager getIccSmsInterfaceManager(){ + return mRuimSmsInterfaceManager; + } + + /** + * 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); + mNvLoadedRegistrants.add(r); + } + + public void unregisterForNvLoaded(Handler h) { + 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); + } + + /** + * {@inheritDoc} + */ + public Handler getHandler(){ + return h; + } + + /** + * {@inheritDoc} + */ + public IccFileHandler getIccFileHandler(){ + return this.mIccFileHandler; + } + + /** + * Set the TTY mode of the CDMAPhone + */ + public void setTTYModeEnabled(boolean enable, Message onComplete) { + this.mCM.setTTYModeEnabled(enable, onComplete); +} + + /** + * Queries the TTY mode of the CDMAPhone + */ + public void queryTTYModeEnabled(Message onComplete) { + this.mCM.queryTTYModeEnabled(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); + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java b/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java new file mode 100644 index 0000000..ea557b2 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma; + +/** + * Call fail causes from TS 24.008 . + * These are mostly the cause codes we need to distinguish for the UI. + * See 22.001 Annex F.4 for mapping of cause codes to local tones. + * + * {@hide} + * + */ +public interface CallFailCause { + 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 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 new file mode 100644 index 0000000..34514d9 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma; + +import java.util.ArrayList; +import java.util.List; + +import com.android.internal.telephony.Call; +import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.DriverCall; +import com.android.internal.telephony.Phone; + +/** + * {@hide} + */ +public final class CdmaCall extends Call { + /*************************** Instance Variables **************************/ + + /*package*/ ArrayList<Connection> connections = new ArrayList<Connection>(); + /*package*/ State state = State.IDLE; + /*package*/ CdmaCallTracker owner; + + /***************************** Class Methods *****************************/ + + static State + stateFromDCState (DriverCall.State dcState) { + switch (dcState) { + case ACTIVE: return State.ACTIVE; + case HOLDING: return State.HOLDING; + case DIALING: return State.DIALING; + case ALERTING: return State.ALERTING; + case INCOMING: return State.INCOMING; + case WAITING: return State.WAITING; + default: throw new RuntimeException ("illegal call state:" + dcState); + } + } + + + /****************************** Constructors *****************************/ + /*package*/ + CdmaCall (CdmaCallTracker owner) { + this.owner = owner; + } + + public void dispose() { + } + + /************************** Overridden from Call *************************/ + public List<Connection> + getConnections() { + // FIXME should return Collections.unmodifiableList(); + return connections; + } + + public State + getState() { + return state; + } + + public Phone + getPhone() { + //TODO, see GsmCall + return null; + } + + public boolean isMultiparty() { + return connections.size() > 1; + } + + /** Please note: if this is the foreground call and a + * background call exists, the background call will be resumed + * because an AT+CHLD=1 will be sent + */ + public void + hangup() throws CallStateException { + owner.hangup(this); + } + + public String + toString() { + return state.toString(); + } + + //***** Called from CdmaConnection + + /*package*/ void + attach(Connection conn, DriverCall dc) { + connections.add(conn); + + state = stateFromDCState (dc.state); + } + + /*package*/ void + attachFake(Connection conn, State state) { + connections.add(conn); + + this.state = state; + } + + /** + * Called by CdmaConnection when it has disconnected + */ + void + connectionDisconnected(CdmaConnection conn) { + if (state != State.DISCONNECTED) { + /* If only disconnected connections remain, we are disconnected*/ + + boolean hasOnlyDisconnectedConnections = true; + + for (int i = 0, s = connections.size() ; i < s; i ++) { + if (connections.get(i).getState() + != State.DISCONNECTED + ) { + hasOnlyDisconnectedConnections = false; + break; + } + } + + if (hasOnlyDisconnectedConnections) { + state = State.DISCONNECTED; + } + } + } + + + /*package*/ void + detach(CdmaConnection conn) { + connections.remove(conn); + + if (connections.size() == 0) { + state = State.IDLE; + } + } + + /*package*/ boolean + update (CdmaConnection conn, DriverCall dc) { + State newState; + boolean changed = false; + + newState = stateFromDCState(dc.state); + + if (newState != state) { + state = newState; + changed = true; + } + + return changed; + } + + /** + * @return true if there's no space in this call for additional + * connections to be added via "conference" + */ + /*package*/ boolean + isFull() { + return connections.size() == CdmaCallTracker.MAX_CONNECTIONS_PER_CALL; + } + + //***** Called from CdmaCallTracker + + + /** + * Called when this Call is being hung up locally (eg, user pressed "end") + * Note that at this point, the hangup request has been dispatched to the radio + * but no response has yet been received so update() has not yet been called + */ + void + onHangupLocal() { + for (int i = 0, s = connections.size() + ; i < s; i++ + ) { + CdmaConnection cn = (CdmaConnection)connections.get(i); + + cn.onHangupLocal(); + } + } + + /** + * Called when it's time to clean up disconnected Connection objects + */ + void clearDisconnected() { + for (int i = connections.size() - 1 ; i >= 0 ; i--) { + CdmaConnection cn = (CdmaConnection)connections.get(i); + + if (cn.getState() == State.DISCONNECTED) { + connections.remove(i); + } + } + + if (connections.size() == 0) { + state = State.IDLE; + } + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java new file mode 100644 index 0000000..a1d362f --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java @@ -0,0 +1,860 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.Registrant; +import android.os.RegistrantList; +import android.telephony.PhoneNumberUtils; +import android.telephony.ServiceState; +import android.util.Log; + +import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.CallTracker; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.DriverCall; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneProxy; + +import java.util.ArrayList; +import java.util.List; + +/** + * {@hide} + */ +public final class CdmaCallTracker extends CallTracker { + static final String LOG_TAG = "CDMA"; + + private static final boolean REPEAT_POLLING = false; + + private static final boolean DBG_POLL = false; + + //***** Constants + + static final int MAX_CONNECTIONS = 1; // only 1 connection allowed in CDMA + static final int MAX_CONNECTIONS_PER_CALL = 1; // only 1 connection allowed per call + + //***** Instance Variables + + CdmaConnection connections[] = new CdmaConnection[MAX_CONNECTIONS]; + RegistrantList voiceCallEndedRegistrants = new RegistrantList(); + RegistrantList voiceCallStartedRegistrants = new RegistrantList(); + + + // connections dropped durin last poll + ArrayList<CdmaConnection> droppedDuringPoll + = new ArrayList<CdmaConnection>(MAX_CONNECTIONS); + + CdmaCall ringingCall = new CdmaCall(this); + // A call that is ringing or (call) waiting + CdmaCall foregroundCall = new CdmaCall(this); + CdmaCall backgroundCall = new CdmaCall(this); + + CdmaConnection pendingMO; + boolean hangupPendingMO; + + CDMAPhone phone; + + boolean desiredMute = false; // false = mute off + + Phone.State state = Phone.State.IDLE; + + +// boolean needsPoll; + + + + //***** Events + + //***** Constructors + CdmaCallTracker(CDMAPhone phone) { + this.phone = phone; + cm = phone.mCM; + cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null); + cm.registerForOn(this, EVENT_RADIO_AVAILABLE, null); + cm.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null); + } + + public void dispose() { + cm.unregisterForCallStateChanged(this); + cm.unregisterForOn(this); + cm.unregisterForNotAvailable(this); + + for(CdmaConnection c : connections) { + try { + if(c != null) hangup(c); + } catch (CallStateException ex) { + Log.e(LOG_TAG, "unexpected error on hangup during dispose"); + } + } + + try { + if(pendingMO != null) hangup(pendingMO); + } catch (CallStateException ex) { + Log.e(LOG_TAG, "unexpected error on hangup during dispose"); + } + + clearDisconnected(); + + } + + protected void finalize() { + Log.d(LOG_TAG, "CdmaCallTracker finalized"); + } + + //***** Instance Methods + + //***** Public Methods + public void registerForVoiceCallStarted(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + voiceCallStartedRegistrants.add(r); + } + public void unregisterForVoiceCallStarted(Handler h) { + voiceCallStartedRegistrants.remove(h); + } + + public void registerForVoiceCallEnded(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + voiceCallEndedRegistrants.add(r); + } + + public void unregisterForVoiceCallEnded(Handler h) { + voiceCallEndedRegistrants.remove(h); + } + + private void + fakeHoldForegroundBeforeDial() { + List<Connection> connCopy; + + // We need to make a copy here, since fakeHoldBeforeDial() + // modifies the lists, and we don't want to reverse the order + connCopy = (List<Connection>) foregroundCall.connections.clone(); + + for (int i = 0, s = connCopy.size() ; i < s ; i++) { + CdmaConnection conn = (CdmaConnection)connCopy.get(i); + + conn.fakeHoldBeforeDial(); + } + } + + /** + * clirMode is one of the CLIR_ constants + */ + Connection + dial (String dialString, int clirMode) throws CallStateException { + // note that this triggers call state changed notif + clearDisconnected(); + + if (!canDial()) { + throw new CallStateException("cannot dial in current state"); + } + + // 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"); + } + + pendingMO = new CdmaConnection(phone.getContext(), dialString, this, foregroundCall); + hangupPendingMO = false; + + if (pendingMO.address == null || pendingMO.address.length() == 0 + || pendingMO.address.indexOf(PhoneNumberUtils.WILD) >= 0 + ) { + // Phone number is invalid + pendingMO.cause = Connection.DisconnectCause.INVALID_NUMBER; + + // handlePollCalls() will notice this call not present + // and will mark it as dropped. + pollCallsWhenSafe(); + } else { + // Always unmute when initiating a new call + setMute(false); + + cm.dial(pendingMO.address, clirMode, obtainCompleteMessage()); + } + + updatePhoneState(); + phone.notifyCallStateChanged(); + + return pendingMO; + } + + + Connection + dial (String dialString) throws CallStateException { + 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 + + 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); + switchWaitingOrHoldingAndActive(); + } else { + throw new CallStateException("phone not ringing"); + } + } + + void + rejectCall () throws CallStateException { + // AT+CHLD=0 means "release held or UDUB" + // so if the phone isn't ringing, this could hang up held + if (ringingCall.getState().isRinging()) { + cm.rejectCall(obtainCompleteMessage()); + } else { + throw new CallStateException("phone not ringing"); + } + } + + void + switchWaitingOrHoldingAndActive() throws CallStateException { + // Should we bother with this check? + if (ringingCall.getState() == CdmaCall.State.INCOMING) { + throw new CallStateException("cannot be in the incoming state"); + } else { + cm.sendCDMAFeatureCode("", obtainCompleteMessage(EVENT_SWITCH_RESULT)); + } + } + + void + conference() throws CallStateException { + // three way calls in CDMA will be handled by feature codes + Log.e(LOG_TAG, "conference: not possible in CDMA"); + } + + void + explicitCallTransfer() throws CallStateException { + cm.explicitCallTransfer(obtainCompleteMessage(EVENT_ECT_RESULT)); + } + + void + clearDisconnected() { + internalClearDisconnected(); + + updatePhoneState(); + phone.notifyCallStateChanged(); + } + + boolean + canConference() { + return foregroundCall.getState() == CdmaCall.State.ACTIVE + && backgroundCall.getState() == CdmaCall.State.HOLDING + && !backgroundCall.isFull() + && !foregroundCall.isFull(); + } + + boolean + canDial() { + boolean ret; + int serviceState = phone.getServiceState().getState(); + + ret = (serviceState != ServiceState.STATE_POWER_OFF) && + pendingMO == null + && !ringingCall.isRinging() + && (!foregroundCall.getState().isAlive() + || !backgroundCall.getState().isAlive()); + + return ret; + } + + boolean + canTransfer() { + Log.e(LOG_TAG, "canTransfer: not possible in CDMA"); + return false; + } + + //***** Private Instance Methods + + private void + internalClearDisconnected() { + ringingCall.clearDisconnected(); + foregroundCall.clearDisconnected(); + backgroundCall.clearDisconnected(); + } + + /** + * Obtain a message to use for signalling "invoke getCurrentCalls() when + * this operation and all other pending operations are complete + */ + private Message + obtainCompleteMessage() { + return obtainCompleteMessage(EVENT_OPERATION_COMPLETE); + } + + /** + * Obtain a message to use for signalling "invoke getCurrentCalls() when + * this operation and all other pending operations are complete + */ + private Message + obtainCompleteMessage(int what) { + pendingOperations++; + lastRelevantPoll = null; + needsPoll = true; + + if (DBG_POLL) log("obtainCompleteMessage: pendingOperations=" + + pendingOperations + ", needsPoll=" + needsPoll); + + return obtainMessage(what); + } + + private void + operationComplete() { + pendingOperations--; + + if (DBG_POLL) log("operationComplete: pendingOperations=" + + pendingOperations + ", needsPoll=" + needsPoll); + + if (pendingOperations == 0 && needsPoll) { + lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); + cm.getCurrentCalls(lastRelevantPoll); + } else if (pendingOperations < 0) { + // this should never happen + Log.e(LOG_TAG,"CdmaCallTracker.pendingOperations < 0"); + pendingOperations = 0; + } + } + + + + private void + updatePhoneState() { + Phone.State oldState = state; + + if (ringingCall.isRinging()) { + state = Phone.State.RINGING; + } else if (pendingMO != null || + !(foregroundCall.isIdle() && backgroundCall.isIdle())) { + state = Phone.State.OFFHOOK; + } else { + state = Phone.State.IDLE; + } + + if (state == Phone.State.IDLE && oldState != state) { + voiceCallEndedRegistrants.notifyRegistrants( + new AsyncResult(null, null, null)); + } else if (oldState == Phone.State.IDLE && oldState != state) { + voiceCallStartedRegistrants.notifyRegistrants ( + new AsyncResult(null, null, null)); + } + + if (state != oldState) { + phone.notifyPhoneStateChanged(); + } + } + + // ***** Overwritten from CallTracker + + protected void + handlePollCalls(AsyncResult ar) { + List polledCalls; + + if (ar.exception == null) { + polledCalls = (List)ar.result; + } else if (isCommandExceptionRadioNotAvailable(ar.exception)) { + // just a dummy empty ArrayList to cause the loop + // to hang up all the calls + polledCalls = new ArrayList(); + } else { + // Radio probably wasn't ready--try again in a bit + // But don't keep polling if the channel is closed + pollCallsAfterDelay(); + return; + } + + Connection newRinging = null; //or waiting + boolean hasNonHangupStateChanged = false; // Any change besides + // a dropped connection + boolean needsPollDelay = false; + boolean unknownConnectionAppeared = false; + + for (int i = 0, curDC = 0, dcSize = polledCalls.size() + ; i < connections.length; i++) { + CdmaConnection conn = connections[i]; + DriverCall dc = null; + + // polledCall list is sparse + if (curDC < dcSize) { + dc = (DriverCall) polledCalls.get(curDC); + + if (dc.index == i+1) { + curDC++; + } else { + dc = null; + } + } + + if (DBG_POLL) log("poll: conn[i=" + i + "]=" + + conn+", dc=" + dc); + + if (conn == null && dc != null) { + // Connection appeared in CLCC response that we don't know about + if (pendingMO != null && pendingMO.compareTo(dc)) { + + if (DBG_POLL) log("poll: pendingMO=" + pendingMO); + + // It's our pending mobile originating call + connections[i] = pendingMO; + pendingMO.index = i; + pendingMO.update(dc); + pendingMO = null; + + // Someone has already asked to hangup this call + if (hangupPendingMO) { + hangupPendingMO = false; + try { + if (Phone.DEBUG_PHONE) log( + "poll: hangupPendingMO, hangup conn " + i); + hangup(connections[i]); + } catch (CallStateException ex) { + Log.e(LOG_TAG, "unexpected error on hangup"); + } + + // Do not continue processing this poll + // Wait for hangup and repoll + return; + } + } else { + connections[i] = new CdmaConnection(phone.getContext(), dc, this, i); + + // it's a ringing call + if (connections[i].getCall() == ringingCall) { + newRinging = connections[i]; + } else { + // Something strange happened: a call appeared + // which is neither a ringing call or one we created. + // Either we've crashed and re-attached to an existing + // call, or something else (eg, SIM) initiated the call. + + Log.i(LOG_TAG,"Phantom call appeared " + dc); + + // If it's a connected call, set the connect time so that + // it's non-zero. It may not be accurate, but at least + // it won't appear as a Missed Call. + if (dc.state != DriverCall.State.ALERTING + && dc.state != DriverCall.State.DIALING) { + connections[i].connectTime = System.currentTimeMillis(); + } + + unknownConnectionAppeared = true; + } + } + hasNonHangupStateChanged = true; + } else if (conn != null && dc == null) { + // Connection missing in CLCC response that we were + // tracking. + droppedDuringPoll.add(conn); + // Dropped connections are removed from the CallTracker + // list but kept in the Call list + connections[i] = null; + } else if (conn != null && dc != null && !conn.compareTo(dc)) { + // Connection in CLCC response does not match what + // we were tracking. Assume dropped call and new call + + droppedDuringPoll.add(conn); + connections[i] = new CdmaConnection (phone.getContext(), dc, this, i); + + if (connections[i].getCall() == ringingCall) { + newRinging = connections[i]; + } // else something strange happened + hasNonHangupStateChanged = true; + } else if (conn != null && dc != null) { /* implicit conn.compareTo(dc) */ + boolean changed; + changed = conn.update(dc); + hasNonHangupStateChanged = hasNonHangupStateChanged || changed; + } + + if (REPEAT_POLLING) { + if (dc != null) { + // FIXME with RIL, we should not need this anymore + if ((dc.state == DriverCall.State.DIALING + /*&& cm.getOption(cm.OPTION_POLL_DIALING)*/) + || (dc.state == DriverCall.State.ALERTING + /*&& cm.getOption(cm.OPTION_POLL_ALERTING)*/) + || (dc.state == DriverCall.State.INCOMING + /*&& cm.getOption(cm.OPTION_POLL_INCOMING)*/) + || (dc.state == DriverCall.State.WAITING + /*&& cm.getOption(cm.OPTION_POLL_WAITING)*/) + ) { + // Sometimes there's no unsolicited notification + // for state transitions + needsPollDelay = true; + } + } + } + } + + // This is the first poll after an ATD. + // We expect the pending call to appear in the list + // If it does not, we land here + if (pendingMO != null) { + Log.d(LOG_TAG,"Pending MO dropped before poll fg state:" + + foregroundCall.getState()); + + droppedDuringPoll.add(pendingMO); + pendingMO = null; + hangupPendingMO = false; + } + + if (newRinging != null) { + phone.notifyNewRingingConnection(newRinging); + } + + // clear the "local hangup" and "missed/rejected call" + // cases from the "dropped during poll" list + // These cases need no "last call fail" reason + for (int i = droppedDuringPoll.size() - 1; i >= 0 ; i--) { + CdmaConnection conn = droppedDuringPoll.get(i); + + if (conn.isIncoming() && conn.getConnectTime() == 0) { + // Missed or rejected call + Connection.DisconnectCause cause; + if (conn.cause == Connection.DisconnectCause.LOCAL) { + cause = Connection.DisconnectCause.INCOMING_REJECTED; + } else { + cause = Connection.DisconnectCause.INCOMING_MISSED; + } + + if (Phone.DEBUG_PHONE) { + log("missed/rejected call, conn.cause=" + conn.cause); + log("setting cause to " + cause); + } + droppedDuringPoll.remove(i); + conn.onDisconnect(cause); + } else if (conn.cause == Connection.DisconnectCause.LOCAL) { + // Local hangup + droppedDuringPoll.remove(i); + conn.onDisconnect(Connection.DisconnectCause.LOCAL); + } else if (conn.cause == Connection.DisconnectCause.INVALID_NUMBER) { + droppedDuringPoll.remove(i); + conn.onDisconnect(Connection.DisconnectCause.INVALID_NUMBER); + } + } + + // Any non-local disconnects: determine cause + if (droppedDuringPoll.size() > 0) { + cm.getLastCallFailCause( + obtainNoPollCompleteMessage(EVENT_GET_LAST_CALL_FAIL_CAUSE)); + } + + if (needsPollDelay) { + pollCallsAfterDelay(); + } + + // Cases when we can no longer keep disconnected Connection's + // with their previous calls + // 1) the phone has started to ring + // 2) A Call/Connection object has changed state... + // we may have switched or held or answered (but not hung up) + if (newRinging != null || hasNonHangupStateChanged) { + internalClearDisconnected(); + } + + updatePhoneState(); + + if (unknownConnectionAppeared) { + phone.notifyUnknownConnection(); + } + + if (hasNonHangupStateChanged || newRinging != null) { + phone.notifyCallStateChanged(); + } + + //dumpState(); + } + + //***** Called from CdmaConnection + /*package*/ void + hangup (CdmaConnection conn) throws CallStateException { + if (conn.owner != this) { + throw new CallStateException ("CdmaConnection " + conn + + "does not belong to CdmaCallTracker " + this); + } + + if (conn == pendingMO) { + // We're hanging up an outgoing call that doesn't have it's + // GSM index assigned yet + + if (Phone.DEBUG_PHONE) log("hangup: set hangupPendingMO to true"); + hangupPendingMO = true; + } else { + try { + cm.hangupConnection (conn.getCDMAIndex(), obtainCompleteMessage()); + } catch (CallStateException ex) { + // Ignore "connection not found" + // Call may have hung up already + Log.w(LOG_TAG,"CdmaCallTracker WARN: hangup() on absent connection " + + conn); + } + } + + conn.onHangupLocal(); + } + + /*package*/ void + separate (CdmaConnection conn) throws CallStateException { + if (conn.owner != this) { + throw new CallStateException ("CdmaConnection " + conn + + "does not belong to CdmaCallTracker " + this); + } + try { + cm.separateConnection (conn.getCDMAIndex(), + obtainCompleteMessage(EVENT_SEPARATE_RESULT)); + } catch (CallStateException ex) { + // Ignore "connection not found" + // Call may have hung up already + Log.w(LOG_TAG,"CdmaCallTracker WARN: separate() on absent connection " + + conn); + } + } + + //***** Called from CDMAPhone + + /*package*/ void + setMute(boolean mute) { + desiredMute = mute; + cm.setMute(desiredMute, null); + } + + /*package*/ boolean + getMute() { + return desiredMute; + } + + + //***** Called from CdmaCall + + /* package */ void + hangup (CdmaCall call) throws CallStateException { + if (call.getConnections().size() == 0) { + throw new CallStateException("no connections in call"); + } + + if (call == ringingCall) { + if (Phone.DEBUG_PHONE) log("(ringing) hangup waiting or background"); + cm.hangupWaitingOrBackground(obtainCompleteMessage()); + } else if (call == foregroundCall) { + if (call.isDialingOrAlerting()) { + if (Phone.DEBUG_PHONE) { + log("(foregnd) hangup dialing or alerting..."); + } + hangup((CdmaConnection)(call.getConnections().get(0))); + } else { + hangupForegroundResumeBackground(); + } + } else if (call == backgroundCall) { + if (ringingCall.isRinging()) { + if (Phone.DEBUG_PHONE) { + log("hangup all conns in background call"); + } + hangupAllConnections(call); + } else { + hangupWaitingOrBackground(); + } + } else { + throw new RuntimeException ("CdmaCall " + call + + "does not belong to CdmaCallTracker " + this); + } + + call.onHangupLocal(); + } + + /* package */ + void hangupWaitingOrBackground() { + if (Phone.DEBUG_PHONE) log("hangupWaitingOrBackground"); + cm.hangupWaitingOrBackground(obtainCompleteMessage()); + } + + /* package */ + void hangupForegroundResumeBackground() { + if (Phone.DEBUG_PHONE) log("hangupForegroundResumeBackground"); + cm.hangupForegroundResumeBackground(obtainCompleteMessage()); + } + + void hangupConnectionByIndex(CdmaCall call, int index) + throws CallStateException { + int count = call.connections.size(); + for (int i = 0; i < count; i++) { + CdmaConnection cn = (CdmaConnection)call.connections.get(i); + if (cn.getCDMAIndex() == index) { + cm.hangupConnection(index, obtainCompleteMessage()); + return; + } + } + + throw new CallStateException("no gsm index found"); + } + + void hangupAllConnections(CdmaCall call) throws CallStateException{ + try { + int count = call.connections.size(); + for (int i = 0; i < count; i++) { + CdmaConnection cn = (CdmaConnection)call.connections.get(i); + cm.hangupConnection(cn.getCDMAIndex(), obtainCompleteMessage()); + } + } catch (CallStateException ex) { + Log.e(LOG_TAG, "hangupConnectionByIndex caught " + ex); + } + } + + /* package */ + CdmaConnection getConnectionByIndex(CdmaCall call, int index) + throws CallStateException { + int count = call.connections.size(); + for (int i = 0; i < count; i++) { + CdmaConnection cn = (CdmaConnection)call.connections.get(i); + if (cn.getCDMAIndex() == index) { + return cn; + } + } + + return null; + } + + private Phone.SuppService getFailedService(int what) { + switch (what) { + case EVENT_SWITCH_RESULT: + return Phone.SuppService.SWITCH; + case EVENT_CONFERENCE_RESULT: + return Phone.SuppService.CONFERENCE; + case EVENT_SEPARATE_RESULT: + return Phone.SuppService.SEPARATE; + case EVENT_ECT_RESULT: + return Phone.SuppService.TRANSFER; + } + return Phone.SuppService.UNKNOWN; + } + + private void handleRadioNotAvailable() { + // handlePollCalls will clear out its + // call list when it gets the CommandException + // error result from this + pollCallsWhenSafe(); + } + + //****** Overridden from Handler + + public void + handleMessage (Message msg) { + AsyncResult ar; + + switch (msg.what) { + case EVENT_POLL_CALLS_RESULT:{ + Log.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received"); + ar = (AsyncResult)msg.obj; + + if(msg == lastRelevantPoll) { + if(DBG_POLL) log( + "handle EVENT_POLL_CALL_RESULT: set needsPoll=F"); + needsPoll = false; + lastRelevantPoll = null; + handlePollCalls((AsyncResult)msg.obj); + } + } + break; + + case EVENT_OPERATION_COMPLETE: + ar = (AsyncResult)msg.obj; + operationComplete(); + break; + + case EVENT_SWITCH_RESULT: + ar = (AsyncResult)msg.obj; + operationComplete(); + break; + + case EVENT_GET_LAST_CALL_FAIL_CAUSE: + int causeCode; + ar = (AsyncResult)msg.obj; + + operationComplete(); + + if (ar.exception != null) { + // An exception occurred...just treat the disconnect + // cause as "normal" + causeCode = CallFailCause.NORMAL_CLEARING; + Log.i(LOG_TAG, + "Exception during getLastCallFailCause, assuming normal disconnect"); + } else { + causeCode = ((int[])ar.result)[0]; + } + + for (int i = 0, s = droppedDuringPoll.size() + ; i < s ; i++ + ) { + CdmaConnection conn = droppedDuringPoll.get(i); + + conn.onRemoteDisconnect(causeCode); + } + + updatePhoneState(); + + phone.notifyCallStateChanged(); + droppedDuringPoll.clear(); + break; + + case EVENT_CALL_STATE_CHANGE: + pollCallsWhenSafe(); + break; + + case EVENT_RADIO_AVAILABLE: + handleRadioAvailable(); + break; + + case EVENT_RADIO_NOT_AVAILABLE: + handleRadioNotAvailable(); + break; + + default:{ + throw new RuntimeException("unexpected event not handled"); + } + } + } + + protected void log(String msg) { + Log.d(LOG_TAG, "[CdmaCallTracker] " + msg); + } + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java new file mode 100644 index 0000000..cdad4a7 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java @@ -0,0 +1,705 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma; + +import com.android.internal.telephony.*; +import android.content.Context; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.PowerManager; +import android.os.Registrant; +import android.os.SystemClock; +import android.util.Config; +import android.util.Log; +import android.telephony.PhoneNumberUtils; +import android.telephony.ServiceState; + + +/** + * {@hide} + */ +public class CdmaConnection extends Connection { + static final String LOG_TAG = "CDMA"; + + //***** Instance Variables + + CdmaCallTracker owner; + CdmaCall parent; + + + String address; // MAY BE NULL!!! + String dialString; // outgoing calls only + String postDialString; // outgoing calls only + boolean isIncoming; + boolean disconnected; + + int index; // index in CdmaCallTracker.connections[], -1 if unassigned + + /* + * These time/timespan values are based on System.currentTimeMillis(), + * i.e., "wall clock" time. + */ + long createTime; + long connectTime; + long disconnectTime; + + /* + * These time/timespan values are based on SystemClock.elapsedRealTime(), + * i.e., time since boot. They are appropriate for comparison and + * calculating deltas. + */ + long connectTimeReal; + long duration; + long holdingStartTime; // The time when the Connection last transitioned + // into HOLDING + + int nextPostDialChar; // index into postDialString + + DisconnectCause cause = DisconnectCause.NOT_DISCONNECTED; + PostDialState postDialState = PostDialState.NOT_STARTED; + int numberPresentation = Connection.PRESENTATION_ALLOWED; + + Handler h; + + private PowerManager.WakeLock mPartialWakeLock; + + //***** Event Constants + static final int EVENT_DTMF_DONE = 1; + 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; + + //***** Inner Classes + + class MyHandler extends Handler { + MyHandler(Looper l) {super(l);} + + public void + handleMessage(Message msg) { + + switch (msg.what) { + case EVENT_NEXT_POST_DIAL: + case EVENT_DTMF_DONE: + case EVENT_PAUSE_DONE: + processNextPostDialChar(); + break; + case EVENT_WAKE_LOCK_TIMEOUT: + releaseWakeLock(); + break; + } + } + } + + //***** Constructors + + /** This is probably an MT call that we first saw in a CLCC response */ + /*package*/ + CdmaConnection (Context context, DriverCall dc, CdmaCallTracker ct, int index) { + createWakeLock(context); + acquireWakeLock(); + + owner = ct; + h = new MyHandler(owner.getLooper()); + + address = dc.number; + + isIncoming = dc.isMT; + createTime = System.currentTimeMillis(); + numberPresentation = dc.numberPresentation; + + this.index = index; + + parent = parentFromDCState (dc.state); + parent.attach(this, dc); + } + + /** This is an MO call, created when dialing */ + /*package*/ + CdmaConnection (Context context, String dialString, CdmaCallTracker ct, CdmaCall parent) { + createWakeLock(context); + acquireWakeLock(); + + owner = ct; + h = new MyHandler(owner.getLooper()); + + this.dialString = dialString; + + this.address = PhoneNumberUtils.extractNetworkPortion(dialString); + this.postDialString = PhoneNumberUtils.extractPostDialPortion(dialString); + + index = -1; + + isIncoming = false; + createTime = System.currentTimeMillis(); + + this.parent = parent; + parent.attachFake(this, CdmaCall.State.DIALING); + } + + public void dispose() { + } + + static boolean + equalsHandlesNulls (Object a, Object b) { + return (a == null) ? (b == null) : a.equals (b); + } + + /*package*/ boolean + compareTo(DriverCall c) { + // On mobile originated (MO) calls, the phone number may have changed + // due to a SIM Toolkit call control modification. + // + // We assume we know when MO calls are created (since we created them) + // and therefore don't need to compare the phone number anyway. + if (! (isIncoming || c.isMT)) return true; + + // ... but we can compare phone numbers on MT calls, and we have + // no control over when they begin, so we might as well + + String cAddress = PhoneNumberUtils.stringFromStringAndTOA(c.number, c.TOA); + return isIncoming == c.isMT && equalsHandlesNulls(address, cAddress); + } + + public String + toString() { + return (isIncoming ? "incoming" : "outgoing"); + } + + public String getAddress() { + return address; + } + + public CdmaCall getCall() { + return parent; + } + + public long getCreateTime() { + return createTime; + } + + public long getConnectTime() { + return connectTime; + } + + public long getDisconnectTime() { + return disconnectTime; + } + + public long getDurationMillis() { + if (connectTimeReal == 0) { + return 0; + } else if (duration == 0) { + return SystemClock.elapsedRealtime() - connectTimeReal; + } else { + return duration; + } + } + + public long getHoldDurationMillis() { + if (getState() != CdmaCall.State.HOLDING) { + // If not holding, return 0 + return 0; + } else { + return SystemClock.elapsedRealtime() - holdingStartTime; + } + } + + public DisconnectCause getDisconnectCause() { + return cause; + } + + public boolean isIncoming() { + return isIncoming; + } + + public CdmaCall.State getState() { + if (disconnected) { + return CdmaCall.State.DISCONNECTED; + } else { + return super.getState(); + } + } + + public void hangup() throws CallStateException { + if (!disconnected) { + owner.hangup(this); + } else { + throw new CallStateException ("disconnected"); + } + } + + public void separate() throws CallStateException { + if (!disconnected) { + owner.separate(this); + } else { + throw new CallStateException ("disconnected"); + } + } + + public PostDialState getPostDialState() { + return postDialState; + } + + public void proceedAfterWaitChar() { + if (postDialState != PostDialState.WAIT) { + Log.w(LOG_TAG, "CdmaConnection.proceedAfterWaitChar(): Expected " + + "getPostDialState() to be WAIT but was " + postDialState); + return; + } + + setPostDialState(PostDialState.STARTED); + + processNextPostDialChar(); + } + + public void proceedAfterWildChar(String str) { + if (postDialState != PostDialState.WILD) { + Log.w(LOG_TAG, "CdmaConnection.proceedAfterWaitChar(): Expected " + + "getPostDialState() to be WILD but was " + postDialState); + return; + } + + setPostDialState(PostDialState.STARTED); + + if (false) { + boolean playedTone = false; + int len = (str != null ? str.length() : 0); + + for (int i=0; i<len; i++) { + char c = str.charAt(i); + Message msg = null; + + if (i == len-1) { + msg = h.obtainMessage(EVENT_DTMF_DONE); + } + + if (PhoneNumberUtils.is12Key(c)) { + owner.cm.sendDtmf(c, msg); + playedTone = true; + } + } + + if (!playedTone) { + processNextPostDialChar(); + } + } else { + // make a new postDialString, with the wild char replacement string + // at the beginning, followed by the remaining postDialString. + + StringBuilder buf = new StringBuilder(str); + buf.append(postDialString.substring(nextPostDialChar)); + postDialString = buf.toString(); + nextPostDialChar = 0; + if (Phone.DEBUG_PHONE) { + log("proceedAfterWildChar: new postDialString is " + + postDialString); + } + + processNextPostDialChar(); + } + } + + public void cancelPostDial() { + setPostDialState(PostDialState.CANCELLED); + } + + /** + * Called when this Connection is being hung up locally (eg, user pressed "end") + * Note that at this point, the hangup request has been dispatched to the radio + * but no response has yet been received so update() has not yet been called + */ + void + onHangupLocal() { + cause = DisconnectCause.LOCAL; + } + + DisconnectCause + disconnectCauseFromCode(int causeCode) { + /** + * See 22.001 Annex F.4 for mapping of cause codes + * to local tones + */ + + switch (causeCode) { + case CallFailCause.USER_BUSY: + return DisconnectCause.BUSY; + case CallFailCause.ERROR_UNSPECIFIED: + case CallFailCause.NORMAL_CLEARING: + default: + CDMAPhone phone = owner.phone; + int serviceState = phone.getServiceState().getState(); + if (serviceState == ServiceState.STATE_POWER_OFF) { + return DisconnectCause.POWER_OFF; + } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE + || 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) { + return DisconnectCause.ICC_ERROR; + } else { + return DisconnectCause.NORMAL; + } + } + } + + /*package*/ void + onRemoteDisconnect(int causeCode) { + onDisconnect(disconnectCauseFromCode(causeCode)); + } + + /** Called when the radio indicates the connection has been disconnected */ + /*package*/ void + onDisconnect(DisconnectCause cause) { + this.cause = cause; + + if (!disconnected) { + index = -1; + + disconnectTime = System.currentTimeMillis(); + duration = SystemClock.elapsedRealtime() - connectTimeReal; + disconnected = true; + + if (Config.LOGD) Log.d(LOG_TAG, + "[CDMAConn] onDisconnect: cause=" + cause); + + owner.phone.notifyDisconnect(this); + + if (parent != null) { + parent.connectionDisconnected(this); + } + } + releaseWakeLock(); + } + + // Returns true if state has changed, false if nothing changed + /*package*/ boolean + update (DriverCall dc) { + CdmaCall newParent; + boolean changed = false; + boolean wasConnectingInOrOut = isConnectingInOrOut(); + boolean wasHolding = (getState() == CdmaCall.State.HOLDING); + + newParent = parentFromDCState(dc.state); + + if (!equalsHandlesNulls(address, dc.number)) { + if (Phone.DEBUG_PHONE) log("update: phone # changed!"); + address = dc.number; + changed = true; + } + + if (newParent != parent) { + if (parent != null) { + parent.detach(this); + } + newParent.attach(this, dc); + parent = newParent; + changed = true; + } else { + boolean parentStateChange; + parentStateChange = parent.update (this, dc); + changed = changed || parentStateChange; + } + + /** Some state-transition events */ + + if (Phone.DEBUG_PHONE) log( + "update: parent=" + parent + + ", hasNewParent=" + (newParent != parent) + + ", wasConnectingInOrOut=" + wasConnectingInOrOut + + ", wasHolding=" + wasHolding + + ", isConnectingInOrOut=" + isConnectingInOrOut() + + ", changed=" + changed); + + + if (wasConnectingInOrOut && !isConnectingInOrOut()) { + onConnectedInOrOut(); + } + + if (changed && !wasHolding && (getState() == CdmaCall.State.HOLDING)) { + // We've transitioned into HOLDING + onStartedHolding(); + } + + return changed; + } + + /** + * Called when this Connection is in the foregroundCall + * when a dial is initiated. + * We know we're ACTIVE, and we know we're going to end up + * HOLDING in the backgroundCall + */ + void + fakeHoldBeforeDial() { + if (parent != null) { + parent.detach(this); + } + + parent = owner.backgroundCall; + parent.attachFake(this, CdmaCall.State.HOLDING); + + onStartedHolding(); + } + + /*package*/ int + getCDMAIndex() throws CallStateException { + if (index >= 0) { + return index + 1; + } else { + throw new CallStateException ("CDMA connection index not assigned"); + } + } + + /** + * An incoming or outgoing call has connected + */ + void + onConnectedInOrOut() { + connectTime = System.currentTimeMillis(); + connectTimeReal = SystemClock.elapsedRealtime(); + duration = 0; + + // bug #678474: incoming call interpreted as missed call, even though + // it sounds like the user has picked up the call. + if (Phone.DEBUG_PHONE) { + log("onConnectedInOrOut: connectTime=" + connectTime); + } + + if (!isIncoming) { + // outgoing calls only + processNextPostDialChar(); + } + releaseWakeLock(); + } + + private void + onStartedHolding() { + holdingStartTime = SystemClock.elapsedRealtime(); + } + /** + * Performs the appropriate action for a post-dial char, but does not + * notify application. returns false if the character is invalid and + * should be ignored + */ + private boolean + processPostDialChar(char c) { + 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...." + + 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), + PAUSE_DELAY_MILLIS); + } + } else if (c == PhoneNumberUtils.WAIT) { + setPostDialState(PostDialState.WAIT); + } else if (c == PhoneNumberUtils.WILD) { + setPostDialState(PostDialState.WILD); + } else { + return false; + } + + return true; + } + + public String + getRemainingPostDialString() { + if (postDialState == PostDialState.CANCELLED + || postDialState == PostDialState.COMPLETE + || postDialString == null + || postDialString.length() <= nextPostDialChar + ) { + return ""; + } + + return postDialString.substring(nextPostDialChar); + } + + @Override + protected void finalize() + { + /** + * It is understood that This finializer is not guaranteed + * to be called and the release lock call is here just in + * case there is some path that doesn't call onDisconnect + * and or onConnectedInOrOut. + */ + if (mPartialWakeLock.isHeld()) { + Log.e(LOG_TAG, "[CdmaConn] UNEXPECTED; mPartialWakeLock is held when finalizing."); + } + releaseWakeLock(); + } + + private void + processNextPostDialChar() { + char c = 0; + Registrant postDialHandler; + + if (postDialState == PostDialState.CANCELLED) { + //Log.v("CDMA", "##### processNextPostDialChar: postDialState == CANCELLED, bail"); + return; + } + + if (postDialString == null || + postDialString.length() <= nextPostDialChar) { + setPostDialState(PostDialState.COMPLETE); + + // notifyMessage.arg1 is 0 on complete + c = 0; + } else { + boolean isValid; + + setPostDialState(PostDialState.STARTED); + + c = postDialString.charAt(nextPostDialChar++); + + isValid = processPostDialChar(c); + + if (!isValid) { + // Will call processNextPostDialChar + h.obtainMessage(EVENT_NEXT_POST_DIAL).sendToTarget(); + // Don't notify application + Log.e("CDMA", "processNextPostDialChar: c=" + c + " isn't valid!"); + return; + } + } + + postDialHandler = owner.phone.mPostDialHandler; + + Message notifyMessage; + + if (postDialHandler != null && + (notifyMessage = postDialHandler.messageForRegistrant()) != null) { + // The AsyncResult.result is the Connection object + PostDialState state = postDialState; + AsyncResult ar = AsyncResult.forMessage(notifyMessage); + ar.result = this; + ar.userObj = state; + + // arg1 is the character that was/is being processed + notifyMessage.arg1 = c; + + notifyMessage.sendToTarget(); + } + } + + + /** "connecting" means "has never been ACTIVE" for both incoming + * and outgoing calls + */ + private boolean + isConnectingInOrOut() { + return parent == null || parent == owner.ringingCall + || parent.state == CdmaCall.State.DIALING + || parent.state == CdmaCall.State.ALERTING; + } + + private CdmaCall + parentFromDCState (DriverCall.State state) { + switch (state) { + case ACTIVE: + case DIALING: + case ALERTING: + return owner.foregroundCall; + //break; + + case HOLDING: + return owner.backgroundCall; + //break; + + case INCOMING: + case WAITING: + return owner.ringingCall; + //break; + + default: + throw new RuntimeException("illegal call state: " + state); + } + } + + /** + * 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 + && s == PostDialState.STARTED) { + acquireWakeLock(); + Message msg = h.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT); + h.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT_MILLIS); + } else if (postDialState == PostDialState.STARTED + && s != PostDialState.STARTED) { + 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"); + mPartialWakeLock.acquire(); + } + + private void + releaseWakeLock() { + synchronized(mPartialWakeLock) { + if (mPartialWakeLock.isHeld()) { + log("releaseWakeLock"); + mPartialWakeLock.release(); + } + } + } + + private void log(String msg) { + Log.d(LOG_TAG, "[CDMAConn] " + msg); + } + + @Override + public int getNumberPresentation() { + return numberPresentation; + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java new file mode 100644 index 0000000..2cbad78 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma; + +import android.os.*; +import android.util.EventLog; +import android.util.Log; + +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.DataConnection; +import com.android.internal.telephony.DataLink; +import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.TelephonyEventLog; + +/** + * {@hide} + * + */ +public class CdmaDataConnection extends DataConnection { + + private static final String LOG_TAG = "CDMA"; + private static final boolean DBG = true; + + /** Fail cause of last Data Call activate from RIL_LastDataCallActivateFailCause */ + private final static int PS_NET_DOWN_REASON_OPERATOR_DETERMINED_BARRING = 8; + private final static int PS_NET_DOWN_REASON_UNKNOWN_APN = 27; + private final static int PS_NET_DOWN_REASON_AUTH_FAILED = 29; + private final static int PS_NET_DOWN_REASON_OPTION_NOT_SUPPORTED = 32; + private final static int PS_NET_DOWN_REASON_OPTION_UNSUBSCRIBED = 33; + +/** It is likely that the number of error codes listed below will be removed + * in the foreseeable future. They have been added, but not agreed upon. + * + */ + private final static int PS_NET_DOWN_REASON_NOT_SPECIFIED = 0; + private final static int PS_NET_DOWN_REASON_CLOSE_IN_PROGRESS = 1; + private final static int PS_NET_DOWN_REASON_NW_INITIATED_TERMINATION = 2; + private final static int PS_NET_DOWN_REASON_APP_PREEMPTED = 3; + private final static int PS_NET_DOWN_REASON_LLC_SNDCP_FAILURE = 25; + private final static int PS_NET_DOWN_REASON_INSUFFICIENT_RESOURCES = 26; + private final static int PS_NET_DOWN_REASON_UNKNOWN_PDP = 28; + private final static int PS_NET_DOWN_REASON_GGSN_REJECT = 30; + private final static int PS_NET_DOWN_REASON_ACTIVATION_REJECT = 31; + private final static int PS_NET_DOWN_REASON_OPTION_TEMP_OOO = 34; + private final static int PS_NET_DOWN_REASON_NSAPI_ALREADY_USED = 35; + private final static int PS_NET_DOWN_REASON_REGULAR_DEACTIVATION = 36; + private final static int PS_NET_DOWN_REASON_QOS_NOT_ACCEPTED = 37; + private final static int PS_NET_DOWN_REASON_NETWORK_FAILURE = 38; + private final static int PS_NET_DOWN_REASON_UMTS_REATTACH_REQ = 39; + private final static int PS_NET_DOWN_REASON_TFT_SEMANTIC_ERROR = 41; + private final static int PS_NET_DOWN_REASON_TFT_SYNTAX_ERROR = 42; + private final static int PS_NET_DOWN_REASON_UNKNOWN_PDP_CONTEXT = 43; + private final static int PS_NET_DOWN_REASON_FILTER_SEMANTIC_ERROR = 44; + private final static int PS_NET_DOWN_REASON_FILTER_SYNTAX_ERROR = 45; + private final static int PS_NET_DOWN_REASON_PDP_WITHOUT_ACTIVE_TFT = 46; + private final static int PS_NET_DOWN_REASON_INVALID_TRANSACTION_ID = 81; + private final static int PS_NET_DOWN_REASON_MESSAGE_INCORRECT_SEMANTIC = 95; + private final static int PS_NET_DOWN_REASON_INVALID_MANDATORY_INFO = 96; + private final static int PS_NET_DOWN_REASON_MESSAGE_TYPE_UNSUPPORTED = 97; + private final static int PS_NET_DOWN_REASON_MSG_TYPE_NONCOMPATIBLE_STATE = 98; + private final static int PS_NET_DOWN_REASON_UNKNOWN_INFO_ELEMENT = 99; + private final static int PS_NET_DOWN_REASON_CONDITIONAL_IE_ERROR = 100; + private final static int PS_NET_DOWN_REASON_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 101; + private final static int PS_NET_DOWN_REASON_PROTOCOL_ERROR = 111; + private final static int PS_NET_DOWN_REASON_APN_TYPE_CONFLICT = 112; + private final static int PS_NET_DOWN_REASON_UNKNOWN_CAUSE_CODE = 113; + private final static int PS_NET_DOWN_REASON_INTERNAL_MIN = 200; + private final static int PS_NET_DOWN_REASON_INTERNAL_ERROR = 201; + private final static int PS_NET_DOWN_REASON_INTERNAL_CALL_ENDED = 202; + private final static int PS_NET_DOWN_REASON_INTERNAL_UNKNOWN_CAUSE_CODE = 203; + private final static int PS_NET_DOWN_REASON_INTERNAL_MAX = 204; + private final static int PS_NET_DOWN_REASON_CDMA_LOCK = 500; + private final static int PS_NET_DOWN_REASON_INTERCEPT = 501; + private final static int PS_NET_DOWN_REASON_REORDER = 502; + private final static int PS_NET_DOWN_REASON_REL_SO_REJ = 503; + private final static int PS_NET_DOWN_REASON_INCOM_CALL = 504; + private final static int PS_NET_DOWN_REASON_ALERT_STOP = 505; + private final static int PS_NET_DOWN_REASON_ACTIVATION = 506; + private final static int PS_NET_DOWN_REASON_MAX_ACCESS_PROBE = 507; + private final static int PS_NET_DOWN_REASON_CCS_NOT_SUPPORTED_BY_BS = 508; + private final static int PS_NET_DOWN_REASON_NO_RESPONSE_FROM_BS = 509; + private final static int PS_NET_DOWN_REASON_REJECTED_BY_BS = 510; + private final static int PS_NET_DOWN_REASON_INCOMPATIBLE = 511; + private final static int PS_NET_DOWN_REASON_ALREADY_IN_TC = 512; + private final static int PS_NET_DOWN_REASON_USER_CALL_ORIG_DURING_GPS = 513; + private final static int PS_NET_DOWN_REASON_USER_CALL_ORIG_DURING_SMS = 514; + private final static int PS_NET_DOWN_REASON_NO_CDMA_SRV = 515; + private final static int PS_NET_DOWN_REASON_CONF_FAILED = 1000; + private final static int PS_NET_DOWN_REASON_INCOM_REJ = 1001; + private final static int PS_NET_DOWN_REASON_NO_GW_SRV = 1002; + private final static int PS_NET_DOWN_REASON_CD_GEN_OR_BUSY = 1500; + private final static int PS_NET_DOWN_REASON_CD_BILL_OR_AUTH = 1501; + private final static int PS_NET_DOWN_REASON_CHG_HDR = 1502; + private final static int PS_NET_DOWN_REASON_EXIT_HDR = 1503; + private final static int PS_NET_DOWN_REASON_HDR_NO_SESSION = 1504; + private final static int PS_NET_DOWN_REASON_HDR_ORIG_DURING_GPS_FIX = 1505; + private final static int PS_NET_DOWN_REASON_HDR_CS_TIMEOUT = 1506; + private final static int PS_NET_DOWN_REASON_HDR_RELEASED_BY_CM = 1507; + private final static int PS_NET_DOWN_REASON_CLIENT_END = 2000; + private final static int PS_NET_DOWN_REASON_NO_SRV = 2001; + private final static int PS_NET_DOWN_REASON_FADE = 2002; + private final static int PS_NET_DOWN_REASON_REL_NORMAL = 2003; + private final static int PS_NET_DOWN_REASON_ACC_IN_PROG = 2004; + private final static int PS_NET_DOWN_REASON_ACC_FAIL = 2005; + private final static int PS_NET_DOWN_REASON_REDIR_OR_HANDOFF = 2006; + + // ***** Instance Variables + + // ***** Constructor + CdmaDataConnection(CDMAPhone phone) { + super(phone); + + if (DBG) log("CdmaDataConnection <constructor>"); + } + + /** + * Setup a data connection + * + * @param onCompleted + * notify success or not after down + */ + void connect(Message onCompleted) { + if (DBG) log("CdmaDataConnection Connecting..."); + + state = State.ACTIVATING; + onConnectCompleted = onCompleted; + createTime = -1; + lastFailTime = -1; + lastFailCause = FailCause.NONE; + receivedDisconnectReq = false; + phone.mCM.setupDataCall(Integer.toString(RILConstants.CDMA_PHONE), null, null, null, + null, obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE)); + } + + 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)); + } + } else if (state == State.ACTIVATING) { + receivedDisconnectReq = true; + } else { + // state == INACTIVE. Nothing to do, so notify immediately. + notifyDisconnect(msg); + } + } + + + public String toString() { + return "State=" + state + " create=" + createTime + " lastFail=" + + lastFailTime + " lastFailCause=" + lastFailCause; + } + + + protected void notifyFail(FailCause cause, Message onCompleted) { + if (onCompleted == null) { + return; + } + state = State.INACTIVE; + lastFailCause = cause; + lastFailTime = System.currentTimeMillis(); + onConnectCompleted = null; + + if(DBG) { + log("Notify data connection fail at " + lastFailTime + + " due to " + lastFailCause); + } + + AsyncResult.forMessage(onCompleted, cause, new Exception()); + onCompleted.sendToTarget(); + } + + protected void notifySuccess(Message onCompleted) { + if (onCompleted == null) { + return; + } + + state = State.ACTIVE; + createTime = System.currentTimeMillis(); + onConnectCompleted = null; + onCompleted.arg1 = cid; + + if (DBG) log("Notify data connection success at " + createTime); + + AsyncResult.forMessage(onCompleted); + onCompleted.sendToTarget(); + } + + protected void notifyDisconnect(Message msg) { + if (DBG) log("Notify data connection disconnect"); + + if (msg != null) { + AsyncResult.forMessage(msg); + msg.sendToTarget(); + } + clearSettings(); + } + + protected void onLinkStateChanged(DataLink.LinkState linkState) { + switch (linkState) { + case LINK_UP: + notifySuccess(onConnectCompleted); + break; + + case LINK_DOWN: + case LINK_EXITED: + phone.mCM.getLastDataCallFailCause(obtainMessage(EVENT_GET_LAST_FAIL_DONE)); + break; + } + } + + protected FailCause getFailCauseFromRequest(int rilCause) { + FailCause cause; + + switch (rilCause) { + case PS_NET_DOWN_REASON_OPERATOR_DETERMINED_BARRING: + cause = FailCause.BARRED; + break; + case PS_NET_DOWN_REASON_AUTH_FAILED: + cause = FailCause.USER_AUTHENTICATION; + break; + case PS_NET_DOWN_REASON_OPTION_NOT_SUPPORTED: + cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED; + break; + case PS_NET_DOWN_REASON_OPTION_UNSUBSCRIBED: + cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED; + break; + default: + cause = FailCause.UNKNOWN; + } + return cause; + } + + protected void log(String s) { + Log.d(LOG_TAG, "[CdmaDataConnection] " + s); + } + + @Override + protected void onDeactivated(AsyncResult ar) { + notifyDisconnect((Message) ar.userObj); + if (DBG) log("CDMA Connection Deactivated"); + } + + @Override + protected void onSetupConnectionCompleted(AsyncResult ar) { + if (ar.exception != null) { + Log.e(LOG_TAG, "CdmaDataConnection Init failed " + ar.exception); + + if (receivedDisconnectReq) { + // Don't bother reporting the error if there's already a + // pending disconnect request, since DataConnectionTracker + // has already updated its state. + notifyDisconnect(onDisconnect); + } else { + if (ar.exception instanceof CommandException + && ((CommandException) (ar.exception)).getCommandError() + == CommandException.Error.RADIO_NOT_AVAILABLE) { + notifyFail(FailCause.RADIO_NOT_AVAILABLE, onConnectCompleted); + } else { + phone.mCM.getLastDataCallFailCause(obtainMessage(EVENT_GET_LAST_FAIL_DONE)); + } + } + } else { + if (receivedDisconnectReq) { + // Don't bother reporting success if there's already a + // pending disconnect request, since DataConnectionTracker + // has already updated its state. + disconnect(onDisconnect); + } else { + String[] response = ((String[]) ar.result); + cid = Integer.parseInt(response[0]); + + if (response.length > 2) { + interfaceName = response[1]; + ipAddress = response[2]; + String prefix = "net." + interfaceName + "."; + gatewayAddress = SystemProperties.get(prefix + "gw"); + dnsServers[0] = SystemProperties.get(prefix + "dns1"); + dnsServers[1] = SystemProperties.get(prefix + "dns2"); + if (DBG) { + log("interface=" + interfaceName + " ipAddress=" + ipAddress + + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0] + + " DNS2=" + dnsServers[1]); + } + + if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1]) + && !((CDMAPhone) phone).isDnsCheckDisabled()) { + // Work around a race condition where QMI does not fill in DNS: + // Deactivate PDP and let DataConnectionTracker retry. + EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS, + dnsServers[0]); + phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_FORCE_RETRY)); + return; + } + } + + onLinkStateChanged(DataLink.LinkState.LINK_UP); + + if (DBG) log("CdmaDataConnection setup on cid = " + cid); + } + } + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java new file mode 100644 index 0000000..84febf3 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java @@ -0,0 +1,929 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.net.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.text.TextUtils; +import android.util.Log; + +import com.android.internal.telephony.CommandsInterface; +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 { + private static final String LOG_TAG = "CDMA"; + private static final boolean DBG = true; + + //***** Instance Variables + + // Indicates baseband will not auto-attach + private boolean noAutoAttach = false; + long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + private boolean mIsScreenOn = true; + + //useful for debugging + boolean failNextConnect = false; + + /** + * dataConnectionList holds all the Data connection + */ + private ArrayList<DataConnection> dataConnectionList; + + /** Currently active CdmaDataConnection */ + private CdmaDataConnection mActiveDataConnection; + + /** Defined cdma connection profiles */ + private static int EXTERNAL_NETWORK_DEFAULT_ID = 0; + private static int EXTERNAL_NETWORK_NUM_TYPES = 1; + + private boolean[] dataEnabled = new boolean[EXTERNAL_NETWORK_NUM_TYPES]; + + //***** Constants + + /** + * Pool size of CdmaDataConnection objects. + */ + private static final int DATA_CONNECTION_POOL_SIZE = 1; + + private static final int POLL_CONNECTION_MILLIS = 5 * 1000; + private static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.cdma-reconnect"; + private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason"; + + // 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. + BroadcastReceiver mIntentReceiver = new BroadcastReceiver () + { + @Override + public void onReceive(Context context, Intent intent) + { + String action = intent.getAction(); + if (action.equals(Intent.ACTION_SCREEN_ON)) { + mIsScreenOn = true; + stopNetStatPoll(); + startNetStatPoll(); + } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { + mIsScreenOn = false; + stopNetStatPoll(); + startNetStatPoll(); + } else if (action.equals((INTENT_RECONNECT_ALARM))) { + Log.d(LOG_TAG, "Data reconnect alarm. Previous state was " + state); + + String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON); + if (state == State.FAILED) { + cleanUpConnection(false, reason); + } + trySetupData(reason); + } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { + final android.net.NetworkInfo networkInfo = (NetworkInfo) + intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); + mIsWifiConnected = (networkInfo != null && networkInfo.isConnected()); + } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { + final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, + WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; + + if (!enabled) { + // when wifi got disabeled, the NETWORK_STATE_CHANGED_ACTION + // quit and wont report disconnected til next enalbing. + mIsWifiConnected = false; + } + } + } + }; + + + //***** Constructor + + CdmaDataConnectionTracker(CDMAPhone p) { + super(p); + + p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); + p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + p.mRuimRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); + p.mCM.registerForNVReady(this, EVENT_NV_READY, null); + p.mCM.registerForDataStateChanged (this, EVENT_DATA_STATE_CHANGED, null); + p.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null); + p.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null); + p.mSST.registerForCdmaDataConnectionAttached(this, EVENT_TRY_SETUP_DATA, null); + p.mSST.registerForCdmaDataConnectionDetached(this, EVENT_CDMA_DATA_DETACHED, null); + p.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null); + p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null); + + this.netstat = INetStatService.Stub.asInterface(ServiceManager.getService("netstat")); + + IntentFilter filter = new IntentFilter(); + filter.addAction(INTENT_RECONNECT_ALARM); + filter.addAction(Intent.ACTION_SCREEN_ON); + filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + + p.getContext().registerReceiver(mIntentReceiver, filter, null, p.h); + + mDataConnectionTracker = this; + + createAllDataConnectionList(); + + // This preference tells us 1) initial condition for "dataEnabled", + // and 2) whether the RIL will setup the baseband to auto-PS attach. + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext()); + + dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID] = + !sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false); + noAutoAttach = !dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID]; + } + + public void dispose() { + //Unregister from all events + phone.mCM.unregisterForAvailable(this); + phone.mCM.unregisterForOffOrNotAvailable(this); + ((CDMAPhone) phone).mRuimRecords.unregisterForRecordsLoaded(this); + phone.mCM.unregisterForNVReady(this); + phone.mCM.unregisterForDataStateChanged(this); + ((CDMAPhone) phone).mCT.unregisterForVoiceCallEnded(this); + ((CDMAPhone) phone).mCT.unregisterForVoiceCallStarted(this); + ((CDMAPhone) phone).mSST.unregisterForCdmaDataConnectionAttached(this); + ((CDMAPhone) phone).mSST.unregisterForCdmaDataConnectionDetached(this); + ((CDMAPhone) phone).mSST.unregisterForRoamingOn(this); + ((CDMAPhone) phone).mSST.unregisterForRoamingOff(this); + + phone.getContext().unregisterReceiver(this.mIntentReceiver); + destroyAllDataConnectionList(); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "CdmaDataConnectionTracker finalized"); + } + + void setState(State s) { + if (DBG) log ("setState: " + s); + if (state != s) { + if (s == State.INITING) { // request Data connection context + Checkin.updateStats(phone.getContext().getContentResolver(), + Checkin.Stats.Tag.PHONE_CDMA_DATA_ATTEMPTED, 1, 0.0); + } + + if (s == State.CONNECTED) { // pppd is up + Checkin.updateStats(phone.getContext().getContentResolver(), + Checkin.Stats.Tag.PHONE_CDMA_DATA_CONNECTED, 1, 0.0); + } + } + + state = s; + } + + public int enableApnType(String type) { + // This request is mainly used to enable MMS APN + // In CDMA there is no need to enable/disable a different APN for MMS + Log.d(LOG_TAG, "Request to enableApnType("+type+")"); + if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { + return Phone.APN_ALREADY_ACTIVE; + } else { + return Phone.APN_REQUEST_FAILED; + } + } + + public int disableApnType(String type) { + // This request is mainly used to disable MMS APN + // In CDMA there is no need to enable/disable a different APN for MMS + Log.d(LOG_TAG, "Request to disableApnType("+type+")"); + if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { + return Phone.APN_REQUEST_STARTED; + } else { + return Phone.APN_REQUEST_FAILED; + } + } + + private boolean isEnabled(int cdmaDataProfile) { + return dataEnabled[cdmaDataProfile]; + } + + private void setEnabled(int cdmaDataProfile, boolean enable) { + Log.d(LOG_TAG, "setEnabled(" + cdmaDataProfile + ", " + enable + ')'); + dataEnabled[cdmaDataProfile] = enable; + Log.d(LOG_TAG, "dataEnabled[DEFAULT_PROFILE]=" + dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID]); + } + + /** + * 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 + * 3. user doesn't explicitly disable data service + * 4. wifi is not on + * + * @return false while no data connection if all above requirements are met. + */ + public boolean isDataConnectionAsDesired() { + boolean roaming = phone.getServiceState().getRoaming(); + + if ( ((phone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) || + ((CDMAPhone) phone).mRuimRecords.getRecordsLoaded()) && + ((CDMAPhone) phone).mSST.getCurrentCdmaDataConnectionState() == + ServiceState.STATE_IN_SERVICE && + (!roaming || getDataOnRoamingEnabled()) && + !mIsWifiConnected ) { + return (state == State.CONNECTED); + } + return true; + } + + /** + * Prevent mobile data connections from being established, + * or once again allow mobile data connections. If the state + * toggles, then either tear down or set up data, as + * appropriate to match the new state. + * <p>This operation only affects the default connection + * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data + * @return {@code true} if the operation succeeded + */ + public boolean setDataEnabled(boolean enable) { + + boolean isEnabled = isEnabled(EXTERNAL_NETWORK_DEFAULT_ID); + + Log.d(LOG_TAG, "setDataEnabled("+enable+") isEnabled=" + isEnabled); + if (!isEnabled && enable) { + setEnabled(EXTERNAL_NETWORK_DEFAULT_ID, true); + return trySetupData(Phone.REASON_DATA_ENABLED); + } else if (!enable) { + setEnabled(EXTERNAL_NETWORK_DEFAULT_ID, false); + return false; + } else // isEnabled && enable + + return true; + } + + /** + * Report the current state of data connectivity (enabled or disabled) + * @return {@code false} if data connectivity has been explicitly disabled, + * {@code true} otherwise. + */ + public boolean getDataEnabled() { + return dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID]; + } + + /** + * Report on whether data connectivity is enabled + * @return {@code false} if data connectivity has been explicitly disabled, + * {@code true} otherwise. + */ + public boolean getAnyDataEnabled() { + for (int i=0; i < EXTERNAL_NETWORK_NUM_TYPES; i++) { + if (isEnabled(i)) return true; + } + return false; + } + + private boolean isDataAllowed() { + boolean roaming = phone.getServiceState().getRoaming(); + return getAnyDataEnabled() && (!roaming || getDataOnRoamingEnabled()); + } + + private boolean trySetupData(String reason) { + if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason)); + + if (phone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + // FIXME this can be improved + setState(State.CONNECTED); + phone.notifyDataConnection(reason); + + Log.i(LOG_TAG, "(fix?) We're on the simulator; assuming data is connected"); + return true; + } + + int psState = ((CDMAPhone) phone).mSST.getCurrentCdmaDataConnectionState(); + boolean roaming = phone.getServiceState().getRoaming(); + + if ((state == State.IDLE || state == State.SCANNING) + && (psState == ServiceState.RADIO_TECHNOLOGY_1xRTT || + psState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 || + psState == ServiceState.RADIO_TECHNOLOGY_EVDO_A) + && ((phone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) || + ((CDMAPhone) phone).mRuimRecords.getRecordsLoaded()) + && (((CDMAPhone) phone).mSST.isConcurrentVoiceAndData() || + phone.getState() == Phone.State.IDLE ) + && isDataAllowed()) { + + return setupData(reason); + + } else { + if (DBG) { + log("trySetupData: Not ready for data: " + + " dataState=" + state + + " PS state=" + psState + + " radio state=" + phone.mCM.getRadioState() + + " ruim=" + ((CDMAPhone) phone).mRuimRecords.getRecordsLoaded() + + " concurrentVoice&Data=" + ((CDMAPhone) phone).mSST.isConcurrentVoiceAndData() + + " phoneState=" + phone.getState() + + " dataEnabled=" + getAnyDataEnabled() + + " roaming=" + roaming + + " dataOnRoamingEnable=" + getDataOnRoamingEnabled()); + } + return false; + } + } + + /** + * If tearDown is true, this only tears down a CONNECTED session. Presently, + * there is no mechanism for abandoning an INITING/CONNECTING session, + * but would likely involve cancelling pending async requests or + * setting a flag or new state to ignore them when they came in + * @param tearDown true if the underlying DataConnection should be + * disconnected. + * @param reason reason for the clean up. + */ + private void cleanUpConnection(boolean tearDown, String reason) { + if (DBG) log("Clean up connection due to " + reason); + + // Clear the reconnect alarm, if set. + if (mReconnectIntent != null) { + AlarmManager am = + (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); + am.cancel(mReconnectIntent); + mReconnectIntent = null; + } + + for (DataConnection connBase : dataConnectionList) { + CdmaDataConnection conn = (CdmaDataConnection) connBase; + + if(conn != null) { + if (tearDown) { + Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason); + conn.disconnect(msg); + } else { + conn.clearSettings(); + } + } + } + + 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); + } + } + + private CdmaDataConnection findFreeDataConnection() { + for (DataConnection connBase : dataConnectionList) { + CdmaDataConnection conn = (CdmaDataConnection) connBase; + if (conn.getState() == DataConnection.State.INACTIVE) { + return conn; + } + } + return null; + } + + private boolean setupData(String reason) { + + CdmaDataConnection conn = findFreeDataConnection(); + + if (conn == null) { + if (DBG) log("setupData: No free CdmaDataConnectionfound!"); + return false; + } + + mActiveDataConnection = conn; + + Message msg = obtainMessage(); + msg.what = EVENT_DATA_SETUP_COMPLETE; + msg.obj = reason; + conn.connect(msg); + + setState(State.INITING); + phone.notifyDataConnection(reason); + return true; + } + + private void notifyDefaultData(String reason) { + setState(State.CONNECTED); + phone.notifyDataConnection(reason); + startNetStatPoll(); + // reset reconnect timer + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + } + + private void resetPollStats() { + txPkts = -1; + rxPkts = -1; + sentSinceLastRecv = 0; + netStatPollPeriod = POLL_NETSTAT_MILLIS; + mNoRecvPollCount = 0; + } + + protected void startNetStatPoll() { + if (state == State.CONNECTED && netStatPollEnabled == false) { + Log.d(LOG_TAG, "[DataConnection] Start poll NetStat"); + resetPollStats(); + netStatPollEnabled = true; + mPollNetStat.run(); + } + } + + protected void stopNetStatPoll() { + netStatPollEnabled = false; + removeCallbacks(mPollNetStat); + Log.d(LOG_TAG, "[DataConnection] Stop poll NetStat"); + } + + protected void restartRadio() { + Log.d(LOG_TAG, "************TURN OFF RADIO**************"); + cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); + phone.mCM.setRadioPower(false, null); + /* Note: no need to call setRadioPower(true). Assuming the desired + * radio power state is still ON (as tracked by ServiceStateTracker), + * ServiceStateTracker will call setRadioPower when it receives the + * RADIO_STATE_CHANGED notification for the power off. And if the + * desired power state has changed in the interim, we don't want to + * override it with an unconditional power on. + */ + } + + private Runnable mPollNetStat = new Runnable() { + + public void run() { + long sent, received; + long preTxPkts = -1, preRxPkts = -1; + + Activity newActivity; + + preTxPkts = txPkts; + preRxPkts = rxPkts; + + // check if netstat is still valid to avoid NullPointerException after NTC + if (netstat != null) { + try { + txPkts = netstat.getMobileTxPackets(); + rxPkts = netstat.getMobileRxPackets(); + } catch (RemoteException e) { + txPkts = 0; + rxPkts = 0; + } + + //Log.d(LOG_TAG, "rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts)); + + if (netStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) { + sent = txPkts - preTxPkts; + received = rxPkts - preRxPkts; + + if ( sent > 0 && received > 0 ) { + sentSinceLastRecv = 0; + newActivity = Activity.DATAINANDOUT; + } else if (sent > 0 && received == 0) { + if (phone.getState() == Phone.State.IDLE) { + sentSinceLastRecv += sent; + } else { + sentSinceLastRecv = 0; + } + newActivity = Activity.DATAOUT; + } else if (sent == 0 && received > 0) { + sentSinceLastRecv = 0; + newActivity = Activity.DATAIN; + } else if (sent == 0 && received == 0) { + newActivity = Activity.NONE; + } else { + sentSinceLastRecv = 0; + newActivity = Activity.NONE; + } + + if (activity != newActivity) { + activity = newActivity; + phone.notifyDataActivity(); + } + } + + if (sentSinceLastRecv >= NUMBER_SENT_PACKETS_OF_HANG) { + // we already have NUMBER_SENT_PACKETS sent without ack + if (mNoRecvPollCount < NO_RECV_POLL_LIMIT) { + mNoRecvPollCount++; + // Slow down the poll interval to let things happen + netStatPollPeriod = POLL_NETSTAT_SLOW_MILLIS; + } else { + if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) + + " pkts since last received"); + // We've exceeded the threshold. Restart the radio. + netStatPollEnabled = false; + stopNetStatPoll(); + restartRadio(); + } + } else { + mNoRecvPollCount = 0; + netStatPollPeriod = POLL_NETSTAT_MILLIS; + } + + if (netStatPollEnabled) { + mDataConnectionTracker.postDelayed(this, netStatPollPeriod); + } + } + } + }; + + /** + * Returns true if the last fail cause is something that + * seems like it deserves an error notification. + * Transient errors are ignored + */ + private boolean + shouldPostNotification(FailCause cause) { + return (cause != FailCause.UNKNOWN); + } + + /** + * 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 + */ + private boolean retryAfterDisconnected(String reason) { + boolean retry = true; + + if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) || + Phone.REASON_DATA_DISABLED.equals(reason) ) { + retry = false; + } + return retry; + } + + private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) { + if (state == State.FAILED) { + Log.d(LOG_TAG, "Data Connection activate failed. Scheduling next attempt for " + + (nextReconnectDelay / 1000) + "s"); + + AlarmManager am = + (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); + Intent intent = new Intent(INTENT_RECONNECT_ALARM); + intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, reason); + mReconnectIntent = PendingIntent.getBroadcast( + phone.getContext(), 0, intent, 0); + am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + nextReconnectDelay, + mReconnectIntent); + + // 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 " + + "-- likely transient error"); + } else { + notifyNoData(lastFailCauseCode); + } + } + } + + private void notifyNoData(FailCause lastFailCauseCode) { + setState(State.FAILED); + } + + protected void onRecordsLoaded() { + if (state == State.FAILED) { + cleanUpConnection(false, null); + } + sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); + } + + protected void onNVReady() { + if (state == State.FAILED) { + cleanUpConnection(false, null); + } + sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onTrySetupData() { + trySetupData(null); + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onRoamingOff() { + trySetupData(Phone.REASON_ROAMING_OFF); + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onRoamingOn() { + if (getDataOnRoamingEnabled()) { + trySetupData(Phone.REASON_ROAMING_ON); + } else { + if (DBG) log("Tear down data connection on roaming."); + cleanUpConnection(true, Phone.REASON_ROAMING_ON); + } + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onRadioAvailable() { + if (phone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + // FIXME this can be improved + setState(State.CONNECTED); + phone.notifyDataConnection(null); + + Log.i(LOG_TAG, "We're on the simulator; assuming data is connected"); + } + + if (state != State.IDLE) { + cleanUpConnection(true, null); + } + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onRadioOffOrNotAvailable() { + // Make sure our reconnect delay starts at the initial value + // next time the radio comes on + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + + if (phone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + // FIXME this can be improved + Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless"); + } else { + if (DBG) log("Radio is off and clean up all connection"); + cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF); + } + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onDataSetupComplete(AsyncResult ar) { + String reason = null; + if (ar.userObj instanceof String) { + reason = (String) ar.userObj; + } + + if (ar.exception == null) { + // everything is setup + notifyDefaultData(reason); + } else { + FailCause cause = (FailCause) (ar.result); + if(DBG) log("Data Connection setup failed " + cause); + + // No try for permanent failure + if (cause.isPermanentFail()) { + notifyNoData(cause); + } + + if (tryAgain(cause)) { + trySetupData(reason); + } else { + startDelayedRetry(cause, reason); + } + } + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onDisconnectDone(AsyncResult ar) { + if(DBG) log("EVENT_DISCONNECT_DONE"); + String reason = null; + if (ar.userObj instanceof String) { + reason = (String) ar.userObj; + } + setState(State.IDLE); + phone.notifyDataConnection(reason); + if (retryAfterDisconnected(reason)) { + trySetupData(reason); + } + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onVoiceCallStarted() { + if (state == State.CONNECTED && !((CDMAPhone) phone).mSST.isConcurrentVoiceAndData()) { + stopNetStatPoll(); + phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); + } + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onVoiceCallEnded() { + if (state == State.CONNECTED) { + if (!((CDMAPhone) phone).mSST.isConcurrentVoiceAndData()) { + startNetStatPoll(); + phone.notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); + } else { + // clean slate after call end. + resetPollStats(); + } + } else { + // 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); + } + + private void createAllDataConnectionList() { + dataConnectionList = new ArrayList<DataConnection>(); + CdmaDataConnection dataConn; + + for (int i = 0; i < DATA_CONNECTION_POOL_SIZE; i++) { + dataConn = new CdmaDataConnection(((CDMAPhone) phone)); + dataConnectionList.add(dataConn); + } + } + + private void destroyAllDataConnectionList() { + if(dataConnectionList != null) { + CdmaDataConnection pdp; + dataConnectionList.removeAll(dataConnectionList); + } + } + + private void onCdmaDataAttached() { + if (state == State.CONNECTED) { + startNetStatPoll(); + phone.notifyDataConnection(Phone.REASON_CDMA_DATA_DETACHED); + } else { + if (state == State.FAILED) { + cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED); + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + } + trySetupData(Phone.REASON_CDMA_DATA_DETACHED); + } + } + + protected void onDataStateChanged (AsyncResult ar) { + if (ar.exception != null) { + // This is probably "radio not available" or something + // of that sort. If so, the whole connection is going + // to come down soon anyway + return; + } + + 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); + } + Log.i(LOG_TAG, "Data connection has changed."); + } + + String getInterfaceName() { + if (mActiveDataConnection != null) { + return mActiveDataConnection.getInterface(); + } + return null; + } + + protected String getIpAddress() { + if (mActiveDataConnection != null) { + return mActiveDataConnection.getIpAddress(); + } + return null; + } + + String getGateway() { + if (mActiveDataConnection != null) { + return mActiveDataConnection.getGatewayAddress(); + } + return null; + } + + protected String[] getDnsServers() { + if (mActiveDataConnection != null) { + return mActiveDataConnection.getDnsServers(); + } + return null; + } + + public ArrayList<DataConnection> getAllDataConnections() { + return dataConnectionList; + } + + private void startDelayedRetry(FailCause cause, String reason) { + notifyNoData(cause); + reconnectAfterFail(cause, reason); + } + + public void handleMessage (Message msg) { + + switch (msg.what) { + case EVENT_RECORDS_LOADED: + onRecordsLoaded(); + break; + + case EVENT_NV_READY: + onNVReady(); + break; + + case EVENT_CDMA_DATA_DETACHED: + onCdmaDataAttached(); + break; + + case EVENT_DATA_STATE_CHANGED: + onDataStateChanged((AsyncResult) msg.obj); + break; + + default: + // handle the message in the super class DataConnectionTracker + super.handleMessage(msg); + break; + } + } + + protected void log(String s) { + Log.d(LOG_TAG, "[CdmaDataConnectionTracker] " + s); + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java new file mode 100644 index 0000000..42c0583 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma; + + +import android.app.PendingIntent; +import android.content.ContentValues; +import android.database.Cursor; +import android.database.SQLException; +import android.os.AsyncResult; +import android.os.Message; +import android.util.Config; +import android.util.Log; + +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.util.HexDump; + +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.HashMap; + + +final class CdmaSMSDispatcher extends SMSDispatcher { + private static final String TAG = "CDMA"; + + CdmaSMSDispatcher(CDMAPhone phone) { + super(phone); + } + + /** + * Called when a status report is received. This should correspond to + * a previously successful SEND. + * Is a special GSM function, should never be called in CDMA!! + * + * @param ar AsyncResult passed into the message handler. ar.result should + * be a String representing the status report PDU, as ASCII hex. + */ + protected void handleStatusReport(AsyncResult ar) { + 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) { + + // If sms is null, means there was a parsing error. + // TODO: Should NAK this. + if (smsb == null) { + return; + } + SmsMessage sms = (SmsMessage) smsb; + int teleService; + boolean handled = false; + + // Decode BD stream and set sms variables. + 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); + } + } + } + + if (null == sms.getUserData()){ + handled = true; + if (Config.LOGD) { + Log.d(TAG, "Received SMS without user data"); + } + } + + if (handled) return; + + if (SmsEnvelope.TELESERVICE_WAP == teleService){ + processCdmaWapPdu(sms.getUserData(), sms.messageRef, sms.getOriginatingAddress()); + return; + } + + // 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 (referenceNumber == -1) { + // notify everyone of the message if it isn't partial + 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()); + } + // The message was sent to a port, so concoct a URI for it + dispatchPortAddressedPdus(pdus, destPort); + } else { + // It's a normal message, dispatch it + dispatchPdus(pdus); + } + } else { + // Process the message part + processMessagePart(sms, referenceNumber, sequence, count, destPort); + } + } + + /** + * Processes inbound messages that are in the WAP-WDP PDU format. See + * wap-259-wdp-20010614-a section 6.5 for details on the WAP-WDP PDU format. + * WDP segments are gathered until a datagram completes and gets dispatched. + * + * @param pdu The WAP-WDP PDU segment + */ + protected void processCdmaWapPdu(byte[] pdu, int referenceNumber, String address) { + int segment; + int totalSegments; + int index = 0; + int msgType; + + int sourcePort; + int destinationPort; + + msgType = pdu[index++]; + if (msgType != 0){ + Log.w(TAG, "Received a WAP SMS which is not WDP. Discard."); + return; + } + 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++]; + + // Lookup all other related parts + StringBuilder where = new StringBuilder("reference_number ="); + where.append(referenceNumber); + where.append(" AND address = ?"); + String[] whereArgs = new String[] {address}; + + Log.i(TAG, "Received WAP PDU. Type = " + msgType + ", originator = " + address + + ", src-port = " + sourcePort + ", dst-port = " + destinationPort + + ", ID = " + referenceNumber + ", segment# = " + segment + "/" + totalSegments); + + byte[][] pdus = null; + Cursor cursor = null; + try { + cursor = mResolver.query(mRawUri, RAW_PROJECTION, where.toString(), whereArgs, null); + int cursorCount = cursor.getCount(); + if (cursorCount != totalSegments - 1) { + // We don't have all the parts yet, store this one away + ContentValues values = new ContentValues(); + values.put("date", new Long(0)); + values.put("pdu", HexDump.toHexString(pdu, index, pdu.length - index)); + values.put("address", address); + values.put("reference_number", referenceNumber); + values.put("count", totalSegments); + values.put("sequence", segment); + values.put("destination_port", destinationPort); + + mResolver.insert(mRawUri, values); + + return; + } + + // All the parts are in place, deal with them + int pduColumn = cursor.getColumnIndex("pdu"); + int sequenceColumn = cursor.getColumnIndex("sequence"); + + pdus = new byte[totalSegments][]; + for (int i = 0; i < cursorCount; i++) { + cursor.moveToNext(); + int cursorSequence = (int)cursor.getLong(sequenceColumn); + pdus[cursorSequence] = HexDump.hexStringToByteArray( + cursor.getString(pduColumn)); + } + // The last part will be added later + + // 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. + } finally { + if (cursor != null) cursor.close(); + } + + // Build up the data stream + ByteArrayOutputStream output = new ByteArrayOutputStream(); + for (int i = 0; i < totalSegments-1; i++) { + // reassemble the (WSP-)pdu + output.write(pdus[i], 0, pdus[i].length); + } + + // This one isn't in the DB, so add it + output.write(pdu, index, pdu.length - index); + + byte[] datagram = output.toByteArray(); + // Dispatch the PDU to applications + switch (destinationPort) { + case SmsHeader.PORT_WAP_PUSH: + // Handle the PUSH + mWapPush.dispatchWapPdu(datagram); + break; + + default:{ + pdus = new byte[1][]; + pdus[0] = datagram; + // The messages were sent to any other WAP port + dispatchPortAddressedPdus(pdus, destinationPort); + break; + } + } + } + + /** {@inheritDoc} */ + 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 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 + + PendingIntent sentIntent = null; + PendingIntent deliveryIntent = null; + + if (sentIntents != null && sentIntents.size() > i) { + sentIntent = sentIntents.get(i); + } + if (deliveryIntents != null && deliveryIntents.size() > i) { + deliveryIntent = deliveryIntents.get(i); + } + + SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, + parts.get(i), deliveryIntent != null, data); + + sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); + } + } + + protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, + PendingIntent deliveryIntent) { + super.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); + } + + /** {@inheritDoc} */ + protected void sendSms(SmsTracker tracker) { + HashMap map = tracker.mData; + + byte smsc[] = (byte[]) map.get("smsc"); + byte pdu[] = (byte[]) map.get("pdu"); + + Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); + + mCm.sendCdmaSms(pdu, reply); + } + + /** {@inheritDoc} */ + protected void sendMultipartSms (SmsTracker tracker) { + Log.d(TAG, "TODO: CdmaSMSDispatcher.sendMultipartSms not implemented"); + } + + /** {@inheritDoc} */ + protected void acknowledgeLastIncomingSms(boolean success, Message response){ + // FIXME unit test leaves cm == null. this should change + if (mCm != null) { + mCm.acknowledgeLastIncomingCdmaSms(success, response); + } + } + + /** {@inheritDoc} */ + protected void activateCellBroadcastSms(int activate, Message response) { + mCm.activateCdmaBroadcastSms(activate, response); + } + + /** {@inheritDoc} */ + protected void getCellBroadcastSmsConfig(Message response) { + mCm.getCdmaBroadcastConfig(response); + } + + /** {@inheritDoc} */ + protected void setCellBroadcastConfig(int[] configValuesArray, Message response) { + mCm.setCdmaBroadcastConfig(configValuesArray, response); + } + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java new file mode 100644 index 0000000..ca40e76 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java @@ -0,0 +1,1016 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma; + +import android.app.AlarmManager; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.database.ContentObserver; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.Registrant; +import android.os.RegistrantList; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.provider.Checkin; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; +import android.provider.Telephony.Intents; +import android.telephony.ServiceState; +import android.telephony.cdma.CdmaCellLocation; +import android.text.TextUtils; +import android.util.EventLog; +import android.util.Log; +import android.util.TimeUtils; + +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.DataConnectionTracker; +// pretty sure importing stuff from GSM is bad: +import com.android.internal.telephony.gsm.MccTable; +import com.android.internal.telephony.PhoneProxy; +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_OPERATOR_ALPHA; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISMANUAL; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISROAMING; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_NUMERIC; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA; + +import java.util.Arrays; +import java.util.Date; +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_ + */ + private int networkType = 0; + private int newNetworkType = 0; + + private boolean mCdmaRoaming = false; + + private int cdmaDataConnectionState = -1;//Initial we assume no data connection + private int newCdmaDataConnectionState = -1;//Initial we assume no data connection + private int mRegistrationState = -1; + private RegistrantList cdmaDataConnectionAttachedRegistrants = new RegistrantList(); + private RegistrantList cdmaDataConnectionDetachedRegistrants = new RegistrantList(); + + private boolean mGotCountryCode = false; + + // We can't register for SIM_RECORDS_LOADED immediately because the + // SIMRecords object may not be instantiated yet. + private boolean mNeedToRegForRuimLoaded; + + // Keep track of SPN display rules, so we only broadcast intent if something changes. + private String curSpn = null; + private String curPlmn = null; + private int curSpnRule = 0; + + //***** Constants + static final String LOG_TAG = "CDMA"; + static final String TMUK = "23430"; + + private ContentResolver cr; + + 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 + } + }; + + + //***** Constructors + + public CdmaServiceStateTracker(CDMAPhone phone) { + super(); + + this.phone = phone; + cm = phone.mCM; + ss = new ServiceState(); + newSS = new ServiceState(); + cellLoc = new CdmaCellLocation(); + newCellLoc = new CdmaCellLocation(); + + 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.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null); + + cm.registerForRUIMReady(this, EVENT_RUIM_READY, null); + + phone.registerForNvLoaded(this, EVENT_NV_LOADED,null); + + // system setting property AIRPLANE_MODE_ON is set in Settings. + int airplaneMode = Settings.System.getInt( + phone.getContext().getContentResolver(), + Settings.System.AIRPLANE_MODE_ON, 0); + mDesiredPowerState = ! (airplaneMode > 0); + + cr = phone.getContext().getContentResolver(); + cr.registerContentObserver( + Settings.System.getUriFor(Settings.System.AUTO_TIME), true, + mAutoTimeObserver); + setRssiDefaultValues(); + + mNeedToRegForRuimLoaded = true; + } + + public void dispose() { + //Unregister for all events + cm.unregisterForAvailable(this); + cm.unregisterForRadioStateChanged(this); + cm.unregisterForNetworkStateChanged(this); + cm.unregisterForRUIMReady(this); + phone.unregisterForNvLoaded(this); + phone.mRuimRecords.unregisterForRecordsLoaded(this); + cm.unSetOnSignalStrengthUpdate(this); + cr.unregisterContentObserver(this.mAutoTimeObserver); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "CdmaServiceStateTracker finalized"); + } + + void registerForNetworkAttach(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + networkAttachedRegistrants.add(r); + + if (ss.getState() == ServiceState.STATE_IN_SERVICE) { + r.notifyRegistrant(); + } + } + + void unregisterForNetworkAttach(Handler h) { + networkAttachedRegistrants.remove(h); + } + + /** + * Registration point for transition into Data attached. + * @param h handler to notify + * @param what what code of message when delivered + * @param obj placed in Message.obj + */ + /*protected*/ void + registerForCdmaDataConnectionAttached(Handler h, int what, Object obj) { + 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) { + r.notifyRegistrant(); + } + } + void unregisterForCdmaDataConnectionAttached(Handler h) { + cdmaDataConnectionAttachedRegistrants.remove(h); + } + + /** + * Registration point for transition into Data detached. + * @param h handler to notify + * @param what what code of message when delivered + * @param obj placed in Message.obj + */ + /*protected*/ void + registerForCdmaDataConnectionDetached(Handler h, int what, Object obj) { + 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) { + r.notifyRegistrant(); + } + } + void unregisterForCdmaDataConnectionDetached(Handler h) { + cdmaDataConnectionDetachedRegistrants.remove(h); + } + + //***** Called from CDMAPhone + public void + getLacAndCid(Message onComplete) { + cm.getRegistrationState(obtainMessage( + EVENT_GET_LOC_DONE_CDMA, onComplete)); + } + + + //***** Overridden from ServiceStateTracker + public void + handleMessage (Message msg) { + AsyncResult ar; + int[] ints; + String[] strings; + + switch (msg.what) { + case EVENT_RADIO_AVAILABLE: + //this is unnecessary + //setPowerStateToDesired(); + break; + + case EVENT_RUIM_READY: + // The RUIM is now ready i.e if it was locked + // it has been unlocked. At this stage, the radio is already + // powered on. + 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_RADIO_STATE_CHANGED: + // This will do nothing in the radio not + // available case + setPowerStateToDesired(); + pollState(); + break; + + case EVENT_NETWORK_STATE_CHANGED_CDMA: + pollState(); + break; + + case EVENT_GET_SIGNAL_STRENGTH: + // This callback is called when signal strength is polled + // all by itself + + if (!(cm.getRadioState().isOn()) || (cm.getRadioState().isGsm())) { + // Polling will continue when radio turns back on + return; + } + ar = (AsyncResult) msg.obj; + onSignalStrengthResult(ar); + queueNextSignalStrengthPoll(); + + break; + + case EVENT_GET_LOC_DONE_CDMA: + ar = (AsyncResult) msg.obj; + + if (ar.exception == null) { + String states[] = (String[])ar.result; + int baseStationId = -1; + int baseStationLongitude = -1; + int baseStationLatitude = -1; + + int baseStationData[] = { + -1, // baseStationId + -1, // baseStationLatitude + -1 // baseStationLongitude + }; + + if (states.length == 3) { + for(int i = 0; i < states.length; i++) { + try { + if (states[i] != null && states[i].length() > 0) { + baseStationData[i] = Integer.parseInt(states[i], 16); + } + } catch (NumberFormatException ex) { + Log.w(LOG_TAG, "error parsing cell location data: " + ex); + } + } + } + + // only update if cell location really changed + if (cellLoc.getBaseStationId() != baseStationData[0] + || cellLoc.getBaseStationLatitude() != baseStationData[1] + || cellLoc.getBaseStationLongitude() != baseStationData[2]) { + cellLoc.setCellLocationData(baseStationData[0], + baseStationData[1], + baseStationData[2]); + phone.notifyLocationChanged(); + } + } + + if (ar.userObj != null) { + AsyncResult.forMessage(((Message) ar.userObj)).exception + = ar.exception; + ((Message) ar.userObj).sendToTarget(); + } + break; + + case EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA: //Fall through + case EVENT_POLL_STATE_REGISTRATION_CDMA: //Fall through + case EVENT_POLL_STATE_OPERATOR_CDMA: + ar = (AsyncResult) msg.obj; + handlePollStateResult(msg.what, ar); + break; + + case EVENT_POLL_SIGNAL_STRENGTH: + // Just poll signal strength...not part of pollState() + + cm.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH)); + break; + + case EVENT_SIGNAL_STRENGTH_UPDATE: + // This is a notification from + // CommandsInterface.setOnSignalStrengthUpdate + + ar = (AsyncResult) msg.obj; + + // The radio is telling us about signal strength changes + // we don't have to ask it + dontPollSignalStrength = true; + + onSignalStrengthResult(ar); + break; + + case EVENT_RUIM_RECORDS_LOADED: + case EVENT_NV_LOADED: + updateSpnDisplay(); + break; + + case EVENT_LOCATION_UPDATES_ENABLED: + ar = (AsyncResult) msg.obj; + + if (ar.exception == null) { + getLacAndCid(null); + } + break; + + default: + Log.e(LOG_TAG, "Unhandled message with number: " + msg.what); + break; + } + } + + //***** Private Instance Methods + + protected void setPowerStateToDesired() + { + // If we want it on and it's off, turn it on + if (mDesiredPowerState + && cm.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) { + cm.setRadioPower(true, null); + } else if (!mDesiredPowerState && cm.getRadioState().isOn()) { + DataConnectionTracker dcTracker = phone.mDataConnection; + if (! dcTracker.isDataConnectionAsDesired()) { + + EventLog.List val = new EventLog.List( + dcTracker.getStateInString(), + (dcTracker.getAnyDataEnabled() ? 1 : 0) ); + EventLog.writeEvent(TelephonyEventLog.EVENT_DATA_STATE_RADIO_OFF, val); + } + dcTracker.cleanConnectionBeforeRadioOff(); + + // poll data state up to 15 times, with a 100ms delay + // totaling 1.5 sec. Normal data disable action will finish in 100ms. + for (int i = 0; i < MAX_NUM_DATA_STATE_READS; i++) { + if (dcTracker.getState() != DataConnectionTracker.State.CONNECTED + && dcTracker.getState() != DataConnectionTracker.State.DISCONNECTING) { + Log.d(LOG_TAG, "Data shutdown complete."); + break; + } + SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS); + } + // If it's on and available and we want it off.. + cm.setRadioPower(false, null); + } // Otherwise, we're in the desired state + } + + protected void updateSpnDisplay() { + + // 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(); + + 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; + Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION); + intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn); + intent.putExtra(Intents.EXTRA_SPN, spn); + intent.putExtra(Intents.EXTRA_SHOW_PLMN, showPlmn); + intent.putExtra(Intents.EXTRA_PLMN, plmn); + phone.getContext().sendStickyBroadcast(intent); + } + + //curSpnRule = rule; + //curSpn = spn; + this.curPlmn = plmn; + } + + /** + * Handle the result of one of the pollState()-related requests + */ + + protected void + handlePollStateResult (int what, AsyncResult ar) { + int ints[]; + String states[]; + + // Ignore stale requests from last poll + if (ar.userObj != pollingContext) return; + + if (ar.exception != null) { + CommandException.Error err=null; + + if (ar.exception instanceof CommandException) { + err = ((CommandException)(ar.exception)).getCommandError(); + } + + if (err == CommandException.Error.RADIO_NOT_AVAILABLE) { + // Radio has crashed or turned off + cancelPollState(); + return; + } + + if (!cm.getRadioState().isOn()) { + // Radio has crashed or turned off + cancelPollState(); + return; + } + + if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW && + err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) { + Log.e(LOG_TAG, + "RIL implementation has returned an error where it must succeed", + ar.exception); + } + } 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; + 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 + }; + + if (states.length > 0) { + 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) { + Log.w(LOG_TAG, "error parsing RegistrationState: " + ex); + } + } + + 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]); + + newNetworkType = responseValuesRegistrationState[0]; + + // values are -1 if not available + newCellLoc.setCellLocationData(responseValuesRegistrationState[1], + responseValuesRegistrationState[2], + responseValuesRegistrationState[3]); + break; + + case EVENT_POLL_STATE_OPERATOR_CDMA: + String opNames[] = (String[])ar.result; + + if (opNames != null && opNames.length >= 4) { + newSS.setOperatorName (opNames[0], opNames[1], opNames[2]); + } + break; + + case EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA: + ints = (int[])ar.result; + newSS.setIsManualSelection(ints[0] == 1); + break; + default: + Log.e(LOG_TAG, "RIL response handle in wrong phone!" + + " Expected CDMA RIL request and get GSM RIL request."); + break; + } + + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "Exception while polling service state. " + + "Probably malformed RIL response.", ex); + } + + pollingContext[0]--; + + if (pollingContext[0] == 0) { + newSS.setRoaming(isRoamingBetweenOperators(mCdmaRoaming, newSS)); + + 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."); + } + pollStateDone(); + } + + } + + private void setRssiDefaultValues() { + rssi = 99; + } + + /** + * A complete "service state" from our perspective is + * composed of a handful of separate requests to the radio. + * + * We make all of these requests at once, but then abandon them + * and start over again if the radio notifies us that some + * event has changed + */ + + private void + pollState() { + pollingContext = new int[1]; + pollingContext[0] = 0; + + switch (cm.getRadioState()) { + case RADIO_UNAVAILABLE: + newSS.setStateOutOfService(); + newCellLoc.setStateInvalid(); + setRssiDefaultValues(); + mGotCountryCode = false; + + pollStateDone(); + break; + + case RADIO_OFF: + newSS.setStateOff(); + newCellLoc.setStateInvalid(); + setRssiDefaultValues(); + mGotCountryCode = false; + + pollStateDone(); + break; + + case SIM_NOT_READY: + case SIM_LOCKED_OR_ABSENT: + case SIM_READY: + log("Radio Technology Change ongoing, setting SS to off"); + newSS.setStateOff(); + newCellLoc.setStateInvalid(); + setRssiDefaultValues(); + mGotCountryCode = false; + + pollStateDone(); + break; + + default: + // Issue all poll-related commands at once + // then count down the responses, which + // 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; + } + } + + private static String networkTypeToString(int type) { + String ret = "unknown"; + + switch (type) { + case DATA_ACCESS_CDMA_IS95A: + case DATA_ACCESS_CDMA_IS95B: + ret = "CDMA"; + break; + case DATA_ACCESS_CDMA_1xRTT: + ret = "CDMA - 1xRTT"; + break; + case DATA_ACCESS_CDMA_EvDo_0: + ret = "CDMA - EvDo rev. 0"; + break; + case DATA_ACCESS_CDMA_EvDo_A: + ret = "CDMA - EvDo rev. A"; + break; + default: + if (DBG) { + Log.e(LOG_TAG, "Wrong network. Can not return a string."); + } + break; + } + + 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); + } + + boolean hasRegistered = + ss.getState() != ServiceState.STATE_IN_SERVICE + && newSS.getState() == ServiceState.STATE_IN_SERVICE; + + boolean hasDeregistered = + ss.getState() == ServiceState.STATE_IN_SERVICE + && 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); + + 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); + + boolean hasCdmaDataConnectionChanged = + cdmaDataConnectionState != newCdmaDataConnectionState; + + boolean hasNetworkTypeChanged = networkType != newNetworkType; + + boolean hasChanged = !newSS.equals(ss); + + boolean hasRoamingOn = !ss.getRoaming() && newSS.getRoaming(); + + boolean hasRoamingOff = ss.getRoaming() && !newSS.getRoaming(); + + boolean hasLocationChanged = !newCellLoc.equals(cellLoc); + + ServiceState tss; + tss = ss; + ss = newSS; + newSS = tss; + // clean slate for next time + newSS.setStateOutOfService(); + + CdmaCellLocation tcl = cellLoc; + cellLoc = newCellLoc; + newCellLoc = tcl; + + cdmaDataConnectionState = newCdmaDataConnectionState; + networkType = newNetworkType; + + newSS.setStateOutOfService(); // clean slate for next time + + if (hasNetworkTypeChanged) { + phone.setSystemProperty(PROPERTY_DATA_NETWORK_TYPE, + networkTypeToString(networkType)); + } + + if (hasRegistered) { + Checkin.updateStats(phone.getContext().getContentResolver(), + Checkin.Stats.Tag.PHONE_CDMA_REGISTERED, 1, 0.0); + networkAttachedRegistrants.notifyRegistrants(); + } + + if (hasChanged) { + String operatorNumeric; + + phone.setSystemProperty(PROPERTY_OPERATOR_ALPHA, + ss.getOperatorAlphaLong()); + + operatorNumeric = ss.getOperatorNumeric(); + phone.setSystemProperty(PROPERTY_OPERATOR_NUMERIC, operatorNumeric); + + if (operatorNumeric == null) { + phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, ""); + } else { + String iso = ""; + try{ + iso = MccTable.countryCodeForMcc(Integer.parseInt( + operatorNumeric.substring(0,3))); + } catch ( NumberFormatException ex){ + Log.w(LOG_TAG, "countryCodeForMcc error" + ex); + } catch ( StringIndexOutOfBoundsException ex) { + Log.w(LOG_TAG, "countryCodeForMcc error" + ex); + } + + phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, iso); + mGotCountryCode = true; + } + + phone.setSystemProperty(PROPERTY_OPERATOR_ISROAMING, + ss.getRoaming() ? "true" : "false"); + phone.setSystemProperty(PROPERTY_OPERATOR_ISMANUAL, + ss.getIsManualSelection() ? "true" : "false"); + + updateSpnDisplay(); + phone.notifyServiceStateChanged(ss); + } + + if (hasCdmaDataConnectionAttached) { + cdmaDataConnectionAttachedRegistrants.notifyRegistrants(); + } + + if (hasCdmaDataConnectionDetached) { + cdmaDataConnectionDetachedRegistrants.notifyRegistrants(); + } + + if (hasCdmaDataConnectionChanged) { + phone.notifyDataConnection(null); + } + + if (hasRoamingOn) { + roamingOnRegistrants.notifyRegistrants(); + } + + if (hasRoamingOff) { + roamingOffRegistrants.notifyRegistrants(); + } + + if (hasLocationChanged) { + phone.notifyLocationChanged(); + } + } + + /** + * Returns a TimeZone object based only on parameters from the NITZ string. + */ + private TimeZone getNitzTimeZone(int offset, boolean dst, long when) { + TimeZone guess = findTimeZone(offset, dst, when); + if (guess == null) { + // 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())); + } + return guess; + } + + private TimeZone findTimeZone(int offset, boolean dst, long when) { + int rawOffset = offset; + if (dst) { + rawOffset -= 3600000; + } + String[] zones = TimeZone.getAvailableIDs(rawOffset); + TimeZone guess = null; + Date d = new Date(when); + for (String zone : zones) { + TimeZone tz = TimeZone.getTimeZone(zone); + if (tz.getOffset(when) == offset && + tz.inDaylightTime(d) == dst) { + guess = tz; + break; + } + } + + return guess; + } + + private void + queueNextSignalStrengthPoll() { + if (dontPollSignalStrength || (cm.getRadioState().isGsm())) { + // The radio is telling us about signal strength changes + // we don't have to ask it + return; + } + + Message msg; + + msg = obtainMessage(); + msg.what = EVENT_POLL_SIGNAL_STRENGTH; + + // TODO Done't poll signal strength if screen is off + sendMessageDelayed(msg, POLL_PERIOD_MILLIS); + } + + /** + * send signal-strength-changed notification if rssi changed + * Called both for solicited and unsolicited signal stength updates + */ + private void + onSignalStrengthResult(AsyncResult ar) { + int oldRSSI = rssi; + + if (ar.exception != null) { + // 99 = unknown + // most likely radio is resetting/disconnected + rssi = 99; + } 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; + } + } + + if (rssi != oldRSSI) { + 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"); + } + } + } + + + private int radioTechnologyToServiceState(int code) { + int retVal = ServiceState.RADIO_TECHNOLOGY_UNKNOWN; + switch(code) { + case 0: + case 1: + case 2: + case 3: + 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; + break; + default: + Log.e(LOG_TAG, "Wrong radioTechnology code."); + break; + } + return(retVal); + } + + /** code is registration state 0-5 from TS 27.007 7.2 */ + private int + regCodeToServiceState(int code) { + switch (code) { + case 0: // Not searching and not registered + return ServiceState.STATE_OUT_OF_SERVICE; + case 1: + return ServiceState.STATE_IN_SERVICE; + case 2: // 2 is "searching", fall through + 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) + return ServiceState.STATE_IN_SERVICE; + + default: + Log.w(LOG_TAG, "unexpected service state " + code); + return ServiceState.STATE_OUT_OF_SERVICE; + } + } + + /** + * @return The current CDMA data connection state. ServiceState.RADIO_TECHNOLOGY_1xRTT or + * ServiceState.RADIO_TECHNOLOGY_EVDO is the same as "attached" and + * ServiceState.RADIO_TECHNOLOGY_UNKNOWN is the same as detached. + */ + /*package*/ int getCurrentCdmaDataConnectionState() { + return cdmaDataConnectionState; + } + + /** + * code is registration state 0-5 from TS 27.007 7.2 + * returns true if registered roam, false otherwise + */ + private boolean + regCodeIsRoaming (int code) { + // 5 is "in service -- roam" + return 5 == code; + } + + /** + * Set roaming state when cdmaRoaming is true and ons is different from spn + * @param cdmaRoaming TS 27.007 7.2 CREG registered roaming + * @param s ServiceState hold current ons + * @return true for roaming state set + */ + private + boolean isRoamingBetweenOperators(boolean cdmaRoaming, ServiceState s) { + String spn = SystemProperties.get(PROPERTY_ICC_OPERATOR_ALPHA, "empty"); + + String onsl = s.getOperatorAlphaLong(); + String onss = s.getOperatorAlphaShort(); + + boolean equalsOnsl = onsl != null && spn.equals(onsl); + boolean equalsOnss = onss != null && spn.equals(onss); + + return cdmaRoaming && !(equalsOnsl || equalsOnss); + } + + private boolean getAutoTime() { + try { + return Settings.System.getInt(phone.getContext().getContentResolver(), + Settings.System.AUTO_TIME) > 0; + } catch (SettingNotFoundException snfe) { + return true; + } + } + + /** + * @return true if phone is camping on a technology + * that could support voice and data simultaneously. + */ + boolean isConcurrentVoiceAndData() { + + // Note: it needs to be confirmed which CDMA network types + // can support voice and data calls concurrently. + // For the time-being, the return value will be false. + return false; + } + + protected void log(String s) { + Log.d(LOG_TAG, "[CdmaServiceStateTracker] " + s); + } + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java b/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java new file mode 100644 index 0000000..65b7336 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma; + +import android.content.Context; +import android.os.*; +import android.util.Log; + +import com.android.internal.telephony.*; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * {@hide} + * + */ +public final class FeatureCode extends Handler implements MmiCode { + static final String LOG_TAG = "CDMA"; + + //***** Constants + + // Call Forwarding + static final String FC_CF_ACTIVATE = "72"; + static final String FC_CF_DEACTIVATE = "73"; + static final String FC_CF_FORWARD_TO_NUMBER = "56"; + + // Call Forwarding Busy Line + static final String FC_CFBL_ACTIVATE = "90"; + static final String FC_CFBL_DEACTIVATE = "91"; + static final String FC_CFBL_FORWARD_TO_NUMBER = "40"; + + // Call Forwarding Don't Answer + static final String FC_CFDA_ACTIVATE = "92"; + static final String FC_CFDA_DEACTIVATE = "93"; + static final String FC_CFDA_FORWARD_TO_NUMBER = "42"; + + // Cancel Call Waiting + static final String FC_CCW = "70"; + + // Usage Sensitive Three-way Calling + static final String FC_3WC = "71"; + + // Do Not Disturb + static final String FC_DND_ACTIVATE = "78"; + static final String FC_DND_DEACTIVATE = "79"; + + // Who Called Me? + static final String FC_WHO = "51"; + + // Rejection of Undesired Annoying Calls + static final String FC_RUAC_ACTIVATE = "60"; + static final String FC_RUAC_DEACTIVATE = "80"; + + // Calling Number Delivery + // Calling Number Identification Presentation + static final String FC_CNIP = "65"; + // Calling Number Identification Restriction + static final String FC_CNIR = "85"; + + + //***** Event Constants + + static final int EVENT_SET_COMPLETE = 1; + static final int EVENT_CDMA_FLASH_COMPLETED = 2; + + + //***** Instance Variables + + CDMAPhone phone; + Context context; + + String action; // '*' in CDMA + String sc; // Service Code + String poundString; // Entire Flash string + String dialingNumber; + + /** Set to true in processCode, not at newFromDialString time */ + + State state = State.PENDING; + CharSequence message; + + //***** Class Variables + + + // Flash Code Pattern + + static Pattern sPatternSuppService = Pattern.compile( + "((\\*)(\\d{2,3})(#?)([^*#]*)?)(.*)"); +/* 1 2 3 4 5 6 + + 1 = Full string up to and including # + 2 = action + 3 = service code + 4 = separator + 5 = dialing number +*/ + + static final int MATCH_GROUP_POUND_STRING = 1; + static final int MATCH_GROUP_ACTION_STRING = 2; + static final int MATCH_GROUP_SERVICE_CODE = 3; + static final int MATCH_GROUP_DIALING_NUMBER = 5; + + + //***** Public Class methods + + /** + * Some dial strings in CDMA are defined to do non-call setup + * things, such as set supplementary service settings (eg, call + * forwarding). These are generally referred to as "Feature Codes". + * We look to see if the dial string contains a valid Feature code (potentially + * with a dial string at the end as well) and return info here. + * + * If the dial string contains no Feature code, we return an instance with + * only "dialingNumber" set + * + * Please see also S.R0006-000-A v2.0 "Wireless Features Description" + */ + + static FeatureCode newFromDialString(String dialString, CDMAPhone phone) { + Matcher m; + FeatureCode ret = null; + + m = sPatternSuppService.matcher(dialString); + + // Is this formatted like a standard supplementary service code? + if (m.matches()) { + ret = new FeatureCode(phone); + ret.poundString = makeEmptyNull(m.group(MATCH_GROUP_POUND_STRING)); + ret.action = makeEmptyNull(m.group(MATCH_GROUP_ACTION_STRING)); + ret.sc = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE)); + ret.dialingNumber = makeEmptyNull(m.group(MATCH_GROUP_DIALING_NUMBER)); + } + + return ret; + } + + //***** Private Class methods + + /** make empty strings be null. + * Java regexp returns empty strings for empty groups + */ + private static String makeEmptyNull (String s) { + if (s != null && s.length() == 0) return null; + + return s; + } + + /** returns true of the string is empty or null */ + private static boolean isEmptyOrNull(CharSequence s) { + return s == null || (s.length() == 0); + } + + static boolean isServiceCodeCallForwarding(String sc) { + return sc != null && + (sc.equals(FC_CF_ACTIVATE) + || sc.equals(FC_CF_DEACTIVATE) || sc.equals(FC_CF_FORWARD_TO_NUMBER) + || sc.equals(FC_CFBL_ACTIVATE) || sc.equals(FC_CFBL_DEACTIVATE) + || sc.equals(FC_CFBL_FORWARD_TO_NUMBER) || sc.equals(FC_CFDA_ACTIVATE) + || sc.equals(FC_CFDA_DEACTIVATE) || sc.equals(FC_CFDA_FORWARD_TO_NUMBER)); + } + + static boolean isServiceCodeCallWaiting(String sc) { + return sc != null && sc.equals(FC_CCW); + } + + static boolean isServiceCodeThreeWayCalling(String sc) { + return sc != null && sc.equals(FC_3WC); + } + + static boolean isServiceCodeAnnoyingCalls(String sc) { + return sc != null && + (sc.equals(FC_RUAC_ACTIVATE) + || sc.equals(FC_RUAC_DEACTIVATE)); + } + + static boolean isServiceCodeCallingNumberDelivery(String sc) { + return sc != null && + (sc.equals(FC_CNIP) + || sc.equals(FC_CNIR)); + } + + static boolean isServiceCodeDoNotDisturb(String sc) { + return sc != null && + (sc.equals(FC_DND_ACTIVATE) + || sc.equals(FC_DND_DEACTIVATE)); + } + + + //***** Constructor + + FeatureCode (CDMAPhone phone) { + super(phone.getHandler().getLooper()); + this.phone = phone; + this.context = phone.getContext(); + } + + + //***** MmiCode implementation + + public State getState() { + return state; + } + + public CharSequence getMessage() { + return message; + } + + // inherited javadoc suffices + public void cancel() { + //Not used here + } + + public boolean isCancelable() { + Log.e(LOG_TAG, "isCancelable: not used in CDMA"); + return false; + } + + public boolean isUssdRequest() { + Log.e(LOG_TAG, "isUssdRequest: not used in CDMA"); + return false; + } + + /** Process a Flash Code...anything that isn't a dialing number */ + void processCode () { + Log.d(LOG_TAG, "send feature code..."); + phone.mCM.sendCDMAFeatureCode(this.poundString, + obtainMessage(EVENT_CDMA_FLASH_COMPLETED)); + } + + /** Called from CDMAPhone.handleMessage; not a Handler subclass */ + public void handleMessage (Message msg) { + AsyncResult ar; + + switch (msg.what) { + case EVENT_SET_COMPLETE: + ar = (AsyncResult) (msg.obj); + onSetComplete(ar); + break; + case EVENT_CDMA_FLASH_COMPLETED: + ar = (AsyncResult) (msg.obj); + + if (ar.exception != null) { + state = State.FAILED; + message = context.getText(com.android.internal.R.string.mmiError); + } else { + state = State.COMPLETE; + message = context.getText(com.android.internal.R.string.mmiComplete); + } + phone.onMMIDone(this); + break; + } + } + + + //***** Private instance methods + + private CharSequence getScString() { + if (sc != null) { + if (isServiceCodeCallForwarding(sc)) { + return context.getText(com.android.internal.R.string.CfMmi); + } else if (isServiceCodeCallWaiting(sc)) { + return context.getText(com.android.internal.R.string.CwMmi); + } else if (sc.equals(FC_CNIP)) { + return context.getText(com.android.internal.R.string.CnipMmi); + } else if (sc.equals(FC_CNIR)) { + return context.getText(com.android.internal.R.string.CnirMmi); + } else if (isServiceCodeThreeWayCalling(sc)) { + return context.getText(com.android.internal.R.string.ThreeWCMmi); + } else if (isServiceCodeAnnoyingCalls(sc)) { + return context.getText(com.android.internal.R.string.RuacMmi); + } else if (isServiceCodeCallingNumberDelivery(sc)) { + return context.getText(com.android.internal.R.string.CndMmi); + } else if (isServiceCodeDoNotDisturb(sc)) { + return context.getText(com.android.internal.R.string.DndMmi); + } + } + + return ""; + } + + private void onSetComplete(AsyncResult ar){ + StringBuilder sb = new StringBuilder(getScString()); + sb.append("\n"); + + if (ar.exception != null) { + state = State.FAILED; + sb.append(context.getText(com.android.internal.R.string.mmiError)); + } else { + state = State.FAILED; + sb.append(context.getText(com.android.internal.R.string.mmiError)); + } + + message = sb; + phone.onMMIDone(this); + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java new file mode 100644 index 0000000..9d9f479 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java @@ -0,0 +1,522 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.Registrant; +import android.os.RegistrantList; +import android.os.RemoteException; +import android.util.Log; + +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.TelephonyProperties; + +import android.app.ActivityManagerNative; +import android.content.Intent; +import android.content.res.Configuration; + +import static android.Manifest.permission.READ_PHONE_STATE; + +/** + * Note: this class shares common code with SimCard, consider a base class to minimize code + * duplication. + * {@hide} + */ +public final class RuimCard extends Handler implements IccCard { + static final String LOG_TAG="CDMA"; + + //***** Instance Variables + private static final boolean DBG = true; + + private CDMAPhone phone; + + private CommandsInterface.IccStatus status = null; + private boolean mDesiredPinLocked; + private boolean mDesiredFdnEnabled; + private boolean mRuimPinLocked = true; // default to locked + private boolean mRuimFdnEnabled = false; // Default to disabled. + // Will be updated when RUIM_READY. +// //***** Constants + +// // FIXME I hope this doesn't conflict with the Dialer's notifications +// Nobody is using this at the moment +// static final int NOTIFICATION_ID_ICC_STATUS = 33456; + + //***** Event Constants + + static final int EVENT_RUIM_LOCKED_OR_ABSENT = 1; + static final int EVENT_GET_RUIM_STATUS_DONE = 2; + static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3; + static final int EVENT_PINPUK_DONE = 4; + static final int EVENT_REPOLL_STATUS_DONE = 5; + static final int EVENT_RUIM_READY = 6; + static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7; + static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8; + static final int EVENT_CHANGE_RUIM_PASSWORD_DONE = 9; + static final int EVENT_QUERY_FACILITY_FDN_DONE = 10; + static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11; + + + //***** Constructor + + RuimCard(CDMAPhone phone) { + this.phone = phone; + + phone.mCM.registerForRUIMLockedOrAbsent( + this, EVENT_RUIM_LOCKED_OR_ABSENT, null); + + phone.mCM.registerForOffOrNotAvailable( + this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + + phone.mCM.registerForRUIMReady( + this, EVENT_RUIM_READY, null); + + updateStateProperty(); + } + + //***** RuimCard implementation + + public State + getState() { + if (status == null) { + switch(phone.mCM.getRadioState()) { + /* This switch block must not return anything in + * State.isLocked() or State.ABSENT. + * If it does, handleSimStatus() may break + */ + case RADIO_OFF: + case RADIO_UNAVAILABLE: + case RUIM_NOT_READY: + return State.UNKNOWN; + case RUIM_LOCKED_OR_ABSENT: + //this should be transient-only + return State.UNKNOWN; + case RUIM_READY: + return State.READY; + case NV_READY: + case NV_NOT_READY: + return State.ABSENT; + } + } else { + switch (status) { + case ICC_ABSENT: return State.ABSENT; + case ICC_NOT_READY: return State.UNKNOWN; + case ICC_READY: return State.READY; + case ICC_PIN: return State.PIN_REQUIRED; + case ICC_PUK: return State.PUK_REQUIRED; + case ICC_NETWORK_PERSONALIZATION: return State.NETWORK_LOCKED; + } + } + + Log.e(LOG_TAG, "RuimCard.getState(): case should never be reached"); + return State.UNKNOWN; + } + + public void dispose() { + //Unregister for all events + phone.mCM.unregisterForRUIMLockedOrAbsent(this); + phone.mCM.unregisterForOffOrNotAvailable(this); + phone.mCM.unregisterForRUIMReady(this); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "RuimCard finalized"); + } + + private RegistrantList absentRegistrants = new RegistrantList(); + private RegistrantList pinLockedRegistrants = new RegistrantList(); + private RegistrantList networkLockedRegistrants = new RegistrantList(); + + + public void registerForAbsent(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + absentRegistrants.add(r); + + if (getState() == State.ABSENT) { + r.notifyRegistrant(); + } + } + + public void unregisterForAbsent(Handler h) { + absentRegistrants.remove(h); + } + + public void registerForNetworkLocked(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + networkLockedRegistrants.add(r); + + if (getState() == State.NETWORK_LOCKED) { + r.notifyRegistrant(); + } + } + + public void unregisterForNetworkLocked(Handler h) { + networkLockedRegistrants.remove(h); + } + + public void registerForLocked(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + pinLockedRegistrants.add(r); + + if (getState().isPinLocked()) { + r.notifyRegistrant(); + } + } + + public void unregisterForLocked(Handler h) { + pinLockedRegistrants.remove(h); + } + + public void supplyPin (String pin, Message onComplete) { + phone.mCM.supplyIccPin(pin, obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public void supplyPuk (String puk, String newPin, Message onComplete) { + phone.mCM.supplyIccPuk(puk, newPin, obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public void supplyPin2 (String pin2, Message onComplete) { + phone.mCM.supplyIccPin2(pin2, obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public void supplyPuk2 (String puk2, String newPin2, Message onComplete) { + phone.mCM.supplyIccPuk2(puk2, newPin2, obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public void supplyNetworkDepersonalization (String pin, Message onComplete) { + if(DBG) log("Network Despersonalization: " + pin); + phone.mCM.supplyNetworkDepersonalization(pin, + obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public boolean getIccLockEnabled() { + return mRuimPinLocked; + } + + public boolean getIccFdnEnabled() { + return mRuimFdnEnabled; + } + + public void setIccLockEnabled (boolean enabled, + String password, Message onComplete) { + int serviceClassX; + serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + + CommandsInterface.SERVICE_CLASS_DATA + + CommandsInterface.SERVICE_CLASS_FAX; + + mDesiredPinLocked = enabled; + + phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM, + enabled, password, serviceClassX, + obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete)); + } + + public void setIccFdnEnabled (boolean enabled, + String password, Message onComplete) { + int serviceClassX; + serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + + CommandsInterface.SERVICE_CLASS_DATA + + CommandsInterface.SERVICE_CLASS_FAX + + CommandsInterface.SERVICE_CLASS_SMS; + + mDesiredFdnEnabled = enabled; + + phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD, + enabled, password, serviceClassX, + obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete)); + } + + public void changeIccLockPassword(String oldPassword, String newPassword, + Message onComplete) { + if(DBG) log("Change Pin1 old: " + oldPassword + " new: " + newPassword); + phone.mCM.changeIccPin(oldPassword, newPassword, + obtainMessage(EVENT_CHANGE_RUIM_PASSWORD_DONE, onComplete)); + } + + public void changeIccFdnPassword(String oldPassword, String newPassword, + Message onComplete) { + if(DBG) log("Change Pin2 old: " + oldPassword + " new: " + newPassword); + phone.mCM.changeIccPin2(oldPassword, newPassword, + obtainMessage(EVENT_CHANGE_RUIM_PASSWORD_DONE, onComplete)); + } + + public String getServiceProviderName() { + return phone.mRuimRecords.getServiceProviderName(); + } + + //***** Handler implementation + @Override + public void handleMessage(Message msg){ + AsyncResult ar; + int serviceClassX; + + serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + + CommandsInterface.SERVICE_CLASS_DATA + + CommandsInterface.SERVICE_CLASS_FAX; + + switch (msg.what) { + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: + Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received"); + status = null; + updateStateProperty(); + broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_NOT_READY, null); + break; + case EVENT_RUIM_READY: + Log.d(LOG_TAG, "Event EVENT_RUIM_READY Received"); + //TODO: put facility read in SIM_READY now, maybe in REG_NW + phone.mCM.getIccStatus(obtainMessage(EVENT_GET_RUIM_STATUS_DONE)); + phone.mCM.queryFacilityLock ( + CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, + obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); + phone.mCM.queryFacilityLock ( + CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX, + obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE)); + break; + case EVENT_RUIM_LOCKED_OR_ABSENT: + Log.d(LOG_TAG, "Event EVENT_RUIM_LOCKED_OR_ABSENT Received"); + phone.mCM.getIccStatus(obtainMessage(EVENT_GET_RUIM_STATUS_DONE)); + phone.mCM.queryFacilityLock ( + CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, + obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); + break; + case EVENT_GET_RUIM_STATUS_DONE: + Log.d(LOG_TAG, "Event EVENT_GET_RUIM_STATUS_DONE Received"); + ar = (AsyncResult)msg.obj; + + getRuimStatusDone(ar); + break; + case EVENT_PINPUK_DONE: + Log.d(LOG_TAG, "Event EVENT_PINPUK_DONE Received"); + // a PIN/PUK/PIN2/PUK2/Network Personalization + // request has completed. ar.userObj is the response Message + // Repoll before returning + ar = (AsyncResult)msg.obj; + // TODO should abstract these exceptions + AsyncResult.forMessage(((Message)ar.userObj)).exception + = ar.exception; + phone.mCM.getIccStatus( + obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj)); + break; + case EVENT_REPOLL_STATUS_DONE: + Log.d(LOG_TAG, "Event EVENT_REPOLL_STATUS_DONE Received"); + // Finished repolling status after PIN operation + // ar.userObj is the response messaeg + // ar.userObj.obj is already an AsyncResult with an + // appropriate exception filled in if applicable + + ar = (AsyncResult)msg.obj; + getRuimStatusDone(ar); + ((Message)ar.userObj).sendToTarget(); + break; + case EVENT_QUERY_FACILITY_LOCK_DONE: + Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_LOCK_DONE Received"); + ar = (AsyncResult)msg.obj; + onQueryFacilityLock(ar); + break; + case EVENT_QUERY_FACILITY_FDN_DONE: + Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_FDN_DONE Received"); + ar = (AsyncResult)msg.obj; + onQueryFdnEnabled(ar); + break; + case EVENT_CHANGE_FACILITY_LOCK_DONE: + Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_LOCK_DONE Received"); + ar = (AsyncResult)msg.obj; + if (ar.exception == null) { + mRuimPinLocked = mDesiredPinLocked; + if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " + + "mRuimPinLocked= " + mRuimPinLocked); + } else { + Log.e(LOG_TAG, "Error change facility lock with exception " + + ar.exception); + } + AsyncResult.forMessage(((Message)ar.userObj)).exception + = ar.exception; + ((Message)ar.userObj).sendToTarget(); + break; + case EVENT_CHANGE_FACILITY_FDN_DONE: + Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_FDN_DONE Received"); + ar = (AsyncResult)msg.obj; + + if (ar.exception == null) { + mRuimFdnEnabled = mDesiredFdnEnabled; + if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " + + "mRuimFdnEnabled=" + mRuimFdnEnabled); + } else { + Log.e(LOG_TAG, "Error change facility fdn with exception " + + ar.exception); + } + AsyncResult.forMessage(((Message)ar.userObj)).exception + = ar.exception; + ((Message)ar.userObj).sendToTarget(); + break; + case EVENT_CHANGE_RUIM_PASSWORD_DONE: + Log.d(LOG_TAG, "Event EVENT_CHANGE_RUIM_PASSWORD_DONE Received"); + ar = (AsyncResult)msg.obj; + if(ar.exception != null) { + Log.e(LOG_TAG, "Error in change sim password with exception" + + ar.exception); + } + AsyncResult.forMessage(((Message)ar.userObj)).exception + = ar.exception; + ((Message)ar.userObj).sendToTarget(); + break; + default: + Log.e(LOG_TAG, "[CdmaRuimCard] Unknown Event " + msg.what); + } + } + + //***** Private methods + + /** + * Interpret EVENT_QUERY_FACILITY_LOCK_DONE + * @param ar is asyncResult of Query_Facility_Locked + */ + private void onQueryFacilityLock(AsyncResult ar) { + if(ar.exception != null) { + if (DBG) log("Error in querying facility lock:" + ar.exception); + return; + } + + int[] ints = (int[])ar.result; + if(ints.length != 0) { + mRuimPinLocked = (0!=ints[0]); + if(DBG) log("Query facility lock : " + mRuimPinLocked); + } else { + Log.e(LOG_TAG, "[CdmaRuimCard] Bogus facility lock response"); + } + } + + /** + * Interpret EVENT_QUERY_FACILITY_LOCK_DONE + * @param ar is asyncResult of Query_Facility_Locked + */ + private void onQueryFdnEnabled(AsyncResult ar) { + if(ar.exception != null) { + if(DBG) log("Error in querying facility lock:" + ar.exception); + return; + } + + int[] ints = (int[])ar.result; + if(ints.length != 0) { + mRuimFdnEnabled = (0!=ints[0]); + if(DBG) log("Query facility lock : " + mRuimFdnEnabled); + } else { + Log.e(LOG_TAG, "[CdmaRuimCard] Bogus facility lock response"); + } + } + + private void + getRuimStatusDone(AsyncResult ar) { + if (ar.exception != null) { + Log.e(LOG_TAG,"Error getting SIM status. " + + "RIL_REQUEST_GET_SIM_STATUS should " + + "never return an error", ar.exception); + return; + } + + CommandsInterface.IccStatus newStatus + = (CommandsInterface.IccStatus) ar.result; + + handleRuimStatus(newStatus); + } + + private void + handleRuimStatus(CommandsInterface.IccStatus newStatus) { + boolean transitionedIntoPinLocked; + boolean transitionedIntoAbsent; + boolean transitionedIntoNetworkLocked; + + RuimCard.State oldState, newState; + + oldState = getState(); + status = newStatus; + newState = getState(); + + updateStateProperty(); + + transitionedIntoPinLocked = ( + (oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED) + || (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED)); + transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT); + transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED + && newState == State.NETWORK_LOCKED); + + if (transitionedIntoPinLocked) { + if(DBG) log("Notify RUIM pin or puk locked."); + pinLockedRegistrants.notifyRegistrants(); + broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED, + (newState == State.PIN_REQUIRED) ? + INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK); + } else if (transitionedIntoAbsent) { + if(DBG) log("Notify RUIM missing."); + absentRegistrants.notifyRegistrants(); + broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_ABSENT, null); + } else if (transitionedIntoNetworkLocked) { + if(DBG) log("Notify RUIM network locked."); + networkLockedRegistrants.notifyRegistrants(); + broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED, + INTENT_VALUE_LOCKED_NETWORK); + } + } + + public void broadcastRuimStateChangedIntent(String value, String reason) { + Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); + intent.putExtra(Phone.PHONE_NAME_KEY, phone.getPhoneName()); + intent.putExtra(RuimCard.INTENT_KEY_ICC_STATE, value); + intent.putExtra(RuimCard.INTENT_KEY_LOCKED_REASON, reason); + if(DBG) log("Broadcasting intent SIM_STATE_CHANGED_ACTION " + value + + " reason " + reason); + ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE); + } + + public void updateImsiConfiguration(String imsi) { + if (imsi.length() >= 6) { + Configuration config = new Configuration(); + config.mcc = ((imsi.charAt(0)-'0')*100) + + ((imsi.charAt(1)-'0')*10) + + (imsi.charAt(2)-'0'); + config.mnc = ((imsi.charAt(3)-'0')*100) + + ((imsi.charAt(4)-'0')*10) + + (imsi.charAt(5)-'0'); + try { + ActivityManagerNative.getDefault().updateConfiguration(config); + } catch (RemoteException e) { + } + } + } + + private void + updateStateProperty() { + phone.setSystemProperty( + TelephonyProperties.PROPERTY_SIM_STATE, + getState().toString()); + } + + private void log(String msg) { + Log.d(LOG_TAG, "[RuimCard] " + msg); + } +} + diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java new file mode 100644 index 0000000..7d392f0 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma; + +import android.os.*; +import android.os.AsyncResult; +import android.util.Log; + +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.IccException; +import com.android.internal.telephony.IccFileHandler; +import com.android.internal.telephony.IccFileTypeMismatch; +import com.android.internal.telephony.IccIoResult; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.PhoneProxy; + +import java.util.ArrayList; + +/** + * {@hide} + */ +public final class RuimFileHandler extends IccFileHandler { + static final String LOG_TAG = "CDMA"; + + //***** Instance Variables + + //***** Constructor + RuimFileHandler(CDMAPhone phone) { + super(phone); + } + + public void dispose() { + } + + protected void finalize() { + Log.d(LOG_TAG, "RuimFileHandler finalized"); + } + + //***** Overridden from IccFileHandler + + @Override + public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset, + int length, Message onLoaded) { + Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0, + onLoaded); + + phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, "img", 0, 0, + GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null, response); + } + + @Override + public void handleMessage(Message msg) { + + super.handleMessage(msg); + } + + protected void logd(String msg) { + Log.d(LOG_TAG, "[RuimFileHandler] " + msg); + } + + protected void loge(String msg) { + Log.e(LOG_TAG, "[RuimFileHandler] " + msg); + } + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java new file mode 100644 index 0000000..78e89d5 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java @@ -0,0 +1,101 @@ +/* +** 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 +** +** 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.pm.PackageManager; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.ServiceManager; +import android.telephony.PhoneNumberUtils; +import android.util.Log; + +import com.android.internal.telephony.AdnRecord; +import com.android.internal.telephony.AdnRecordCache; +import com.android.internal.telephony.IccPhoneBookInterfaceManager; +import com.android.internal.telephony.PhoneProxy; + +import java.util.ArrayList; +import java.util.List; + +/** + * RuimPhoneBookInterfaceManager to provide an inter-process communication to + * access ADN-like SIM records. + */ + + +public class RuimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager { + static final String LOG_TAG = "CDMA"; + + + Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + + switch(msg.what) { + default: + mBaseHandler.handleMessage(msg); + break; + } + } + }; + + public RuimPhoneBookInterfaceManager(CDMAPhone phone) { + super(phone); + adnCache = phone.mRuimRecords.getAdnCache(); + //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy + } + + public void dispose() { + super.dispose(); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "RuimPhoneBookInterfaceManager finalized"); + } + + public int[] getAdnRecordsSize(int efid) { + if (DBG) logd("getAdnRecordsSize: efid=" + efid); + synchronized(mLock) { + checkThread(); + recordSize = new int[3]; + + //Using mBaseHandler, no difference in EVENT_GET_SIZE_DONE handling + Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE); + + phone.getIccFileHandler().getEFLinearRecordSize(efid, response); + try { + mLock.wait(); + } catch (InterruptedException e) { + logd("interrupted while trying to load from the RUIM"); + } + } + + return recordSize; + } + + protected void logd(String msg) { + Log.d(LOG_TAG, "[RuimPbInterfaceManager] " + msg); + } + + protected void loge(String msg) { + Log.e(LOG_TAG, "[RuimPbInterfaceManager] " + msg); + } +} + diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java new file mode 100644 index 0000000..7776f8b --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java @@ -0,0 +1,380 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.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.cdma.RuimCard; +import com.android.internal.telephony.gsm.MccTable; + +// can't be used since VoiceMailConstants is not public +//import com.android.internal.telephony.gsm.VoiceMailConstants; +import com.android.internal.telephony.IccException; +import com.android.internal.telephony.IccRecords; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.PhoneProxy; + + +/** + * {@hide} + */ +public final class RuimRecords extends IccRecords { + static final String LOG_TAG = "CDMA"; + + private static final boolean DBG = true; + + //***** Instance Variables + String imsi_m; + String mdn = null; // My mobile number + String h_sid; + String h_nid; + + // is not initialized + + //***** Event Constants + + private static final int EVENT_RUIM_READY = 1; + 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_GET_CDMA_SUBSCRIPTION_DONE = 10; + private static final int EVENT_UPDATE_DONE = 14; + private static final int EVENT_GET_SST_DONE = 17; + private static final int EVENT_GET_ALL_SMS_DONE = 18; + private static final int EVENT_MARK_SMS_READ_DONE = 19; + + private static final int EVENT_SMS_ON_RUIM = 21; + private static final int EVENT_GET_SMS_DONE = 22; + + private static final int EVENT_RUIM_REFRESH = 31; + + //***** Constructor + + RuimRecords(CDMAPhone p) { + super(p); + + adnCache = new AdnRecordCache(phone); + + recordsRequested = false; // No load request is made till SIM ready + + // recordsToLoad is set to 0 because no requests are made yet + recordsToLoad = 0; + + + p.mCM.registerForRUIMReady(this, EVENT_RUIM_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(); + + } + + public void dispose() { + //Unregister for all events + phone.mCM.unregisterForRUIMReady(this); + phone.mCM.unregisterForOffOrNotAvailable( this); + phone.mCM.unSetOnIccRefresh(this); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "RuimRecords finalized"); + } + + protected void onRadioOffOrNotAvailable() { + countVoiceMessages = 0; + mncLength = 0; + iccid = null; + + adnCache.reset(); + + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, null); + phone.setSystemProperty(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 + // true only when fresh set of read requests are made. + recordsRequested = false; + } + + //***** Public Methods + + /** Returns null if RUIM is not yet ready */ + public String getIMSI_M() { + return imsi_m; + } + + public String getMdnNumber() { + return mdn; + } + + public void setVoiceMailNumber(String alphaTag, String voiceNumber, Message onComplete){ + // In CDMA this is Operator/OEM dependent + AsyncResult.forMessage((onComplete)).exception = + new IccException("setVoiceMailNumber not implemented"); + onComplete.sendToTarget(); + Log.e(LOG_TAG, "method setVoiceMailNumber is not implemented"); + } + + /** + * Called by CCAT Service when REFRESH is received. + * @param fileChanged indicates whether any files changed + * @param fileList if non-null, a list of EF files that changed + */ + public void onRefresh(boolean fileChanged, int[] fileList) { + if (fileChanged) { + // A future optimization would be to inspect fileList and + // only reload those files that we care about. For now, + // just re-fetch all RUIM records that we cache. + fetchRuimRecords(); + } + } + + /** 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) { + return null; + } + + 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); + } + + // 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)); + } + + //***** Overridden from Handler + public void handleMessage(Message msg) { + AsyncResult ar; + + byte data[]; + + boolean isRecordLoadResponse = false; + + try { switch (msg.what) { + case EVENT_RUIM_READY: + onRuimReady(); + break; + + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: + onRadioOffOrNotAvailable(); + break; + + case EVENT_GET_DEVICE_IDENTITY_DONE: + Log.d(LOG_TAG, "Event EVENT_GET_DEVICE_IDENTITY_DONE Received"); + break; + + /* IO events */ + + case EVENT_GET_CDMA_SUBSCRIPTION_DONE: + ar = (AsyncResult)msg.obj; + String localTemp[] = (String[])ar.result; + if (ar.exception != null) { + break; + } + + mdn = localTemp[0]; + h_sid = localTemp[1]; + h_nid = localTemp[2]; + + Log.d(LOG_TAG, "MDN: " + mdn); + + break; + + case EVENT_GET_ICCID_DONE: + isRecordLoadResponse = true; + + ar = (AsyncResult)msg.obj; + data = (byte[])ar.result; + + if (ar.exception != null) { + break; + } + + iccid = IccUtils.bcdToString(data, 0, data.length); + + Log.d(LOG_TAG, "iccid: " + iccid); + + break; + + case EVENT_UPDATE_DONE: + ar = (AsyncResult)msg.obj; + if (ar.exception != null) { + Log.i(LOG_TAG, "RuimRecords update failed", ar.exception); + } + break; + + case EVENT_GET_ALL_SMS_DONE: + case EVENT_MARK_SMS_READ_DONE: + case EVENT_SMS_ON_RUIM: + case EVENT_GET_SMS_DONE: + Log.w(LOG_TAG, "Event not supported: " + msg.what); + break; + + // TODO: probably EF_CST should be read instead + case EVENT_GET_SST_DONE: + Log.d(LOG_TAG, "Event EVENT_GET_SST_DONE Received"); + break; + + case EVENT_RUIM_REFRESH: + isRecordLoadResponse = false; + ar = (AsyncResult)msg.obj; + if (ar.exception == null) { + handleRuimRefresh((int[])(ar.result)); + } + break; + + }}catch (RuntimeException exc) { + // I don't want these exceptions to be fatal + Log.w(LOG_TAG, "Exception parsing RUIM record", exc); + } finally { + // Count up record load responses even if they are fails + if (isRecordLoadResponse) { + onRecordLoaded(); + } + } + } + + protected void onRecordLoaded() { + // One record loaded successfully or failed, In either case + // we need to update the recordsToLoad count + recordsToLoad -= 1; + + if (recordsToLoad == 0 && recordsRequested == true) { + onAllRecordsLoaded(); + } else if (recordsToLoad < 0) { + Log.e(LOG_TAG, "RuimRecords: recordsToLoad <0, programmer error suspected"); + recordsToLoad = 0; + } + } + + protected void onAllRecordsLoaded() { + Log.d(LOG_TAG, "RuimRecords: record load complete"); + + // Further records that can be inserted are Operator/OEM dependent + + recordsLoadedRegistrants.notifyRegistrants( + new AsyncResult(null, null, null)); + ((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent( + 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 + */ + + ((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent( + RuimCard.INTENT_VALUE_ICC_READY, null); + + fetchRuimRecords(); + + phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE)); + + } + + private void fetchRuimRecords() { + recordsRequested = true; + + Log.v(LOG_TAG, "RuimRecords:fetchRuimRecords " + recordsToLoad); + + phone.getIccFileHandler().loadEFTransparent(EF_ICCID, + obtainMessage(EVENT_GET_ICCID_DONE)); + recordsToLoad++; + + // Further records that can be inserted are Operator/OEM dependent + } + + @Override + protected int getDisplayRule(String plmn) { + // TODO together with spn + return 0; + } + + @Override + public void setVoiceMessageWaiting(int line, int countWaiting) { + Log.i(LOG_TAG, "RuimRecords: setVoiceMessageWaiting not supported."); + } + + private void handleRuimRefresh(int[] result) { + if (result == null || result.length == 0) { + if (DBG) log("handleRuimRefresh without input"); + return; + } + + switch ((result[0])) { + case CommandsInterface.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"); + // need to reload all files (that we care about) + fetchRuimRecords(); + break; + case CommandsInterface.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), + * ServiceStateTracker will call setRadioPower when it receives the + * RADIO_STATE_CHANGED notification for the power off. And if the + * desired power state has changed in the interim, we don't want to + * override it with an unconditional power on. + */ + break; + default: + // unknown refresh operation + if (DBG) log("handleRuimRefresh with unknown operation"); + break; + } + } + + protected void log(String s) { + Log.d(LOG_TAG, "[RuimRecords] " + s); + } + +} + diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java new file mode 100644 index 0000000..9439359 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.android.internal.telephony.cdma; + +import android.content.Context; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.IccSmsInterfaceManager; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.SmsRawData; + +import java.util.ArrayList; +import java.util.List; + +import static android.telephony.SmsManager.STATUS_ON_ICC_FREE; + +/** + * RuimSmsInterfaceManager to provide an inter-process communication to + * access Sms in Ruim. + */ +public class RuimSmsInterfaceManager extends IccSmsInterfaceManager { + static final String LOG_TAG = "CDMA"; + static final boolean DBG = true; + + private final Object mLock = new Object(); + private boolean mSuccess; + private List<SmsRawData> mSms; + + private static final int EVENT_LOAD_DONE = 1; + private static final int EVENT_UPDATE_DONE = 2; + + Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + + switch (msg.what) { + case EVENT_UPDATE_DONE: + ar = (AsyncResult) msg.obj; + synchronized (mLock) { + mSuccess = (ar.exception == null); + mLock.notifyAll(); + } + break; + case EVENT_LOAD_DONE: + ar = (AsyncResult)msg.obj; + synchronized (mLock) { + if (ar.exception == null) { + mSms = (List<SmsRawData>) + buildValidRawData((ArrayList<byte[]>) ar.result); + } else { + if(DBG) log("Cannot load Sms records"); + if (mSms != null) + mSms.clear(); + } + mLock.notifyAll(); + } + break; + } + } + }; + + public RuimSmsInterfaceManager(CDMAPhone phone) { + super(phone); + mDispatcher = new CdmaSMSDispatcher(phone); + } + + public void dispose() { + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "RuimSmsInterfaceManager finalized"); + } + + /** + * Update the specified message on the RUIM. + * + * @param index record index of message to update + * @param status new message status (STATUS_ON_ICC_READ, + * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, + * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) + * @param pdu the raw PDU to store + * @return success or not + * + */ + public boolean + updateMessageOnIccEf(int index, int status, byte[] pdu) { + if (DBG) log("updateMessageOnIccEf: index=" + index + + " status=" + status + " ==> " + + "("+ pdu + ")"); + enforceReceiveAndSend("Updating message on RUIM"); + synchronized(mLock) { + mSuccess = false; + Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); + + if (status == STATUS_ON_ICC_FREE) { + // Special case FREE: call deleteSmsOnRuim instead of + // manipulating the RUIM record + mPhone.mCM.deleteSmsOnRuim(index, response); + } else { + byte[] record = makeSmsRecordData(status, pdu); + mPhone.getIccFileHandler().updateEFLinearFixed( + IccConstants.EF_SMS, index, record, null, response); + } + try { + mLock.wait(); + } catch (InterruptedException e) { + log("interrupted while trying to update by index"); + } + } + return mSuccess; + } + + /** + * Copy a raw SMS PDU to the RUIM. + * + * @param pdu the raw PDU to store + * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, + * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) + * @return success or not + * + */ + public boolean copyMessageToIccEf(int status, byte[] pdu, byte[] smsc) { + //NOTE smsc not used in RUIM + if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " + + "pdu=("+ pdu + ")"); + enforceReceiveAndSend("Copying message to RUIM"); + synchronized(mLock) { + mSuccess = false; + Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); + + mPhone.mCM.writeSmsToRuim(status, IccUtils.bytesToHexString(pdu), + response); + + try { + mLock.wait(); + } catch (InterruptedException e) { + log("interrupted while trying to update by index"); + } + } + return mSuccess; + } + + /** + * Retrieves all messages currently stored on RUIM. + */ + public List<SmsRawData> getAllMessagesFromIccEf() { + if (DBG) log("getAllMessagesFromEF"); + + Context context = mPhone.getContext(); + + context.enforceCallingPermission( + "android.permission.RECEIVE_SMS", + "Reading messages from RUIM"); + synchronized(mLock) { + Message response = mHandler.obtainMessage(EVENT_LOAD_DONE); + mPhone.getIccFileHandler().loadEFLinearFixedAll(IccConstants.EF_SMS, response); + + try { + mLock.wait(); + } catch (InterruptedException e) { + log("interrupted while trying to load from the RUIM"); + } + } + return mSms; + } + + protected void log(String msg) { + Log.d(LOG_TAG, "[RuimSmsInterfaceManager] " + msg); + } +} + diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java new file mode 100644 index 0000000..e4b474a --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java @@ -0,0 +1,905 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma; + +import android.os.Parcel; +import android.text.format.Time; +import android.util.Config; +import android.util.Log; +import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.cdma.sms.BearerData; +import com.android.internal.telephony.cdma.sms.CdmaSmsAddress; +import com.android.internal.telephony.cdma.sms.SmsDataCoding; +import com.android.internal.telephony.cdma.sms.SmsEnvelope; +import com.android.internal.telephony.cdma.sms.UserData; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Random; + +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; +import static android.telephony.SmsMessage.MessageClass; +import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_NONE; +import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_TEMPORARY; +import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_PERMANENT; +import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_DELIVER; +import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_SUBMIT; +import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_CANCELLATION; +import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_DELIVERY_ACK; +import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_USER_ACK; +import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_READ_ACK; +import static com.android.internal.telephony.cdma.sms.CdmaSmsAddress.SMS_ADDRESS_MAX; +import static com.android.internal.telephony.cdma.sms.CdmaSmsAddress.SMS_SUBADDRESS_MAX; +import static com.android.internal.telephony.cdma.sms.SmsEnvelope.SMS_BEARER_DATA_MAX; +import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_7BIT_ASCII; +import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_GSM_7BIT_ALPHABET; +import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_IA5; +import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_OCTET; +import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_UNICODE_16; + +/** + * A Short Message Service message. + * + */ +public class SmsMessage extends SmsMessageBase { + static final String LOG_TAG = "CDMA"; + + /** + * Status of a previously submitted SMS. + * This field applies to SMS Delivery Acknowledge messages. 0 indicates success; + * Here, the error class is defined by the bits from 9-8, the status code by the bits from 7-0. + * See C.S0015-B, v2.0, 4.5.21 for a detailed description of possible values. + */ + private int status; + + /** The next message ID for the BearerData. Shall be a random value on first use. + * (See C.S0015-B, v2.0, 4.3.1.5) + */ + private static int nextMessageId = 0; + + /** Specifies if this is the first SMS message submit */ + private static boolean firstSMS = true; + + /** Specifies if a return of an acknowledgment is requested for send SMS */ + private static final int RETURN_NO_ACK = 0; + private static final int RETURN_ACK = 1; + + private SmsEnvelope mEnvelope; + private BearerData mBearerData; + + public static class SubmitPdu extends SubmitPduBase { + } + + /** + * Create an SmsMessage from a raw PDU. + * Note: In CDMA the PDU is just a byte representation of the received Sms. + */ + public static SmsMessage createFromPdu(byte[] pdu) { + SmsMessage msg = new SmsMessage(); + + try { + msg.parsePdu(pdu); + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); + return null; + } + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public static SmsMessage newFromCMT(String[] lines) { + Log.w(LOG_TAG, "newFromCMT: is not supported in CDMA mode."); + return null; + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public static SmsMessage newFromCMTI(String line) { + Log.w(LOG_TAG, "newFromCMTI: is not supported in CDMA mode."); + return null; + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public static SmsMessage newFromCDS(String line) { + Log.w(LOG_TAG, "newFromCDS: is not supported in CDMA mode."); + return null; + } + + /** + * Create a "raw" CDMA SmsMessage from a Parcel that was forged in ril.cpp. + * Note: Only primitive fields are set. + */ + public static SmsMessage newFromParcel(Parcel p) { + // Note: Parcel.readByte actually reads one Int and masks to byte + SmsMessage msg = new SmsMessage(); + SmsEnvelope env = new SmsEnvelope(); + CdmaSmsAddress addr = new CdmaSmsAddress(); + byte[] data; + byte count; + int countInt; + + //currently not supported by the modem-lib: env.mMessageType + env.teleService = p.readInt(); //p_cur->uTeleserviceID + + if (0 != p.readByte()) { //p_cur->bIsServicePresent + env.messageType = SmsEnvelope.MESSAGE_TYPE_BROADCAST; + } + else { + if (SmsEnvelope.TELESERVICE_NOT_SET == env.teleService) { + // assume type ACK + env.messageType = SmsEnvelope.MESSAGE_TYPE_ACKNOWLEDGE; + } else { + env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT; + } + } + env.serviceCategory = p.readInt(); //p_cur->uServicecategory + + // address + addr.digitMode = (byte) (0xFF & p.readInt()); //p_cur->sAddress.digit_mode + addr.numberMode = (byte) (0xFF & p.readInt()); //p_cur->sAddress.number_mode + addr.ton = p.readInt(); //p_cur->sAddress.number_type + addr.numberPlan = (byte) (0xFF & p.readInt()); //p_cur->sAddress.number_plan + count = p.readByte(); //p_cur->sAddress.number_of_digits + addr.numberOfDigits = count; + data = new byte[count]; + //p_cur->sAddress.digits[digitCount] + for (int index=0; index < count; index++) { + data[index] = p.readByte(); + } + addr.origBytes = data; + + // ignore subaddress + p.readInt(); //p_cur->sSubAddress.subaddressType + p.readByte(); //p_cur->sSubAddress.odd + count = p.readByte(); //p_cur->sSubAddress.number_of_digits + //p_cur->sSubAddress.digits[digitCount] : + for (int index=0; index < count; index++) { + p.readByte(); + } + + /* currently not supported by the modem-lib: + env.bearerReply + env.replySeqNo + env.errorClass + env.causeCode + */ + + // bearer data + countInt = p.readInt(); //p_cur->uBearerDataLen + if (countInt >0) { + data = new byte[countInt]; + //p_cur->aBearerData[digitCount] : + for (int index=0; index < countInt; index++) { + data[index] = p.readByte(); + } + env.bearerData = data; + // BD gets further decoded when accessed in SMSDispatcher + } + + // link the the filled objects to the SMS + env.origAddress = addr; + msg.originatingAddress = addr; + msg.mEnvelope = env; + + // create byte stream representation for transportation through the layers. + msg.createPdu(); + + return msg; + } + + /** + * Create an SmsMessage from an SMS EF record. + * + * @param index Index of SMS record. This should be index in ArrayList + * returned by RuimSmsInterfaceManager.getAllMessagesFromIcc + 1. + * @param data Record data. + * @return An SmsMessage representing the record. + * + * @hide + */ + public static SmsMessage createFromEfRecord(int index, byte[] data) { + try { + SmsMessage msg = new SmsMessage(); + + msg.indexOnIcc = index; + + // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT, + // or STORED_UNSENT + // See 3GPP2 C.S0023 3.4.27 + if ((data[0] & 1) == 0) { + Log.w(LOG_TAG, "SMS parsing failed: Trying to parse a free record"); + return null; + } else { + msg.statusOnIcc = data[0] & 0x07; + } + + // Second byte is the MSG_LEN, length of the message + // See 3GPP2 C.S0023 3.4.27 + int size = data[1]; + + // Note: Data may include trailing FF's. That's OK; message + // should still parse correctly. + byte[] pdu = new byte[size]; + System.arraycopy(data, 2, pdu, 0, size); + // the message has to be parsed before it can be displayed + // see gsm.SmsMessage + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); + return null; + } + + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public static int getTPLayerLengthForPDU(String pdu) { + Log.w(LOG_TAG, "getTPLayerLengthForPDU: is not supported in CDMA mode."); + return 0; + } + + /** + * Get an SMS-SUBMIT PDU for a destination address and a message + * + * @param scAddress Service Centre address. Null means use default. + * @param destinationAddress Address of the recipient. + * @param message String representation of the message payload. + * @param statusReportRequested Indicates whether a report is requested for this message. + * @param headerData Array containing the data for the User Data Header, preceded + * by the Element Identifiers. + * @return a <code>SubmitPdu</code> containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + * @hide + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, String message, + boolean statusReportRequested, byte[] headerData) { + + SmsMessage sms = new SmsMessage(); + SubmitPdu ret = new SubmitPdu(); + UserData uData = new UserData(); + SmsHeader smsHeader; + + // Perform null parameter checks. + if (message == null || destinationAddress == null) { + return null; + } + + // ** Set UserData + SmsHeader ** + try { + // First, try encoding it with the GSM alphabet + int septetCount = GsmAlphabet.countGsmSeptets(message, true); + // User Data (and length) + + uData.userData = message.getBytes(); + + if (uData.userData.length > MAX_USER_DATA_SEPTETS) { + // Message too long + return null; + } + + // desired TP-Data-Coding-Scheme + uData.userDataEncoding = UserData.UD_ENCODING_GSM_7BIT_ALPHABET; + + // paddingBits not needed for UD_ENCODING_GSM_7BIT_ALPHABET + + // sms header + if(headerData != null) { + smsHeader = SmsHeader.parse(headerData); + uData.userDataHeader = smsHeader; + } else { + // no user data header available! + } + + } catch (EncodeException ex) { + byte[] textPart; + // Encoding to the 7-bit alphabet failed. Let's see if we can + // send it as a UCS-2 encoded message + + try { + textPart = message.getBytes("utf-16be"); + } catch (UnsupportedEncodingException uex) { + Log.e(LOG_TAG, "Implausible UnsupportedEncodingException ", uex); + return null; + } + + uData.userData = textPart; + + if (uData.userData.length > MAX_USER_DATA_BYTES) { + // Message too long + return null; + } + + // TP-Data-Coding-Scheme + uData.userDataEncoding = UserData.UD_ENCODING_UNICODE_16; + + // sms header + if(headerData != null) { + smsHeader = SmsHeader.parse(headerData); + uData.userDataHeader = smsHeader; + } else { + // no user data header available! + } + } + + byte[] data = sms.getEnvelope(destinationAddress, statusReportRequested, uData, + (headerData != null), (null == headerData)); + + if (null == data) return null; + + ret.encodedMessage = data; + ret.encodedScAddress = null; + return ret; + } + + + /** + * 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); + } + + /** + * 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 + * 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 destinationAddress, short destinationPort, byte[] data, + boolean statusReportRequested) { + + SmsMessage sms = new SmsMessage(); + SubmitPdu ret = new SubmitPdu(); + UserData uData = new UserData(); + SmsHeader smsHeader = new SmsHeader(); + + if (data.length > (MAX_USER_DATA_BYTES - 7 /* UDH size */)) { + Log.e(LOG_TAG, "SMS data message may only contain " + + (MAX_USER_DATA_BYTES - 7) + " bytes"); + return null; + } + + 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.add( + new SmsHeader.Element(SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT, destPort)); + + smsHeader.nbrOfHeaders = smsHeader.getElements().size(); + uData.userDataHeader = smsHeader; + + // TP-Data-Coding-Scheme + // No class, 8 bit data + uData.userDataEncoding = UserData.UD_ENCODING_OCTET; + uData.userData = data; + + byte[] msgData = sms.getEnvelope(destinationAddress, statusReportRequested, uData, + true, true); + + ret.encodedMessage = msgData; + ret.encodedScAddress = null; + return ret; + } + + 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); + } + + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public int getProtocolIdentifier() { + Log.w(LOG_TAG, "getProtocolIdentifier: is not supported in CDMA mode."); + // (3GPP TS 23.040): "no interworking, but SME to SME protocol": + return 0; + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public boolean isReplace() { + Log.w(LOG_TAG, "isReplace: is not supported in CDMA mode."); + return false; + } + + /** + * {@inheritDoc} + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public boolean isCphsMwiMessage() { + Log.w(LOG_TAG, "isCphsMwiMessage: is not supported in CDMA mode."); + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isMWIClearMessage() { + if ((mBearerData != null) && (0 == mBearerData.numberOfMessages)) { + return true; + } + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isMWISetMessage() { + if ((mBearerData != null) && (mBearerData.numberOfMessages >0)) { + return true; + } + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isMwiDontStore() { + if ((mBearerData != null) && (mBearerData.numberOfMessages >0) + && (null == mBearerData.userData)) { + return true; + } + return false; + } + + /** + * Returns the status for a previously submitted message. + * For not interfering with status codes from GSM, this status code is + * shifted to the bits 31-16. + */ + public int getStatus() { + return(status<<16); + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public boolean isStatusReportMessage() { + Log.w(LOG_TAG, "isStatusReportMessage: is not supported in CDMA mode."); + return false; + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public boolean isReplyPathPresent() { + Log.w(LOG_TAG, "isReplyPathPresent: is not supported in CDMA mode."); + return false; + } + + /** + * Returns the teleservice type of the message. + * @return the teleservice: + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_NOT_SET}, + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WMT}, + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WEMT}, + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_VMN}, + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WAP} + */ + public int getTeleService() { + return mEnvelope.teleService; + } + + /** + * Decodes pdu to an empty SMS object. + * In the CDMA case the pdu is just an internal byte stream representation + * of the SMS Java-object. + * @see #createPdu() + */ + private void parsePdu(byte[] pdu) { + ByteArrayInputStream bais = new ByteArrayInputStream(pdu); + DataInputStream dis = new DataInputStream(new BufferedInputStream(bais)); + byte length; + SmsEnvelope env = new SmsEnvelope(); + CdmaSmsAddress addr = new CdmaSmsAddress(); + + try { + env.messageType = dis.readInt(); + env.teleService = dis.readInt(); + env.serviceCategory = dis.readInt(); + + addr.digitMode = dis.readByte(); + addr.numberMode = dis.readByte(); + addr.ton = dis.readByte(); + addr.numberPlan = dis.readByte(); + + length = dis.readByte(); + addr.numberOfDigits = length; + addr.origBytes = new byte[length]; + dis.read(addr.origBytes, 0, length); // digits + + env.bearerReply = dis.readInt(); + // CauseCode values: + env.replySeqNo = dis.readByte(); + env.errorClass = dis.readByte(); + env.causeCode = dis.readByte(); + + //encoded BearerData: + length = dis.readByte(); + env.bearerData = new byte[length]; + dis.read(env.bearerData, 0, length); + dis.close(); + } catch (Exception ex) { + Log.e(LOG_TAG, "createFromPdu: conversion from byte array to object failed: " + ex); + } + + // link the filled objects to this SMS + originatingAddress = addr; + env.origAddress = addr; + mEnvelope = env; + + parseSms(); + } + + /** + * Parses a SMS message from its BearerData stream. (mobile-terminated only) + */ + protected void parseSms() { + mBearerData = SmsDataCoding.decodeCdmaSms(mEnvelope.bearerData); + messageRef = mBearerData.messageID; + + // TP-Message-Type-Indicator + // (See 3GPP2 C.S0015-B, v2, 4.5.1) + int messageType = mBearerData.messageType; + + switch (messageType) { + case MESSAGE_TYPE_USER_ACK: + case MESSAGE_TYPE_READ_ACK: + case MESSAGE_TYPE_DELIVER: + // Deliver (mobile-terminated only) + parseSmsDeliver(); + break; + case MESSAGE_TYPE_DELIVERY_ACK: + parseSmsDeliveryAck(); + break; + + default: + // the rest of these + throw new RuntimeException("Unsupported message type: " + messageType); + } + } + + /** + * 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 (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) { + status = mBearerData.errorClass << 8; + status |= mBearerData.messageStatus; + } + + parseUserData(mBearerData.userData); + + } + + /** + * Parses the User Data of an SMS. + */ + private void parseUserData(UserData uData) { + int encodingType; + + if (null == uData) { + return; + } + + encodingType = uData.userDataEncoding; + + // insert DCS-decoding here when type is supported by ril-library + + userData = uData.userData; + userDataHeader = uData.userDataHeader; + + switch (encodingType) { + case UD_ENCODING_GSM_7BIT_ALPHABET: + case UD_ENCODING_UNICODE_16: + // user data was already decoded by wmsts-library + messageBody = new String(userData); + break; + + // data and unsupported encodings: + case UD_ENCODING_OCTET: + default: + messageBody = null; + break; + } + + if (Config.LOGV) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'"); + + if (messageBody != null) { + parseMessageBody(); + } + } + + /** + * {@inheritDoc} + */ + public MessageClass getMessageClass() { + if (BearerData.DISPLAY_IMMEDIATE == mBearerData.displayMode ) { + return MessageClass.CLASS_0; + } else { + return MessageClass.UNKNOWN; + } + } + + /** + * Creates BearerData and Envelope from parameters for a Submit SMS. + * @return byte stream for SubmitPdu. + */ + private byte[] getEnvelope(String destinationAddress, boolean statusReportRequested, + UserData userData, boolean hasHeaders, boolean useNewId) { + + BearerData mBearerData = new BearerData(); + SmsEnvelope env = new SmsEnvelope(); + CdmaSmsAddress mSmsAddress = new CdmaSmsAddress(); + + // ** set SmsAddress ** + mSmsAddress.digitMode = CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR; + try { + mSmsAddress.origBytes = destinationAddress.getBytes("UTF-8"); + } catch (Exception e) { + Log.e(LOG_TAG, "doGetSubmitPdu: conversion of destinationAddress from string to byte[]" + + " failed: " + e.getMessage()); + return null; + } + mSmsAddress.numberOfDigits = (byte)mSmsAddress.origBytes.length; + mSmsAddress.numberMode = CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK; + // see C.S0015-B, v2.0, 3.4.3.3 + mSmsAddress.numberPlan = CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY; + mSmsAddress.ton = CdmaSmsAddress.TON_INTERNATIONAL_OR_IP; + + // ** set BearerData ** + mBearerData.userData = userData; + mBearerData.messageType = BearerData.MESSAGE_TYPE_SUBMIT; + + if (useNewId) { + setNextMessageId(); + } + mBearerData.messageID = nextMessageId; + + // Set the reply options (See C.S0015-B, v2.0, 4.5.11) + if(statusReportRequested) { + mBearerData.deliveryAckReq = true; + } else { + mBearerData.deliveryAckReq = false; + } + // Currently settings applications do not support this + mBearerData.userAckReq = false; + mBearerData.readAckReq = false; + mBearerData.reportReq = false; + + // Set the display mode (See C.S0015-B, v2.0, 4.5.16) + mBearerData.displayMode = BearerData.DISPLAY_DEFAULT; + + // number of messages: not needed for encoding! + + // indicate whether a user data header is available + mBearerData.hasUserDataHeader = hasHeaders; + + // ** encode BearerData ** + byte[] encodedBearerData = null; + try { + encodedBearerData = SmsDataCoding.encodeCdmaSms(mBearerData); + } catch (Exception e) { + Log.e(LOG_TAG, "doGetSubmitPdu: EncodeCdmaSMS function in JNI interface failed: " + + e.getMessage()); + return null; + } + + // ** SmsEnvelope ** + env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT; + env.teleService = SmsEnvelope.TELESERVICE_WEMT; + env.destAddress = mSmsAddress; + env.bearerReply = RETURN_ACK; + env.bearerData = encodedBearerData; + mEnvelope = env; + + // get byte array output stream from SmsAddress object and SmsEnvelope member. + return serialize(mSmsAddress); + } + + /** + * Set the nextMessageId to a random value between 0 and 65536 + * See C.S0015-B, v2.0, 4.3.1.5 + */ + private void setNextMessageId() { + // Message ID, modulo 65536 + if(firstSMS) { + Random generator = new Random(); + nextMessageId = generator.nextInt(65536); + firstSMS = false; + } else { + nextMessageId = ++nextMessageId & 0xFFFF; + } + } + + /** + * Creates ByteArrayOutputStream from CdmaSmsAddress and SmsEnvelope objects + * + * @param address CdmaSmsAddress object + * @return ByteArrayOutputStream + */ + private byte[] serialize(CdmaSmsAddress destAddress) { + SmsEnvelope env = mEnvelope; + ByteArrayOutputStream baos = new ByteArrayOutputStream(100); + DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos)); + + try { + dos.writeInt(env.teleService); + dos.writeInt(0); //servicePresent + dos.writeInt(0); //serviceCategory + dos.write(destAddress.digitMode); + dos.write(destAddress.numberMode); + dos.write(destAddress.ton); // number_type + dos.write(destAddress.numberPlan); + dos.write(destAddress.numberOfDigits); + dos.write(destAddress.origBytes, 0, destAddress.origBytes.length); // digits + // Subaddress is not supported. + dos.write(0); //subaddressType + dos.write(0); //subaddr_odd + dos.write(0); //subaddr_nbr_of_digits + dos.write(env.bearerData.length); + dos.write(env.bearerData, 0, env.bearerData.length); + dos.close(); + return baos.toByteArray(); + } catch(IOException ex) { + Log.e(LOG_TAG, "serialize: conversion from object to data output stream failed: " + ex); + return null; + } + } + + /** + * Creates byte array (pseudo pdu) from SMS object. + * Note: Do not call this method more than once per object! + */ + private void createPdu() { + SmsEnvelope env = mEnvelope; + CdmaSmsAddress addr = env.origAddress; + ByteArrayOutputStream baos = new ByteArrayOutputStream(100); + DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos)); + + try { + dos.writeInt(env.messageType); + dos.writeInt(env.teleService); + dos.writeInt(env.serviceCategory); + + dos.writeByte(addr.digitMode); + dos.writeByte(addr.numberMode); + dos.writeByte(addr.ton); + dos.writeByte(addr.numberPlan); + dos.writeByte(addr.numberOfDigits); + dos.write(addr.origBytes, 0, addr.origBytes.length); // digits + + dos.writeInt(env.bearerReply); + // CauseCode values: + dos.writeByte(env.replySeqNo); + dos.writeByte(env.errorClass); + dos.writeByte(env.causeCode); + //encoded BearerData: + dos.writeByte(env.bearerData.length); + dos.write(env.bearerData, 0, env.bearerData.length); + dos.close(); + + mPdu = baos.toByteArray(); + } catch (IOException ex) { + Log.e(LOG_TAG, "createPdu: conversion from object to byte array failed: " + ex); + } + } + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/TtyIntent.java b/telephony/java/com/android/internal/telephony/cdma/TtyIntent.java new file mode 100644 index 0000000..f27f79c --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/TtyIntent.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma; + +public class TtyIntent { + + private static final String TAG = "TtyIntent"; + + + /** Event for TTY mode change */ + + /** + * Broadcast intent action indicating that the TTY has either been + * enabled or disabled. An intent extra provides this state as a boolean, + * where {@code true} means enabled. + * @see #TTY_ENABLED + * + * {@hide} + */ + public static final String TTY_ENABLED_CHANGE_ACTION = + "com.android.internal.telephony.cdma.intent.action.TTY_ENABLED_CHANGE"; + + /** + * The lookup key for a boolean that indicates whether TTY mode is enabled or + * disabled. {@code true} means TTY mode is enabled. Retrieve it with + * {@link android.content.Intent#getBooleanExtra(String,boolean)}. + * + * {@hide} + */ + public static final String TTY_ENABLED = "ttyEnabled"; + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/package.html b/telephony/java/com/android/internal/telephony/cdma/package.html new file mode 100644 index 0000000..cf1ad4a --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/package.html @@ -0,0 +1,6 @@ +<HTML> +<BODY> +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 new file mode 100644 index 0000000..fec9529 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma.sms; + +public final class BearerData{ + + // For completeness the following fields are listed, though not used yet. + /** + * Supported priority modes for CDMA SMS messages + * (See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1) + */ + //public static final int PRIORITY_NORMAL = 0x0; + //public static final int PRIORITY_INTERACTIVE = 0x1; + //public static final int PRIORITY_URGENT = 0x2; + //public static final int PRIORITY_EMERGENCY = 0x3; + + /** + * Supported privacy modes for CDMA SMS messages + * (See 3GPP2 C.S0015-B, v2.0, table 4.5.10-1) + */ + //public static final int PRIVACY_NOT_RESTRICTED = 0x0; + //public static final int PRIVACY_RESTRICTED = 0x1; + //public static final int PRIVACY_CONFIDENTIAL = 0x2; + //public static final int PRIVACY_SECRET = 0x3; + + /** + * Supported alert modes for CDMA SMS messages + * (See 3GPP2 C.S0015-B, v2.0, table 4.5.13-1) + */ + //public static final int ALERT_DEFAULT = 0x0; + //public static final int ALERT_LOW_PRIO = 0x1; + //public static final int ALERT_MEDIUM_PRIO = 0x2; + //public static final int ALERT_HIGH_PRIO = 0x3; + + /** + * Supported display modes for CDMA SMS messages + * (See 3GPP2 C.S0015-B, v2.0, table 4.5.16-1) + */ + public static final int DISPLAY_IMMEDIATE = 0x0; + public static final int DISPLAY_DEFAULT = 0x1; + public static final int DISPLAY_USER = 0x2; + + /** + * Supported message types for CDMA SMS messages + * (See 3GPP2 C.S0015-B, v2.0, table 4.5.1-1) + */ + public static final int MESSAGE_TYPE_DELIVER = 0x01; + public static final int MESSAGE_TYPE_SUBMIT = 0x02; + public static final int MESSAGE_TYPE_CANCELLATION = 0x03; + public static final int MESSAGE_TYPE_DELIVERY_ACK = 0x04; + public static final int MESSAGE_TYPE_USER_ACK = 0x05; + public static final int MESSAGE_TYPE_READ_ACK = 0x06; + public static final int MESSAGE_TYPE_DELIVER_REPORT = 0x07; + public static final int MESSAGE_TYPE_SUBMIT_REPORT = 0x08; + + /** + * SMS Message Status Codes + * (See 3GPP2 C.S0015-B, v2.0, table 4.5.21-1) + */ + /* no-error codes */ + public static final int ERROR_NONE = 0x00; + public static final int STATUS_ACCEPTED = 0x00; + public static final int STATUS_DEPOSITED_TO_INTERNET = 0x01; + public static final int STATUS_DELIVERED = 0x02; + public static final int STATUS_CANCELLED = 0x03; + /* temporary-error and permanent-error codes */ + public static final int ERROR_TEMPORARY = 0x02; + public static final int STATUS_NETWORK_CONGESTION = 0x04; + public static final int STATUS_NETWORK_ERROR = 0x05; + public static final int STATUS_UNKNOWN_ERROR = 0x1F; + /* permanent-error codes */ + public static final int ERROR_PERMANENT = 0x03; + public static final int STATUS_CANCEL_FAILED = 0x06; + public static final int STATUS_BLOCKED_DESTINATION = 0x07; + public static final int STATUS_TEXT_TOO_LONG = 0x08; + public static final int STATUS_DUPLICATE_MESSAGE = 0x09; + public static final int STATUS_INVALID_DESTINATION = 0x0A; + public static final int STATUS_MESSAGE_EXPIRED = 0x0D; + /* undefined-status codes */ + public static final int ERROR_UNDEFINED = 0xFF; + public static final int STATUS_UNDEFINED = 0xFF; + + /** Bit-mask indicating used fields for SmsDataCoding */ + public int mask; + + /** + * 4-bit value indicating the message type in accordance to + * table 4.5.1-1 + * (See 3GPP2 C.S0015-B, v2, 4.5.1) + */ + public byte messageType; + + /** + * 16-bit value indicating the message ID, which increments modulo 65536. + * (Special rules apply for WAP-messages.) + * (See 3GPP2 C.S0015-B, v2, 4.5.1) + */ + public int messageID; + + /** + * 1-bit value that indicates whether a User Data Header is present. + * (See 3GPP2 C.S0015-B, v2, 4.5.1) + */ + public boolean hasUserDataHeader; + + /** + * provides the information for the user data + * (e.g. padding bits, user data, user data header, etc) + * (See 3GPP2 C.S.0015-B, v2, 4.5.2) + */ + public UserData userData; + + //public UserResponseCode userResponseCode; + + /** + * 6-byte-field, see 3GPP2 C.S0015-B, v2, 4.5.4 + * year, month, day, hours, minutes, seconds; + */ + public byte[] timeStamp; + + //public SmsTime validityPeriodAbsolute; + //public SmsRelTime validityPeriodRelative; + //public SmsTime deferredDeliveryTimeAbsolute; + //public SmsRelTime deferredDeliveryTimeRelative; + //public byte priority; + //public byte privacy; + + /** + * Reply Option + * 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; + public boolean readAckReq; + 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) + */ + public int numberOfMessages; + + //public int alert; + //public int language; + + /** + * 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) + */ + public CdmaSmsAddress callbackNumber; + + /** + * 2-bit value that is used to indicate to the mobile station when to display + * the received message. + * (See 3GPP2 C.S0015-B, v2, 4.5.16) + */ + public byte displayMode = DISPLAY_DEFAULT; + + /** + * First component of the Message status, that indicates if an error has occurred + * and whether the error is considered permanent or temporary. + * (See 3GPP2 C.S0015-B, v2, 4.5.21) + */ + public int errorClass = ERROR_UNDEFINED; + + /** + * Second component of the Message status, that indicates if an error has occurred + * and the cause of the error. + * (See 3GPP2 C.S0015-B, v2, 4.5.21) + */ + public int messageStatus = STATUS_UNDEFINED; + +} + diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java new file mode 100644 index 0000000..1643cab --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma.sms; + +import com.android.internal.telephony.SmsAddress; + +public class CdmaSmsAddress extends SmsAddress { + /** + * digit mode indicators + * (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; + + /** + * number mode indicators + * (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; + + /** + * number types for data networks + * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + */ + static public final int TON_UNKNOWN = 0x00; + static public final int TON_INTERNATIONAL_OR_IP = 0x01; + static public final int TON_NATIONAL_OR_EMAIL = 0x02; + static public final int TON_NETWORK = 0x03; + static public final int TON_SUBSCRIBER = 0x04; + static public final int TON_ALPHANUMERIC = 0x05; + static public final int TON_ABBREVIATED = 0x06; + static public final int TON_RESERVED = 0x07; + + /** + * 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) + */ + static public final int NUMBERING_PLAN_UNKNOWN = 0x0; + static public final int NUMBERING_PLAN_ISDN_TELEPHONY = 0x1; + //static protected final int NUMBERING_PLAN_DATA = 0x3; + //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; + + /** + * 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) + */ + 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(){ + } + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsDataCoding.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsDataCoding.java new file mode 100644 index 0000000..6ba7463 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsDataCoding.java @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma.sms; + +import com.android.internal.telephony.SmsHeader; + +/* + * The SMSDataCoding class encodes and decodes CDMA SMS messages. + */ +public class SmsDataCoding { + private final static String TAG = "CDMA_SMS_JNI"; + + private final static int CDMA_SMS_WMS_MASK_BD_NULL = 0x00000000; + private final static int CDMA_SMS_WMS_MASK_BD_MSG_ID = 0x00000001; + private final static int CDMA_SMS_WMS_MASK_BD_USER_DATA = 0x00000002; +// private final static int CDMA_SMS_WMS_MASK_BD_USER_RESP = 0x00000004; + private final static int CDMA_SMS_WMS_MASK_BD_MC_TIME = 0x00000008; +// private final static int CDMA_SMS_WMS_MASK_BD_VALID_ABS = 0x00000010; +// private final static int CDMA_SMS_WMS_MASK_BD_VALID_REL = 0x00000020; +// private final static int CDMA_SMS_WMS_MASK_BD_DEFER_ABS = 0x00000040; +// private final static int CDMA_SMS_WMS_MASK_BD_DEFER_REL = 0x00000080; +// private final static int CDMA_SMS_WMS_MASK_BD_PRIORITY = 0x00000100; +// private final static int CDMA_SMS_WMS_MASK_BD_PRIVACY = 0x00000200; +// private final static int CDMA_SMS_WMS_MASK_BD_REPLY_OPTION = 0x00000400; + private final static int CDMA_SMS_WMS_MASK_BD_NUM_OF_MSGS = 0x00000800; +// private final static int CDMA_SMS_WMS_MASK_BD_ALERT = 0x00001000; +// private final static int CDMA_SMS_WMS_MASK_BD_LANGUAGE = 0x00002000; + private final static int CDMA_SMS_WMS_MASK_BD_CALLBACK = 0x00004000; + private final static int CDMA_SMS_WMS_MASK_BD_DISPLAY_MODE = 0x00008000; +// private final static int CDMA_SMS_WMS_MASK_BD_SCPT_DATA = 0x00010000; +// private final static int CDMA_SMS_WMS_MASK_BD_SCPT_RESULT = 0x00020000; +// private final static int CDMA_SMS_WMS_MASK_BD_DEPOSIT_INDEX = 0x00040000; +// private final static int CDMA_SMS_WMS_MASK_BD_DELIVERY_STATUS = 0x00080000; +// private final static int CDMA_SMS_WMS_MASK_BD_IP_ADDRESS = 0x10000000; +// private final static int CDMA_SMS_WMS_MASK_BD_RSN_NO_NOTIFY = 0x20000000; +// private final static int CDMA_SMS_WMS_MASK_BD_OTHER = 0x40000000; + + /** + * Successful operation. + */ + private static final int JNI_CDMA_SMS_SUCCESS = 0; + + /** + * General failure. + */ + private static final int JNI_CDMA_SMS_FAILURE = 1; + + /** + * Data length is out of length. + */ + private static final int JNI_CDMA_SMS_DATA_LEN_OUT_OF_RANGE = 2; + + /** + * Class name unknown. + */ + private static final int JNI_CDMA_SMS_CLASS_UNKNOWN = 3; + + /** + * Field ID unknown. + */ + private static final int JNI_CDMA_SMS_FIELD_ID_UNKNOWN = 4; + + /** + * Memory allocation failed. + */ + private static final int JNI_CDMA_SMS_OUT_OF_MEMORY = 5; + + /** + * Encode SMS. + * + * @param bearerData an instance of BearerData. + * + * @return the encoded SMS as byte[]. + */ + public static byte[] encodeCdmaSms(BearerData bearerData) { + byte[] encodedSms; + + if( nativeCdmaSmsConstructClientBD() == JNI_CDMA_SMS_FAILURE){ + return null; + } + + // check bearer data and generate bit mask + generateBearerDataBitMask(bearerData); + encodedSms = startEncoding(bearerData); + + if( nativeCdmaSmsDestructClientBD() == JNI_CDMA_SMS_FAILURE){ + return null; + } + return encodedSms; + } + + /** + * Decode SMS. + * + * @param SmsData the encoded SMS. + * + * @return an instance of BearerData. + */ + public static BearerData decodeCdmaSms(byte[] SmsData) { + BearerData bearerData; + + if( nativeCdmaSmsConstructClientBD() == JNI_CDMA_SMS_FAILURE){ + return null; + } + + bearerData = startDecoding(SmsData); + + if( nativeCdmaSmsDestructClientBD() == JNI_CDMA_SMS_FAILURE){ + return null; + } + return bearerData; + } + + private static void generateBearerDataBitMask(BearerData bearerData) { + // initial + bearerData.mask = CDMA_SMS_WMS_MASK_BD_NULL; + + // check message type + if (bearerData.messageType != 0){ + bearerData.mask |= CDMA_SMS_WMS_MASK_BD_MSG_ID; + } + + // check mUserData + if (bearerData.userData != null){ + bearerData.mask |= CDMA_SMS_WMS_MASK_BD_USER_DATA; + } + + // check mTimeStamp + if (bearerData.timeStamp != null){ + bearerData.mask |= CDMA_SMS_WMS_MASK_BD_MC_TIME; + } + + // check mNumberOfMessages + if (bearerData.numberOfMessages > 0){ + bearerData.mask |= CDMA_SMS_WMS_MASK_BD_NUM_OF_MSGS; + } + + // check mCallbackNumber + if(bearerData.callbackNumber != null){ + bearerData.mask |= CDMA_SMS_WMS_MASK_BD_CALLBACK; + } + + // check DisplayMode + if(bearerData.displayMode == BearerData.DISPLAY_DEFAULT || + bearerData.displayMode == BearerData.DISPLAY_IMMEDIATE || + bearerData.displayMode == BearerData.DISPLAY_USER){ + bearerData.mask |= CDMA_SMS_WMS_MASK_BD_DISPLAY_MODE; + } + } + + private static byte[] startEncoding(BearerData bearerData) { + int m_id; + byte[] m_data; + int dataLength; + byte[] encodedSms; + int nbrOfHeaders = 0; + + if( nativeCdmaSmsSetBearerDataPrimitives(bearerData) == JNI_CDMA_SMS_FAILURE){ + return null; + } + + if ((bearerData.mask & CDMA_SMS_WMS_MASK_BD_USER_DATA) == CDMA_SMS_WMS_MASK_BD_USER_DATA){ + if( nativeCdmaSmsSetUserData(bearerData.userData) == JNI_CDMA_SMS_FAILURE){ + return null; + } + + if (bearerData.userData.userDataHeader != null){ + nbrOfHeaders = bearerData.userData.userDataHeader.nbrOfHeaders; + } + + for (int i = 0; i < nbrOfHeaders; i++) { + m_id = bearerData.userData.userDataHeader.getElements().get(i).getID(); + m_data = bearerData.userData.userDataHeader.getElements().get(i).getData(); + dataLength = m_data.length; + if( nativeCdmaSmsSetUserDataHeader(m_id, m_data, dataLength, i) + == JNI_CDMA_SMS_FAILURE){ + return null; + } + } + } + + if ((bearerData.mask & CDMA_SMS_WMS_MASK_BD_CALLBACK) == CDMA_SMS_WMS_MASK_BD_CALLBACK) { + if( nativeCdmaSmsSetSmsAddress(bearerData.callbackNumber) == JNI_CDMA_SMS_FAILURE){ + return null; + } + } + + /* call native method to encode SMS */ + encodedSms = nativeCdmaSmsEncodeSms(); + + return encodedSms; + } + + private static BearerData startDecoding(byte[] SmsData) { + BearerData bData = new BearerData(); + byte[] udhData; + + /* call native method to decode SMS */ + if( nativeCdmaSmsDecodeSms(SmsData) == JNI_CDMA_SMS_FAILURE){ + return null; + } + + if( nativeCdmaSmsGetBearerDataPrimitives(bData) == JNI_CDMA_SMS_FAILURE){ + return null; + } + + if ((bData.mask & CDMA_SMS_WMS_MASK_BD_USER_DATA) == CDMA_SMS_WMS_MASK_BD_USER_DATA) { + bData.userData = new UserData(); + if( nativeCdmaSmsGetUserData(bData.userData) == JNI_CDMA_SMS_FAILURE){ + return null; + } + + udhData = nativeCdmaSmsGetUserDataHeader(); + if (udhData != null) { + bData.userData.userDataHeader = SmsHeader.parse(udhData); + } + } + + if ((bData.mask & CDMA_SMS_WMS_MASK_BD_CALLBACK) == CDMA_SMS_WMS_MASK_BD_CALLBACK) { + bData.callbackNumber = new CdmaSmsAddress(); + if( nativeCdmaSmsGetSmsAddress(bData.callbackNumber) == JNI_CDMA_SMS_FAILURE){ + return null; + } + } + + return bData; + } + + // native methods + + /** + * native method: Allocate memory for clientBD structure + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsConstructClientBD(); + + /** + * native method: Free memory used for clientBD structure + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsDestructClientBD(); + + /** + * native method: fill clientBD structure with bearerData primitives + * + * @param bearerData an instance of BearerData. + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsSetBearerDataPrimitives(BearerData bearerData); + + /** + * native method: fill bearerData primitives with clientBD variables + * + * @param bearerData an instance of BearerData. + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsGetBearerDataPrimitives(BearerData bearerData); + + /** + * native method: fill clientBD.user_data with UserData primitives + * + * @param userData an instance of UserData. + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsSetUserData(UserData userData); + + /** + * native method: fill UserData primitives with clientBD.user_data + * + * @param userData an instance of UserData. + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsGetUserData(UserData userData); + + /** + * native method: fill clientBD.user_data.headers with UserDataHeader primitives + * + * @param ID ID of element. + * @param data element data. + * @param dataLength data length + * @param index index of element + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsSetUserDataHeader( + int ID, byte[] data, int dataLength, int index); + + /** + * native method: fill UserDataHeader primitives with clientBD.user_data.headers + * + * @return user data headers + */ + private static native byte[] nativeCdmaSmsGetUserDataHeader(); + + /** + * native method: fill clientBD.callback with SmsAddress primitives + * + * @param smsAddr an instance of SmsAddress. + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsSetSmsAddress(CdmaSmsAddress smsAddr); + + /** + * native method: fill SmsAddress primitives with clientBD.callback + * + * @param smsAddr an instance of SmsAddress. + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsGetSmsAddress(CdmaSmsAddress smsAddr); + + /** + * native method: call encoding functions and get encoded SMS + * + * @return the encoded SMS + */ + private static native byte[] nativeCdmaSmsEncodeSms(); + + /** + * native method: call decode functions + * + * @param encodedSMS encoded SMS. + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsDecodeSms(byte[] encodedSMS); + + /** + * Load the shared library to link the native methods. + */ + static { + try { + System.loadLibrary("cdma_sms_jni"); + } + catch (UnsatisfiedLinkError ule) { + System.err.println("WARNING: Could not load cdma_sms_jni.so"); + } + } +} + diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java new file mode 100644 index 0000000..f80e8c0 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma.sms; + + +public final class SmsEnvelope{ + /** + * Message Types + * (See 3GPP2 C.S0015-B 3.4.1) + */ + static public final int MESSAGE_TYPE_POINT_TO_POINT = 0x00; + static public final int MESSAGE_TYPE_BROADCAST = 0x01; + static public final int MESSAGE_TYPE_ACKNOWLEDGE = 0x02; + + /** + * Supported Teleservices + * (See 3GPP2 N.S0005 and TIA-41) + */ + static public final int TELESERVICE_NOT_SET = 0x0000; + static public final int TELESERVICE_WMT = 0x1002; + static public final int TELESERVICE_VMN = 0x1003; + static public final int TELESERVICE_WAP = 0x1004; + static public final int TELESERVICE_WEMT = 0x1005; + + // ServiceCategories for Cell Broadcast, see 3GPP2 C.R1001 table 9.3.1-1 + //static public final int SERVICECATEGORY_EMERGENCY = 0x0010; + //... + + /** + * maximum lengths for fields as defined in ril_cdma_sms.h + */ + static public final int SMS_BEARER_DATA_MAX = 255; + + /** + * Provides the type of a SMS message like point to point, broadcast or acknowledge + */ + public int messageType; + + /** + * The 16-bit Teleservice parameter identifies which upper layer service access point is sending + * or receiving the message. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.1) + */ + public int teleService = TELESERVICE_NOT_SET; + + /** + * The 16-bit service category parameter identifies the type of service provided + * by the SMS message. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.2) + */ + public int serviceCategory; + + /** + * The origination address identifies the originator of the SMS message. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.4) + */ + public CdmaSmsAddress origAddress; + + /** + * The destination address identifies the target of the SMS message. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.4) + */ + public CdmaSmsAddress destAddress; + + /** + * The 6-bit bearer reply parameter is used to request the return of a + * SMS Acknowledge Message. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.5) + */ + public int bearerReply; + + /** + * Cause Code values: + * The cause code parameters are an indication whether an SMS error has occurred and if so, + * whether the condition is considered temporary or permanent. + * ReplySeqNo 6-bit value, + * ErrorClass 2-bit value, + * CauseCode 0-bit or 8-bit value + * (See 3GPP2 C.S0015-B, v2, 3.4.3.6) + */ + public byte replySeqNo; + public byte errorClass; + public byte causeCode; + + /** + * encoded bearer data + * (See 3GPP2 C.S0015-B, v2, 3.4.3.7) + */ + public byte[] bearerData; + + public SmsEnvelope() { + // nothing to see here + } + +} + diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java new file mode 100644 index 0000000..e761469 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma.sms; + +import com.android.internal.telephony.SmsHeader; + +public class UserData{ + + /** + * Supported user data encoding types + * (See 3GPP2 C.R1001-F, v1.0, table 9.1-1) + */ + public static final int UD_ENCODING_OCTET = 0x00; + //public static final int UD_ENCODING_EXTENDED_PROTOCOL = 0x01; + public static final int UD_ENCODING_7BIT_ASCII = 0x02; + public static final int UD_ENCODING_IA5 = 0x03; + public static final int UD_ENCODING_UNICODE_16 = 0x04; + //public static final int UD_ENCODING_SHIFT_JIS = 0x05; + //public static final int UD_ENCODING_KOREAN = 0x06; + //public static final int UD_ENCODING_LATIN_HEBREW = 0x07; + //public static final int UD_ENCODING_LATIN = 0x08; + public static final int UD_ENCODING_GSM_7BIT_ALPHABET = 0x09; + //public static final int UD_ENCODING_GSM_DCS = 0x0A; + + /** + * Contains the data header of the user data + */ + public SmsHeader userDataHeader; + + /** + * Contains the data encoding type for the SMS message + */ + public int userDataEncoding; + + // needed when encoding is IS91 or DCS (not supported yet): + //public int messageType; + + /** + * Number of invalid bits in the last byte of data. + */ + public int paddingBits; + + /** + * Contains the user data of a SMS message + * (See 3GPP2 C.S0015-B, v2, 4.5.2) + */ + public byte[] userData; + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/package.html b/telephony/java/com/android/internal/telephony/cdma/sms/package.html new file mode 100644 index 0000000..48e1034 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/package.html @@ -0,0 +1,6 @@ +<HTML> +<BODY> +Provides CDMA-specific features for text/data/PDU SMS messages +@hide +</BODY> +</HTML> diff --git a/telephony/java/com/android/internal/telephony/gsm/AdnRecord.java b/telephony/java/com/android/internal/telephony/gsm/AdnRecord.java deleted file mode 100644 index 30df699..0000000 --- a/telephony/java/com/android/internal/telephony/gsm/AdnRecord.java +++ /dev/null @@ -1,570 +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 com.android.internal.telephony.*; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.Message; -import android.os.Handler; -import android.os.Looper; -import android.os.AsyncResult; -import android.util.Log; -import android.telephony.PhoneNumberUtils; -import java.util.ArrayList; - -class AdnRecordLoader extends Handler -{ - static final String LOG_TAG = "GSM"; - - //***** Instance Variables - - GSMPhone phone; - int ef; - int extensionEF; - int pendingExtLoads; - Message userResponse; - String pin2; - - // For "load one" - int recordNumber; - - // for "load all" - ArrayList<AdnRecord> adns; // only valid after EVENT_ADN_LOAD_ALL_DONE - - // Either an AdnRecord or a reference to adns depending - // if this is a load one or load all operation - Object result; - - //***** Event Constants - - static final int EVENT_ADN_LOAD_DONE = 1; - static final int EVENT_EXT_RECORD_LOAD_DONE = 2; - static final int EVENT_ADN_LOAD_ALL_DONE = 3; - static final int EVENT_EF_LINEAR_RECORD_SIZE_DONE = 4; - static final int EVENT_UPDATE_RECORD_DONE = 5; - - //***** Constructor - - AdnRecordLoader(GSMPhone phone) - { - // The telephony unit-test cases may create AdnRecords - // in secondary threads - super(phone.h.getLooper()); - - this.phone = phone; - } - - /** - * Resulting AdnRecord is placed in response.obj.result - * or response.obj.exception is set - */ - void - loadFromEF(int ef, int extensionEF, int recordNumber, - Message response) - { - this.ef = ef; - this.extensionEF = extensionEF; - this.recordNumber = recordNumber; - this.userResponse = response; - - phone.mSIMFileHandler.loadEFLinearFixed( - ef, recordNumber, - obtainMessage(EVENT_ADN_LOAD_DONE)); - - } - - - /** - * Resulting ArrayList<adnRecord> is placed in response.obj.result - * or response.obj.exception is set - */ - void - loadAllFromEF(int ef, int extensionEF, - Message response) - { - this.ef = ef; - this.extensionEF = extensionEF; - this.userResponse = response; - - phone.mSIMFileHandler.loadEFLinearFixedAll( - ef, - obtainMessage(EVENT_ADN_LOAD_ALL_DONE)); - - } - - /** - * Write adn to a EF SIM record - * It will get the record size of EF record and compose hex adn array - * then write the hex array to EF record - * - * @param adn is set with alphaTag and phoneNubmer - * @param ef EF fileid - * @param extensionEF extension EF fileid - * @param recordNumber 1-based record index - * @param pin2 for CHV2 operations, must be null if pin2 is not needed - * @param response will be sent to its handler when completed - */ - void - updateEF(AdnRecord adn, int ef, int extensionEF, int recordNumber, - String pin2, Message response) - { - this.ef = ef; - this.extensionEF = extensionEF; - this.recordNumber = recordNumber; - this.userResponse = response; - this.pin2 = pin2; - - phone.mSIMFileHandler.getEFLinearRecordSize( ef, - obtainMessage(EVENT_EF_LINEAR_RECORD_SIZE_DONE, adn)); - } - - //***** Overridden from Handler - - public void - handleMessage(Message msg) - { - AsyncResult ar; - byte data[]; - AdnRecord adn; - - try { - switch (msg.what) { - case EVENT_EF_LINEAR_RECORD_SIZE_DONE: - ar = (AsyncResult)(msg.obj); - adn = (AdnRecord)(ar.userObj); - - if (ar.exception != null) { - throw new RuntimeException("get EF record size failed", - ar.exception); - } - - int[] recordSize = (int[])ar.result; - // recordSize is int[3] array - // int[0] is the record length - // int[1] is the total length of the EF file - // int[2] is the number of records in the EF file - // So int[0] * int[2] = int[1] - if (recordSize.length != 3 || recordNumber > recordSize[2]) { - throw new RuntimeException("get wrong EF record size format", - ar.exception); - } - - data = adn.buildAdnString(recordSize[0]); - - if(data == null) { - throw new RuntimeException("worong ADN format", - ar.exception); - } - - phone.mSIMFileHandler.updateEFLinearFixed(ef, recordNumber, - data, pin2, obtainMessage(EVENT_UPDATE_RECORD_DONE)); - - pendingExtLoads = 1; - - break; - case EVENT_UPDATE_RECORD_DONE: - ar = (AsyncResult)(msg.obj); - if (ar.exception != null) { - throw new RuntimeException("update EF adn record failed", - ar.exception); - } - pendingExtLoads = 0; - result = null; - break; - case EVENT_ADN_LOAD_DONE: - ar = (AsyncResult)(msg.obj); - data = (byte[])(ar.result); - - if (ar.exception != null) { - throw new RuntimeException("load failed", ar.exception); - } - - if (false) { - Log.d(LOG_TAG,"ADN EF: 0x" - + Integer.toHexString(ef) - + ":" + recordNumber - + "\n" + SimUtils.bytesToHexString(data)); - } - - adn = new AdnRecord(ef, recordNumber, data); - result = adn; - - if (adn.hasExtendedRecord()) { - // If we have a valid value in the ext record field, - // we're not done yet: we need to read the corresponding - // ext record and append it - - pendingExtLoads = 1; - - phone.mSIMFileHandler.loadEFLinearFixed( - extensionEF, adn.extRecord, - obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn)); - } - break; - - case EVENT_EXT_RECORD_LOAD_DONE: - ar = (AsyncResult)(msg.obj); - data = (byte[])(ar.result); - adn = (AdnRecord)(ar.userObj); - - if (ar.exception != null) { - throw new RuntimeException("load failed", ar.exception); - } - - Log.d(LOG_TAG,"ADN extention EF: 0x" - + Integer.toHexString(extensionEF) - + ":" + adn.extRecord - + "\n" + SimUtils.bytesToHexString(data)); - - adn.appendExtRecord(data); - - pendingExtLoads--; - // result should have been set in - // EVENT_ADN_LOAD_DONE or EVENT_ADN_LOAD_ALL_DONE - break; - - case EVENT_ADN_LOAD_ALL_DONE: - ar = (AsyncResult)(msg.obj); - ArrayList<byte[]> datas = (ArrayList<byte[]>)(ar.result); - - if (ar.exception != null) { - throw new RuntimeException("load failed", ar.exception); - } - - adns = new ArrayList<AdnRecord>(datas.size()); - result = adns; - pendingExtLoads = 0; - - for(int i = 0, s = datas.size() ; i < s ; i++) { - adn = new AdnRecord(ef, 1 + i, datas.get(i)); - adns.add(adn); - - if (adn.hasExtendedRecord()) { - // If we have a valid value in the ext record field, - // we're not done yet: we need to read the corresponding - // ext record and append it - - pendingExtLoads++; - - phone.mSIMFileHandler.loadEFLinearFixed( - extensionEF, adn.extRecord, - obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn)); - } - } - break; - } - } catch (RuntimeException exc) { - if (userResponse != null) { - AsyncResult.forMessage(userResponse) - .exception = exc; - userResponse.sendToTarget(); - // Loading is all or nothing--either every load succeeds - // or we fail the whole thing. - userResponse = null; - } - return; - } - - if (userResponse != null && pendingExtLoads == 0) { - AsyncResult.forMessage(userResponse).result - = result; - - userResponse.sendToTarget(); - userResponse = null; - } - } - - -} - -/** - * - * Used to load or store ADNs (Abbreviated Dialing Numbers). - * - * {@hide} - * - */ -public class AdnRecord implements Parcelable -{ - static final String LOG_TAG = "GSM"; - - //***** Instance Variables - - String alphaTag = ""; - String number = ""; - int extRecord = 0xff; - int efid; // or 0 if none - int recordNumber; // or 0 if none - - - //***** Constants - - // In an ADN record, everything but the alpha identifier - // is in a footer that's 14 bytes - static final int FOOTER_SIZE_BYTES = 14; - - // Maximum size of the un-extended number field - static final int MAX_NUMBER_SIZE_BYTES = 11; - - static final int EXT_RECORD_LENGTH_BYTES = 13; - static final int EXT_RECORD_TYPE_ADDITIONAL_DATA = 2; - static final int EXT_RECORD_TYPE_MASK = 3; - static final int MAX_EXT_CALLED_PARTY_LENGTH = 0xa; - - // ADN offset - static final int ADN_BCD_NUMBER_LENGTH = 0; - static final int ADN_TON_AND_NPI = 1; - static final int ADN_DAILING_NUMBER_START = 2; - static final int ADN_DAILING_NUMBER_END = 11; - static final int ADN_CAPABILITY_ID = 12; - static final int ADN_EXTENSION_ID = 13; - - //***** Static Methods - - public static final Parcelable.Creator<AdnRecord> CREATOR - = new Parcelable.Creator<AdnRecord>() - { - public AdnRecord createFromParcel(Parcel source) - { - int efid; - int recordNumber; - String alphaTag; - String number; - - efid = source.readInt(); - recordNumber = source.readInt(); - alphaTag = source.readString(); - number = source.readString(); - - return new AdnRecord(efid, recordNumber, alphaTag, number); - } - - public AdnRecord[] newArray(int size) - { - return new AdnRecord[size]; - } - }; - - - //***** Constructor - public - AdnRecord (byte[] record) - { - this(0, 0, record); - } - - public - AdnRecord (int efid, int recordNumber, byte[] record) - { - this.efid = efid; - this.recordNumber = recordNumber; - parseRecord(record); - } - - public - AdnRecord (String alphaTag, String number) - { - this(0, 0, alphaTag, number); - } - - public - AdnRecord (int efid, int recordNumber, String alphaTag, String number) - { - this.efid = efid; - this.recordNumber = recordNumber; - this.alphaTag = alphaTag; - this.number = number; - } - - //***** Instance Methods - - public String getAlphaTag() - { - return alphaTag; - } - - public String getNumber() - { - return number; - } - - public String toString() - { - return "ADN Record '" + alphaTag + "' '" + number + "'"; - } - - public boolean isEmpty() - { - return alphaTag.equals("") && number.equals(""); - } - - public boolean hasExtendedRecord() - { - return extRecord != 0 && extRecord != 0xff; - } - - public boolean isEqual(AdnRecord adn) { - return ( alphaTag.equals(adn.getAlphaTag()) && - number.equals(adn.getNumber()) ); - } - //***** Parcelable Implementation - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) - { - dest.writeInt(efid); - dest.writeInt(recordNumber); - dest.writeString(alphaTag); - dest.writeString(number); - } - - /** - * Build adn hex byte array based on record size - * The format of byte array is defined in 51.011 10.5.1 - * - * @param recordSize is the size X of EF record - * @return hex byte[recordSize] to be written to EF record - * return nulll for wrong format of dialing nubmer or tag - */ - public byte[] buildAdnString(int recordSize) { - byte[] bcdNumber; - byte[] byteTag; - byte[] adnString = null; - int footerOffset = recordSize - FOOTER_SIZE_BYTES; - - if (number == null || number.equals("") || - alphaTag == null || alphaTag.equals("")) { - - Log.w(LOG_TAG, "[buildAdnString] Empty alpha tag or number"); - adnString = new byte[recordSize]; - for (int i = 0; i < recordSize; i++) { - adnString[i] = (byte) 0xFF; - } - } else if (number.length() - > (ADN_DAILING_NUMBER_END - ADN_DAILING_NUMBER_START + 1) * 2) { - Log.w(LOG_TAG, - "[buildAdnString] Max length of dailing number is 20"); - } else if (alphaTag.length() > footerOffset) { - Log.w(LOG_TAG, - "[buildAdnString] Max length of tag is " + footerOffset); - } else { - - adnString = new byte[recordSize]; - for (int i = 0; i < recordSize; i++) { - adnString[i] = (byte) 0xFF; - } - - bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(number); - - System.arraycopy(bcdNumber, 0, adnString, - footerOffset + ADN_TON_AND_NPI, bcdNumber.length); - - adnString[footerOffset + ADN_BCD_NUMBER_LENGTH] - = (byte) (bcdNumber.length); - adnString[footerOffset + ADN_CAPABILITY_ID] - = (byte) 0xFF; // Capacility Id - adnString[footerOffset + ADN_EXTENSION_ID] - = (byte) 0xFF; // Extension Record Id - - byteTag = GsmAlphabet.stringToGsm8BitPacked(alphaTag); - System.arraycopy(byteTag, 0, adnString, 0, byteTag.length); - - } - - return adnString; - } - - /** - * See TS 51.011 10.5.10 - */ - public void - appendExtRecord (byte[] extRecord) { - try { - if (extRecord.length != EXT_RECORD_LENGTH_BYTES) { - return; - } - - if ((extRecord[0] & EXT_RECORD_TYPE_MASK) - != EXT_RECORD_TYPE_ADDITIONAL_DATA - ) { - return; - } - - if ((0xff & extRecord[1]) > MAX_EXT_CALLED_PARTY_LENGTH) { - // invalid or empty record - return; - } - - number += PhoneNumberUtils.calledPartyBCDFragmentToString( - extRecord, 2, 0xff & extRecord[1]); - - // We don't support ext record chaining. - - } catch (RuntimeException ex) { - - - - - Log.w(LOG_TAG, "Error parsing AdnRecord ext record", ex); - } - } - - //***** Private Methods - - /** - * alphaTag and number are set to null on invalid format - */ - private void - parseRecord(byte[] record) { - try { - alphaTag = SimUtils.adnStringFieldToString( - record, 0, record.length - FOOTER_SIZE_BYTES); - - int footerOffset = record.length - FOOTER_SIZE_BYTES; - - int numberLength = 0xff & record[footerOffset]; - - if (numberLength > MAX_NUMBER_SIZE_BYTES) { - // Invalid number length - number = ""; - return; - } - - // Please note 51.011 10.5.1: - // - // "If the Dialling Number/SSC String does not contain - // a dialling number, e.g. a control string deactivating - // a service, the TON/NPI byte shall be set to 'FF' by - // the ME (see note 2)." - - number = PhoneNumberUtils.calledPartyBCDToString( - record, footerOffset + 1, numberLength); - - - extRecord = 0xff & record[record.length - 1]; - - } catch (RuntimeException ex) { - Log.w(LOG_TAG, "Error parsing AdnRecord", ex); - number = ""; - alphaTag = ""; - } - } -} diff --git a/telephony/java/com/android/internal/telephony/gsm/BaseCommands.java b/telephony/java/com/android/internal/telephony/gsm/BaseCommands.java deleted file mode 100644 index 8e14b43..0000000 --- a/telephony/java/com/android/internal/telephony/gsm/BaseCommands.java +++ /dev/null @@ -1,367 +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.content.Context; -import android.os.RegistrantList; -import android.os.Registrant; -import android.os.Handler; -import android.os.AsyncResult; -import android.os.SystemProperties; -import android.provider.Checkin; -import android.util.Config; -import android.util.Log; - -/** - * {@hide} - */ -public abstract class BaseCommands implements CommandsInterface -{ - static final String LOG_TAG = "GSM"; - - //***** Instance Variables - protected Context mContext; - protected RadioState mState = RadioState.RADIO_UNAVAILABLE; - protected Object mStateMonitor = new Object(); - - protected RegistrantList mRadioStateChangedRegistrants = new RegistrantList(); - protected RegistrantList mOnRegistrants = new RegistrantList(); - protected RegistrantList mAvailRegistrants = new RegistrantList(); - protected RegistrantList mOffOrNotAvailRegistrants = new RegistrantList(); - protected RegistrantList mNotAvailRegistrants = new RegistrantList(); - protected RegistrantList mSIMReadyRegistrants = new RegistrantList(); - protected RegistrantList mSIMLockedRegistrants = new RegistrantList(); - protected RegistrantList mCallStateRegistrants = new RegistrantList(); - protected RegistrantList mNetworkStateRegistrants = new RegistrantList(); - protected RegistrantList mPDPRegistrants = 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 SMS storage full messages */ - protected Registrant mSimSmsFullRegistrant; - /** Registrant for handling SIM Refresh notifications */ - protected Registrant mSimRefreshRegistrant; - /** Registrant for handling RING notifications */ - protected Registrant mRingRegistrant; - /** Registrant for handling RESTRICTED STATE changed notification */ - protected Registrant mRestrictedStateRegistrant; - - public BaseCommands(Context context) { - mContext = context; // May be null (if so we won't log statistics) - } - - //***** CommandsInterface implementation - - public RadioState - getRadioState() - { - return mState; - } - - - public void - registerForRadioStateChanged(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - synchronized (mStateMonitor) { - mRadioStateChangedRegistrants.add(r); - r.notifyRegistrant(); - } - } - - public void - registerForOn(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - synchronized (mStateMonitor) { - mOnRegistrants.add(r); - - if (mState.isOn()) { - r.notifyRegistrant(new AsyncResult(null, null, null)); - } - } - } - - - public void - registerForAvailable(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - synchronized (mStateMonitor) { - mAvailRegistrants.add(r); - - if (mState.isAvailable()) { - r.notifyRegistrant(new AsyncResult(null, null, null)); - } - } - } - - public void - registerForNotAvailable(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - synchronized (mStateMonitor) { - mNotAvailRegistrants.add(r); - - if (!mState.isAvailable()) { - r.notifyRegistrant(new AsyncResult(null, null, null)); - } - } - } - - public void - registerForOffOrNotAvailable(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - synchronized (mStateMonitor) { - mOffOrNotAvailRegistrants.add(r); - - if (mState == RadioState.RADIO_OFF || !mState.isAvailable()) { - r.notifyRegistrant(new AsyncResult(null, null, null)); - } - } - } - - - /** Any transition into SIM_READY */ - public void - registerForSIMReady(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - synchronized (mStateMonitor) { - mSIMReadyRegistrants.add(r); - - if (mState.isSIMReady()) { - r.notifyRegistrant(new AsyncResult(null, null, null)); - } - } - } - - public void - registerForSIMLockedOrAbsent(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - synchronized (mStateMonitor) { - mSIMLockedRegistrants.add(r); - - if (mState == RadioState.SIM_LOCKED_OR_ABSENT) { - r.notifyRegistrant(new AsyncResult(null, null, null)); - } - } - } - - public void - registerForCallStateChanged(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - mCallStateRegistrants.add(r); - } - - public void - registerForNetworkStateChanged(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - mNetworkStateRegistrants.add(r); - } - - public void - registerForPDPStateChanged(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - mPDPRegistrants.add(r); - } - - public void - setOnNewSMS(Handler h, int what, Object obj) - { - mSMSRegistrant = new Registrant (h, what, obj); - } - - public void - setOnSmsOnSim(Handler h, int what, Object obj) - { - mSmsOnSimRegistrant = new Registrant (h, what, obj); - } - - public void setOnSmsStatus(Handler h, int what, Object obj) { - mSmsStatusRegistrant = new Registrant (h, what, obj); - } - - public void - setOnSignalStrengthUpdate(Handler h, int what, Object obj) - { - mSignalStrengthRegistrant = new Registrant (h, what, obj); - } - - public void - setOnNITZTime(Handler h, int what, Object obj) - { - mNITZTimeRegistrant = new Registrant (h, what, obj); - } - - public void - setOnUSSD(Handler h, int what, Object obj) - { - mUSSDRegistrant = new Registrant (h, what, obj); - } - - public void - setOnSuppServiceNotification(Handler h, int what, Object obj) - { - mSsnRegistrant = new Registrant (h, what, obj); - } - - public void - setOnStkSessionEnd(Handler h, int what, Object obj) - { - mStkSessionEndRegistrant = new Registrant (h, what, obj); - } - - public void - setOnStkProactiveCmd(Handler h, int what, Object obj) - { - mStkProCmdRegistrant = new Registrant (h, what, obj); - } - - public void - setOnStkEvent(Handler h, int what, Object obj) - { - mStkEventRegistrant = new Registrant (h, what, obj); - } - - public void - setOnStkCallSetUp(Handler h, int what, Object obj) - { - mStkCallSetUpRegistrant = new Registrant (h, what, obj); - } - - public void setOnSimSmsFull(Handler h, int what, Object obj) { - mSimSmsFullRegistrant = new Registrant (h, what, obj); - } - - public void setOnSimRefresh(Handler h, int what, Object obj) { - mSimRefreshRegistrant = new Registrant (h, what, obj); - } - - public void setOnCallRing(Handler h, int what, Object obj) { - mRingRegistrant = new Registrant (h, what, obj); - } - - public void - setOnRestrictedStateChanged(Handler h, int what, Object obj) - { - mRestrictedStateRegistrant = new Registrant (h, what, obj); - } - - //***** Protected Methods - /** - * Store new RadioState and send notification based on the changes - * - * This function is called only by RIL.java when receiving unsolicited - * RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED - * - * RadioState has 5 values : RADIO_OFF, RADIO_UNAVAILABLE, SIM_NOT_READY, - * SIM_LOCKED_OR_ABSENT, and SIM_READY. - * - * @param newState new RadioState decoded from RIL_UNSOL_RADIO_STATE_CHANGED - */ - protected void setRadioState(RadioState newState) { - RadioState oldState; - - synchronized (mStateMonitor) { - if (Config.LOGV) { - Log.v(LOG_TAG, "setRadioState old: " + mState - + " new " + newState); - } - - oldState = mState; - mState = newState; - - if (oldState == mState) { - // no state transition - return; - } - - if (mContext != null && - newState == RadioState.RADIO_UNAVAILABLE && - oldState != RadioState.RADIO_OFF) { - Checkin.updateStats(mContext.getContentResolver(), - Checkin.Stats.Tag.PHONE_RADIO_RESETS, 1, 0.0); - } - - mRadioStateChangedRegistrants.notifyRegistrants(); - - if (mState.isAvailable() && !oldState.isAvailable()) { - Log.d(LOG_TAG,"Notifying: radio available"); - mAvailRegistrants.notifyRegistrants(); - onRadioAvailable(); - } - - if (!mState.isAvailable() && oldState.isAvailable()) { - Log.d(LOG_TAG,"Notifying: radio not available"); - mNotAvailRegistrants.notifyRegistrants(); - } - - if (mState.isSIMReady() && !oldState.isSIMReady()) { - Log.d(LOG_TAG,"Notifying: SIM ready"); - mSIMReadyRegistrants.notifyRegistrants(); - } - - if (mState == RadioState.SIM_LOCKED_OR_ABSENT) { - Log.d(LOG_TAG,"Notifying: SIM locked or absent"); - mSIMLockedRegistrants.notifyRegistrants(); - } - - if (mState.isOn() && !oldState.isOn()) { - Log.d(LOG_TAG,"Notifying: Radio On"); - mOnRegistrants.notifyRegistrants(); - } - - if ((!mState.isOn() || !mState.isAvailable()) - && !((!oldState.isOn() || !oldState.isAvailable())) - ) { - Log.d(LOG_TAG,"Notifying: radio off or not available"); - mOffOrNotAvailRegistrants.notifyRegistrants(); - } - } - } - - protected void - onRadioAvailable() - { - } -} diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java index f93c724..d1ae997 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java @@ -16,18 +16,6 @@ package com.android.internal.telephony.gsm; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION; -import static com.android.internal.telephony.gsm.CommandsInterface.CF_ACTION_DISABLE; -import static com.android.internal.telephony.gsm.CommandsInterface.CF_ACTION_ENABLE; -import static com.android.internal.telephony.gsm.CommandsInterface.CF_ACTION_ERASURE; -import static com.android.internal.telephony.gsm.CommandsInterface.CF_ACTION_REGISTRATION; -import static com.android.internal.telephony.gsm.CommandsInterface.CF_REASON_ALL; -import static com.android.internal.telephony.gsm.CommandsInterface.CF_REASON_ALL_CONDITIONAL; -import static com.android.internal.telephony.gsm.CommandsInterface.CF_REASON_BUSY; -import static com.android.internal.telephony.gsm.CommandsInterface.CF_REASON_NOT_REACHABLE; -import static com.android.internal.telephony.gsm.CommandsInterface.CF_REASON_NO_REPLY; -import static com.android.internal.telephony.gsm.CommandsInterface.CF_REASON_UNCONDITIONAL; -import static com.android.internal.telephony.gsm.CommandsInterface.SERVICE_CLASS_VOICE; import android.content.ContentValues; import android.content.Context; import android.content.SharedPreferences; @@ -41,26 +29,47 @@ import android.os.Registrant; import android.os.RegistrantList; import android.os.SystemProperties; import android.preference.PreferenceManager; +import android.provider.Settings; import android.provider.Telephony; import android.telephony.CellLocation; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; -import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; -import com.android.internal.telephony.Call; +import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE; +import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; +import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE; +import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; +import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION; + +import com.android.internal.telephony.CallForwardInfo; import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Connection; +import com.android.internal.telephony.DataConnection; +import com.android.internal.telephony.DataConnectionTracker; +import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.IccFileHandler; +import com.android.internal.telephony.IccPhoneBookInterfaceManager; +import com.android.internal.telephony.IccSmsInterfaceManager; import com.android.internal.telephony.MmiCode; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneBase; import com.android.internal.telephony.PhoneNotifier; +import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.PhoneSubInfo; -import com.android.internal.telephony.SimCard; -import com.android.internal.telephony.gsm.SimException; +import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.gsm.stk.StkService; import com.android.internal.telephony.test.SimulatedRadioControl; +import com.android.internal.telephony.IccVmNotSupportedException; import java.io.IOException; import java.net.InetSocketAddress; @@ -77,40 +86,28 @@ public class GSMPhone extends PhoneBase { // from this file will go into the radio log rather than the main // log. (Use "adb logcat -b radio" to see them.) static final String LOG_TAG = "GSM"; - private static final boolean LOCAL_DEBUG = false; + private static final boolean LOCAL_DEBUG = true; - // Key used to read and write the saved network selection value - public static final String NETWORK_SELECTION_KEY = "network_selection_key"; - // Key used to read/write "disable data connection on boot" pref (used for testing) - public static final String DATA_DISABLED_ON_BOOT_KEY = "disabled_on_boot_key"; // Key used to read/write current ciphering state public static final String CIPHERING_KEY = "ciphering_key"; - // Key used to read/write current CLIR setting - public static final String CLIR_KEY = "clir_key"; // Key used to read/write voice mail number public static final String VM_NUMBER = "vm_number_key"; // Key used to read/write the SIM IMSI used for storing the voice mail public static final String VM_SIM_IMSI = "vm_sim_imsi_key"; - // Key used to read/write "disable DNS server check" pref (used for testing) - public static final String DNS_SERVER_CHECK_DISABLED_KEY = "dns_server_check_disabled_key"; //***** Instance Variables - - CallTracker mCT; - ServiceStateTracker mSST; - CommandsInterface mCM; - SMSDispatcher mSMS; - DataConnectionTracker mDataConnection; - SIMFileHandler mSIMFileHandler; + GsmCallTracker mCT; + GsmServiceStateTracker mSST; + GsmSMSDispatcher mSMS; + GsmDataConnectionTracker mDataConnection; SIMRecords mSIMRecords; - GsmSimCard mSimCard; + SimCard mSimCard; StkService mStkService; MyHandler h; ArrayList <GsmMmiCode> mPendingMMIs = new ArrayList<GsmMmiCode>(); SimPhoneBookInterfaceManager mSimPhoneBookIntManager; SimSmsInterfaceManager mSimSmsIntManager; PhoneSubInfo mSubInfo; - boolean mDnsCheckDisabled = false; Registrant mPostDialHandler; @@ -129,44 +126,17 @@ public class GSMPhone extends PhoneBase { private String mImeiSv; private String mVmNumber; - //***** Event Constants - - static final int EVENT_RADIO_AVAILABLE = 1; - /** Supplemnetary Service Notification received. */ - static final int EVENT_SSN = 2; - static final int EVENT_SIM_RECORDS_LOADED = 3; - static final int EVENT_MMI_DONE = 4; - static final int EVENT_RADIO_ON = 5; - static final int EVENT_GET_BASEBAND_VERSION_DONE = 6; - static final int EVENT_USSD = 7; - static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 8; - static final int EVENT_GET_IMEI_DONE = 9; - static final int EVENT_GET_IMEISV_DONE = 10; - static final int EVENT_GET_SIM_STATUS_DONE = 11; - static final int EVENT_SET_CALL_FORWARD_DONE = 12; - static final int EVENT_GET_CALL_FORWARD_DONE = 13; - static final int EVENT_CALL_RING = 14; - // Used to intercept the carriere selection calls so that - // we can save the values. - static final int EVENT_SET_NETWORK_MANUAL_COMPLETE = 15; - static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 16; - static final int EVENT_SET_CLIR_COMPLETE = 17; - static final int EVENT_REGISTERED_TO_NETWORK = 18; - static final int EVENT_SET_VM_NUMBER_DONE = 19; //***** Constructors public - GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier) - { + GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier) { this(context,ci,notifier, false); } public - GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) - { + GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) { super(notifier, context, unitTestMode); - h = new MyHandler(); mCM = ci; @@ -174,34 +144,31 @@ public class GSMPhone extends PhoneBase { mSimulatedRadioControl = (SimulatedRadioControl) ci; } - mCT = new CallTracker(this); - mSST = new ServiceStateTracker (this); - mSMS = new SMSDispatcher(this); - mSIMFileHandler = new SIMFileHandler(this); + mCM.setPhoneType(RILConstants.GSM_PHONE); + mCT = new GsmCallTracker(this); + mSST = new GsmServiceStateTracker (this); + mSMS = new GsmSMSDispatcher(this); + mIccFileHandler = new SIMFileHandler(this); mSIMRecords = new SIMRecords(this); - mDataConnection = new DataConnectionTracker (this); - mSimCard = new GsmSimCard(this); + mDataConnection = new GsmDataConnectionTracker (this); + mSimCard = new SimCard(this); if (!unitTestMode) { mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this); mSimSmsIntManager = new SimSmsInterfaceManager(this); mSubInfo = new PhoneSubInfo(this); } mStkService = StkService.getInstance(mCM, mSIMRecords, mContext, - mSIMFileHandler, mSimCard); - + (SIMFileHandler)mIccFileHandler, mSimCard); + mCM.registerForAvailable(h, EVENT_RADIO_AVAILABLE, null); mSIMRecords.registerForRecordsLoaded(h, EVENT_SIM_RECORDS_LOADED, null); - mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, - null); + mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); mCM.registerForOn(h, EVENT_RADIO_ON, null); mCM.setOnUSSD(h, EVENT_USSD, null); mCM.setOnSuppServiceNotification(h, EVENT_SSN, null); mCM.setOnCallRing(h, EVENT_CALL_RING, null); mSST.registerForNetworkAttach(h, EVENT_REGISTERED_TO_NETWORK, null); - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false); - if (false) { try { //debugSocket = new LocalServerSocket("com.android.internal.telephony.debug"); @@ -221,7 +188,7 @@ public class GSMPhone extends PhoneBase { mCM.resetRadio(null); sock.close(); } catch (IOException ex) { - Log.w(LOG_TAG, + Log.w(LOG_TAG, "Exception accepting socket", ex); } } @@ -235,13 +202,64 @@ public class GSMPhone extends PhoneBase { Log.w(LOG_TAG, "Failure to open com.android.internal.telephony.debug socket", ex); } } + + //Change the system setting + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.CURRENT_ACTIVE_PHONE, RILConstants.GSM_PHONE); + } + + public void dispose() { + synchronized(PhoneProxy.lockForRadioTechnologyChange) { + //Unregister from all former registered events + mCM.unregisterForAvailable(h); //EVENT_RADIO_AVAILABLE + mSIMRecords.unregisterForRecordsLoaded(h); //EVENT_SIM_RECORDS_LOADED + mCM.unregisterForOffOrNotAvailable(h); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE + mCM.unregisterForOn(h); //EVENT_RADIO_ON + mSST.unregisterForNetworkAttach(h); //EVENT_REGISTERED_TO_NETWORK + mCM.unSetOnUSSD(h); + mCM.unSetOnSuppServiceNotification(h); + mCM.unSetOnCallRing(h); + + mPendingMMIs.clear(); + + //Force all referenced classes to unregister their former registered events + mStkService.dispose(); + mCT.dispose(); + mDataConnection.dispose(); + mSST.dispose(); + mIccFileHandler.dispose(); // instance of SimFileHandler + mSIMRecords.dispose(); + mSimCard.dispose(); + mSimPhoneBookIntManager.dispose(); + mSimSmsIntManager.dispose(); + mSubInfo.dispose(); + } } - + + public void removeReferences() { + this.mSimulatedRadioControl = null; + this.mStkService = null; + this.mSimPhoneBookIntManager = null; + this.mSimSmsIntManager = null; + this.mSMS = null; + this.mSubInfo = null; + this.mSIMRecords = null; + this.mIccFileHandler = null; + this.mSimCard = null; + this.mDataConnection = null; + this.mCT = null; + this.mSST = null; + } + + protected void finalize() { + if(LOCAL_DEBUG) Log.d(LOG_TAG, "GSMPhone finalized"); + } + + //***** Overridden from Phone - public ServiceState - getServiceState() - { + public ServiceState + getServiceState() { return mSST.ss; } @@ -249,15 +267,13 @@ public class GSMPhone extends PhoneBase { return mSST.cellLoc; } - public Phone.State - getState() - { + public Phone.State + getState() { return mCT.state; } public String - getPhoneName() - { + getPhoneName() { return "GSM"; } @@ -270,14 +286,12 @@ public class GSMPhone extends PhoneBase { } public int - getSignalStrengthASU() - { + getSignalStrengthASU() { return mSST.rssi == 99 ? -1 : mSST.rssi; } public boolean - getMessageWaitingIndicator() - { + getMessageWaitingIndicator() { return mSIMRecords.getVoiceMessageWaiting(); } @@ -287,8 +301,7 @@ public class GSMPhone extends PhoneBase { } public List<? extends MmiCode> - getPendingMmiCodes() - { + getPendingMmiCodes() { return mPendingMMIs; } @@ -309,27 +322,27 @@ public class GSMPhone extends PhoneBase { // but no data will flow ret = DataState.DISCONNECTED; } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */ - switch (mDataConnection.state) { - case FAILED: - case IDLE: - ret = DataState.DISCONNECTED; - break; + switch (mDataConnection.getState()) { + case FAILED: + case IDLE: + ret = DataState.DISCONNECTED; + break; - case CONNECTED: - case DISCONNECTING: - if ( mCT.state != Phone.State.IDLE - && !mSST.isConcurrentVoiceAndData()) { - ret = DataState.SUSPENDED; - } else { - ret = DataState.CONNECTED; - } - break; + case CONNECTED: + case DISCONNECTING: + if ( mCT.state != Phone.State.IDLE + && !mSST.isConcurrentVoiceAndData()) { + ret = DataState.SUSPENDED; + } else { + ret = DataState.CONNECTED; + } + break; - case INITING: - case CONNECTING: - case SCANNING: - ret = DataState.CONNECTING; - break; + case INITING: + case CONNECTING: + case SCANNING: + ret = DataState.CONNECTING; + break; } } @@ -340,19 +353,18 @@ public class GSMPhone extends PhoneBase { DataActivityState ret = DataActivityState.NONE; if (mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE) { - switch (mDataConnection.activity) { - - case DATAIN: - ret = DataActivityState.DATAIN; - break; + switch (mDataConnection.getActivity()) { + case DATAIN: + ret = DataActivityState.DATAIN; + break; - case DATAOUT: - ret = DataActivityState.DATAOUT; - break; + case DATAOUT: + ret = DataActivityState.DATAOUT; + break; - case DATAINANDOUT: - ret = DataActivityState.DATAINANDOUT; - break; + case DATAINANDOUT: + ret = DataActivityState.DATAINANDOUT; + break; } } @@ -371,15 +383,13 @@ public class GSMPhone extends PhoneBase { * changes to call state (including Phone and Connection changes). */ /*package*/ void - notifyCallStateChanged() - { + notifyCallStateChanged() { /* we'd love it if this was package-scoped*/ super.notifyCallStateChangedP(); } /*package*/ void - notifyNewRingingConnection(Connection c) - { + notifyNewRingingConnection(Connection c) { /* we'd love it if this was package-scoped*/ super.notifyNewRingingConnectionP(c); } @@ -387,28 +397,26 @@ public class GSMPhone extends PhoneBase { /** * Notifiy registrants of a RING event. */ - void notifyIncomingRing() { + void notifyIncomingRing() { AsyncResult ar = new AsyncResult(null, this, null); mIncomingRingRegistrants.notifyRegistrants(ar); } - + /*package*/ void - notifyDisconnect(Connection cn) - { + notifyDisconnect(Connection cn) { mDisconnectRegistrants.notifyResult(cn); } void notifyUnknownConnection() { mUnknownConnectionRegistrants.notifyResult(this); } - + void notifySuppServiceFailed(SuppService code) { mSuppServiceFailedRegistrants.notifyResult(code); } /*package*/ void - notifyServiceStateChanged(ServiceState ss) - { + notifyServiceStateChanged(ServiceState ss) { super.notifyServiceStateChangedP(ss); } @@ -418,55 +426,38 @@ public class GSMPhone extends PhoneBase { } /*package*/ void - notifySignalStrength() - { + notifySignalStrength() { mNotifier.notifySignalStrength(this); } /*package*/ void - notifyDataConnection(String reason) { - mNotifier.notifyDataConnection(this, reason); - } - - /*package*/ void notifyDataConnectionFailed(String reason) { mNotifier.notifyDataConnectionFailed(this, reason); } /*package*/ void - notifyDataActivity() { - mNotifier.notifyDataActivity(this); - } - - /*package*/ void - updateMessageWaitingIndicator(boolean mwi) - { + updateMessageWaitingIndicator(boolean mwi) { // this also calls notifyMessageWaitingIndicator() mSIMRecords.setVoiceMessageWaiting(1, mwi ? -1 : 0); } - /*package*/ void - notifyMessageWaitingIndicator() - { + public void + notifyMessageWaitingIndicator() { mNotifier.notifyMessageWaitingChanged(this); } - /*package*/ void + public void notifyCallForwardingIndicator() { mNotifier.notifyCallForwardingChanged(this); } + // override for allowing access from other classes of this package /** - * Set a system property, unless we're in unit test mode + * {@inheritDoc} */ - - /*package*/ void - setSystemProperty(String property, String value) - { - if(getUnitTestMode()) { - return; - } - SystemProperties.set(property, value); + public final void + setSystemProperty(String property, String value) { + super.setSystemProperty(property, value); } public void registerForSuppServiceNotification( @@ -480,71 +471,57 @@ public class GSMPhone extends PhoneBase { if (mSsnRegistrants.size() == 0) mCM.setSuppServiceNotifications(false, null); } - public void - acceptCall() throws CallStateException - { + public void + acceptCall() throws CallStateException { mCT.acceptCall(); } - public void - rejectCall() throws CallStateException - { + public void + rejectCall() throws CallStateException { mCT.rejectCall(); } public void - switchHoldingAndActive() throws CallStateException - { + switchHoldingAndActive() throws CallStateException { mCT.switchWaitingOrHoldingAndActive(); } - - public boolean canConference() - { + public boolean canConference() { return mCT.canConference(); } - public boolean canDial() - { + public boolean canDial() { return mCT.canDial(); } - public void conference() throws CallStateException - { + public void conference() throws CallStateException { mCT.conference(); } - public void clearDisconnected() - { - + public void clearDisconnected() { mCT.clearDisconnected(); } - public boolean canTransfer() - { + public boolean canTransfer() { return mCT.canTransfer(); } - public void explicitCallTransfer() throws CallStateException - { + public void explicitCallTransfer() throws CallStateException { mCT.explicitCallTransfer(); } - public Call - getForegroundCall() - { + public GsmCall + getForegroundCall() { return mCT.foregroundCall; } - public Call - getBackgroundCall() - { + public GsmCall + getBackgroundCall() { return mCT.backgroundCall; } - public Call - getRingingCall() - { + public GsmCall + getRingingCall() { return mCT.ringingCall; } @@ -554,7 +531,7 @@ public class GSMPhone extends PhoneBase { return false; } - if (getRingingCall().getState() != Call.State.IDLE) { + if (getRingingCall().getState() != GsmCall.State.IDLE) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "MmiCode 0: rejectCall"); try { mCT.rejectCall(); @@ -563,7 +540,7 @@ public class GSMPhone extends PhoneBase { "reject failed", e); notifySuppServiceFailed(Phone.SuppService.REJECT); } - } else if (getBackgroundCall().getState() != Call.State.IDLE) { + } else if (getBackgroundCall().getState() != GsmCall.State.IDLE) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "MmiCode 0: hangupWaitingOrBackground"); mCT.hangupWaitingOrBackground(); @@ -580,21 +557,21 @@ public class GSMPhone extends PhoneBase { return false; } - GSMCall call = (GSMCall) getForegroundCall(); + GsmCall call = (GsmCall) getForegroundCall(); try { if (len > 1) { char ch = dialString.charAt(1); int callIndex = ch - '0'; - if (callIndex >= 1 && callIndex <= CallTracker.MAX_CONNECTIONS) { + if (callIndex >= 1 && callIndex <= GsmCallTracker.MAX_CONNECTIONS) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "MmiCode 1: hangupConnectionByIndex " + callIndex); mCT.hangupConnectionByIndex(call, callIndex); } } else { - if (call.getState() != Call.State.IDLE) { + if (call.getState() != GsmCall.State.IDLE) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "MmiCode 1: hangup foreground"); //mCT.hangupForegroundResumeBackground(); @@ -622,16 +599,16 @@ public class GSMPhone extends PhoneBase { return false; } - GSMCall call = (GSMCall) getForegroundCall(); + GsmCall call = (GsmCall) getForegroundCall(); if (len > 1) { try { char ch = dialString.charAt(1); int callIndex = ch - '0'; - GSMConnection conn = mCT.getConnectionByIndex(call, callIndex); - + GsmConnection conn = mCT.getConnectionByIndex(call, callIndex); + // gsm index starts at 1, up to 5 connections in a call, - if (conn != null && callIndex >= 1 && callIndex <= CallTracker.MAX_CONNECTIONS) { + if (conn != null && callIndex >= 1 && callIndex <= GsmCallTracker.MAX_CONNECTIONS) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "MmiCode 2: separate call "+ callIndex); mCT.separate(conn); @@ -647,7 +624,7 @@ public class GSMPhone extends PhoneBase { } } else { try { - if (getRingingCall().getState() != Call.State.IDLE) { + if (getRingingCall().getState() != GsmCall.State.IDLE) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "MmiCode 2: accept ringing call"); mCT.acceptCall(); @@ -756,9 +733,9 @@ public class GSMPhone extends PhoneBase { } boolean isInCall() { - Call.State foregroundCallState = getForegroundCall().getState(); - Call.State backgroundCallState = getBackgroundCall().getState(); - Call.State ringingCallState = getRingingCall().getState(); + GsmCall.State foregroundCallState = getForegroundCall().getState(); + GsmCall.State backgroundCallState = getBackgroundCall().getState(); + GsmCall.State ringingCallState = getRingingCall().getState(); return (foregroundCallState.isAlive() || backgroundCallState.isAlive() || @@ -797,15 +774,15 @@ public class GSMPhone extends PhoneBase { public boolean handlePinMmi(String dialString) { GsmMmiCode mmi = GsmMmiCode.newFromDialString(dialString, this); - + if (mmi != null && mmi.isPinCommand()) { mPendingMMIs.add(mmi); mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); mmi.processCode(); return true; } - - return false; + + return false; } public void sendUssdResponse(String ussdMessge) { @@ -814,11 +791,11 @@ public class GSMPhone extends PhoneBase { mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); mmi.sendUssd(ussdMessge); } - + public void sendDtmf(char c) { if (!PhoneNumberUtils.is12Key(c)) { - Log.e(LOG_TAG, + Log.e(LOG_TAG, "sendDtmf called with invalid character '" + c + "'"); } else { if (mCT.state == Phone.State.OFFHOOK) { @@ -887,7 +864,7 @@ public class GSMPhone extends PhoneBase { com.android.internal.R.string.defaultVoiceMailAlphaTag).toString(); } - return ret; + return ret; } public String getDeviceId() { @@ -898,11 +875,21 @@ public class GSMPhone extends PhoneBase { return mImeiSv; } + public String getEsn() { + Log.e(LOG_TAG, "[GSMPhone] getEsn() is a CDMA method"); + return "0"; + } + + public String getMeid() { + Log.e(LOG_TAG, "[GSMPhone] getMeid() is a CDMA method"); + return "0"; + } + public String getSubscriberId() { return mSIMRecords.imsi; } - public String getSimSerialNumber() { + public String getIccSerialNumber() { return mSIMRecords.iccid; } @@ -939,37 +926,35 @@ public class GSMPhone extends PhoneBase { private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) { switch (commandInterfaceCFReason) { - case CF_REASON_UNCONDITIONAL: - case CF_REASON_BUSY: - case CF_REASON_NO_REPLY: - case CF_REASON_NOT_REACHABLE: - case CF_REASON_ALL: - case CF_REASON_ALL_CONDITIONAL: - return true; - default: - return false; + case CF_REASON_UNCONDITIONAL: + case CF_REASON_BUSY: + case CF_REASON_NO_REPLY: + case CF_REASON_NOT_REACHABLE: + case CF_REASON_ALL: + case CF_REASON_ALL_CONDITIONAL: + return true; + default: + return false; } } private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) { switch (commandInterfaceCFAction) { - case CF_ACTION_DISABLE: - case CF_ACTION_ENABLE: - case CF_ACTION_REGISTRATION: - case CF_ACTION_ERASURE: - return true; - default: - return false; + case CF_ACTION_DISABLE: + case CF_ACTION_ENABLE: + case CF_ACTION_REGISTRATION: + case CF_ACTION_ERASURE: + return true; + default: + return false; } } - - private boolean isCfEnable(int action) { + + protected boolean isCfEnable(int action) { return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION); } - - public void getCallForwardingOption(int commandInterfaceCFReason, - Message onComplete) { - + + public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) { if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "requesting call forwarding query."); Message resp; @@ -983,14 +968,13 @@ public class GSMPhone extends PhoneBase { } public void setCallForwardingOption(int commandInterfaceCFAction, - int commandInterfaceCFReason, - String dialingNumber, - int timerSeconds, - Message onComplete) { - - if ((isValidCommandInterfaceCFAction(commandInterfaceCFAction)) && - (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) { - + int commandInterfaceCFReason, + String dialingNumber, + int timerSeconds, + Message onComplete) { + if ( (isValidCommandInterfaceCFAction(commandInterfaceCFAction)) && + (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) { + Message resp; if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) { resp = h.obtainMessage(EVENT_SET_CALL_FORWARD_DONE, @@ -1006,12 +990,12 @@ public class GSMPhone extends PhoneBase { resp); } } - + public void getOutgoingCallerIdDisplay(Message onComplete) { mCM.getCLIR(onComplete); } - - public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, + + public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) { mCM.setCLIR(commandInterfaceCLIRMode, h.obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete)); @@ -1020,162 +1004,111 @@ public class GSMPhone extends PhoneBase { public void getCallWaiting(Message onComplete) { mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete); } - + public void setCallWaiting(boolean enable, Message onComplete) { mCM.setCallWaiting(enable, CommandsInterface.SERVICE_CLASS_VOICE, onComplete); } - + public boolean - getSimRecordsLoaded() { + getIccRecordsLoaded() { return mSIMRecords.getRecordsLoaded(); } - public SimCard - getSimCard() { + public IccCard getIccCard() { return mSimCard; } - public void + public void getAvailableNetworks(Message response) { mCM.getAvailableNetworks(response); } /** - * Small container class used to hold information relevant to + * Small container class used to hold information relevant to * the carrier selection process. operatorNumeric can be "" - * if we are looking for automatic selection. + * if we are looking for automatic selection. */ private static class NetworkSelectMessage { public Message message; public String operatorNumeric; } - - public void + + public void setNetworkSelectionModeAutomatic(Message response) { // wrap the response message in our own message along with - // an empty string (to indicate automatic selection) for the + // an empty string (to indicate automatic selection) for the // operator's id. NetworkSelectMessage nsm = new NetworkSelectMessage(); nsm.message = response; nsm.operatorNumeric = ""; - + // get the message Message msg = h.obtainMessage(EVENT_SET_NETWORK_AUTOMATIC_COMPLETE, nsm); - if (LOCAL_DEBUG) + if (LOCAL_DEBUG) Log.d(LOG_TAG, "wrapping and sending message to connect automatically"); mCM.setNetworkSelectionModeAutomatic(msg); } - public void + public void selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo network, - Message response) { + Message response) { // wrap the response message in our own message along with // the operator's id. NetworkSelectMessage nsm = new NetworkSelectMessage(); nsm.message = response; nsm.operatorNumeric = network.operatorNumeric; - + // get the message Message msg = h.obtainMessage(EVENT_SET_NETWORK_MANUAL_COMPLETE, nsm); mCM.setNetworkSelectionModeManual(network.operatorNumeric, msg); } - - /** - * Method to retrieve the saved operator id from the Shared Preferences - */ - private String getSavedNetworkSelection() { - // open the shared preferences and search with our key. - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); - return sp.getString(NETWORK_SELECTION_KEY, ""); - } - - /** - * Method to restore the previously saved operator id, or reset to - * automatic selection, all depending upon the value in the shared - * preferences. - */ - void restoreSavedNetworkSelection(Message response) { - // retrieve the operator id - String networkSelection = getSavedNetworkSelection(); - - // set to auto if the id is empty, otherwise select the network. - if (TextUtils.isEmpty(networkSelection)) { - mCM.setNetworkSelectionModeAutomatic(response); - } else { - mCM.setNetworkSelectionModeManual(networkSelection, response); - } - } - - public void - setPreferredNetworkType(int networkType, Message response) { - mCM.setPreferredNetworkType(networkType, response); - } - - public void - getPreferredNetworkType(Message response) { - mCM.getPreferredNetworkType(response); - } public void getNeighboringCids(Message response) { mCM.getNeighboringCids(response); } - - public void setOnPostDialCharacter(Handler h, int what, Object obj) - { + + public void setOnPostDialCharacter(Handler h, int what, Object obj) { mPostDialHandler = new Registrant(h, what, obj); } - - public void setMute(boolean muted) - { + public void setMute(boolean muted) { mCT.setMute(muted); } - - public boolean getMute() - { - return mCT.getMute(); - } - - public void invokeOemRilRequestRaw(byte[] data, Message response) - { - mCM.invokeOemRilRequestRaw(data, response); - } - - public void invokeOemRilRequestStrings(String[] strings, Message response) - { - mCM.invokeOemRilRequestStrings(strings, response); + public boolean getMute() { + return mCT.getMute(); } + /** + * @deprecated + */ public void getPdpContextList(Message response) { - mCM.getPDPContextList(response); + getDataCallList(response); } - public List<PdpConnection> getCurrentPdpList () { - return mDataConnection.getAllPdps(); + public void getDataCallList(Message response) { + mCM.getDataCallList(response); } /** - * Disables the DNS check (i.e., allows "0.0.0.0"). - * Useful for lab testing environment. - * @param b true disables the check, false enables. + * @deprecated */ - public void disableDnsCheck(boolean b) { - mDnsCheckDisabled = b; - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); - SharedPreferences.Editor editor = sp.edit(); - editor.putBoolean(DNS_SERVER_CHECK_DISABLED_KEY, b); - editor.commit(); + public List<PdpConnection> getCurrentPdpList() { + ArrayList<DataConnection> connections = new ArrayList<DataConnection>(); + ArrayList<PdpConnection> pdp_list = new ArrayList<PdpConnection>(); + + for(int n = 0; n < connections.size(); n++) { + pdp_list.add((PdpConnection) connections.get(n)); + } + + return pdp_list; } - /** - * Returns true if the DNS check is currently disabled. - */ - public boolean isDnsCheckDisabled() { - return mDnsCheckDisabled; + public List<DataConnection> getCurrentDataConnectionList () { + return mDataConnection.getAllDataConnections(); } public void updateServiceLocation(Message response) { @@ -1190,14 +1123,6 @@ public class GSMPhone extends PhoneBase { mSST.disableLocationUpdates(); } - public void setBandMode(int bandMode, Message response) { - mCM.setBandMode(bandMode, response); - } - - public void queryAvailableBandMode(Message response) { - mCM.queryAvailableBandMode(response); - } - public boolean getDataRoamingEnabled() { return mDataConnection.getDataOnRoamingEnabled(); } @@ -1254,7 +1179,7 @@ public class GSMPhone extends PhoneBase { // check for "default"? boolean noData = mDataConnection.getDataEnabled() && getDataConnectionState() == DataState.DISCONNECTED; - return !noData && getSimCard().getState() == SimCard.State.READY && + return !noData && getIccCard().getState() == SimCard.State.READY && getServiceState().getState() == ServiceState.STATE_IN_SERVICE && (mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming()); } @@ -1265,9 +1190,8 @@ public class GSMPhone extends PhoneBase { * @param mmi MMI that is done */ /*package*/ void - onMMIDone(GsmMmiCode mmi) - { - /* Only notify complete if it's on the pending list. + onMMIDone(GsmMmiCode mmi) { + /* Only notify complete if it's on the pending list. * Otherwise, it's already been handled (eg, previously canceled). * The exception is cancellation of an incoming USSD-REQUEST, which is * not on the list. @@ -1279,9 +1203,8 @@ public class GSMPhone extends PhoneBase { } - private void - onNetworkInitiatedUssd(GsmMmiCode mmi) - { + private void + onNetworkInitiatedUssd(GsmMmiCode mmi) { mMmiCompleteRegistrants.notifyRegistrants( new AsyncResult(null, mmi, null)); } @@ -1289,18 +1212,17 @@ public class GSMPhone extends PhoneBase { /** ussdMode is one of CommandsInterface.USSD_MODE_* */ private void - onIncomingUSSD (int ussdMode, String ussdMessage) - { + onIncomingUSSD (int ussdMode, String ussdMessage) { boolean isUssdError; boolean isUssdRequest; - - isUssdRequest + + isUssdRequest = (ussdMode == CommandsInterface.USSD_MODE_REQUEST); - isUssdError + isUssdError = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY && ussdMode != CommandsInterface.USSD_MODE_REQUEST); - + // See comments in GsmMmiCode.java // USSD requests aren't finished until one // of these two events happen @@ -1327,7 +1249,7 @@ public class GSMPhone extends PhoneBase { // also, discard if there is no message to present if (!isUssdError && ussdMessage != null) { GsmMmiCode mmi; - mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage, + mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage, isUssdRequest, GSMPhone.this); onNetworkInitiatedUssd(mmi); @@ -1338,7 +1260,7 @@ public class GSMPhone extends PhoneBase { /** * Make sure the network knows our preferred setting. */ - private void syncClirSetting() { + protected void syncClirSetting() { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); int clirSetting = sp.getInt(CLIR_KEY, -1); if (clirSetting >= 0) { @@ -1348,20 +1270,16 @@ public class GSMPhone extends PhoneBase { //***** Inner Classes - class MyHandler extends Handler - { - MyHandler() - { + class MyHandler extends Handler { + MyHandler() { } - MyHandler(Looper l) - { + MyHandler(Looper l) { super(l); } public void - handleMessage (Message msg) - { + handleMessage (Message msg) { AsyncResult ar; Message onComplete; @@ -1422,11 +1340,10 @@ public class GSMPhone extends PhoneBase { if (ar.exception != null) { break; } - + mImeiSv = (String)ar.result; break; - case EVENT_USSD: ar = (AsyncResult)msg.obj; @@ -1441,7 +1358,7 @@ public class GSMPhone extends PhoneBase { } break; - case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: // Some MMI requests (eg USSD) are not completed // within the course of a CommandsInterface request // If the radio shuts off or resets while one of these @@ -1450,10 +1367,10 @@ public class GSMPhone extends PhoneBase { for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) { if (mPendingMMIs.get(i).isPendingUSSD()) { mPendingMMIs.get(i).onUssdFinishedError(); - } + } } break; - + case EVENT_SSN: ar = (AsyncResult)msg.obj; SuppServiceNotification not = (SuppServiceNotification) ar.result; @@ -1474,7 +1391,7 @@ public class GSMPhone extends PhoneBase { case EVENT_SET_VM_NUMBER_DONE: ar = (AsyncResult)msg.obj; - if (SimVmNotSupportedException.class.isInstance(ar.exception)) { + if (IccVmNotSupportedException.class.isInstance(ar.exception)) { storeVoiceMailNumber(mVmNumber); ar.exception = null; } @@ -1497,15 +1414,15 @@ public class GSMPhone extends PhoneBase { onComplete.sendToTarget(); } break; - + case EVENT_CALL_RING: ar = (AsyncResult)msg.obj; if (ar.exception == null) { notifyIncomingRing(); } break; - - // handle the select network completion callbacks. + + // handle the select network completion callbacks. case EVENT_SET_NETWORK_MANUAL_COMPLETE: case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE: handleSetSelectNetwork((AsyncResult) msg.obj); @@ -1550,29 +1467,29 @@ public class GSMPhone extends PhoneBase { * Used to track the settings upon completion of the network change. */ private void handleSetSelectNetwork(AsyncResult ar) { - // look for our wrapper within the asyncresult, skip the rest if it - // is null. + // look for our wrapper within the asyncresult, skip the rest if it + // is null. if (!(ar.userObj instanceof NetworkSelectMessage)) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "unexpected result from user object."); return; } - + NetworkSelectMessage nsm = (NetworkSelectMessage) ar.userObj; - + // found the object, now we send off the message we had originally - // attached to the request. + // attached to the request. if (nsm.message != null) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "sending original message to recipient"); AsyncResult.forMessage(nsm.message, ar.result, ar.exception); nsm.message.sendToTarget(); } - + // open the shared preferences editor, and write the value. // nsm.operatorNumeric is "" if we're in automatic.selection. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); SharedPreferences.Editor editor = sp.edit(); editor.putString(NETWORK_SELECTION_KEY, nsm.operatorNumeric); - + // commit and log the result. if (! editor.commit()) { Log.e(LOG_TAG, "failed to commit network selection preference"); @@ -1584,17 +1501,16 @@ public class GSMPhone extends PhoneBase { * Saves CLIR setting so that we can re-apply it as necessary * (in case the RIL resets it across reboots). */ - /* package */ void saveClirSetting(int commandInterfaceCLIRMode) { + public void saveClirSetting(int commandInterfaceCLIRMode) { // open the shared preferences editor, and write the value. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); SharedPreferences.Editor editor = sp.edit(); editor.putInt(CLIR_KEY, commandInterfaceCLIRMode); - + // commit and log the result. if (! editor.commit()) { Log.e(LOG_TAG, "failed to commit CLIR preference"); } - } private void handleCfuQueryResult(CallForwardInfo[] infos) { @@ -1618,7 +1534,7 @@ public class GSMPhone extends PhoneBase { * simulates various data connection states. This messes with * DataConnectionTracker's internal states, but doesn't actually change * the underlying radio connection states. - * + * * @param state Phone.DataState enum. */ public void simulateDataConnection(Phone.DataState state) { @@ -1642,4 +1558,52 @@ public class GSMPhone extends PhoneBase { mDataConnection.setState(dcState); notifyDataConnection(null); } + + /** + * Retrieves the PhoneSubInfo of the GSMPhone + */ + public PhoneSubInfo getPhoneSubInfo(){ + return mSubInfo; + } + + /** + * Retrieves the IccSmsInterfaceManager of the GSMPhone + */ + public IccSmsInterfaceManager getIccSmsInterfaceManager(){ + return mSimSmsIntManager; + } + + /** + * Retrieves the IccPhoneBookInterfaceManager of the GSMPhone + */ + public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){ + return mSimPhoneBookIntManager; + } + + /** + * {@inheritDoc} + */ + public Handler getHandler(){ + return h; + } + + /** + * {@inheritDoc} + */ + public IccFileHandler getIccFileHandler(){ + return this.mIccFileHandler; + } + + public void activateCellBroadcastSms(int activate, Message response) { + Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM."); + } + + public void getCellBroadcastSmsConfig(Message response) { + Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM."); + } + + public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){ + Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM."); + } + } diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMCall.java b/telephony/java/com/android/internal/telephony/gsm/GsmCall.java index 4feaf21..a92e52d 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMCall.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmCall.java @@ -15,26 +15,30 @@ */ package com.android.internal.telephony.gsm; -import com.android.internal.telephony.*; + +import com.android.internal.telephony.Call; +import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.DriverCall; +import com.android.internal.telephony.Phone; + import java.util.ArrayList; import java.util.List; /** * {@hide} */ -class GSMCall extends Call -{ +class GsmCall extends Call { /*************************** Instance Variables **************************/ /*package*/ ArrayList<Connection> connections = new ArrayList<Connection>(); - /*package*/ State state = State.IDLE; - /*package*/ CallTracker owner; + /*package*/ GsmCallTracker owner; + /***************************** Class Methods *****************************/ static State - stateFromDCState (DriverCall.State dcState) - { + stateFromDCState (DriverCall.State dcState) { switch (dcState) { case ACTIVE: return State.ACTIVE; case HOLDING: return State.HOLDING; @@ -45,40 +49,33 @@ class GSMCall extends Call default: throw new RuntimeException ("illegal call state:" + dcState); } } - + /****************************** Constructors *****************************/ /*package*/ - GSMCall (CallTracker owner) - { + GsmCall (GsmCallTracker owner) { this.owner = owner; } + public void dispose() { + } + /************************** Overridden from Call *************************/ public List<Connection> - getConnections() - { + getConnections() { // FIXME should return Collections.unmodifiableList(); return connections; } - public State - getState() - { - return state; - } - - public Phone - getPhone() - { + public Phone + getPhone() { //TODO return null; } public boolean - isMultiparty() - { + isMultiparty() { return connections.size() > 1; } @@ -86,66 +83,60 @@ class GSMCall extends Call * background call exists, the background call will be resumed * because an AT+CHLD=1 will be sent */ - public void - hangup() throws CallStateException - { + public void + hangup() throws CallStateException { owner.hangup(this); } public String - toString() - { + toString() { return state.toString(); } - //***** Called from GSMConnection + //***** Called from GsmConnection /*package*/ void - attach(GSMConnection conn, DriverCall dc) - { + attach(Connection conn, DriverCall dc) { connections.add(conn); state = stateFromDCState (dc.state); } /*package*/ void - attachFake(GSMConnection conn, State state) - { + attachFake(Connection conn, State state) { connections.add(conn); this.state = state; } /** - * Called by GSMConnection when it has disconnected + * Called by GsmConnection when it has disconnected */ void - connectionDisconnected(GSMConnection conn) - { + connectionDisconnected(GsmConnection conn) { if (state != State.DISCONNECTED) { /* If only disconnected connections remain, we are disconnected*/ boolean hasOnlyDisconnectedConnections = true; - + for (int i = 0, s = connections.size() ; i < s; i ++) { - if (connections.get(i).getState() + if (connections.get(i).getState() != State.DISCONNECTED ) { hasOnlyDisconnectedConnections = false; break; - } + } } if (hasOnlyDisconnectedConnections) { - state = State.DISCONNECTED; + state = State.DISCONNECTED; } - } + } } /*package*/ void - detach(GSMConnection conn) - { + detach(GsmConnection conn) { connections.remove(conn); if (connections.size() == 0) { @@ -154,13 +145,12 @@ class GSMCall extends Call } /*package*/ boolean - update (GSMConnection conn, DriverCall dc) - { + update (GsmConnection conn, DriverCall dc) { State newState; boolean changed = false; - + newState = stateFromDCState(dc.state); - + if (newState != state) { state = newState; changed = true; @@ -174,44 +164,41 @@ class GSMCall extends Call * connections to be added via "conference" */ /*package*/ boolean - isFull() - { - return connections.size() == CallTracker.MAX_CONNECTIONS_PER_CALL; + isFull() { + return connections.size() == GsmCallTracker.MAX_CONNECTIONS_PER_CALL; } - //***** Called from CallTracker + //***** Called from GsmCallTracker - /** + /** * Called when this Call is being hung up locally (eg, user pressed "end") * Note that at this point, the hangup request has been dispatched to the radio * but no response has yet been received so update() has not yet been called */ void - onHangupLocal() - { + onHangupLocal() { for (int i = 0, s = connections.size() ; i < s; i++ ) { - GSMConnection cn = (GSMConnection)connections.get(i); + GsmConnection cn = (GsmConnection)connections.get(i); cn.onHangupLocal(); } } - + /** * Called when it's time to clean up disconnected Connection objects */ void - clearDisconnected() - { + clearDisconnected() { for (int i = connections.size() - 1 ; i >= 0 ; i--) { - GSMConnection cn = (GSMConnection)connections.get(i); - + GsmConnection cn = (GsmConnection)connections.get(i); + if (cn.getState() == State.DISCONNECTED) { connections.remove(i); } - } + } if (connections.size() == 0) { state = State.IDLE; diff --git a/telephony/java/com/android/internal/telephony/gsm/CallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java index 2d716bb..5c5090f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/CallTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java @@ -16,37 +16,34 @@ package com.android.internal.telephony.gsm; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE; -import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_EDGE; -import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_GPRS; -import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_UMTS; -import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_UNKNOWN; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Message; -import android.os.Registrant; -import android.os.RegistrantList; -import android.os.SystemProperties; +import android.os.*; +import android.telephony.gsm.GsmCellLocation; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; import android.telephony.TelephonyManager; -import android.telephony.gsm.GsmCellLocation; import android.util.EventLog; import android.util.Log; -import com.android.internal.telephony.Call; import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.CallTracker; +import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Connection; +import com.android.internal.telephony.DriverCall; +import com.android.internal.telephony.gsm.CallFailCause; +import com.android.internal.telephony.gsm.GsmCall; +import com.android.internal.telephony.gsm.GsmConnection; +import com.android.internal.telephony.gsm.GSMPhone; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.TelephonyEventLog; +import com.android.internal.telephony.*; -import java.util.ArrayList; import java.util.List; +import java.util.ArrayList; /** * {@hide} */ -public final class CallTracker extends Handler -{ +public final class GsmCallTracker extends CallTracker { static final String LOG_TAG = "GSM"; private static final boolean REPEAT_POLLING = false; @@ -54,59 +51,41 @@ public final class CallTracker extends Handler //***** Constants - static final int POLL_DELAY_MSEC = 250; static final int MAX_CONNECTIONS = 7; // only 7 connections allowed in GSM static final int MAX_CONNECTIONS_PER_CALL = 5; // only 5 connections allowed per call //***** Instance Variables - - GSMConnection connections[] = new GSMConnection[MAX_CONNECTIONS]; + GsmConnection connections[] = new GsmConnection[MAX_CONNECTIONS]; RegistrantList voiceCallEndedRegistrants = new RegistrantList(); RegistrantList voiceCallStartedRegistrants = new RegistrantList(); // connections dropped durin last poll - ArrayList<GSMConnection> droppedDuringPoll - = new ArrayList<GSMConnection>(MAX_CONNECTIONS); + ArrayList<GsmConnection> droppedDuringPoll + = new ArrayList<GsmConnection>(MAX_CONNECTIONS); - GSMCall ringingCall = new GSMCall(this); + GsmCall ringingCall = new GsmCall(this); // A call that is ringing or (call) waiting - GSMCall foregroundCall = new GSMCall(this); - GSMCall backgroundCall = new GSMCall(this); + GsmCall foregroundCall = new GsmCall(this); + GsmCall backgroundCall = new GsmCall(this); - GSMConnection pendingMO; + GsmConnection pendingMO; boolean hangupPendingMO; GSMPhone phone; - CommandsInterface cm; + boolean desiredMute = false; // false = mute off Phone.State state = Phone.State.IDLE; - int pendingOperations; - boolean needsPoll; - Message lastRelevantPoll; //***** Events - static final int EVENT_POLL_CALLS_RESULT = 1; - static final int EVENT_CALL_STATE_CHANGE = 2; - static final int EVENT_REPOLL_AFTER_DELAY = 3; - static final int EVENT_OPERATION_COMPLETE = 4; - static final int EVENT_GET_LAST_CALL_FAIL_CAUSE = 5; - - static final int EVENT_SWITCH_RESULT = 8; - static final int EVENT_RADIO_AVAILABLE = 9; - static final int EVENT_RADIO_NOT_AVAILABLE = 10; - static final int EVENT_CONFERENCE_RESULT = 11; - static final int EVENT_SEPARATE_RESULT = 12; - static final int EVENT_ECT_RESULT = 13; //***** Constructors - CallTracker (GSMPhone phone) - { + GsmCallTracker (GSMPhone phone) { this.phone = phone; cm = phone.mCM; @@ -116,24 +95,56 @@ public final class CallTracker extends Handler cm.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null); } + public void dispose() { + //Unregister for all events + cm.unregisterForCallStateChanged(this); + cm.unregisterForOn(this); + cm.unregisterForNotAvailable(this); + + for(GsmConnection c : connections) { + try { + if(c != null) hangup(c); + } catch (CallStateException ex) { + Log.e(LOG_TAG, "unexpected error on hangup during dispose"); + } + } + + try { + if(pendingMO != null) hangup(pendingMO); + } catch (CallStateException ex) { + Log.e(LOG_TAG, "unexpected error on hangup during dispose"); + } + + clearDisconnected(); + } + + protected void finalize() { + Log.d(LOG_TAG, "GsmCallTracker finalized"); + } + //***** Instance Methods //***** Public Methods - public void registerForVoiceCallStarted(Handler h, int what, Object obj) - { + public void registerForVoiceCallStarted(Handler h, int what, Object obj) { Registrant r = new Registrant(h, what, obj); voiceCallStartedRegistrants.add(r); } - public void registerForVoiceCallEnded(Handler h, int what, Object obj) - { + public void unregisterForVoiceCallStarted(Handler h) { + voiceCallStartedRegistrants.remove(h); + } + + public void registerForVoiceCallEnded(Handler h, int what, Object obj) { Registrant r = new Registrant(h, what, obj); voiceCallEndedRegistrants.add(r); } + public void unregisterForVoiceCallEnded(Handler h) { + voiceCallEndedRegistrants.remove(h); + } + private void - fakeHoldForegroundBeforeDial() - { + fakeHoldForegroundBeforeDial() { List<Connection> connCopy; // We need to make a copy here, since fakeHoldBeforeDial() @@ -141,7 +152,7 @@ public final class CallTracker extends Handler connCopy = (List<Connection>) foregroundCall.connections.clone(); for (int i = 0, s = connCopy.size() ; i < s ; i++) { - GSMConnection conn = (GSMConnection)connCopy.get(i); + GsmConnection conn = (GsmConnection)connCopy.get(i); conn.fakeHoldBeforeDial(); } @@ -162,7 +173,7 @@ public final class CallTracker extends Handler // 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() == Call.State.ACTIVE) { + if (foregroundCall.getState() == GsmCall.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 @@ -176,12 +187,12 @@ public final class CallTracker extends Handler fakeHoldForegroundBeforeDial(); } - if (foregroundCall.getState() != Call.State.IDLE) { + if (foregroundCall.getState() != GsmCall.State.IDLE) { //we should have failed in !canDial() above before we get here throw new CallStateException("cannot dial in current state"); } - pendingMO = new GSMConnection(phone.getContext(), dialString, this, foregroundCall); + pendingMO = new GsmConnection(phone.getContext(), dialString, this, foregroundCall); hangupPendingMO = false; if (pendingMO.address == null || pendingMO.address.length() == 0 @@ -208,24 +219,22 @@ public final class CallTracker extends Handler Connection - dial (String dialString) throws CallStateException - { + dial (String dialString) throws CallStateException { return dial(dialString, CommandsInterface.CLIR_DEFAULT); } void - acceptCall () throws CallStateException - { + 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 - if (ringingCall.getState() == Call.State.INCOMING) { + if (ringingCall.getState() == GsmCall.State.INCOMING) { Log.i("phone", "acceptCall: incoming..."); // Always unmute when answering a new call setMute(false); cm.acceptCall(obtainCompleteMessage()); - } else if (ringingCall.getState() == Call.State.WAITING) { + } else if (ringingCall.getState() == GsmCall.State.WAITING) { setMute(false); switchWaitingOrHoldingAndActive(); } else { @@ -234,8 +243,7 @@ public final class CallTracker extends Handler } void - rejectCall () throws CallStateException - { + rejectCall () throws CallStateException { // AT+CHLD=0 means "release held or UDUB" // so if the phone isn't ringing, this could hang up held if (ringingCall.getState().isRinging()) { @@ -248,7 +256,7 @@ public final class CallTracker extends Handler void switchWaitingOrHoldingAndActive() throws CallStateException { // Should we bother with this check? - if (ringingCall.getState() == Call.State.INCOMING) { + if (ringingCall.getState() == GsmCall.State.INCOMING) { throw new CallStateException("cannot be in the incoming state"); } else { cm.switchWaitingOrHoldingAndActive( @@ -257,20 +265,17 @@ public final class CallTracker extends Handler } void - conference() throws CallStateException - { + conference() throws CallStateException { cm.conference(obtainCompleteMessage(EVENT_CONFERENCE_RESULT)); } void - explicitCallTransfer() throws CallStateException - { + explicitCallTransfer() throws CallStateException { cm.explicitCallTransfer(obtainCompleteMessage(EVENT_ECT_RESULT)); } void - clearDisconnected() - { + clearDisconnected() { internalClearDisconnected(); updatePhoneState(); @@ -278,17 +283,15 @@ public final class CallTracker extends Handler } boolean - canConference() - { - return foregroundCall.getState() == Call.State.ACTIVE - && backgroundCall.getState() == Call.State.HOLDING + canConference() { + return foregroundCall.getState() == GsmCall.State.ACTIVE + && backgroundCall.getState() == GsmCall.State.HOLDING && !backgroundCall.isFull() && !foregroundCall.isFull(); } boolean - canDial() - { + canDial() { boolean ret; int serviceState = phone.getServiceState().getState(); @@ -302,42 +305,26 @@ public final class CallTracker extends Handler } boolean - canTransfer() - { - return foregroundCall.getState() == Call.State.ACTIVE - && backgroundCall.getState() == Call.State.HOLDING; + canTransfer() { + return foregroundCall.getState() == GsmCall.State.ACTIVE + && backgroundCall.getState() == GsmCall.State.HOLDING; } //***** Private Instance Methods private void - internalClearDisconnected() - { + internalClearDisconnected() { ringingCall.clearDisconnected(); foregroundCall.clearDisconnected(); backgroundCall.clearDisconnected(); } /** - * @return true if we're idle or there's a call to getCurrentCalls() pending - * but nothing else - */ - private boolean - checkNoOperationsPending() - { - if (DBG_POLL) log("checkNoOperationsPending: pendingOperations=" + - pendingOperations); - return pendingOperations == 0; - } - - - /** * Obtain a message to use for signalling "invoke getCurrentCalls() when * this operation and all other pending operations are complete */ private Message - obtainCompleteMessage() - { + obtainCompleteMessage() { return obtainCompleteMessage(EVENT_OPERATION_COMPLETE); } @@ -346,8 +333,7 @@ public final class CallTracker extends Handler * this operation and all other pending operations are complete */ private Message - obtainCompleteMessage(int what) - { + obtainCompleteMessage(int what) { pendingOperations++; lastRelevantPoll = null; needsPoll = true; @@ -358,26 +344,8 @@ public final class CallTracker extends Handler return obtainMessage(what); } - /** - * Obtain a complete message that indicates that this operation - * does not require polling of getCurrentCalls(). However, if other - * operations that do need getCurrentCalls() are pending or are - * scheduled while this operation is pending, the invocatoin - * of getCurrentCalls() will be postponed until this - * operation is also complete. - */ - private Message - obtainNoPollCompleteMessage(int what) - { - pendingOperations++; - lastRelevantPoll = null; - return obtainMessage(what); - } - - private void - operationComplete() - { + operationComplete() { pendingOperations--; if (DBG_POLL) log("operationComplete: pendingOperations=" + @@ -388,42 +356,13 @@ public final class CallTracker extends Handler cm.getCurrentCalls(lastRelevantPoll); } else if (pendingOperations < 0) { // this should never happen - Log.e(LOG_TAG,"CallTracker.pendingOperations < 0"); + Log.e(LOG_TAG,"GsmCallTracker.pendingOperations < 0"); pendingOperations = 0; } } private void - pollCallsWhenSafe() - { - needsPoll = true; - - if (checkNoOperationsPending()) { - lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); - cm.getCurrentCalls(lastRelevantPoll); - } - } - - private void - pollCallsAfterDelay() - { - Message msg = obtainMessage(); - - msg.what = EVENT_REPOLL_AFTER_DELAY; - sendMessageDelayed(msg, POLL_DELAY_MSEC); - } - - private boolean - isCommandExceptionRadioNotAvailable(Throwable e) - { - return e != null && e instanceof CommandException - && ((CommandException)e).getCommandError() - == CommandException.Error.RADIO_NOT_AVAILABLE; - } - - private void - updatePhoneState() - { + updatePhoneState() { Phone.State oldState = state; if (ringingCall.isRinging()) { @@ -448,9 +387,8 @@ public final class CallTracker extends Handler } } - private void - handlePollCalls(AsyncResult ar) - { + protected void + handlePollCalls(AsyncResult ar) { List polledCalls; if (ar.exception == null) { @@ -474,7 +412,7 @@ public final class CallTracker extends Handler for (int i = 0, curDC = 0, dcSize = polledCalls.size() ; i < connections.length; i++) { - GSMConnection conn = connections[i]; + GsmConnection conn = connections[i]; DriverCall dc = null; // polledCall list is sparse @@ -519,7 +457,7 @@ public final class CallTracker extends Handler return; } } else { - connections[i] = new GSMConnection(phone.getContext(), dc, this, i); + connections[i] = new GsmConnection(phone.getContext(), dc, this, i); // it's a ringing call if (connections[i].getCall() == ringingCall) { @@ -549,14 +487,14 @@ public final class CallTracker extends Handler // tracking. droppedDuringPoll.add(conn); // Dropped connections are removed from the CallTracker - // list but kept in the GSMCall list + // list but kept in the GsmCall list connections[i] = null; } else if (conn != null && dc != null && !conn.compareTo(dc)) { // Connection in CLCC response does not match what // we were tracking. Assume dropped call and new call droppedDuringPoll.add(conn); - connections[i] = new GSMConnection (phone.getContext(), dc, this, i); + connections[i] = new GsmConnection (phone.getContext(), dc, this, i); if (connections[i].getCall() == ringingCall) { newRinging = connections[i]; @@ -608,7 +546,7 @@ public final class CallTracker extends Handler // cases from the "dropped during poll" list // These cases need no "last call fail" reason for (int i = droppedDuringPoll.size() - 1; i >= 0 ; i--) { - GSMConnection conn = droppedDuringPoll.get(i); + GsmConnection conn = droppedDuringPoll.get(i); if (conn.isIncoming() && conn.getConnectTime() == 0) { // Missed or rejected call @@ -630,7 +568,7 @@ public final class CallTracker extends Handler droppedDuringPoll.remove(i); conn.onDisconnect(Connection.DisconnectCause.LOCAL); } else if (conn.cause == - Connection.DisconnectCause.INVALID_NUMBER) { + Connection.DisconnectCause.INVALID_NUMBER) { droppedDuringPoll.remove(i); conn.onDisconnect(Connection.DisconnectCause.INVALID_NUMBER); } @@ -669,14 +607,7 @@ public final class CallTracker extends Handler } private void - handleRadioAvailable() - { - pollCallsWhenSafe(); - } - - private void - handleRadioNotAvailable() - { + handleRadioNotAvailable() { // handlePollCalls will clear out its // call list when it gets the CommandException // error result from this @@ -684,8 +615,7 @@ public final class CallTracker extends Handler } private void - dumpState() - { + dumpState() { List l; Log.i(LOG_TAG,"Phone State:" + state); @@ -713,14 +643,13 @@ public final class CallTracker extends Handler } - //***** Called from GSMConnection + //***** Called from GsmConnection /*package*/ void - hangup (GSMConnection conn) throws CallStateException - { + hangup (GsmConnection conn) throws CallStateException { if (conn.owner != this) { - throw new CallStateException ("Connection " + conn - + "does not belong to CallTracker " + this); + throw new CallStateException ("GsmConnection " + conn + + "does not belong to GsmCallTracker " + this); } if (conn == pendingMO) { @@ -735,7 +664,7 @@ public final class CallTracker extends Handler } catch (CallStateException ex) { // Ignore "connection not found" // Call may have hung up already - Log.w(LOG_TAG,"CallTracker WARN: hangup() on absent connection " + Log.w(LOG_TAG,"GsmCallTracker WARN: hangup() on absent connection " + conn); } } @@ -744,11 +673,10 @@ public final class CallTracker extends Handler } /*package*/ void - separate (GSMConnection conn) throws CallStateException - { + separate (GsmConnection conn) throws CallStateException { if (conn.owner != this) { - throw new CallStateException ("Connection " + conn - + "does not belong to CallTracker " + this); + throw new CallStateException ("GsmConnection " + conn + + "does not belong to GsmCallTracker " + this); } try { cm.separateConnection (conn.getGSMIndex(), @@ -756,7 +684,7 @@ public final class CallTracker extends Handler } catch (CallStateException ex) { // Ignore "connection not found" // Call may have hung up already - Log.w(LOG_TAG,"CallTracker WARN: separate() on absent connection " + Log.w(LOG_TAG,"GsmCallTracker WARN: separate() on absent connection " + conn); } } @@ -764,24 +692,21 @@ public final class CallTracker extends Handler //***** Called from GSMPhone /*package*/ void - setMute(boolean mute) - { + setMute(boolean mute) { desiredMute = mute; cm.setMute(desiredMute, null); } /*package*/ boolean - getMute() - { + getMute() { return desiredMute; } - //***** Called from GSMCall + //***** Called from GsmCall /* package */ void - hangup (GSMCall call) throws CallStateException - { + hangup (GsmCall call) throws CallStateException { if (call.getConnections().size() == 0) { throw new CallStateException("no connections in call"); } @@ -794,7 +719,7 @@ public final class CallTracker extends Handler if (Phone.DEBUG_PHONE) { log("(foregnd) hangup dialing or alerting..."); } - hangup((GSMConnection)(call.getConnections().get(0))); + hangup((GsmConnection)(call.getConnections().get(0))); } else { hangupForegroundResumeBackground(); } @@ -808,8 +733,8 @@ public final class CallTracker extends Handler hangupWaitingOrBackground(); } } else { - throw new RuntimeException ("Call " + call + - "does not belong to CallTracker " + this); + throw new RuntimeException ("GsmCall " + call + + "does not belong to GsmCallTracker " + this); } call.onHangupLocal(); @@ -827,11 +752,11 @@ public final class CallTracker extends Handler cm.hangupForegroundResumeBackground(obtainCompleteMessage()); } - void hangupConnectionByIndex(GSMCall call, int index) + void hangupConnectionByIndex(GsmCall call, int index) throws CallStateException { int count = call.connections.size(); for (int i = 0; i < count; i++) { - GSMConnection cn = (GSMConnection)call.connections.get(i); + GsmConnection cn = (GsmConnection)call.connections.get(i); if (cn.getGSMIndex() == index) { cm.hangupConnection(index, obtainCompleteMessage()); return; @@ -841,11 +766,11 @@ public final class CallTracker extends Handler throw new CallStateException("no gsm index found"); } - void hangupAllConnections(GSMCall call) throws CallStateException{ + void hangupAllConnections(GsmCall call) throws CallStateException{ try { int count = call.connections.size(); for (int i = 0; i < count; i++) { - GSMConnection cn = (GSMConnection)call.connections.get(i); + GsmConnection cn = (GsmConnection)call.connections.get(i); cm.hangupConnection(cn.getGSMIndex(), obtainCompleteMessage()); } } catch (CallStateException ex) { @@ -854,11 +779,11 @@ public final class CallTracker extends Handler } /* package */ - GSMConnection getConnectionByIndex(GSMCall call, int index) + GsmConnection getConnectionByIndex(GsmCall call, int index) throws CallStateException { int count = call.connections.size(); for (int i = 0; i < count; i++) { - GSMConnection cn = (GSMConnection)call.connections.get(i); + GsmConnection cn = (GsmConnection)call.connections.get(i); if (cn.getGSMIndex() == index) { return cn; } @@ -884,8 +809,7 @@ public final class CallTracker extends Handler //****** Overridden from Handler public void - handleMessage (Message msg) - { + handleMessage (Message msg) { AsyncResult ar; switch (msg.what) { @@ -952,7 +876,7 @@ public final class CallTracker extends Handler for (int i = 0, s = droppedDuringPoll.size() ; i < s ; i++ ) { - GSMConnection conn = droppedDuringPoll.get(i); + GsmConnection conn = droppedDuringPoll.get(i); conn.onRemoteDisconnect(causeCode); } @@ -978,7 +902,7 @@ public final class CallTracker extends Handler } } - private void log(String msg) { - Log.d(LOG_TAG, "[CallTracker] " + msg); + protected void log(String msg) { + Log.d(LOG_TAG, "[GsmCallTracker] " + msg); } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java index 4777892..2b2f077 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java @@ -15,39 +15,39 @@ */ package com.android.internal.telephony.gsm; -import com.android.internal.telephony.*; - import android.content.Context; +import android.os.AsyncResult; import android.os.Handler; -import android.os.PowerManager; -import android.os.Registrant; import android.os.Looper; import android.os.Message; -import android.os.AsyncResult; +import android.os.PowerManager; +import android.os.Registrant; import android.os.SystemClock; -import android.util.Log; import android.util.Config; +import android.util.Log; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; +import com.android.internal.telephony.*; + /** * {@hide} */ -public class GSMConnection extends Connection { +public class GsmConnection extends Connection { static final String LOG_TAG = "GSM"; //***** Instance Variables - CallTracker owner; - GSMCall parent; + GsmCallTracker owner; + GsmCall parent; String address; // MAY BE NULL!!! String dialString; // outgoing calls only - String postDialString; // outgoing calls only + String postDialString; // outgoing calls only boolean isIncoming; - boolean disconnected; + boolean disconnected; - int index; // index in CallTracker.connections[], -1 if unassigned + int index; // index in GsmCallTracker.connections[], -1 if unassigned // The GSM index is 1 + this /* @@ -65,7 +65,7 @@ public class GSMConnection extends Connection { */ long connectTimeReal; long duration; - long holdingStartTime; // The time when the Connection last transitioned + long holdingStartTime; // The time when the Connection last transitioned // into HOLDING int nextPostDialChar; // index into postDialString @@ -95,8 +95,8 @@ public class GSMConnection extends Connection { MyHandler(Looper l) {super(l);} public void - handleMessage(Message msg) - { + handleMessage(Message msg) { + switch (msg.what) { case EVENT_NEXT_POST_DIAL: case EVENT_DTMF_DONE: @@ -114,11 +114,10 @@ public class GSMConnection extends Connection { /** This is probably an MT call that we first saw in a CLCC response */ /*package*/ - GSMConnection (Context context, DriverCall dc, CallTracker ct, int index) - { + GsmConnection (Context context, DriverCall dc, GsmCallTracker ct, int index) { createWakeLock(context); acquireWakeLock(); - + owner = ct; h = new MyHandler(owner.getLooper()); @@ -136,11 +135,10 @@ public class GSMConnection extends Connection { /** This is an MO call, created when dialing */ /*package*/ - GSMConnection (Context context, String dialString, CallTracker ct, GSMCall parent) - { + GsmConnection (Context context, String dialString, GsmCallTracker ct, GsmCall parent) { createWakeLock(context); acquireWakeLock(); - + owner = ct; h = new MyHandler(owner.getLooper()); @@ -155,18 +153,19 @@ public class GSMConnection extends Connection { createTime = System.currentTimeMillis(); this.parent = parent; - parent.attachFake(this, Call.State.DIALING); + parent.attachFake(this, GsmCall.State.DIALING); } - + + public void dispose() { + } + static boolean - equalsHandlesNulls (Object a, Object b) - { + equalsHandlesNulls (Object a, Object b) { return (a == null) ? (b == null) : a.equals (b); } /*package*/ boolean - compareTo(DriverCall c) - { + compareTo(DriverCall c) { // On mobile originated (MO) calls, the phone number may have changed // due to a SIM Toolkit call control modification. // @@ -178,43 +177,35 @@ public class GSMConnection extends Connection { // no control over when they begin, so we might as well String cAddress = PhoneNumberUtils.stringFromStringAndTOA(c.number, c.TOA); - return isIncoming == c.isMT && equalsHandlesNulls(address, cAddress); + return isIncoming == c.isMT && equalsHandlesNulls(address, cAddress); } public String - toString() - { + toString() { return (isIncoming ? "incoming" : "outgoing"); } - public String getAddress() - { - return address; + public String getAddress() { + return address; } - - public Call getCall() - { + public GsmCall getCall() { return parent; } - public long getCreateTime() - { + public long getCreateTime() { return createTime; } - public long getConnectTime() - { + public long getConnectTime() { return connectTime; } - public long getDisconnectTime() - { + public long getDisconnectTime() { return disconnectTime; } - public long getDurationMillis() - { + public long getDurationMillis() { if (connectTimeReal == 0) { return 0; } else if (duration == 0) { @@ -224,9 +215,8 @@ public class GSMConnection extends Connection { } } - public long getHoldDurationMillis() - { - if (getState() != Call.State.HOLDING) { + public long getHoldDurationMillis() { + if (getState() != GsmCall.State.HOLDING) { // If not holding, return 0 return 0; } else { @@ -234,52 +224,45 @@ public class GSMConnection extends Connection { } } - public DisconnectCause getDisconnectCause() - { + public DisconnectCause getDisconnectCause() { return cause; } - public boolean isIncoming() - { + public boolean isIncoming() { return isIncoming; } - public Call.State getState() - { + public GsmCall.State getState() { if (disconnected) { - return Call.State.DISCONNECTED; - } else { + return GsmCall.State.DISCONNECTED; + } else { return super.getState(); } } - public void hangup() throws CallStateException - { - if (!disconnected) { + public void hangup() throws CallStateException { + if (!disconnected) { owner.hangup(this); } else { throw new CallStateException ("disconnected"); } } - public void separate() throws CallStateException - { - if (!disconnected) { + public void separate() throws CallStateException { + if (!disconnected) { owner.separate(this); } else { throw new CallStateException ("disconnected"); } } - public PostDialState getPostDialState() - { + public PostDialState getPostDialState() { return postDialState; } - public void proceedAfterWaitChar() - { + public void proceedAfterWaitChar() { if (postDialState != PostDialState.WAIT) { - Log.w(LOG_TAG, "Connection.proceedAfterWaitChar(): Expected " + Log.w(LOG_TAG, "GsmConnection.proceedAfterWaitChar(): Expected " + "getPostDialState() to be WAIT but was " + postDialState); return; } @@ -288,10 +271,10 @@ public class GSMConnection extends Connection { processNextPostDialChar(); } - + public void proceedAfterWildChar(String str) { if (postDialState != PostDialState.WILD) { - Log.w(LOG_TAG, "Connection.proceedAfterWaitChar(): Expected " + Log.w(LOG_TAG, "GsmConnection.proceedAfterWaitChar(): Expected " + "getPostDialState() to be WILD but was " + postDialState); return; } @@ -328,38 +311,35 @@ public class GSMConnection extends Connection { postDialString = buf.toString(); nextPostDialChar = 0; if (Phone.DEBUG_PHONE) { - log("proceedAfterWildChar: new postDialString is " + + log("proceedAfterWildChar: new postDialString is " + postDialString); } processNextPostDialChar(); } } - - public void cancelPostDial() - { + + public void cancelPostDial() { setPostDialState(PostDialState.CANCELLED); } - /** + /** * Called when this Connection is being hung up locally (eg, user pressed "end") * Note that at this point, the hangup request has been dispatched to the radio - * but no response has yet been received so update() has not yet been called + * but no response has yet been received so update() has not yet been called */ void - onHangupLocal() - { + onHangupLocal() { cause = DisconnectCause.LOCAL; } DisconnectCause - disconnectCauseFromCode(int causeCode) - { + disconnectCauseFromCode(int causeCode) { /** * See 22.001 Annex F.4 for mapping of cause codes * to local tones */ - + switch (causeCode) { case CallFailCause.USER_BUSY: return DisconnectCause.BUSY; @@ -382,7 +362,7 @@ public class GSMConnection extends Connection { return DisconnectCause.FDN_BLOCKED; case CallFailCause.ERROR_UNSPECIFIED: - case CallFailCause.NORMAL_CLEARING: + case CallFailCause.NORMAL_CLEARING: default: GSMPhone phone = owner.phone; int serviceState = phone.getServiceState().getState(); @@ -391,8 +371,8 @@ public class GSMConnection extends Connection { } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE || serviceState == ServiceState.STATE_EMERGENCY_ONLY ) { return DisconnectCause.OUT_OF_SERVICE; - } else if (phone.getSimCard().getState() != GsmSimCard.State.READY) { - return DisconnectCause.SIM_ERROR; + } else if (phone.getIccCard().getState() != SimCard.State.READY) { + return DisconnectCause.ICC_ERROR; } else if (causeCode == CallFailCause.ERROR_UNSPECIFIED) { if (phone.mSST.rs.isCsRestricted()) { return DisconnectCause.CS_RESTRICTED; @@ -410,20 +390,18 @@ public class GSMConnection extends Connection { } /*package*/ void - onRemoteDisconnect(int causeCode) - { + onRemoteDisconnect(int causeCode) { onDisconnect(disconnectCauseFromCode(causeCode)); } /** Called when the radio indicates the connection has been disconnected */ /*package*/ void - onDisconnect(DisconnectCause cause) - { + onDisconnect(DisconnectCause cause) { this.cause = cause; - - if (!disconnected) { + + if (!disconnected) { index = -1; - + disconnectTime = System.currentTimeMillis(); duration = SystemClock.elapsedRealtime() - connectTimeReal; disconnected = true; @@ -434,7 +412,7 @@ public class GSMConnection extends Connection { owner.phone.notifyDisconnect(this); if (parent != null) { - parent.connectionDisconnected(this); + parent.connectionDisconnected(this); } } releaseWakeLock(); @@ -443,10 +421,10 @@ public class GSMConnection extends Connection { // Returns true if state has changed, false if nothing changed /*package*/ boolean update (DriverCall dc) { - GSMCall newParent; + GsmCall newParent; boolean changed = false; boolean wasConnectingInOrOut = isConnectingInOrOut(); - boolean wasHolding = (getState() == Call.State.HOLDING); + boolean wasHolding = (getState() == GsmCall.State.HOLDING); newParent = parentFromDCState(dc.state); @@ -484,7 +462,7 @@ public class GSMConnection extends Connection { onConnectedInOrOut(); } - if (changed && !wasHolding && (getState() == Call.State.HOLDING)) { + if (changed && !wasHolding && (getState() == GsmCall.State.HOLDING)) { // We've transitioned into HOLDING onStartedHolding(); } @@ -499,14 +477,13 @@ public class GSMConnection extends Connection { * HOLDING in the backgroundCall */ void - fakeHoldBeforeDial() - { + fakeHoldBeforeDial() { if (parent != null) { parent.detach(this); } parent = owner.backgroundCall; - parent.attachFake(this, Call.State.HOLDING); + parent.attachFake(this, GsmCall.State.HOLDING); onStartedHolding(); } @@ -552,28 +529,27 @@ public class GSMConnection extends Connection { * should be ignored */ private boolean - processPostDialChar(char c) - { + processPostDialChar(char c) { 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 + // "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...." 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), + 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 + // "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), + h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE), PAUSE_DELAY_MILLIS); } } else if (c == PhoneNumberUtils.WAIT) { @@ -588,9 +564,8 @@ public class GSMConnection extends Connection { } public String - getRemainingPostDialString() - { - if (postDialState == PostDialState.CANCELLED + getRemainingPostDialString() { + if (postDialState == PostDialState.CANCELLED || postDialState == PostDialState.COMPLETE || postDialString == null || postDialString.length() <= nextPostDialChar @@ -617,8 +592,7 @@ public class GSMConnection extends Connection { } private void - processNextPostDialChar() - { + processNextPostDialChar() { char c = 0; Registrant postDialHandler; @@ -655,7 +629,8 @@ public class GSMConnection extends Connection { Message notifyMessage; - if (postDialHandler != null && (notifyMessage = postDialHandler.messageForRegistrant()) != null) { + if (postDialHandler != null + && (notifyMessage = postDialHandler.messageForRegistrant()) != null) { // The AsyncResult.result is the Connection object PostDialState state = postDialState; AsyncResult ar = AsyncResult.forMessage(notifyMessage); @@ -668,14 +643,6 @@ public class GSMConnection extends Connection { //Log.v("GSM", "##### processNextPostDialChar: send msg to postDialHandler, arg1=" + c); notifyMessage.sendToTarget(); } - /* - else { - if (postDialHandler == null) - Log.v("GSM", "##### processNextPostDialChar: postDialHandler is NULL!"); - else - Log.v("GSM", "##### processNextPostDialChar: postDialHandler.messageForRegistrant() returned NULL!"); - } - */ } @@ -683,16 +650,14 @@ public class GSMConnection extends Connection { * and outgoing calls */ private boolean - isConnectingInOrOut() - { - return parent == null || parent == owner.ringingCall - || parent.state == Call.State.DIALING - || parent.state == Call.State.ALERTING; + isConnectingInOrOut() { + return parent == null || parent == owner.ringingCall + || parent.state == GsmCall.State.DIALING + || parent.state == GsmCall.State.ALERTING; } - private GSMCall - parentFromDCState (DriverCall.State state) - { + private GsmCall + parentFromDCState (DriverCall.State state) { switch (state) { case ACTIVE: case DIALING: diff --git a/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index 02a6841..e2da7cb 100644 --- a/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -50,8 +50,12 @@ import android.text.TextUtils; import android.util.EventLog; import android.util.Log; +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.gsm.PdpConnection.PdpFailCause; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.TelephonyEventLog; import java.io.IOException; import java.util.ArrayList; @@ -59,45 +63,11 @@ import java.util.ArrayList; /** * {@hide} */ -final class DataConnectionTracker extends Handler -{ +public final class GsmDataConnectionTracker extends DataConnectionTracker { private static final String LOG_TAG = "GSM"; private static final boolean DBG = true; /** - * IDLE: ready to start data connection setup, default state - * INITING: state of issued setupDefaultPDP() but not finish yet - * CONNECTING: state of issued startPppd() but not finish yet - * SCANNING: data connection fails with one apn but other apns are available - * ready to start data connection on other apns (before INITING) - * CONNECTED: IP connection is setup - * DISCONNECTING: PdpConnection.disconnect() has been called, but PDP - * context is not yet deactivated - * FAILED: data connection fail for all apns settings - * - * getDataConnectionState() maps State to DataState - * FAILED or IDLE : DISCONNECTED - * INITING or CONNECTING or SCANNING: CONNECTING - * CONNECTED : CONNECTED or DISCONNECTING - */ - enum State { - IDLE, - INITING, - CONNECTING, - SCANNING, - CONNECTED, - DISCONNECTING, - FAILED - } - - enum Activity { - NONE, - DATAIN, - DATAOUT, - DATAINANDOUT - } - - /** * Handles changes to the APN db. */ private class ApnChangeObserver extends ContentObserver { @@ -113,20 +83,12 @@ final class DataConnectionTracker extends Handler //***** Instance Variables - GSMPhone phone; INetStatService netstat; - State state = State.IDLE; - Activity activity = Activity.NONE; - boolean netStatPollEnabled = false; // Indicates baseband will not auto-attach private boolean noAutoAttach = false; long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - Handler mDataConnectionTracker = null; private ContentResolver mResolver; - long txPkts, rxPkts, sentSinceLastRecv; - int netStatPollPeriod; - private int mNoRecvPollCount = 0; private boolean mPingTestActive = false; // Count of PDP reset attempts; reset when we see incoming, // call reRegisterNetwork, or pingTest succeeds. @@ -156,10 +118,7 @@ final class DataConnectionTracker extends Handler /** * pdpList holds all the PDP connection, i.e. IP Link in GPRS */ - private ArrayList<PdpConnection> pdpList; - - /** CID of active PDP */ - int cidActive; + private ArrayList<DataConnection> pdpList; /** Currently requested APN type */ private String mRequestedApnType = Phone.APN_TYPE_DEFAULT; @@ -176,12 +135,6 @@ final class DataConnectionTracker extends Handler private boolean[] dataEnabled = new boolean[APN_NUM_TYPES]; - /** wifi connection status will be updated by sticky intent */ - private boolean mIsWifiConnected = false; - - /** Intent sent when the reconnect alarm fires. */ - private PendingIntent mReconnectIntent = null; - /** Is packet service restricted by network */ private boolean mIsPsRestricted = false; @@ -195,69 +148,17 @@ final class DataConnectionTracker extends Handler private static final int PDP_CONNECTION_POOL_SIZE = 1; private static final int POLL_PDP_MILLIS = 5 * 1000; - private static final int RECONNECT_DELAY_INITIAL_MILLIS = 5 * 1000; - /** Cap out with 1 hour retry interval. */ - private static final int RECONNECT_DELAY_MAX_MILLIS = 60 * 60 * 1000; - - /** Slow poll when attempting connection recovery. */ - private static final int POLL_NETSTAT_SLOW_MILLIS = 5000; - - /** Default ping deadline, in seconds. */ - private static final int DEFAULT_PING_DEADLINE = 5; - /** Default max failure count before attempting to network re-registration. */ - private static final int DEFAULT_MAX_PDP_RESET_FAIL = 3; - - /** - * After detecting a potential connection problem, this is the max number - * of subsequent polls before attempting a radio reset. At this point, - * poll interval is 5 seconds (POLL_NETSTAT_SLOW_MILLIS), so set this to - * poll for about 2 more minutes. - */ - private static final int NO_RECV_POLL_LIMIT = 24; - - // 1 sec. default polling interval when screen is on. - private static final int POLL_NETSTAT_MILLIS = 1000; - // 10 min. default polling interval when screen is off. - private static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10; - // 2 min for round trip time - private static final int POLL_LONGEST_RTT = 120 * 1000; - // 10 for packets without ack - private static final int NUMBER_SENT_PACKETS_OF_HANG = 10; - // how long to wait before switching back to default APN - private static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000; - // system property that can override the above value - private static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore"; - // represents an invalid IP address - private static final String NULL_IP = "0.0.0.0"; + //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"; - - //***** Event Codes - static final int EVENT_DATA_SETUP_COMPLETE = 1; - static final int EVENT_RADIO_AVAILABLE = 3; - static final int EVENT_RECORDS_LOADED = 4; - static final int EVENT_TRY_SETUP_DATA = 5; - static final int EVENT_PDP_STATE_CHANGED = 6; - static final int EVENT_POLL_PDP = 7; - static final int EVENT_GET_PDP_LIST_COMPLETE = 11; - static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 12; - static final int EVENT_VOICE_CALL_STARTED = 14; - static final int EVENT_VOICE_CALL_ENDED = 15; - static final int EVENT_GPRS_DETACHED = 19; - static final int EVENT_LINK_STATE_CHANGED = 20; - static final int EVENT_ROAMING_ON = 21; - static final int EVENT_ROAMING_OFF = 22; - static final int EVENT_ENABLE_NEW_APN = 23; - static final int EVENT_RESTORE_DEFAULT_APN = 24; - static final int EVENT_DISCONNECT_DONE = 25; - static final int EVENT_GPRS_ATTACHED = 26; - static final int EVENT_START_NETSTAT_POLL = 27; - static final int EVENT_START_RECOVERY = 28; - static final int EVENT_APN_CHANGED = 29; - static final int EVENT_PS_RESTRICT_ENABLED = 30; - static final int EVENT_PS_RESTRICT_DISABLED = 31; + //***** Tag IDs for EventLog + private static final int EVENT_LOG_RADIO_RESET_COUNTDOWN_TRIGGERED = 50101; + private static final int EVENT_LOG_RADIO_RESET = 50102; + private static final int EVENT_LOG_PDP_RESET = 50103; + private static final int EVENT_LOG_REREGISTER_NETWORK = 50104; + private static final int EVENT_LOG_RADIO_PDP_SETUP_FAIL = 50105; static final Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn"); static final String APN_ID = "apn_id"; @@ -307,21 +208,21 @@ final class DataConnectionTracker extends Handler //***** Constructor - DataConnectionTracker(GSMPhone phone) - { - this.phone = phone; - phone.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); - phone.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); - phone.mSIMRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); - phone.mCM.registerForPDPStateChanged (this, EVENT_PDP_STATE_CHANGED, null); - phone.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null); - phone.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null); - phone.mSST.registerForGprsAttached(this, EVENT_GPRS_ATTACHED, null); - phone.mSST.registerForGprsDetached(this, EVENT_GPRS_DETACHED, null); - phone.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null); - phone.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null); - phone.mSST.registerForPsRestrictedEnabled(this, EVENT_PS_RESTRICT_ENABLED, null); - phone.mSST.registerForPsRestrictedDisabled(this, EVENT_PS_RESTRICT_DISABLED, null); + GsmDataConnectionTracker(GSMPhone p) { + super(p); + + p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); + p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + p.mSIMRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); + p.mCM.registerForDataStateChanged (this, EVENT_DATA_STATE_CHANGED, null); + p.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null); + p.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null); + p.mSST.registerForGprsAttached(this, EVENT_GPRS_ATTACHED, null); + p.mSST.registerForGprsDetached(this, EVENT_GPRS_DETACHED, null); + p.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null); + p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null); + p.mSST.registerForPsRestrictedEnabled(this, EVENT_PS_RESTRICT_ENABLED, null); + p.mSST.registerForPsRestrictedDisabled(this, EVENT_PS_RESTRICT_DISABLED, null); this.netstat = INetStatService.Stub.asInterface(ServiceManager.getService("netstat")); @@ -332,14 +233,14 @@ final class DataConnectionTracker extends Handler filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - phone.getContext().registerReceiver(mIntentReceiver, filter, null, phone.h); + p.getContext().registerReceiver(mIntentReceiver, filter, null, p.h); mDataConnectionTracker = this; mResolver = phone.getContext().getContentResolver(); apnObserver = new ApnChangeObserver(); - phone.getContext().getContentResolver().registerContentObserver( + p.getContext().getContentResolver().registerContentObserver( Telephony.Carriers.CONTENT_URI, true, apnObserver); createAllPdpList(); @@ -351,6 +252,31 @@ final class DataConnectionTracker extends Handler noAutoAttach = !dataEnabled[APN_DEFAULT_ID]; } + public void dispose() { + //Unregister for all events + phone.mCM.unregisterForAvailable(this); + phone.mCM.unregisterForOffOrNotAvailable(this); + ((GSMPhone) phone).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); + + phone.getContext().unregisterReceiver(this.mIntentReceiver); + phone.getContext().getContentResolver().unregisterContentObserver(this.apnObserver); + + destroyAllPdpList(); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "GsmDataConnectionTracker finalized"); + } + void setState(State s) { if (DBG) log ("setState: " + s); if (state != s) { @@ -375,19 +301,6 @@ final class DataConnectionTracker extends Handler } } - String getStateInString() { - switch (state) { - case IDLE: return "IDLE"; - case INITING: return "INIT"; - case CONNECTING: return "CING"; - case SCANNING: return "SCAN"; - case CONNECTED: return "CNTD"; - case DISCONNECTING: return "DING"; - case FAILED: return "FAIL"; - default: return "ERRO"; - } - } - String[] getActiveApnTypes() { String[] result; if (mActiveApn != null) { @@ -399,7 +312,7 @@ final class DataConnectionTracker extends Handler return result; } - String getActiveApnString() { + protected String getActiveApnString() { String result = null; if (mActiveApn != null) { result = mActiveApn.apn; @@ -417,7 +330,7 @@ final class DataConnectionTracker extends Handler * will be sent by the ConnectivityManager when a connection to * the APN has been established. */ - int enableApnType(String type) { + protected int enableApnType(String type) { if (!TextUtils.equals(type, Phone.APN_TYPE_MMS)) { return Phone.APN_REQUEST_FAILED; } @@ -456,7 +369,7 @@ final class DataConnectionTracker extends Handler * @param type the APN type. The only valid value currently is {@link Phone#APN_TYPE_MMS}. * @return */ - int disableApnType(String type) { + protected int disableApnType(String type) { Log.d(LOG_TAG, "disableApnType("+type+")"); if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { removeMessages(EVENT_RESTORE_DEFAULT_APN); @@ -489,16 +402,15 @@ final class DataConnectionTracker extends Handler * 2. registered to gprs service * 3. user doesn't explicitly disable data service * 4. wifi is not on - * 5. packet service is not restricted * * @return false while no data connection if all above requirements are met. */ - boolean isDataConnectionAsDesired() { + public boolean isDataConnectionAsDesired() { boolean roaming = phone.getServiceState().getRoaming(); - if (phone.mSIMRecords.getRecordsLoaded() && - phone.mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE && - (!roaming || getDataOnRoamingEnabled()) && + if (((GSMPhone) phone).mSIMRecords.getRecordsLoaded() && + ((GSMPhone) phone).mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE && + (!roaming || getDataOnRoamingEnabled()) && !mIsWifiConnected && !mIsPsRestricted ) { return (state == State.CONNECTED); @@ -571,10 +483,12 @@ final class DataConnectionTracker extends Handler return true; } return false; - } else // isEnabled && enable + } else { + // isEnabled && enable return true; + } } - + /** * Simply tear down data connections due to radio off * and don't setup again. @@ -582,7 +496,7 @@ final class DataConnectionTracker extends Handler public void cleanConnectionBeforeRadioOff() { cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); } - + /** * Report the current state of data connectivity (enabled or disabled) for * the default APN. @@ -602,31 +516,11 @@ final class DataConnectionTracker extends Handler return dataEnabled[APN_DEFAULT_ID] || dataEnabled[APN_MMS_ID]; } - //The data roaming setting is now located in the shared preferences. - // See if the requested preference value is the same as that stored in - // the shared values. If it is not, then update it. - public void setDataOnRoamingEnabled(boolean enabled) { - if (getDataOnRoamingEnabled() != enabled) { - Settings.Secure.putInt(phone.getContext().getContentResolver(), - Settings.Secure.DATA_ROAMING, enabled ? 1 : 0); - } - Message roamingMsg = phone.getServiceState().getRoaming() ? - obtainMessage(EVENT_ROAMING_ON) : obtainMessage(EVENT_ROAMING_OFF); - sendMessage(roamingMsg); - } - - //Retrieve the data roaming setting from the shared preferences. - public boolean getDataOnRoamingEnabled() { - try { - return Settings.Secure.getInt(phone.getContext().getContentResolver(), - Settings.Secure.DATA_ROAMING) > 0; - } catch (SettingNotFoundException snfe) { - return false; - } - } - - public ArrayList<PdpConnection> getAllPdps() { - ArrayList<PdpConnection> pdps = (ArrayList<PdpConnection>)pdpList.clone(); + /** + * Formerly this method was ArrayList<PdpConnection> getAllPdps() + */ + public ArrayList<DataConnection> getAllDataConnections() { + ArrayList<DataConnection> pdps = (ArrayList<DataConnection>)pdpList.clone(); return pdps; } @@ -640,8 +534,7 @@ final class DataConnectionTracker extends Handler * Invoked when ServiceStateTracker observes a transition from GPRS * attach to detach. */ - private void onGprsDetached() - { + protected void onGprsDetached() { /* * We presently believe it is unnecessary to tear down the PDP context * when GPRS detaches, but we should stop the network polling. @@ -663,8 +556,7 @@ final class DataConnectionTracker extends Handler } } - private boolean trySetupData(String reason) - { + private boolean trySetupData(String reason) { if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason)); Log.d(LOG_TAG, "[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted); @@ -679,13 +571,14 @@ final class DataConnectionTracker extends Handler return true; } - int gprsState = phone.mSST.getCurrentGprsState(); + int gprsState = ((GSMPhone) phone).mSST.getCurrentGprsState(); boolean roaming = phone.getServiceState().getRoaming(); if ((state == State.IDLE || state == State.SCANNING) && (gprsState == ServiceState.STATE_IN_SERVICE || noAutoAttach) - && phone.mSIMRecords.getRecordsLoaded() - && phone.getState() == Phone.State.IDLE + && ((GSMPhone) phone).mSIMRecords.getRecordsLoaded() + && ( ((GSMPhone) phone).mSST.isConcurrentVoiceAndData() || + phone.getState() == Phone.State.IDLE ) && isDataAllowed() && !mIsPsRestricted ) { @@ -693,7 +586,7 @@ final class DataConnectionTracker extends Handler waitingApns = buildWaitingApns(); if (waitingApns.isEmpty()) { if (DBG) log("No APN found"); - notifyNoData(PdpConnection.PdpFailCause.BAD_APN); + notifyNoData(PdpConnection.FailCause.BAD_APN); return false; } else { log ("Create from allApns : " + apnListToString(allApns)); @@ -709,8 +602,8 @@ final class DataConnectionTracker extends Handler log("trySetupData: Not ready for data: " + " dataState=" + state + " gprsState=" + gprsState + - " sim=" + phone.mSIMRecords.getRecordsLoaded() + - " UMTS=" + phone.mSST.isConcurrentVoiceAndData() + + " sim=" + ((GSMPhone) phone).mSIMRecords.getRecordsLoaded() + + " UMTS=" + ((GSMPhone) phone).mSST.isConcurrentVoiceAndData() + " phoneState=" + phone.getState() + " dataEnabled=" + getAnyDataEnabled() + " roaming=" + roaming + @@ -740,7 +633,8 @@ final class DataConnectionTracker extends Handler mReconnectIntent = null; } - for (PdpConnection pdp : pdpList) { + for (DataConnection conn : pdpList) { + PdpConnection pdp = (PdpConnection) conn; if (tearDown) { Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason); pdp.disconnect(msg); @@ -762,7 +656,7 @@ final class DataConnectionTracker extends Handler * 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); @@ -814,8 +708,9 @@ final class DataConnectionTracker extends Handler } private PdpConnection findFreePdp() { - for (PdpConnection pdp : pdpList) { - if (pdp.getState() == PdpConnection.PdpState.INACTIVE) { + for (DataConnection conn : pdpList) { + PdpConnection pdp = (PdpConnection) conn; + if (pdp.getState() == DataConnection.State.INACTIVE) { return pdp; } } @@ -854,7 +749,7 @@ final class DataConnectionTracker extends Handler return null; } - String getIpAddress(String apnType) { + protected String getIpAddress(String apnType) { if (mActivePdp != null && (apnType == null || mActiveApn.canHandleType(apnType))) { return mActivePdp.getIpAddress(); @@ -870,7 +765,7 @@ final class DataConnectionTracker extends Handler return null; } - String[] getDnsServers(String apnType) { + protected String[] getDnsServers(String apnType) { if (mActivePdp != null && (apnType == null || mActiveApn.canHandleType(apnType))) { return mActivePdp.getDnsServers(); @@ -879,8 +774,7 @@ final class DataConnectionTracker extends Handler } private boolean - pdpStatesHasCID (ArrayList<PDPContextState> states, int cid) - { + pdpStatesHasCID (ArrayList<PDPContextState> states, int cid) { for (int i = 0, s = states.size() ; i < s ; i++) { if (states.get(i).cid == cid) return true; } @@ -889,8 +783,7 @@ final class DataConnectionTracker extends Handler } private boolean - pdpStatesHasActiveCID (ArrayList<PDPContextState> states, int cid) - { + pdpStatesHasActiveCID (ArrayList<PDPContextState> states, int cid) { for (int i = 0, s = states.size() ; i < s ; i++) { if (states.get(i).cid == cid) return states.get(i).active; } @@ -907,7 +800,7 @@ final class DataConnectionTracker extends Handler isConnected = (state != State.IDLE && state != State.FAILED); // The "current" may no longer be valid. MMS depends on this to send properly. - phone.updateCurrentCarrierInProvider(); + ((GSMPhone) phone).updateCurrentCarrierInProvider(); // TODO: It'd be nice to only do this if the changed entrie(s) // match the current operator. @@ -926,9 +819,7 @@ final class DataConnectionTracker extends Handler * via an unsolicited response (which could have happened at any * previous state */ - private void - onPdpStateChanged (AsyncResult ar, boolean explicitPoll) - { + protected void onPdpStateChanged (AsyncResult ar, boolean explicitPoll) { ArrayList<PDPContextState> pdpStates; pdpStates = (ArrayList<PDPContextState>)(ar.result); @@ -1062,9 +953,7 @@ final class DataConnectionTracker extends Handler * with certain RIL impl's/basebands * */ - private void - startPeriodicPdpPoll() - { + private void startPeriodicPdpPoll() { removeMessages(EVENT_POLL_PDP); sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS); @@ -1074,6 +963,7 @@ final class DataConnectionTracker extends Handler txPkts = -1; rxPkts = -1; sentSinceLastRecv = 0; + netStatPollPeriod = POLL_NETSTAT_MILLIS; mNoRecvPollCount = 0; } @@ -1089,16 +979,14 @@ final class DataConnectionTracker extends Handler } else { mPdpResetCount = 0; EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_REREGISTER_NETWORK, sentSinceLastRecv); - phone.mSST.reRegisterNetwork(null); + ((GSMPhone) phone).mSST.reRegisterNetwork(null); } // TODO: Add increasingly drastic recovery steps, eg, // reset the radio, reset the device. } } - private void - startNetStatPoll() - { + protected void startNetStatPoll() { if (state == State.CONNECTED && mPingTestActive == false && netStatPollEnabled == false) { Log.d(LOG_TAG, "[DataConnection] Start poll NetStat"); resetPollStats(); @@ -1107,17 +995,13 @@ final class DataConnectionTracker extends Handler } } - private void - stopNetStatPoll() - { + protected void stopNetStatPoll() { netStatPollEnabled = false; removeCallbacks(mPollNetStat); Log.d(LOG_TAG, "[DataConnection] Stop poll NetStat"); } - private void - restartRadio() - { + protected void restartRadio() { Log.d(LOG_TAG, "************TURN OFF RADIO**************"); cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); phone.mCM.setRadioPower(false, null); @@ -1133,7 +1017,7 @@ final class DataConnectionTracker extends Handler SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset+1)); } - Runnable mPollNetStat = new Runnable() + private Runnable mPollNetStat = new Runnable() { public void run() { @@ -1164,7 +1048,7 @@ final class DataConnectionTracker extends Handler newActivity = Activity.DATAINANDOUT; mPdpResetCount = 0; } else if (sent > 0 && received == 0) { - if (phone.mCT.state == Phone.State.IDLE) { + if (phone.getState() == Phone.State.IDLE) { sentSinceLastRecv += sent; } else { sentSinceLastRecv = 0; @@ -1188,7 +1072,8 @@ final class DataConnectionTracker extends Handler } int watchdogTrigger = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, NUMBER_SENT_PACKETS_OF_HANG); + Settings.Gservices.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, + NUMBER_SENT_PACKETS_OF_HANG); if (sentSinceLastRecv >= watchdogTrigger) { // we already have NUMBER_SENT_PACKETS sent without ack @@ -1204,13 +1089,14 @@ final class DataConnectionTracker extends Handler // It's possible the PDP context went down and we weren't notified. // Start polling the context list in an attempt to recover. if (DBG) log("no DATAIN in a while; polling PDP"); - phone.mCM.getPDPContextList(obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); + phone.mCM.getDataCallList(obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); mNoRecvPollCount++; // Slow down the poll interval to let things happen netStatPollPeriod = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS, POLL_NETSTAT_SLOW_MILLIS); + Settings.Gservices.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS, + POLL_NETSTAT_SLOW_MILLIS); } else { if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) + " pkts since last received"); @@ -1242,7 +1128,7 @@ final class DataConnectionTracker extends Handler } } }; - + private void runPingTest () { int status = -1; try { @@ -1279,15 +1165,13 @@ final class DataConnectionTracker extends Handler * seems like it deserves an error notification. * Transient errors are ignored */ - private boolean - shouldPostNotification(PdpConnection.PdpFailCause cause) - { + private boolean shouldPostNotification(PdpConnection.FailCause cause) { boolean shouldPost = true; // TODO CHECK // if (dataLink != null) { // shouldPost = dataLink.getLastLinkExitCode() != DataLink.EXIT_OPEN_FAILED; //} - return (shouldPost && cause != PdpConnection.PdpFailCause.UNKNOWN); + return (shouldPost && cause != PdpConnection.FailCause.UNKNOWN); } /** @@ -1301,14 +1185,13 @@ final class DataConnectionTracker extends Handler boolean retry = true; if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) || - Phone.REASON_DATA_DISABLED.equals(reason) || - Phone.REASON_PS_RESTRICT_ENABLED.equals(reason)) { + Phone.REASON_DATA_DISABLED.equals(reason) ) { retry = false; } return retry; - } - - private void reconnectAfterFail(PdpFailCause lastFailCauseCode, String reason) { + } + + private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) { if (state == State.FAILED) { Log.d(LOG_TAG, "PDP activate failed. Scheduling next attempt for " + (nextReconnectDelay / 1000) + "s"); @@ -1338,314 +1221,215 @@ final class DataConnectionTracker extends Handler } } - private void notifyNoData(PdpConnection.PdpFailCause lastFailCauseCode) { + private void notifyNoData(PdpConnection.FailCause lastFailCauseCode) { setState(State.FAILED); } - - private void log(String s) { - Log.d(LOG_TAG, "[DataConnectionTracker] " + s); + protected void onRecordsLoaded() { + createAllApnList(); + if (state == State.FAILED) { + cleanUpConnection(false, null); + } + sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); } - //***** Overridden from Handler - public void - handleMessage (Message msg) - { - AsyncResult ar; - String reason = null; - - switch (msg.what) { - case EVENT_RECORDS_LOADED: - createAllApnList(); - if (state == State.FAILED) { - cleanUpConnection(false, null); - } - sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED)); - break; - - case EVENT_ENABLE_NEW_APN: - // TODO: To support simultaneous PDP contexts, this should really only call - // cleanUpConnection if it needs to free up a PdpConnection. - reason = Phone.REASON_APN_SWITCHED; - cleanUpConnection(true, reason); - break; - - case EVENT_TRY_SETUP_DATA: - if (msg.obj instanceof String) { - reason = (String)msg.obj; - } - - trySetupData(reason); - break; - - case EVENT_RESTORE_DEFAULT_APN: - if (DBG) Log.d(LOG_TAG, "Restore default APN"); - setEnabled(Phone.APN_TYPE_MMS, false); - if (!isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { - cleanUpConnection(true, Phone.REASON_RESTORE_DEFAULT_APN); - mRequestedApnType = Phone.APN_TYPE_DEFAULT; - } - break; - - case EVENT_ROAMING_OFF: - trySetupData(Phone.REASON_ROAMING_OFF); - break; + protected void onEnableNewApn() { + // TODO: To support simultaneous PDP contexts, this should really only call + // cleanUpConnection if it needs to free up a PdpConnection. + cleanUpConnection(true, Phone.REASON_APN_SWITCHED); + } - case EVENT_GPRS_DETACHED: - onGprsDetached(); - break; + protected void onTrySetupData() { + trySetupData(null); + } - case EVENT_GPRS_ATTACHED: - onGprsAttached(); - break; + protected void onRestoreDefaultApn() { + if (DBG) Log.d(LOG_TAG, "Restore default APN"); + setEnabled(Phone.APN_TYPE_MMS, false); - case EVENT_ROAMING_ON: - if (getDataOnRoamingEnabled()) { - trySetupData(Phone.REASON_ROAMING_ON); - } else { - if (DBG) log("Tear down data connection on roaming."); - cleanUpConnection(true, Phone.REASON_ROAMING_ON); - } - break; + if (!isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { + cleanUpConnection(true, Phone.REASON_RESTORE_DEFAULT_APN); + mRequestedApnType = Phone.APN_TYPE_DEFAULT; + } + } - case EVENT_RADIO_AVAILABLE: - if (phone.getSimulatedRadioControl() != null) { - // Assume data is connected on the simulator - // FIXME this can be improved - setState(State.CONNECTED); - phone.notifyDataConnection(null); + protected void onRoamingOff() { + trySetupData(Phone.REASON_ROAMING_OFF); + } + protected void onRoamingOn() { + if (getDataOnRoamingEnabled()) { + trySetupData(Phone.REASON_ROAMING_ON); + } else { + if (DBG) log("Tear down data connection on roaming."); + cleanUpConnection(true, Phone.REASON_ROAMING_ON); + } + } - Log.i(LOG_TAG, "We're on the simulator; assuming data is connected"); - } + protected void onRadioAvailable() { + if (phone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + // FIXME this can be improved + setState(State.CONNECTED); + phone.notifyDataConnection(null); - if (state != State.IDLE) { - cleanUpConnection(true, null); - } - break; + Log.i(LOG_TAG, "We're on the simulator; assuming data is connected"); + } - case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: - // Make sure our reconnect delay starts at the initial value - // next time the radio comes on - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + if (state != State.IDLE) { + cleanUpConnection(true, null); + } + } - if (phone.getSimulatedRadioControl() != null) { - // Assume data is connected on the simulator - // FIXME this can be improved - Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless"); - } else { - if (DBG) log("Radio is off and clean up all connection"); - // TODO: Should we reset mRequestedApnType to "default"? - cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF); - } - break; + protected void onRadioOffOrNotAvailable() { + // Make sure our reconnect delay starts at the initial value + // next time the radio comes on + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - case EVENT_DATA_SETUP_COMPLETE: - ar = (AsyncResult) msg.obj; - if (ar.userObj instanceof String) { - reason = (String) ar.userObj; - } + if (phone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + // FIXME this can be improved + Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless"); + } else { + if (DBG) log("Radio is off and clean up all connection"); + // TODO: Should we reset mRequestedApnType to "default"? + cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF); + } + } - if (ar.exception == null) { - // everything is setup - - // arg1 contains CID for this PDP context - cidActive = msg.arg1; - /* - * We may have switched away from the default PDP context - * in order to enable a "special" APN (e.g., for MMS - * traffic). Set a timer to switch back and/or disable the - * special APN, so that a negligient application doesn't - * permanently prevent data connectivity. What we are - * protecting against here is not malicious apps, but - * rather an app that inadvertantly fails to reset to the - * default APN, or that dies before doing so. - */ - if (dataEnabled[APN_MMS_ID]) { - removeMessages(EVENT_RESTORE_DEFAULT_APN); - sendMessageDelayed( - obtainMessage(EVENT_RESTORE_DEFAULT_APN), - getRestoreDefaultApnDelay()); - } - if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { - SystemProperties.set("gsm.defaultpdpcontext.active", "true"); + protected void onDataSetupComplete(AsyncResult ar) { + String reason = null; + if (ar.userObj instanceof String) { + reason = (String) ar.userObj; + } + + if (ar.exception == null) { + // everything is setup + + /* + * We may have switched away from the default PDP context + * in order to enable a "special" APN (e.g., for MMS + * traffic). Set a timer to switch back and/or disable the + * special APN, so that a negligient application doesn't + * permanently prevent data connectivity. What we are + * protecting against here is not malicious apps, but + * rather an app that inadvertantly fails to reset to the + * default APN, or that dies before doing so. + */ + if (dataEnabled[APN_MMS_ID]) { + removeMessages(EVENT_RESTORE_DEFAULT_APN); + sendMessageDelayed(obtainMessage(EVENT_RESTORE_DEFAULT_APN), + getRestoreDefaultApnDelay()); + } + if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { + SystemProperties.set("gsm.defaultpdpcontext.active", "true"); if (canSetPreferApn && preferredApn == null) { Log.d(LOG_TAG, "PREFERED APN is null"); preferredApn = mActiveApn; setPreferredApn(preferredApn.id); } - } else { - SystemProperties.set("gsm.defaultpdpcontext.active", "false"); - } - notifyDefaultData(reason); + } else { + SystemProperties.set("gsm.defaultpdpcontext.active", "false"); + } + notifyDefaultData(reason); - // TODO: For simultaneous PDP support, we need to build another - // trigger another TRY_SETUP_DATA for the next APN type. (Note - // that the existing connection may service that type, in which - // case we should try the next type, etc. - } else { - PdpConnection.PdpFailCause cause; - cause = (PdpConnection.PdpFailCause) (ar.result); - if(DBG) - log("PDP setup failed " + cause); + // TODO: For simultaneous PDP support, we need to build another + // trigger another TRY_SETUP_DATA for the next APN type. (Note + // that the existing connection may service that type, in which + // case we should try the next type, etc. + } else { + PdpConnection.FailCause cause; + cause = (PdpConnection.FailCause) (ar.result); + if(DBG) log("PDP setup failed " + cause); // Log this failure to the Event Logs. - if (cause == PdpConnection.PdpFailCause.BAD_APN || - cause == PdpConnection.PdpFailCause.BAD_PAP_SECRET || - cause == PdpConnection.PdpFailCause.BARRED || - cause == PdpConnection.PdpFailCause.RADIO_ERROR_RETRY || - cause == PdpConnection.PdpFailCause.SUSPENED_TEMPORARY || - cause == PdpConnection.PdpFailCause.UNKNOWN || - cause == PdpConnection.PdpFailCause.USER_AUTHENTICATION) { - int cid = -1; - GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); - if (loc != null) cid = loc.getCid(); - - EventLog.List val = new EventLog.List( - cause.ordinal(), cid, - TelephonyManager.getDefault().getNetworkType()); - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_PDP_SETUP_FAIL, val); - } - // No try for permanent failure - if (cause.isPermanentFail()) { - notifyNoData(cause); - } + 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) { + int cid = -1; + GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); + if (loc != null) cid = loc.getCid(); + + EventLog.List val = new EventLog.List( + cause.ordinal(), cid, + TelephonyManager.getDefault().getNetworkType()); + EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_PDP_SETUP_FAIL, val); + } - 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); - // 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); - } - } else { - startDelayedRetry(cause, reason); - } - } - break; + // No try for permanent failure + if (cause.isPermanentFail()) { + notifyNoData(cause); + } - case EVENT_DISCONNECT_DONE: - if(DBG) log("EVENT_DISCONNECT_DONE"); - ar = (AsyncResult) msg.obj; - if (ar.userObj instanceof String) { - reason = (String) ar.userObj; - } - setState(State.IDLE); - phone.notifyDataConnection(reason); - mActiveApn = null; - if ( retryAfterDisconnected(reason) ) { + 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); } - break; - - case EVENT_PDP_STATE_CHANGED: - ar = (AsyncResult) msg.obj; - - onPdpStateChanged(ar, false); - break; - - case EVENT_GET_PDP_LIST_COMPLETE: - ar = (AsyncResult) msg.obj; - - onPdpStateChanged(ar, true); - break; - - case EVENT_POLL_PDP: - /* See comment in startPeriodicPdpPoll */ - ar = (AsyncResult) msg.obj; - - if (!(state == State.CONNECTED)) { - // not connected; don't poll anymore - break; - } - - phone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); + } else { + startDelayedRetry(cause, reason); + } + } + } - sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), - POLL_PDP_MILLIS); - break; + protected void onDisconnectDone(AsyncResult ar) { + String reason = null; + if(DBG) log("EVENT_DISCONNECT_DONE"); + if (ar.userObj instanceof String) { + reason = (String) ar.userObj; + } + setState(State.IDLE); + phone.notifyDataConnection(reason); + mActiveApn = null; + if (retryAfterDisconnected(reason)) { + trySetupData(reason); + } + } - case EVENT_VOICE_CALL_STARTED: - if (state == State.CONNECTED && - !phone.mSST.isConcurrentVoiceAndData()) { - stopNetStatPoll(); - phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); - } - break; + protected void onPollPdp() { + if (state == State.CONNECTED) { + // only poll when connected + phone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); + sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS); + } + } - case EVENT_VOICE_CALL_ENDED: - if (state == State.CONNECTED) { - if (!phone.mSST.isConcurrentVoiceAndData()) { - startNetStatPoll(); - phone.notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); - } else { - // clean slate after call end. - resetPollStats(); - } - } else { - // in case data setup was attempted when we were on a voice call - trySetupData(Phone.REASON_VOICE_CALL_ENDED); - } - break; + protected void onVoiceCallStarted() { + if (state == State.CONNECTED && !((GSMPhone) phone).mSST.isConcurrentVoiceAndData()) { + stopNetStatPoll(); + phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); + } + } - case EVENT_START_NETSTAT_POLL: - mPingTestActive = false; + protected void onVoiceCallEnded() { + if (state == State.CONNECTED) { + if (!((GSMPhone) phone).mSST.isConcurrentVoiceAndData()) { startNetStatPoll(); - break; - - case EVENT_START_RECOVERY: - mPingTestActive = false; - doRecovery(); - break; - - case EVENT_APN_CHANGED: - onApnChanged(); - break; - - case EVENT_PS_RESTRICT_ENABLED: - /** - * We don't need to explicitly to tear down the PDP context - * when PS restricted is enabled. The base band will deactive - * 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); - stopNetStatPoll(); - mIsPsRestricted = true; - break; - - case EVENT_PS_RESTRICT_DISABLED: - /** - * When PS restrict is removed, we need setup PDP connection if - * PDP connection is down. - */ - Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted); - mIsPsRestricted = false; - if (state == State.CONNECTED) { - startNetStatPoll(); - } else { - if (state == State.FAILED) { - cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED); - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - } - trySetupData(Phone.REASON_PS_RESTRICT_ENABLED); - } - break; - + phone.notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); + } else { + // clean slate after call end. + resetPollStats(); + } + } else { + // in case data setup was attempted when we were on a voice call + trySetupData(Phone.REASON_VOICE_CALL_ENDED); } } - private boolean tryNextApn(PdpFailCause cause) { - return (cause != PdpFailCause.RADIO_NOT_AVIALABLE) - && (cause != PdpFailCause.RADIO_OFF) - && (cause != PdpFailCause.RADIO_ERROR_RETRY) - && (cause != PdpFailCause.NO_SIGNAL) - && (cause != PdpFailCause.SIM_LOCKED); + 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); } private int getRestoreDefaultApnDelay() { @@ -1668,7 +1452,7 @@ final class DataConnectionTracker extends Handler */ private void createAllApnList() { allApns = new ArrayList<ApnSetting>(); - String operator = phone.mSIMRecords.getSIMOperatorNumeric(); + String operator = ((GSMPhone) phone).mSIMRecords.getSIMOperatorNumeric(); if (operator != null) { String selection = "numeric = '" + operator + "'"; @@ -1694,7 +1478,7 @@ final class DataConnectionTracker extends Handler if (allApns.isEmpty()) { if (DBG) log("No APN found for carrier: " + operator); preferredApn = null; - notifyNoData(PdpConnection.PdpFailCause.BAD_APN); + notifyNoData(PdpConnection.FailCause.BAD_APN); } else { preferredApn = getPreferredApn(); Log.d(LOG_TAG, "Get PreferredAPN"); @@ -1706,15 +1490,22 @@ final class DataConnectionTracker extends Handler } private void createAllPdpList() { - pdpList = new ArrayList<PdpConnection>(); - PdpConnection pdp; + pdpList = new ArrayList<DataConnection>(); + DataConnection pdp; for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) { - pdp = new PdpConnection(phone); + pdp = new PdpConnection((GSMPhone) phone); pdpList.add(pdp); } } + private void destroyAllPdpList() { + if(pdpList != null) { + PdpConnection pdp; + pdpList.removeAll(pdpList); + } + } + /** * * @return waitingApns list to be used to create PDP @@ -1722,7 +1513,7 @@ final class DataConnectionTracker extends Handler */ private ArrayList<ApnSetting> buildWaitingApns() { ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>(); - String operator = phone.mSIMRecords.getSIMOperatorNumeric(); + String operator = ((GSMPhone )phone).mSIMRecords.getSIMOperatorNumeric(); if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { if (canSetPreferApn && preferredApn != null) { @@ -1775,7 +1566,7 @@ final class DataConnectionTracker extends Handler return result.toString(); } - private void startDelayedRetry(PdpConnection.PdpFailCause cause, String reason) { + private void startDelayedRetry(PdpConnection.FailCause cause, String reason) { notifyNoData(cause); if (mRequestedApnType != Phone.APN_TYPE_DEFAULT) { sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN)); @@ -1833,4 +1624,95 @@ final class DataConnectionTracker extends Handler return null; } + + public void handleMessage (Message msg) { + + switch (msg.what) { + case EVENT_RECORDS_LOADED: + onRecordsLoaded(); + break; + + case EVENT_ENABLE_NEW_APN: + onEnableNewApn(); + break; + + case EVENT_RESTORE_DEFAULT_APN: + onRestoreDefaultApn(); + break; + + case EVENT_GPRS_DETACHED: + onGprsDetached(); + break; + + case EVENT_GPRS_ATTACHED: + onGprsAttached(); + break; + + case EVENT_DATA_STATE_CHANGED: + onPdpStateChanged((AsyncResult) msg.obj, false); + break; + + case EVENT_GET_PDP_LIST_COMPLETE: + onPdpStateChanged((AsyncResult) msg.obj, true); + break; + + case EVENT_POLL_PDP: + onPollPdp(); + break; + + case EVENT_START_NETSTAT_POLL: + mPingTestActive = false; + startNetStatPoll(); + break; + + case EVENT_START_RECOVERY: + mPingTestActive = false; + doRecovery(); + break; + + case EVENT_APN_CHANGED: + onApnChanged(); + break; + + case EVENT_PS_RESTRICT_ENABLED: + /** + * We don't need to explicitly to tear down the PDP context + * when PS restricted is enabled. The base band will deactive + * 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); + stopNetStatPoll(); + mIsPsRestricted = true; + break; + + case EVENT_PS_RESTRICT_DISABLED: + /** + * When PS restrict is removed, we need setup PDP connection if + * PDP connection is down. + */ + Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted); + mIsPsRestricted = false; + if (state == State.CONNECTED) { + startNetStatPoll(); + } else { + if (state == State.FAILED) { + cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED); + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + } + trySetupData(Phone.REASON_PS_RESTRICT_ENABLED); + } + break; + + default: + // handle the message in the super class DataConnectionTracker + super.handleMessage(msg); + break; + } + } + + protected void log(String s) { + Log.d(LOG_TAG, "[GsmDataConnectionTracker] " + s); + } + } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java index 04f8332..4db8fc6 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java @@ -18,39 +18,40 @@ package com.android.internal.telephony.gsm; import android.content.Context; import com.android.internal.telephony.*; + import android.os.*; -import android.os.AsyncResult; +import android.telephony.PhoneNumberUtils; +import android.text.SpannableStringBuilder; +import android.text.TextUtils; import android.util.Log; + +import static com.android.internal.telephony.CommandsInterface.*; + import java.util.regex.Pattern; import java.util.regex.Matcher; -import android.text.SpannableStringBuilder; -import android.text.TextUtils; -import android.telephony.PhoneNumberUtils; -import static com.android.internal.telephony.gsm.CommandsInterface.*; /** * The motto for this file is: * - * "NOTE: By using the # as a separator, most cases are expected to be unambiguous." + * "NOTE: By using the # as a separator, most cases are expected to be unambiguous." * -- TS 22.030 6.5.2 * * {@hide} * */ -public final class GsmMmiCode extends Handler implements MmiCode -{ +public final class GsmMmiCode extends Handler implements MmiCode { static final String LOG_TAG = "GSM"; //***** Constants - + // From TS 22.030 6.5.2 static final String ACTION_ACTIVATE = "*"; static final String ACTION_DEACTIVATE = "#"; static final String ACTION_INTERROGATE = "*#"; static final String ACTION_REGISTER = "**"; static final String ACTION_ERASURE = "##"; - - // Supp Service cocdes from TS 22.030 Annex B + + // Supp Service cocdes from TS 22.030 Annex B //Called line presentation static final String SC_CLIP = "30"; @@ -102,25 +103,24 @@ public final class GsmMmiCode extends Handler implements MmiCode GSMPhone phone; Context context; - + String action; // One of ACTION_* String sc; // Service Code String sia, sib, sic; // Service Info a,b,c String poundString; // Entire MMI string up to and including # String dialingNumber; String pwd; // For password registration - - /** Set to true in processCode, not at newFromDialString time */ + /** Set to true in processCode, not at newFromDialString time */ private boolean isPendingUSSD; private boolean isUssdRequest; - State state = State.PENDING; + State state = State.PENDING; CharSequence message; - + //***** Class Variables - + // See TS 22.030 6.5.2 "Structure of the MMI" @@ -137,9 +137,9 @@ public final class GsmMmiCode extends Handler implements MmiCode 10 = dialing number */ - static final int MATCH_GROUP_POUND_STRING = 1; + static final int MATCH_GROUP_POUND_STRING = 1; - static final int MATCH_GROUP_ACTION = 2; + static final int MATCH_GROUP_ACTION = 2; //(activation/interrogation/registration/erasure) static final int MATCH_GROUP_SERVICE_CODE = 3; @@ -151,7 +151,7 @@ public final class GsmMmiCode extends Handler implements MmiCode //***** Public Class methods - + /** * Some dial strings in GSM are defined to do non-call setup * things, such as modify or query supplementry service settings (eg, call @@ -165,9 +165,8 @@ public final class GsmMmiCode extends Handler implements MmiCode * Please see flow chart in TS 22.030 6.5.3.2 */ - static GsmMmiCode - newFromDialString(String dialString, GSMPhone phone) - { + static GsmMmiCode + newFromDialString(String dialString, GSMPhone phone) { Matcher m; GsmMmiCode ret = null; @@ -187,7 +186,7 @@ public final class GsmMmiCode extends Handler implements MmiCode } else if (dialString.endsWith("#")) { // TS 22.030 sec 6.5.3.2 - // "Entry of any characters defined in the 3GPP TS 23.038 [8] Default Alphabet + // "Entry of any characters defined in the 3GPP TS 23.038 [8] Default Alphabet // (up to the maximum defined in 3GPP TS 24.080 [10]), followed by #SEND". ret = new GsmMmiCode(phone); @@ -202,16 +201,15 @@ public final class GsmMmiCode extends Handler implements MmiCode } static GsmMmiCode - newNetworkInitiatedUssd (String ussdMessage, - boolean isUssdRequest, GSMPhone phone) - { + newNetworkInitiatedUssd (String ussdMessage, + boolean isUssdRequest, GSMPhone phone) { GsmMmiCode ret; ret = new GsmMmiCode(phone); ret.message = ussdMessage; ret.isUssdRequest = isUssdRequest; - + // If it's a request, set to PENDING so that it's cancelable. if (isUssdRequest) { ret.isPendingUSSD = true; @@ -225,42 +223,39 @@ public final class GsmMmiCode extends Handler implements MmiCode static GsmMmiCode newFromUssdUserInput(String ussdMessge, GSMPhone phone) { GsmMmiCode ret = new GsmMmiCode(phone); - + ret.message = ussdMessge; ret.state = State.PENDING; ret.isPendingUSSD = true; - + return ret; } //***** Private Class methods - /** make empty strings be null. - * Regexp returns empty strings for empty groups + /** make empty strings be null. + * Regexp returns empty strings for empty groups */ private static String - makeEmptyNull (String s) - { + makeEmptyNull (String s) { if (s != null && s.length() == 0) return null; return s; } /** returns true of the string is empty or null */ - private static boolean - isEmptyOrNull(CharSequence s) - { + private static boolean + isEmptyOrNull(CharSequence s) { return s == null || (s.length() == 0); } private static int - scToCallForwardReason(String sc) - { - if (sc == null) { + scToCallForwardReason(String sc) { + if (sc == null) { throw new RuntimeException ("invalid call forward sc"); } - + if (sc.equals(SC_CF_All)) { return CommandsInterface.CF_REASON_ALL; } else if (sc.equals(SC_CFU)) { @@ -279,8 +274,7 @@ public final class GsmMmiCode extends Handler implements MmiCode } private static int - siToServiceClass(String si) - { + siToServiceClass(String si) { if (si == null || si.length() == 0) { return SERVICE_CLASS_NONE; } else { @@ -299,7 +293,7 @@ public final class GsmMmiCode extends Handler implements MmiCode /* Note for code 20: From TS 22.030 Annex C: - "All GPRS bearer services" are not included in "All tele and bearer services" + "All GPRS bearer services" are not included in "All tele and bearer services" and "All bearer services"." ....so SERVICE_CLASS_DATA, which (according to 27.007) includes GPRS */ @@ -319,8 +313,7 @@ public final class GsmMmiCode extends Handler implements MmiCode } private static int - siToTime (String si) - { + siToTime (String si) { if (si == null || si.length() == 0) { return 0; } else { @@ -330,33 +323,30 @@ public final class GsmMmiCode extends Handler implements MmiCode } static boolean - isServiceCodeCallForwarding(String sc) - { - return sc != null && - (sc.equals(SC_CFU) - || sc.equals(SC_CFB) || sc.equals(SC_CFNRy) - || sc.equals(SC_CFNR) || sc.equals(SC_CF_All) + isServiceCodeCallForwarding(String sc) { + return sc != null && + (sc.equals(SC_CFU) + || sc.equals(SC_CFB) || sc.equals(SC_CFNRy) + || sc.equals(SC_CFNR) || sc.equals(SC_CF_All) || sc.equals(SC_CF_All_Conditional)); } static boolean - isServiceCodeCallBarring(String sc) - { + isServiceCodeCallBarring(String sc) { return sc != null && - (sc.equals(SC_BAOC) + (sc.equals(SC_BAOC) || sc.equals(SC_BAOIC) || sc.equals(SC_BAOICxH) || sc.equals(SC_BAIC) || sc.equals(SC_BAICr) || sc.equals(SC_BA_ALL) || sc.equals(SC_BA_MO) - || sc.equals(SC_BA_MT)); + || sc.equals(SC_BA_MT)); } static String - scToBarringFacility(String sc) - { - if (sc == null) { + scToBarringFacility(String sc) { + if (sc == null) { throw new RuntimeException ("invalid call barring sc"); } @@ -383,11 +373,10 @@ public final class GsmMmiCode extends Handler implements MmiCode //***** Constructor - GsmMmiCode (GSMPhone phone) - { + GsmMmiCode (GSMPhone phone) { // The telephony unit-test cases may create GsmMmiCode's // in secondary threads - super(phone.h.getLooper()); + super(phone.getHandler().getLooper()); this.phone = phone; this.context = phone.getContext(); } @@ -395,21 +384,18 @@ public final class GsmMmiCode extends Handler implements MmiCode //***** MmiCode implementation public State - getState() - { + getState() { return state; } public CharSequence - getMessage() - { + getMessage() { return message; } // inherited javadoc suffices public void - cancel() - { + cancel() { // Complete or failed cannot be cancelled if (state == State.COMPLETE || state == State.FAILED) { return; @@ -423,7 +409,7 @@ public final class GsmMmiCode extends Handler implements MmiCode * cancel it. */ phone.mCM.cancelPendingUssd(obtainMessage(EVENT_USSD_CANCEL_COMPLETE, this)); - + /* * Don't call phone.onMMIDone here; wait for CANCEL_COMPLETE notice * from RIL. @@ -436,7 +422,6 @@ public final class GsmMmiCode extends Handler implements MmiCode phone.onMMIDone (this); } - } public boolean isCancelable() { @@ -445,20 +430,17 @@ public final class GsmMmiCode extends Handler implements MmiCode } //***** Instance Methods - /** Does this dial string contain a structured or unstructured MMI code? */ boolean - isMMI() - { + isMMI() { return poundString != null; } /* Is this a 1 or 2 digit "short code" as defined in TS 22.030 sec 6.5.3.2? */ boolean - isShortCode() - { - return poundString == null + isShortCode() { + return poundString == null && dialingNumber != null && dialingNumber.length() <= 2; } @@ -479,7 +461,7 @@ public final class GsmMmiCode extends Handler implements MmiCode * for treating "0" and "00" as call setup strings. */ || dialString.equals("0") - || dialString.equals("00")))); + || dialString.equals("00")))); } /** * @return true if the Service Code is PIN/PIN2/PUK/PUK2-related @@ -489,17 +471,16 @@ public final class GsmMmiCode extends Handler implements MmiCode || sc.equals(SC_PUK) || sc.equals(SC_PUK2)); } - /** + /** * *See TS 22.030 Annex B - * In temporary mode, to suppress CLIR for a single call, enter: + * In temporary mode, to suppress CLIR for a single call, enter: * " * 31 # <called number> SEND " - * In temporary mode, to invoke CLIR for a single call enter: + * In temporary mode, to invoke CLIR for a single call enter: * " # 31 # <called number> SEND " */ - - boolean - isTemporaryModeCLIR() - { + + boolean + isTemporaryModeCLIR() { return sc != null && sc.equals(SC_CLIR) && dialingNumber != null && (isActivate() || isDeactivate()); } @@ -509,50 +490,43 @@ public final class GsmMmiCode extends Handler implements MmiCode * See also isTemporaryModeCLIR() */ int - getCLIRMode() - { + getCLIRMode() { if (sc != null && sc.equals(SC_CLIR)) { if (isActivate()) { return CommandsInterface.CLIR_SUPPRESSION; } else if (isDeactivate()) { - return CommandsInterface.CLIR_INVOCATION; + return CommandsInterface.CLIR_INVOCATION; } } - + return CommandsInterface.CLIR_DEFAULT; } - - boolean isActivate() - { + + boolean isActivate() { return action != null && action.equals(ACTION_ACTIVATE); } - boolean isDeactivate() - { + boolean isDeactivate() { return action != null && action.equals(ACTION_DEACTIVATE); } - - boolean isInterrogate() - { + + boolean isInterrogate() { return action != null && action.equals(ACTION_INTERROGATE); } - boolean isRegister() - { + boolean isRegister() { return action != null && action.equals(ACTION_REGISTER); } - boolean isErasure() - { + boolean isErasure() { return action != null && action.equals(ACTION_ERASURE); } - /** + /** * Returns true if this is a USSD code that's been submitted to the * network...eg, after processCode() is called */ - public boolean isPendingUSSD() - { + public boolean isPendingUSSD() { return isPendingUSSD; } @@ -562,8 +536,7 @@ public final class GsmMmiCode extends Handler implements MmiCode /** Process a MMI code or short code...anything that isn't a dialing number */ void - processCode () - { + processCode () { try { if (isShortCode()) { Log.d(LOG_TAG, "isShortCode"); @@ -573,7 +546,7 @@ public final class GsmMmiCode extends Handler implements MmiCode // We should have no dialing numbers here throw new RuntimeException ("Invalid or Unsupported MMI Code"); } else if (sc != null && sc.equals(SC_CLIP)) { - Log.d(LOG_TAG, "is CLIP"); + Log.d(LOG_TAG, "is CLIP"); if (isInterrogate()) { phone.mCM.queryCLIP( obtainMessage(EVENT_QUERY_COMPLETE, this)); @@ -581,7 +554,7 @@ public final class GsmMmiCode extends Handler implements MmiCode throw new RuntimeException ("Invalid or Unsupported MMI Code"); } } else if (sc != null && sc.equals(SC_CLIR)) { - Log.d(LOG_TAG, "is CLIR"); + Log.d(LOG_TAG, "is CLIR"); if (isActivate()) { phone.mCM.setCLIR(CommandsInterface.CLIR_INVOCATION, obtainMessage(EVENT_SET_COMPLETE, this)); @@ -688,13 +661,13 @@ public final class GsmMmiCode extends Handler implements MmiCode // sia = basic service group int serviceClass = siToServiceClass(sia); - if (isActivate() || isDeactivate()) { + if (isActivate() || isDeactivate()) { phone.mCM.setCallWaiting(isActivate(), serviceClass, obtainMessage(EVENT_SET_COMPLETE, this)); - } else if (isInterrogate()) { + } else if (isInterrogate()) { phone.mCM.queryCallWaiting(serviceClass, obtainMessage(EVENT_QUERY_COMPLETE, this)); - } else { + } else { throw new RuntimeException ("Invalid or Unsupported MMI Code"); } } else if (isPinCommand()) { @@ -718,16 +691,16 @@ public final class GsmMmiCode extends Handler implements MmiCode } else { // pre-checks OK if (sc.equals(SC_PIN)) { - phone.mCM.changeSimPin(oldPinOrPuk, newPin, + phone.mCM.changeIccPin(oldPinOrPuk, newPin, obtainMessage(EVENT_SET_COMPLETE, this)); } else if (sc.equals(SC_PIN2)) { - phone.mCM.changeSimPin2(oldPinOrPuk, newPin, + phone.mCM.changeIccPin2(oldPinOrPuk, newPin, obtainMessage(EVENT_SET_COMPLETE, this)); } else if (sc.equals(SC_PUK)) { - phone.mCM.supplySimPuk(oldPinOrPuk, newPin, + phone.mCM.supplyIccPuk(oldPinOrPuk, newPin, obtainMessage(EVENT_SET_COMPLETE, this)); } else if (sc.equals(SC_PUK2)) { - phone.mCM.supplySimPuk2(oldPinOrPuk, newPin, + phone.mCM.supplyIccPuk2(oldPinOrPuk, newPin, obtainMessage(EVENT_SET_COMPLETE, this)); } } @@ -743,7 +716,7 @@ public final class GsmMmiCode extends Handler implements MmiCode state = State.FAILED; message = context.getText(com.android.internal.R.string.mmiError); phone.onMMIDone(this); - } + } } private void handlePasswordError(int res) { @@ -755,8 +728,8 @@ public final class GsmMmiCode extends Handler implements MmiCode phone.onMMIDone(this); } - /** - * Called from GSMPhone + /** + * Called from GSMPhone * * An unsolicited USSD NOTIFY or REQUEST has come in matching * up with this pending USSD request @@ -765,8 +738,7 @@ public final class GsmMmiCode extends Handler implements MmiCode * active (ie, the network expects user input). */ void - onUssdFinished(String ussdMessage, boolean isUssdRequest) - { + onUssdFinished(String ussdMessage, boolean isUssdRequest) { if (state == State.PENDING) { if (ussdMessage == null) { message = context.getText(com.android.internal.R.string.mmiComplete); @@ -783,15 +755,14 @@ public final class GsmMmiCode extends Handler implements MmiCode } } - /** - * Called from GSMPhone + /** + * Called from GSMPhone * * The radio has reset, and this is still pending */ void - onUssdFinishedError() - { + onUssdFinishedError() { if (state == State.PENDING) { state = State.FAILED; message = context.getText(com.android.internal.R.string.mmiError); @@ -808,15 +779,14 @@ public final class GsmMmiCode extends Handler implements MmiCode // response does not complete this MMI code...we wait for // an unsolicited USSD "Notify" or "Request". // The matching up of this is doene in GSMPhone. - - phone.mCM.sendUSSD(ussdMessage, + + phone.mCM.sendUSSD(ussdMessage, obtainMessage(EVENT_USSD_COMPLETE, this)); } /** Called from GSMPhone.handleMessage; not a Handler subclass */ public void - handleMessage (Message msg) - { + handleMessage (Message msg) { AsyncResult ar; switch (msg.what) { @@ -865,13 +835,13 @@ public final class GsmMmiCode extends Handler implements MmiCode com.android.internal.R.string.mmiError); phone.onMMIDone(this); - } + } // Note that unlike most everything else, the USSD complete // response does not complete this MMI code...we wait for // an unsolicited USSD "Notify" or "Request". // The matching up of this is done in GSMPhone. - + break; case EVENT_USSD_CANCEL_COMPLETE: @@ -976,8 +946,7 @@ public final class GsmMmiCode extends Handler implements MmiCode } private void - onGetClirComplete(AsyncResult ar) - { + onGetClirComplete(AsyncResult ar) { StringBuilder sb = new StringBuilder(getScString()); sb.append("\n"); @@ -996,35 +965,35 @@ public final class GsmMmiCode extends Handler implements MmiCode com.android.internal.R.string.serviceNotProvisioned)); state = State.COMPLETE; break; - + case 1: // CLIR provisioned in permanent mode sb.append(context.getText( com.android.internal.R.string.CLIRPermanent)); state = State.COMPLETE; break; - case 2: // unknown (e.g. no network, etc.) + case 2: // unknown (e.g. no network, etc.) sb.append(context.getText( com.android.internal.R.string.mmiError)); state = State.FAILED; break; - case 3: // CLIR temporary mode presentation restricted + case 3: // CLIR temporary mode presentation restricted // the 'n' parameter from TS 27.007 7.7 switch (clirArgs[0]) { default: case 0: // Default sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOnNextCallOn)); + com.android.internal.R.string.CLIRDefaultOnNextCallOn)); break; case 1: // CLIR invocation sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOnNextCallOn)); + com.android.internal.R.string.CLIRDefaultOnNextCallOn)); break; case 2: // CLIR suppression sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOnNextCallOff)); + com.android.internal.R.string.CLIRDefaultOnNextCallOff)); break; } state = State.COMPLETE; @@ -1036,21 +1005,21 @@ public final class GsmMmiCode extends Handler implements MmiCode default: case 0: // Default sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOffNextCallOff)); + com.android.internal.R.string.CLIRDefaultOffNextCallOff)); break; case 1: // CLIR invocation sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOffNextCallOn)); + com.android.internal.R.string.CLIRDefaultOffNextCallOn)); break; case 2: // CLIR suppression sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOffNextCallOff)); + com.android.internal.R.string.CLIRDefaultOffNextCallOff)); break; } state = State.COMPLETE; break; - } + } } message = sb; @@ -1059,23 +1028,29 @@ public final class GsmMmiCode extends Handler implements MmiCode /** * @param serviceClass 1 bit of the service class bit vectory - * @return String to be used for call forward query MMI response text. + * @return String to be used for call forward query MMI response text. * Returns null if unrecognized */ private CharSequence - serviceClassToCFString (int serviceClass) - { + serviceClassToCFString (int serviceClass) { switch (serviceClass) { - case SERVICE_CLASS_VOICE: return context.getText(com.android.internal.R.string.serviceClassVoice); - case SERVICE_CLASS_DATA: return context.getText(com.android.internal.R.string.serviceClassData); - case SERVICE_CLASS_FAX: return context.getText(com.android.internal.R.string.serviceClassFAX); - case SERVICE_CLASS_SMS: return context.getText(com.android.internal.R.string.serviceClassSMS); - case SERVICE_CLASS_DATA_SYNC: return context.getText(com.android.internal.R.string.serviceClassDataSync); - case SERVICE_CLASS_DATA_ASYNC: return context.getText(com.android.internal.R.string.serviceClassDataAsync); - case SERVICE_CLASS_PACKET: return context.getText(com.android.internal.R.string.serviceClassPacket); - case SERVICE_CLASS_PAD: return context.getText(com.android.internal.R.string.serviceClassPAD); - + case SERVICE_CLASS_VOICE: + return context.getText(com.android.internal.R.string.serviceClassVoice); + case SERVICE_CLASS_DATA: + return context.getText(com.android.internal.R.string.serviceClassData); + case SERVICE_CLASS_FAX: + return context.getText(com.android.internal.R.string.serviceClassFAX); + case SERVICE_CLASS_SMS: + return context.getText(com.android.internal.R.string.serviceClassSMS); + case SERVICE_CLASS_DATA_SYNC: + return context.getText(com.android.internal.R.string.serviceClassDataSync); + case SERVICE_CLASS_DATA_ASYNC: + return context.getText(com.android.internal.R.string.serviceClassDataAsync); + case SERVICE_CLASS_PACKET: + return context.getText(com.android.internal.R.string.serviceClassPacket); + case SERVICE_CLASS_PAD: + return context.getText(com.android.internal.R.string.serviceClassPAD); default: return null; } @@ -1084,8 +1059,7 @@ public final class GsmMmiCode extends Handler implements MmiCode /** one CallForwardInfo + serviceClassMask -> one line of text */ private CharSequence - makeCFQueryResultMessage(CallForwardInfo info, int serviceClassMask) - { + makeCFQueryResultMessage(CallForwardInfo info, int serviceClassMask) { CharSequence template; String sources[] = {"{0}", "{1}", "{2}"}; CharSequence destinations[] = new CharSequence[3]; @@ -1094,7 +1068,7 @@ public final class GsmMmiCode extends Handler implements MmiCode // CF_REASON_NO_REPLY also has a time value associated with // it. All others don't. - needTimeTemplate = + needTimeTemplate = (info.reason == CommandsInterface.CF_REASON_NO_REPLY); if (info.status == 1) { @@ -1122,8 +1096,8 @@ public final class GsmMmiCode extends Handler implements MmiCode } // In the template (from strings.xmls) - // {0} is one of "bearerServiceCode*" - // {1} is dialing number + // {0} is one of "bearerServiceCode*" + // {1} is dialing number // {2} is time in seconds destinations[0] = serviceClassToCFString(info.serviceClass & serviceClassMask); @@ -1142,8 +1116,7 @@ public final class GsmMmiCode extends Handler implements MmiCode private void - onQueryCfComplete(AsyncResult ar) - { + onQueryCfComplete(AsyncResult ar) { StringBuilder sb = new StringBuilder(getScString()); sb.append("\n"); @@ -1152,7 +1125,7 @@ public final class GsmMmiCode extends Handler implements MmiCode sb.append(context.getText(com.android.internal.R.string.mmiError)); } else { CallForwardInfo infos[]; - + infos = (CallForwardInfo[]) ar.result; if (infos.length == 0) { @@ -1166,18 +1139,18 @@ public final class GsmMmiCode extends Handler implements MmiCode SpannableStringBuilder tb = new SpannableStringBuilder(); // Each bit in the service class gets its own result line - // The service classes may be split up over multiple + // The service classes may be split up over multiple // CallForwardInfos. So, for each service classs, find out // which CallForwardInfo represents it and then build // the response text based on that - for (int serviceClassMask = 1 + for (int serviceClassMask = 1 ; serviceClassMask <= SERVICE_CLASS_MAX - ; serviceClassMask <<= 1 + ; serviceClassMask <<= 1 ) { for (int i = 0, s = infos.length; i < s ; i++) { if ((serviceClassMask & infos[i].serviceClass) != 0) { - tb.append(makeCFQueryResultMessage(infos[i], + tb.append(makeCFQueryResultMessage(infos[i], serviceClassMask)); tb.append("\n"); } @@ -1191,12 +1164,11 @@ public final class GsmMmiCode extends Handler implements MmiCode message = sb; phone.onMMIDone(this); - + } private void - onQueryComplete(AsyncResult ar) - { + onQueryComplete(AsyncResult ar) { StringBuilder sb = new StringBuilder(getScString()); sb.append("\n"); @@ -1230,15 +1202,15 @@ public final class GsmMmiCode extends Handler implements MmiCode message = sb; phone.onMMIDone(this); } - + private CharSequence - createQueryCallWaitingResultMessage(int serviceClass) - { - StringBuilder sb = new StringBuilder(context.getText(com.android.internal.R.string.serviceEnabledFor)); + createQueryCallWaitingResultMessage(int serviceClass) { + 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"); @@ -1267,8 +1239,8 @@ public final class GsmMmiCode extends Handler implements MmiCode /*** * 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 - * some of the string parsing functionality in the Phone App's - * SpecialCharSequenceMgr class. + * some of the string parsing functionality in the Phone App's + * SpecialCharSequenceMgr class. */ } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java new file mode 100644 index 0000000..3e73caf --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java @@ -0,0 +1,379 @@ +/* + * 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.app.Activity; +import android.app.PendingIntent; +import android.app.PendingIntent.CanceledException; +import android.content.Intent; +import android.os.AsyncResult; +import android.os.Message; +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.SMSDispatcher; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.SmsMessageBase; + +import java.util.ArrayList; +import java.util.HashMap; + + +final class GsmSMSDispatcher extends SMSDispatcher { + private static final String TAG = "GSM"; + + GsmSMSDispatcher(GSMPhone phone) { + super(phone); + } + + /** + * Called when a status report is received. This should correspond to + * a previously successful SEND. + * + * @param ar AsyncResult passed into the message handler. ar.result should + * be a String representing the status report PDU, as ASCII hex. + */ + protected void handleStatusReport(AsyncResult ar) { + String pduString = (String) ar.result; + SmsMessage sms = SmsMessage.newFromCDS(pduString); + + if (sms != null) { + int messageRef = sms.messageRef; + for (int i = 0, count = deliveryPendingList.size(); i < count; i++) { + SmsTracker tracker = deliveryPendingList.get(i); + if (tracker.mMessageRef == messageRef) { + // Found it. Remove from list and broadcast. + deliveryPendingList.remove(i); + PendingIntent intent = tracker.mDeliveryIntent; + Intent fillIn = new Intent(); + fillIn.putExtra("pdu", IccUtils.hexStringToBytes(pduString)); + try { + intent.send(mContext, Activity.RESULT_OK, fillIn); + } catch (CanceledException ex) {} + + // Only expect to see one tracker matching this messageref + break; + } + } + } + + if (mCm != null) { + mCm.acknowledgeLastIncomingSMS(true, null); + } + } + + + /** + * Dispatches an incoming SMS messages. + * + * @param sms the incoming message from the phone + */ + protected void dispatchMessage(SmsMessageBase smsb) { + + // If sms is null, means there was a parsing error. + // TODO: Should NAK this. + if (smsb == null) { + return; + } + 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; + } + + if (Config.LOGD) { + Log.d(TAG, + "Received voice mail indicator set SMS shouldStore=" + + !handled); + } + } else if (sms.isMWIClearMessage()) { + ((GSMPhone) mPhone).updateMessageWaitingIndicator(false); + + if (sms.isMwiDontStore()) { + handled = true; + } + + if (Config.LOGD) { + Log.d(TAG, + "Received voice mail indicator clear SMS shouldStore=" + + !handled); + } + } + + if (handled) { + return; + } + + // 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 + byte[][] pdus = new byte[1][]; + pdus[0] = sms.getPdu(); + + if (destPort != -1) { + if (destPort == SmsHeader.PORT_WAP_PUSH) { + mWapPush.dispatchWapPdu(sms.getUserData()); + } + // The message was sent to a port, so concoct a URI for it + dispatchPortAddressedPdus(pdus, destPort); + } else { + // It's a normal message, dispatch it + dispatchPdus(pdus); + } + } else { + // Process the message part + processMessagePart(sms, referenceNumber, sequence, count, destPort); + } + } + + /** {@inheritDoc} */ + 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; + + if (sentIntents != null && sentIntents.size() > i) { + sentIntent = sentIntents.get(i); + } + if (deliveryIntents != null && deliveryIntents.size() > i) { + deliveryIntent = deliveryIntents.get(i); + } + + SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, + parts.get(i), deliveryIntent != null, header.toByteArray()); + + sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); + } + } + + /** + * 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 + * @param parts an <code>ArrayList</code> of strings that, in order, + * comprise the original message + * @param sentIntents if not null, an <code>ArrayList</code> of + * <code>PendingIntent</code>s (one for each message part) that is + * broadcast when the corresponding message part has been sent. + * The result code will be <code>Activity.RESULT_OK<code> for success, + * or one of these errors: + * <code>RESULT_ERROR_GENERIC_FAILURE</code> + * <code>RESULT_ERROR_RADIO_OFF</code> + * <code>RESULT_ERROR_NULL_PDU</code>. + * @param deliveryIntents if not null, an <code>ArrayList</code> of + * <code>PendingIntent</code>s (one for each message part) that is + * broadcast when the corresponding message part has been delivered + * to the recipient. The raw pdu of the status report is in the + * extended data ("pdu"). + */ + private void sendMultipartTextWithPermit(String destinationAddress, + String scAddress, ArrayList<String> parts, + 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++) { + if (sentIntents != null && sentIntents.size() > i) { + sentIntent = sentIntents.get(i); + } + SmsTracker tracker = SmsTrackerFactory(null, sentIntent, null); + handleNotInService(ss, tracker); + } + 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)); + + if (sentIntents != null && sentIntents.size() > i) { + sentIntent = sentIntents.get(i); + } + if (deliveryIntents != null && deliveryIntents.size() > i) { + deliveryIntent = deliveryIntents.get(i); + } + + SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, + parts.get(i), deliveryIntent != null, header.toByteArray()); + + HashMap<String, Object> map = new HashMap<String, Object>(); + map.put("smsc", pdus.encodedScAddress); + map.put("pdu", pdus.encodedMessage); + + SmsTracker tracker = SmsTrackerFactory(map, sentIntent, deliveryIntent); + sendSms(tracker); + } + } + + /** {@inheritDoc} */ + protected void sendSms(SmsTracker tracker) { + HashMap map = tracker.mData; + + byte smsc[] = (byte[]) map.get("smsc"); + byte pdu[] = (byte[]) map.get("pdu"); + + Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); + mCm.sendSMS(IccUtils.bytesToHexString(smsc), + IccUtils.bytesToHexString(pdu), reply); + } + + /** + * 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, + scAddress, parts, sentIntents, deliveryIntents); + + } + + /** {@inheritDoc} */ + protected void acknowledgeLastIncomingSms(boolean success, Message response){ + // FIXME unit test leaves cm == null. this should change + if (mCm != null) { + mCm.acknowledgeLastIncomingSMS(success, response); + } + } + + /** {@inheritDoc} */ + protected void activateCellBroadcastSms(int activate, Message response) { + // Unless CBS is implemented for GSM, this point should be unreachable. + Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM."); + response.recycle(); + } + + /** {@inheritDoc} */ + protected void getCellBroadcastSmsConfig(Message response){ + // Unless CBS is implemented for GSM, this point should be unreachable. + Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM."); + response.recycle(); + } + + /** {@inheritDoc} */ + protected void setCellBroadcastConfig(int[] configValuesArray, Message response) { + // Unless CBS is implemented for GSM, this point should be unreachable. + Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM."); + response.recycle(); + } + +} + diff --git a/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java index e336d7d..3c0b603 100644 --- a/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java @@ -16,19 +16,7 @@ package com.android.internal.telephony.gsm; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE; -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 static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_OPERATOR_ALPHA; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_OPERATOR_NUMERIC; - -import com.android.internal.telephony.SimCard; -import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.gsm.DataConnectionTracker.State; - import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; @@ -49,13 +37,32 @@ import android.provider.Checkin; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.provider.Telephony.Intents; -import android.telephony.gsm.GsmCellLocation; import android.telephony.ServiceState; +import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; import android.util.Config; +import android.util.EventLog; import android.util.Log; import android.util.TimeUtils; -import android.util.EventLog; + +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; @@ -65,30 +72,9 @@ import java.util.TimeZone; /** * {@hide} */ -final class ServiceStateTracker extends Handler -{ - /** - * The access technology currently in use: - * 0 = unknown - * 1 = GPRS only - * 2 = EDGE - * 3 = UMTS - */ - static final int DATA_ACCESS_UNKNOWN = 0; - static final int DATA_ACCESS_GPRS = 1; - static final int DATA_ACCESS_EDGE = 2; - static final int DATA_ACCESS_UMTS = 3; - - static final int MAX_NUM_DATA_STATE_READS = 15; - static final int DATA_STATE_POLL_SLEEP_MS = 100; - +final class GsmServiceStateTracker extends ServiceStateTracker { //***** Instance Variables - GSMPhone phone; - CommandsInterface cm; - - ServiceState ss; - ServiceState newSS; GsmCellLocation cellLoc; GsmCellLocation newCellLoc; int mPreferredNetworkType; @@ -97,18 +83,6 @@ final class ServiceStateTracker extends Handler int rssi = 99; // signal strength 0-31, 99=unknown // That's "received signal strength indication" fyi - int[] pollingContext; // 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 - - boolean mDesiredPowerState; - - boolean dontPollSignalStrength = false; // Default is to poll strength - // If we're getting unsolicited signal strength updates from the radio, - // set value to true and don't bother polling any more - private int gprsState = ServiceState.STATE_OUT_OF_SERVICE; private int newGPRSState = ServiceState.STATE_OUT_OF_SERVICE; @@ -120,14 +94,10 @@ final class ServiceStateTracker extends Handler /* gsm roaming status solely based on TS 27.007 7.2 CREG */ private boolean mGsmRoaming = false; - private RegistrantList networkAttachedRegistrants = new RegistrantList(); private RegistrantList gprsAttachedRegistrants = new RegistrantList(); private RegistrantList gprsDetachedRegistrants = new RegistrantList(); - private RegistrantList roamingOnRegistrants = new RegistrantList(); - private RegistrantList roamingOffRegistrants = new RegistrantList(); private RegistrantList psRestrictEnabledRegistrants = new RegistrantList(); private RegistrantList psRestrictDisabledRegistrants = 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 @@ -137,6 +107,7 @@ final class ServiceStateTracker extends Handler private boolean mZoneDst; private long mZoneTime; private boolean mGotCountryCode = false; + private ContentResolver cr; String mSavedTimeZone; long mSavedTime; @@ -170,13 +141,10 @@ final class ServiceStateTracker extends Handler static final boolean DBG = true; static final String LOG_TAG = "GSM"; - // signal strength poll rate - static final int POLL_PERIOD_MILLIS = 20 * 1000; - // waiting period before recheck gprs and voice registration static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000; - // restricted state type + // notification type static final int PS_ENABLED = 1001; // Access Control blocks data service static final int PS_DISABLED = 1002; // Access Control enables data service static final int CS_ENABLED = 1003; // Access Control blocks all voice/sms service @@ -187,72 +155,21 @@ final class ServiceStateTracker extends Handler // notification id 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 - - //***** Events - static final int EVENT_RADIO_STATE_CHANGED = 1; - static final int EVENT_NETWORK_STATE_CHANGED = 2; - static final int EVENT_GET_SIGNAL_STRENGTH = 3; - static final int EVENT_POLL_STATE_REGISTRATION = 4; - static final int EVENT_POLL_STATE_GPRS = 5; - static final int EVENT_POLL_STATE_OPERATOR = 6; - static final int EVENT_POLL_SIGNAL_STRENGTH = 10; - static final int EVENT_NITZ_TIME = 11; - static final int EVENT_SIGNAL_STRENGTH_UPDATE = 12; - static final int EVENT_RADIO_AVAILABLE = 13; - static final int EVENT_POLL_STATE_NETWORK_SELECTION_MODE = 14; - static final int EVENT_GET_LOC_DONE = 15; - static final int EVENT_SIM_RECORDS_LOADED = 16; - static final int EVENT_SIM_READY = 17; - static final int EVENT_LOCATION_UPDATES_ENABLED = 18; - static final int EVENT_GET_PREFERRED_NETWORK_TYPE = 19; - static final int EVENT_SET_PREFERRED_NETWORK_TYPE = 20; - static final int EVENT_RESET_PREFERRED_NETWORK_TYPE = 21; - static final int EVENT_CHECK_REPORT_GPRS = 22; - static final int EVENT_RESTRICTED_STATE_CHANGED = 23; - - //***** Time Zones - - private static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; - - // List of ISO codes for countries that can have an offset of GMT+0 - // when not in daylight savings time. This ignores some small places - // such as the Canary Islands (Spain) and Danmarkshavn (Denmark). - // The list must be sorted by code. - private static final String[] GMT_COUNTRY_CODES = { - "bf", // Burkina Faso - "ci", // Cote d'Ivoire - "eh", // Western Sahara - "fo", // Faroe Islands, Denmark - "gh", // Ghana - "gm", // Gambia - "gn", // Guinea - "gw", // Guinea Bissau - "ie", // Ireland - "lr", // Liberia - "is", // Iceland - "ma", // Morocco - "ml", // Mali - "mr", // Mauritania - "pt", // Portugal - "sl", // Sierra Leone - "sn", // Senegal - "st", // Sao Tome and Principe - "tg", // Togo - "uk", // U.K - }; private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { - Log.i("ServiceStateTracker", "Auto time state changed"); + Log.i("GsmServiceStateTracker", "Auto time state changed"); revertToNitz(); } }; - + + //***** Constructors - ServiceStateTracker(GSMPhone phone) - { + public GsmServiceStateTracker(GSMPhone phone) { + super(); + this.phone = phone; cm = phone.mCM; ss = new ServiceState(); @@ -265,13 +182,13 @@ final class ServiceStateTracker extends Handler (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); - cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); + cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); cm.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); cm.registerForNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null); cm.setOnNITZTime(this, EVENT_NITZ_TIME, null); cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null); - cm.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null); + cm.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null); cm.registerForSIMReady(this, EVENT_SIM_READY, null); // system setting property AIRPLANE_MODE_ON is set in Settings. @@ -280,7 +197,7 @@ final class ServiceStateTracker extends Handler Settings.System.AIRPLANE_MODE_ON, 0); mDesiredPowerState = ! (airplaneMode > 0); - ContentResolver cr = phone.getContext().getContentResolver(); + cr = phone.getContext().getContentResolver(); cr.registerContentObserver( Settings.System.getUriFor(Settings.System.AUTO_TIME), true, mAutoTimeObserver); @@ -288,6 +205,24 @@ final class ServiceStateTracker extends Handler mNeedToRegForSimLoaded = true; } + public void dispose() { + //Unregister for all events + cm.unregisterForAvailable(this); + cm.unregisterForRadioStateChanged(this); + cm.unregisterForNetworkStateChanged(this); + cm.unregisterForSIMReady(this); + + phone.mSIMRecords.unregisterForRecordsLoaded(this); + cm.unSetOnSignalStrengthUpdate(this); + cm.unSetOnRestrictedStateChanged(this); + cm.unSetOnNITZTime(this); + cr.unregisterContentObserver(this.mAutoTimeObserver); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "GsmServiceStateTracker finalized"); + } + /** * Registration point for transition into GPRS attached. * @param h handler to notify @@ -303,7 +238,11 @@ final class ServiceStateTracker extends Handler } } - void registerForNetworkAttach(Handler h, int what, Object obj) { + /*protected*/ void unregisterForGprsAttached(Handler h) { + gprsAttachedRegistrants.remove(h); + } + + /*protected*/ void registerForNetworkAttach(Handler h, int what, Object obj) { Registrant r = new Registrant(h, what, obj); networkAttachedRegistrants.add(r); @@ -311,6 +250,10 @@ final class ServiceStateTracker extends Handler r.notifyRegistrant(); } } + + /*protected*/ void unregisterForNetworkAttach(Handler h) { + networkAttachedRegistrants.remove(h); + } /** * Registration point for transition into GPRS detached. * @param h handler to notify @@ -326,52 +269,8 @@ final class ServiceStateTracker extends Handler } } - /** - * Registration point for combined roaming on - * combined roaming is true when roaming is true and ONS differs SPN - * - * @param h handler to notify - * @param what what code of message when delivered - * @param obj placed in Message.obj - */ - void registerForRoamingOn(Handler h, int what, Object obj) { - Registrant r = new Registrant(h, what, obj); - roamingOnRegistrants.add(r); - - if (ss.getRoaming()) { - r.notifyRegistrant(); - } - } - - /** - * Registration point for combined roaming off - * combined roaming is true when roaming is true and ONS differs SPN - * - * @param h handler to notify - * @param what what code of message when delivered - * @param obj placed in Message.obj - */ - void registerForRoamingOff(Handler h, int what, Object obj) { - Registrant r = new Registrant(h, what, obj); - roamingOffRegistrants.add(r); - - if (!ss.getRoaming()) { - r.notifyRegistrant(); - } - } - - /** - * Reregister network through toggle perferred network type - * This is a work aorund to deregister and register network since there is - * no ril api to set COPS=2 (deregister) only. - * - * @param onComplete is dispatched when this is complete. it will be - * an AsyncResult, and onComplete.obj.exception will be non-null - * on failure. - */ - void reRegisterNetwork(Message onComplete) { - cm.getPreferredNetworkType( - obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE, onComplete)); + /*protected*/ void unregisterForGprsDetached(Handler h) { + gprsDetachedRegistrants.remove(h); } /** @@ -380,7 +279,7 @@ final class ServiceStateTracker extends Handler * @param what what code of message when delivered * @param obj placed in Message.obj */ - void registerForPsRestrictedEnabled(Handler h, int what, Object obj) { + /*protected*/ void registerForPsRestrictedEnabled(Handler h, int what, Object obj) { Log.d(LOG_TAG, "[DSAC DEB] " + "registerForPsRestrictedEnabled "); Registrant r = new Registrant(h, what, obj); psRestrictEnabledRegistrants.add(r); @@ -389,14 +288,18 @@ final class ServiceStateTracker extends Handler r.notifyRegistrant(); } } - + + /*protected*/ void unregisterForPsRestrictedEnabled(Handler h) { + psRestrictEnabledRegistrants.remove(h); + } + /** * Registration point for transition out of packet service restricted zone. * @param h handler to notify * @param what what code of message when delivered * @param obj placed in Message.obj */ - void registerForPsRestrictedDisabled(Handler h, int what, Object obj) { + /*protected*/ void registerForPsRestrictedDisabled(Handler h, int what, Object obj) { Log.d(LOG_TAG, "[DSAC DEB] " + "registerForPsRestrictedDisabled "); Registrant r = new Registrant(h, what, obj); psRestrictDisabledRegistrants.add(r); @@ -406,34 +309,21 @@ final class ServiceStateTracker extends Handler } } - //***** Called from GSMPhone - - public void - setRadioPower(boolean power) - { - mDesiredPowerState = power; - - setPowerStateToDesired(); + /*protected*/ void unregisterForPsRestrictedDisabled(Handler h) { + psRestrictDisabledRegistrants.remove(h); } + //***** Called from GSMPhone public void getLacAndCid(Message onComplete) { cm.getRegistrationState(obtainMessage( EVENT_GET_LOC_DONE, onComplete)); } - /*package*/ void enableLocationUpdates() { - cm.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED)); - } - - /*package*/ void disableLocationUpdates() { - cm.setLocationUpdates(false, null); - } - //***** Overridden from Handler + //***** Overridden from ServiceStateTracker public void - handleMessage (Message msg) - { + handleMessage (Message msg) { AsyncResult ar; int[] ints; String[] strings; @@ -476,8 +366,8 @@ final class ServiceStateTracker extends Handler // This callback is called when signal strength is polled // all by itself - if (!(cm.getRadioState().isOn())) { - // Polling will continue when radio turns back on + if (!(cm.getRadioState().isOn()) || (cm.getRadioState().isCdma())) { + // Polling will continue when radio turns back on and not CDMA return; } ar = (AsyncResult) msg.obj; @@ -591,13 +481,11 @@ final class ServiceStateTracker extends Handler if (ar.exception == null) { mPreferredNetworkType = ((int[])ar.result)[0]; } else { - mPreferredNetworkType = Phone.NT_AUTO_TYPE; + mPreferredNetworkType = RILConstants.NETWORK_MODE_GLOBAL; } message = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE, ar.userObj); - int toggledNetworkType = - (mPreferredNetworkType == Phone.NT_AUTO_TYPE) ? - Phone.NT_GSM_TYPE : Phone.NT_AUTO_TYPE; + int toggledNetworkType = RILConstants.NETWORK_MODE_GLOBAL; cm.setPreferredNetworkType(toggledNetworkType, message); break; @@ -630,42 +518,19 @@ final class ServiceStateTracker extends Handler onRestrictedStateChanged(ar); break; + default: + Log.e(LOG_TAG, "Unhandled message with number: " + msg.what); + break; } } //***** Private Instance Methods - private void updateSpnDisplay() { - int rule = phone.mSIMRecords.getDisplayRule(ss.getOperatorNumeric()); - String spn = phone.mSIMRecords.getServiceProviderName(); - String plmn = ss.getOperatorAlphaLong(); - - if (rule != curSpnRule - || !TextUtils.equals(spn, curSpn) - || !TextUtils.equals(plmn, curPlmn)) { - boolean showSpn = - (rule & SIMRecords.SPN_RULE_SHOW_SPN) == SIMRecords.SPN_RULE_SHOW_SPN; - boolean showPlmn = - (rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN; - Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION); - intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn); - intent.putExtra(Intents.EXTRA_SPN, spn); - intent.putExtra(Intents.EXTRA_SHOW_PLMN, showPlmn); - intent.putExtra(Intents.EXTRA_PLMN, plmn); - phone.getContext().sendStickyBroadcast(intent); - } - curSpnRule = rule; - curSpn = spn; - curPlmn = plmn; - } - - private void - setPowerStateToDesired() + protected void setPowerStateToDesired() { // If we want it on and it's off, turn it on if (mDesiredPowerState - && cm.getRadioState() == CommandsInterface.RadioState.RADIO_OFF - ) { + && cm.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) { cm.setRadioPower(true, null); } else if (!mDesiredPowerState && cm.getRadioState().isOn()) { DataConnectionTracker dcTracker = phone.mDataConnection; @@ -681,8 +546,8 @@ final class ServiceStateTracker extends Handler // 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.state != State.CONNECTED - && dcTracker.state != State.DISCONNECTING) { + if (dcTracker.getState() != DataConnectionTracker.State.CONNECTED + && dcTracker.getState() != DataConnectionTracker.State.DISCONNECTING) { Log.d(LOG_TAG, "Data shutdown complete."); break; } @@ -692,22 +557,37 @@ final class ServiceStateTracker extends Handler 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(); + String plmn = ss.getOperatorAlphaLong(); - /** Cancel a pending (if any) pollState() operation */ - private void - cancelPollState() - { - // This will effectively cancel the rest of the poll requests - pollingContext = new int[1]; + if (rule != curSpnRule + || !TextUtils.equals(spn, curSpn) + || !TextUtils.equals(plmn, curPlmn)) { + boolean showSpn = + (rule & SIMRecords.SPN_RULE_SHOW_SPN) == SIMRecords.SPN_RULE_SHOW_SPN; + boolean showPlmn = + (rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN; + Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION); + intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn); + intent.putExtra(Intents.EXTRA_SPN, spn); + intent.putExtra(Intents.EXTRA_SHOW_PLMN, showPlmn); + intent.putExtra(Intents.EXTRA_PLMN, plmn); + phone.getContext().sendStickyBroadcast(intent); + } + curSpnRule = rule; + curSpn = spn; + curPlmn = plmn; } /** * Handle the result of one of the pollState()-related requests */ - private void - handlePollStateResult (int what, AsyncResult ar) - { + protected void + handlePollStateResult (int what, AsyncResult ar) { int ints[]; String states[]; @@ -820,8 +700,7 @@ final class ServiceStateTracker extends Handler } private void - setRssiDefaultValues() - { + setRssiDefaultValues() { rssi = 99; } @@ -835,8 +714,7 @@ final class ServiceStateTracker extends Handler */ private void - pollState() - { + pollState() { pollingContext = new int[1]; pollingContext[0] = 0; @@ -850,7 +728,6 @@ final class ServiceStateTracker extends Handler pollStateDone(); break; - case RADIO_OFF: newSS.setStateOff(); newCellLoc.setStateInvalid(); @@ -860,6 +737,20 @@ final class ServiceStateTracker extends Handler pollStateDone(); break; + case RUIM_NOT_READY: + case RUIM_READY: + case RUIM_LOCKED_OR_ABSENT: + case NV_NOT_READY: + case NV_READY: + Log.d(LOG_TAG, "Radio Technology Change ongoing, setting SS to off"); + newSS.setStateOff(); + newCellLoc.setStateInvalid(); + setRssiDefaultValues(); + mGotCountryCode = false; + + pollStateDone(); + break; + default: // Issue all poll-related commands at once // then count down the responses, which @@ -889,6 +780,7 @@ final class ServiceStateTracker extends Handler } private static String networkTypeToString(int type) { + //Network Type from GPRS_REGISTRATION_STATE String ret = "unknown"; switch (type) { @@ -901,14 +793,16 @@ final class ServiceStateTracker extends Handler case DATA_ACCESS_UMTS: ret = "UMTS"; break; + default: + Log.e(LOG_TAG, "Wrong network type: " + Integer.toString(type)); + break; } return ret; } private void - pollStateDone() - { + pollStateDone() { if (DBG) { Log.d(LOG_TAG, "Poll ServiceState done: " + " oldSS=[" + ss + "] newSS=[" + newSS + @@ -1131,9 +1025,8 @@ final class ServiceStateTracker extends Handler } private void - queueNextSignalStrengthPoll() - { - if (dontPollSignalStrength) { + queueNextSignalStrengthPoll() { + if (dontPollSignalStrength || (cm.getRadioState().isCdma())) { // The radio is telling us about signal strength changes // we don't have to ask it return; @@ -1155,8 +1048,7 @@ final class ServiceStateTracker extends Handler * Called both for solicited and unsolicited signal stength updates */ private void - onSignalStrengthResult(AsyncResult ar) - { + onSignalStrengthResult(AsyncResult ar) { int oldRSSI = rssi; if (ar.exception != null) { @@ -1176,15 +1068,21 @@ final class ServiceStateTracker extends Handler } if (rssi != oldRSSI) { - phone.notifySignalStrength(); + 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"); + } } } - + /** * Set restricted state based on the OnRestrictedStateChanged notification * If any voice or packet restricted state changes, trigger a UI * notification and notify registrants when sim is ready. - * + * * @param ar an int value of RIL_RESTRICTED_STATE_* */ private void onRestrictedStateChanged(AsyncResult ar) @@ -1201,10 +1099,8 @@ final class ServiceStateTracker extends Handler 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.getSimCard().getState() == SimCard.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) ); @@ -1272,7 +1168,7 @@ final class ServiceStateTracker extends Handler setNotification(CS_NORMAL_ENABLED); } } - + rs = newRs; } Log.d(LOG_TAG, "[DSAC DEB] " + "current rs at return "+ rs); @@ -1280,8 +1176,7 @@ final class ServiceStateTracker extends Handler /** code is registration state 0-5 from TS 27.007 7.2 */ private int - regCodeToServiceState(int code) - { + regCodeToServiceState(int code) { switch (code) { case 0: case 2: // 2 is "searching" @@ -1308,8 +1203,7 @@ final class ServiceStateTracker extends Handler * returns true if registered roam, false otherwise */ private boolean - regCodeIsRoaming (int code) - { + regCodeIsRoaming (int code) { // 5 is "in service -- roam" return 5 == code; } @@ -1323,7 +1217,7 @@ final class ServiceStateTracker extends Handler */ private boolean isRoamingBetweenOperators(boolean gsmRoaming, ServiceState s) { - String spn = SystemProperties.get(PROPERTY_SIM_OPERATOR_ALPHA, "empty"); + String spn = SystemProperties.get(PROPERTY_ICC_OPERATOR_ALPHA, "empty"); String onsl = s.getOperatorAlphaLong(); String onss = s.getOperatorAlphaShort(); @@ -1331,7 +1225,7 @@ final class ServiceStateTracker extends Handler boolean equalsOnsl = onsl != null && spn.equals(onsl); boolean equalsOnss = onss != null && spn.equals(onss); - String simNumeric = SystemProperties.get(PROPERTY_SIM_OPERATOR_NUMERIC, ""); + String simNumeric = SystemProperties.get(PROPERTY_ICC_OPERATOR_NUMERIC, ""); String operatorNumeric = s.getOperatorNumeric(); boolean equalsMcc = true; @@ -1345,8 +1239,7 @@ final class ServiceStateTracker extends Handler } private static - int twoDigitsAt(String s, int offset) - { + int twoDigitsAt(String s, int offset) { int a, b; a = Character.digit(s.charAt(offset), 10); @@ -1631,7 +1524,7 @@ final class ServiceStateTracker extends Handler + (SystemClock.elapsedRealtime() - mSavedAtTime)); } } - + /** * Post a notification to NotificationManager for restricted state * @@ -1640,7 +1533,6 @@ final class ServiceStateTracker extends Handler private void setNotification(int notifyType) { Log.d(LOG_TAG, "[DSAC DEB] " + "create notification " + notifyType); - Context context = phone.getContext(); mNotification = new Notification(); diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java new file mode 100644 index 0000000..c163803 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java @@ -0,0 +1,148 @@ +/* + * 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.telephony.PhoneNumberUtils; + +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.SmsAddress; + +public class GsmSmsAddress extends SmsAddress { + + static final int OFFSET_ADDRESS_LENGTH = 0; + + static final int OFFSET_TOA = 1; + + static final int OFFSET_ADDRESS_VALUE = 2; + + /** + * New GsmSmsAddress from TS 23.040 9.1.2.5 Address Field + * + * @param offset the offset of the Address-Length byte + * @param length the length in bytes rounded up, e.g. "2 + + * (addressLength + 1) / 2" + */ + + public GsmSmsAddress(byte[] data, int offset, int length) { + origBytes = new byte[length]; + System.arraycopy(data, offset, origBytes, 0, length); + + // addressLength is the count of semi-octets, not bytes + int addressLength = origBytes[OFFSET_ADDRESS_LENGTH] & 0xff; + + int toa = origBytes[OFFSET_TOA] & 0xff; + ton = 0x7 & (toa >> 4); + + // TOA must have its high bit set + if ((toa & 0x80) != 0x80) { + throw new RuntimeException("Invalid TOA - high bit must be set"); + } + + if (isAlphanumeric()) { + // An alphanumeric address + int countSeptets = addressLength * 4 / 7; + + address = GsmAlphabet.gsm7BitPackedToString(origBytes, + OFFSET_ADDRESS_VALUE, countSeptets); + } else { + // TS 23.040 9.1.2.5 says + // that "the MS shall interpret reserved values as 'Unknown' + // but shall store them exactly as received" + + byte lastByte = origBytes[length - 1]; + + if ((addressLength & 1) == 1) { + // Make sure the final unused BCD digit is 0xf + origBytes[length - 1] |= 0xf0; + } + address = PhoneNumberUtils.calledPartyBCDToString(origBytes, + OFFSET_TOA, length - OFFSET_TOA); + + // And restore origBytes + origBytes[length - 1] = lastByte; + } + } + + public String getAddressString() { + return address; + } + + /** + * Returns true if this is an alphanumeric address + */ + public boolean isAlphanumeric() { + return ton == TON_ALPHANUMERIC; + } + + public boolean isNetworkSpecific() { + return ton == TON_NETWORK; + } + + /** + * Returns true of this is a valid CPHS voice message waiting indicator + * address + */ + public boolean isCphsVoiceMessageIndicatorAddress() { + // CPHS-style MWI message + // See CPHS 4.7 B.4.2.1 + // + // Basically: + // + // - Originating address should be 4 bytes long and alphanumeric + // - Decode will result with two chars: + // - Char 1 + // 76543210 + // ^ set/clear indicator (0 = clear) + // ^^^ type of indicator (000 = voice) + // ^^^^ must be equal to 0001 + // - Char 2: + // 76543210 + // ^ line number (0 = line 1) + // ^^^^^^^ set to 0 + // + // Remember, since the alpha address is stored in 7-bit compact form, + // the "line number" is really the top bit of the first address value + // byte + + return (origBytes[OFFSET_ADDRESS_LENGTH] & 0xff) == 4 + && isAlphanumeric() && (origBytes[OFFSET_TOA] & 0x0f) == 0; + } + + /** + * Returns true if this is a valid CPHS voice message waiting indicator + * address indicating a "set" of "indicator 1" of type "voice message + * waiting" + */ + public boolean isCphsVoiceMessageSet() { + // 0x11 means "set" "voice message waiting" "indicator 1" + return isCphsVoiceMessageIndicatorAddress() + && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x11; + + } + + /** + * Returns true if this is a valid CPHS voice message waiting indicator + * address indicating a "clear" of "indicator 1" of type "voice message + * waiting" + */ + public boolean isCphsVoiceMessageClear() { + // 0x10 means "clear" "voice message waiting" "indicator 1" + return isCphsVoiceMessageIndicatorAddress() + && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x10; + + } +} diff --git a/telephony/java/com/android/internal/telephony/gsm/MccTable.java b/telephony/java/com/android/internal/telephony/gsm/MccTable.java index bb17cc4..8473a21 100644 --- a/telephony/java/com/android/internal/telephony/gsm/MccTable.java +++ b/telephony/java/com/android/internal/telephony/gsm/MccTable.java @@ -62,11 +62,11 @@ public final class MccTable entryForMcc(int mcc) { int index; - + MccEntry m; m = new MccEntry(mcc, null, 0); - + index = Collections.binarySearch(table, m); if (index < 0) { @@ -154,7 +154,7 @@ public final class MccTable /* * The table below is built from two resources: - * + * * 1) ITU "Mobile Network Code (MNC) for the international * identification plan for mobile terminals and mobile users" * which is available as an annex to the ITU operational bulletin diff --git a/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.aidl b/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.aidl index c600530..d88d0b7 100644 --- a/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.aidl +++ b/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.aidl @@ -16,11 +16,11 @@ package com.android.internal.telephony.gsm; -/** +/** * Used to indicate that the NetworkInfo object is parcelable to aidl. * This is a simple effort to make NetworkInfo parcelable rather than * trying to make the conventional containing object (AsyncResult), - * implement parcelable. This functionality is needed for the + * implement parcelable. This functionality is needed for the * NetworkQueryService to fix 1128695 */ parcelable NetworkInfo; diff --git a/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.java b/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.java index bebf9ba..04fd13e 100644 --- a/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.java +++ b/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.java @@ -22,8 +22,7 @@ import android.os.Parcelable; /** * {@hide} */ -public class NetworkInfo implements Parcelable -{ +public class NetworkInfo implements Parcelable { public enum State { UNKNOWN, AVAILABLE, @@ -39,34 +38,29 @@ public class NetworkInfo implements Parcelable public String - getOperatorAlphaLong() - { + getOperatorAlphaLong() { return operatorAlphaLong; } public String - getOperatorAlphaShort() - { + getOperatorAlphaShort() { return operatorAlphaShort; } public String - getOperatorNumeric() - { + getOperatorNumeric() { return operatorNumeric; } public State - getState() - { + getState() { return state; } - NetworkInfo(String operatorAlphaLong, - String operatorAlphaShort, - String operatorNumeric, - State state) - { + NetworkInfo(String operatorAlphaLong, + String operatorAlphaShort, + String operatorNumeric, + State state) { this.operatorAlphaLong = operatorAlphaLong; this.operatorAlphaShort = operatorAlphaShort; @@ -76,20 +70,18 @@ public class NetworkInfo implements Parcelable } - NetworkInfo(String operatorAlphaLong, - String operatorAlphaShort, - String operatorNumeric, - String stateString) - { - this (operatorAlphaLong, operatorAlphaShort, + public NetworkInfo(String operatorAlphaLong, + String operatorAlphaShort, + String operatorNumeric, + String stateString) { + this (operatorAlphaLong, operatorAlphaShort, operatorNumeric, rilStateToState(stateString)); } /** * See state strings defined in ril.h RIL_REQUEST_QUERY_AVAILABLE_NETWORKS */ - private static State rilStateToState(String s) - { + private static State rilStateToState(String s) { if (s.equals("unknown")) { return State.UNKNOWN; } else if (s.equals("available")) { @@ -105,29 +97,28 @@ public class NetworkInfo implements Parcelable } - public String toString() - { - return "NetworkInfo " + operatorAlphaLong - + "/" + operatorAlphaShort - + "/" + operatorNumeric + public String toString() { + return "NetworkInfo " + operatorAlphaLong + + "/" + operatorAlphaShort + + "/" + operatorNumeric + "/" + state; } - - /** + + /** * Parcelable interface implemented below. * This is a simple effort to make NetworkInfo parcelable rather than * trying to make the conventional containing object (AsyncResult), - * implement parcelable. This functionality is needed for the + * implement parcelable. This functionality is needed for the * NetworkQueryService to fix 1128695. */ - + public int describeContents() { return 0; } - /** + /** * Implement the Parcelable interface. - * Method to serialize a NetworkInfo object. + * Method to serialize a NetworkInfo object. */ public void writeToParcel(Parcel dest, int flags) { dest.writeString(operatorAlphaLong); @@ -136,9 +127,9 @@ public class NetworkInfo implements Parcelable dest.writeSerializable(state); } - /** + /** * Implement the Parcelable interface - * Method to deserialize a NetworkInfo object, or an array thereof. + * Method to deserialize a NetworkInfo object, or an array thereof. */ public static final Creator<NetworkInfo> CREATOR = new Creator<NetworkInfo>() { diff --git a/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java b/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java index d5d481a..feb78f8 100644 --- a/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java +++ b/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java @@ -19,8 +19,7 @@ package com.android.internal.telephony.gsm; /** * {@hide} */ -public class PDPContextState -{ +public class PDPContextState { public int cid; public boolean active; public String type; diff --git a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java index 66f8b72..88acb1b 100644 --- a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java @@ -17,88 +17,26 @@ package com.android.internal.telephony.gsm; import android.os.*; -import android.database.Cursor; -import android.provider.Telephony; import android.text.util.Regex; import android.util.EventLog; import android.util.Log; -import java.util.ArrayList; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.DataConnection; +import com.android.internal.telephony.DataLink; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.TelephonyEventLog; /** * {@hide} */ -public class PdpConnection extends Handler { +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; - public enum PdpState { - ACTIVE, /* has active pdp context */ - ACTIVATING, /* during connecting process */ - INACTIVE; /* has empty pdp context */ - - public String toString() { - switch (this) { - case ACTIVE: return "active"; - case ACTIVATING: return "setting up"; - default: return "inactive"; - } - } - - public boolean isActive() { - return this == ACTIVE; - } - - public boolean isInactive() { - return this == INACTIVE; - } - } - - public enum PdpFailCause { - NONE, - BAD_APN, - BAD_PAP_SECRET, - BARRED, - USER_AUTHENTICATION, - SERVICE_OPTION_NOT_SUPPORTED, - SERVICE_OPTION_NOT_SUBSCRIBED, - SIM_LOCKED, - RADIO_OFF, - NO_SIGNAL, - NO_DATA_PLAN, - RADIO_NOT_AVIALABLE, - SUSPENED_TEMPORARY, - RADIO_ERROR_RETRY, - UNKNOWN; - - public boolean isPermanentFail() { - return (this == RADIO_OFF); - } - - 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"; - case USER_AUTHENTICATION: return "error user autentication"; - case SERVICE_OPTION_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"; - case RADIO_NOT_AVIALABLE: return "radio not available"; - case SUSPENED_TEMPORARY: return "suspend temporary"; - case RADIO_ERROR_RETRY: return "transient radio error"; - default: return "unknown data error"; - } - } - } - /** 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; @@ -107,54 +45,20 @@ public class PdpConnection extends Handler { private static final int PDP_FAIL_RIL_SERVICE_OPTION_NOT_SUBSCRIBED = 33; private static final int PDP_FAIL_RIL_ERROR_UNSPECIFIED = 0xffff; - //***** Event codes - private static final int EVENT_SETUP_PDP_DONE = 1; - private static final int EVENT_GET_LAST_FAIL_DONE = 2; - private static final int EVENT_LINK_STATE_CHANGED = 3; - private static final int EVENT_DEACTIVATE_DONE = 4; - private static final int EVENT_FORCE_RETRY = 5; - //***** Instance Variables - private GSMPhone phone; private String pdp_name; - private PdpState state; - private Message onConnectCompleted; - private Message onDisconnect; - private int cid; - private long createTime; - private long lastFailTime; - private PdpFailCause lastFailCause; private ApnSetting apn; - private String interfaceName; - private String ipAddress; - private String gatewayAddress; - private String[] dnsServers; - - private static final String NULL_IP = "0.0.0.0"; // dataLink is only used to support pppd link - DataLink dataLink; - // receivedDisconnectReq is set when disconnect pdp link during activating - private boolean receivedDisconnectReq; + private DataLink dataLink; //***** Constructor - PdpConnection(GSMPhone phone) - { - this.phone = phone; - this.state = PdpState.INACTIVE; - onConnectCompleted = null; - onDisconnect = null; - this.cid = -1; - this.createTime = -1; - this.lastFailTime = -1; - this.lastFailCause = PdpFailCause.NONE; - this.apn = null; + PdpConnection(GSMPhone phone) { + super(phone); this.dataLink = null; - receivedDisconnectReq = false; - this.dnsServers = new String[2]; if (SystemProperties.get("ro.radio.use-ppp","no").equals("yes")) { - dataLink = new PppLink(phone.mDataConnection); + dataLink = new PppLink((GsmDataConnectionTracker) phone.mDataConnection, phone); dataLink.setOnLinkChange(this, EVENT_LINK_STATE_CHANGED, null); } } @@ -171,37 +75,37 @@ public class PdpConnection extends Handler { setHttpProxy (apn.proxy, apn.port); - state = PdpState.ACTIVATING; + state = State.ACTIVATING; this.apn = apn; onConnectCompleted = onCompleted; createTime = -1; lastFailTime = -1; - lastFailCause = PdpFailCause.NONE; + lastFailCause = FailCause.NONE; receivedDisconnectReq = false; if (FAKE_FAIL) { // for debug before baseband implement error in setup PDP if (apn.apn.equalsIgnoreCase("badapn")){ - notifyFail(PdpFailCause.BAD_APN, onConnectCompleted); + notifyFail(FailCause.BAD_APN, onConnectCompleted); return; } } - phone.mCM.setupDefaultPDP(apn.apn, apn.user, apn.password, - obtainMessage(EVENT_SETUP_PDP_DONE)); + phone.mCM.setupDataCall(Integer.toString(RILConstants.GSM_PHONE), null, apn.apn, apn.user, + apn.password, obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE)); } - void disconnect(Message msg) { + protected void disconnect(Message msg) { onDisconnect = msg; - if (state == PdpState.ACTIVE) { + if (state == State.ACTIVE) { if (dataLink != null) { dataLink.disconnect(); } if (phone.mCM.getRadioState().isOn()) { - phone.mCM.deactivateDefaultPDP(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg)); + phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg)); } - } else if (state == PdpState.ACTIVATING) { + } else if (state == State.ACTIVATING) { receivedDisconnectReq = true; } else { // state == INACTIVE. Nothing to do, so notify immediately. @@ -209,20 +113,9 @@ public class PdpConnection extends Handler { } } - private void - setHttpProxy(String httpProxy, String httpPort) - { - if (httpProxy == null || httpProxy.length() == 0) { - phone.setSystemProperty("net.gprs.http-proxy", null); - return; - } - - if (httpPort == null || httpPort.length() == 0) { - httpPort = "8080"; // Default to port 8080 - } - - phone.setSystemProperty("net.gprs.http-proxy", - "http://" + httpProxy + ":" + httpPort + "/"); + public void clearSettings() { + super.clearSettings(); + apn = null; } public String toString() { @@ -231,61 +124,30 @@ public class PdpConnection extends Handler { " lastFailCause=" + lastFailCause; } - public long getConnectionTime() { - return createTime; - } - - public long getLastFailTime() { - return lastFailTime; - } - - public PdpFailCause getLastFailCause() { - return lastFailCause; - } - - public ApnSetting getApn() { - return apn; - } - - String getInterface() { - return interfaceName; - } - - String getIpAddress() { - return ipAddress; - } - - String getGatewayAddress() { - return gatewayAddress; - } - - String[] getDnsServers() { - return dnsServers; - } - - public PdpState getState() { - return state; - } - private void notifyFail(PdpFailCause cause, Message onCompleted) { + protected void notifyFail(FailCause cause, Message onCompleted) { if (onCompleted == null) return; - state = PdpState.INACTIVE; + state = State.INACTIVE; lastFailCause = cause; lastFailTime = System.currentTimeMillis(); onConnectCompleted = null; - if (DBG) log("Notify PDP fail at " + lastFailTime - + " due to " + lastFailCause); + if (DBG) { + log("Notify PDP fail at " + lastFailTime + + " due to " + lastFailCause); + } AsyncResult.forMessage(onCompleted, cause, new Exception()); onCompleted.sendToTarget(); } - private void notifySuccess(Message onCompleted) { - if (onCompleted == null) return; + protected void notifySuccess(Message onCompleted) { + if (onCompleted == null) { + return; + } - state = PdpState.ACTIVE; + state = State.ACTIVE; createTime = System.currentTimeMillis(); onConnectCompleted = null; onCompleted.arg1 = cid; @@ -296,7 +158,7 @@ public class PdpConnection extends Handler { onCompleted.sendToTarget(); } - private void notifyDisconnect(Message msg) { + protected void notifyDisconnect(Message msg) { if (DBG) log("Notify PDP disconnect"); if (msg != null) { @@ -306,22 +168,7 @@ public class PdpConnection extends Handler { clearSettings(); } - void clearSettings() { - state = PdpState.INACTIVE; - receivedDisconnectReq = false; - createTime = -1; - lastFailTime = -1; - lastFailCause = PdpFailCause.NONE; - apn = null; - onConnectCompleted = null; - interfaceName = null; - ipAddress = null; - gatewayAddress = null; - dnsServers[0] = null; - dnsServers[1] = null; - } - - private void onLinkStateChanged(DataLink.LinkState linkState) { + protected void onLinkStateChanged(DataLink.LinkState linkState) { switch (linkState) { case LINK_UP: notifySuccess(onConnectCompleted); @@ -335,151 +182,110 @@ public class PdpConnection extends Handler { } } - private PdpFailCause getFailCauseFromRequest(int rilCause) { - PdpFailCause cause; + protected FailCause getFailCauseFromRequest(int rilCause) { + FailCause cause; switch (rilCause) { case PDP_FAIL_RIL_BARRED: - cause = PdpFailCause.BARRED; + cause = FailCause.BARRED; break; case PDP_FAIL_RIL_BAD_APN: - cause = PdpFailCause.BAD_APN; + cause = FailCause.BAD_APN; break; case PDP_FAIL_RIL_USER_AUTHENTICATION: - cause = PdpFailCause.USER_AUTHENTICATION; + cause = FailCause.USER_AUTHENTICATION; break; case PDP_FAIL_RIL_SERVICE_OPTION_NOT_SUPPORTED: - cause = PdpFailCause.SERVICE_OPTION_NOT_SUPPORTED; + cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED; break; case PDP_FAIL_RIL_SERVICE_OPTION_NOT_SUBSCRIBED: - cause = PdpFailCause.SERVICE_OPTION_NOT_SUBSCRIBED; + cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED; break; default: - cause = PdpFailCause.UNKNOWN; + cause = FailCause.UNKNOWN; } return cause; } - - private void log(String s) { + protected void log(String s) { Log.d(LOG_TAG, "[PdpConnection] " + s); } @Override - public void handleMessage(Message msg) { - AsyncResult ar; - - switch (msg.what) { - case EVENT_SETUP_PDP_DONE: - ar = (AsyncResult) msg.obj; - - if (ar.exception != null) { - Log.e(LOG_TAG, "PDP Context Init failed " + ar.exception); - - if (receivedDisconnectReq) { - // Don't bother reporting the error if there's already a - // pending disconnect request, since DataConnectionTracker - // has already updated its state. - notifyDisconnect(onDisconnect); - } else { - if ( ar.exception instanceof CommandException && - ((CommandException) (ar.exception)).getCommandError() - == CommandException.Error.RADIO_NOT_AVAILABLE) { - notifyFail(PdpFailCause.RADIO_NOT_AVIALABLE, - onConnectCompleted); - } else { - phone.mCM.getLastPdpFailCause( - obtainMessage(EVENT_GET_LAST_FAIL_DONE)); - } - } + protected void onDeactivated(AsyncResult ar) { + notifyDisconnect((Message) ar.userObj); + if (DBG) log("PDP Connection Deactivated"); + } + + @Override + protected void onSetupConnectionCompleted(AsyncResult ar) { + if (ar.exception != null) { + Log.e(LOG_TAG, "PDP Context Init failed " + ar.exception); + + if (receivedDisconnectReq) { + // Don't bother reporting the error if there's already a + // pending disconnect request, since DataConnectionTracker + // has already updated its state. + notifyDisconnect(onDisconnect); + } else { + if ( ar.exception instanceof CommandException && + ((CommandException) (ar.exception)).getCommandError() + == CommandException.Error.RADIO_NOT_AVAILABLE) { + notifyFail(FailCause.RADIO_NOT_AVAILABLE, + onConnectCompleted); } else { - if (receivedDisconnectReq) { - // Don't bother reporting success if there's already a - // pending disconnect request, since DataConnectionTracker - // has already updated its state. - // Set ACTIVE so that disconnect does the right thing. - state = PdpState.ACTIVE; - disconnect(onDisconnect); - } else { - String[] response = ((String[]) ar.result); - cid = Integer.parseInt(response[0]); - - if (response.length > 2) { - interfaceName = response[1]; - ipAddress = response[2]; - String prefix = "net." + interfaceName + "."; - gatewayAddress = SystemProperties.get(prefix + "gw"); - dnsServers[0] = SystemProperties.get(prefix + "dns1"); - dnsServers[1] = SystemProperties.get(prefix + "dns2"); - if (DBG) { - log("interface=" + interfaceName + " ipAddress=" + ipAddress - + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0] - + " DNS2=" + dnsServers[1]); - } - - if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1]) - && !phone.isDnsCheckDisabled()) { - // Work around a race condition where QMI does not fill in DNS: - // Deactivate PDP and let DataConnectionTracker retry. - // Do not apply the race condition workaround for MMS APN - // if Proxy is an IP-address. - // Otherwise, the default APN will not be restored anymore. - if (!apn.types[0].equals(Phone.APN_TYPE_MMS) - || !isIpAddress(apn.mmsProxy)) { - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS, - dnsServers[0]); - phone.mCM.deactivateDefaultPDP(cid, - obtainMessage(EVENT_FORCE_RETRY)); - break; - } - } - } + phone.mCM.getLastPdpFailCause( + obtainMessage(EVENT_GET_LAST_FAIL_DONE)); + } + } + } else { + if (receivedDisconnectReq) { + // Don't bother reporting success if there's already a + // pending disconnect request, since DataConnectionTracker + // has already updated its state. + disconnect(onDisconnect); + } else { + String[] response = ((String[]) ar.result); + cid = Integer.parseInt(response[0]); + + if (response.length > 2) { + interfaceName = response[1]; + ipAddress = response[2]; + String prefix = "net." + interfaceName + "."; + gatewayAddress = SystemProperties.get(prefix + "gw"); + dnsServers[0] = SystemProperties.get(prefix + "dns1"); + dnsServers[1] = SystemProperties.get(prefix + "dns2"); + if (DBG) { + log("interface=" + interfaceName + " ipAddress=" + ipAddress + + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0] + + " DNS2=" + dnsServers[1]); + } - if (dataLink != null) { - dataLink.connect(); - } else { - onLinkStateChanged(DataLink.LinkState.LINK_UP); + if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1]) + && !((GSMPhone) phone).isDnsCheckDisabled()) { + // Work around a race condition where QMI does not fill in DNS: + // Deactivate PDP and let DataConnectionTracker retry. + // Do not apply the race condition workaround for MMS APN + // if Proxy is an IP-address. + // Otherwise, the default APN will not be restored anymore. + if (!apn.types[0].equals(Phone.APN_TYPE_MMS) + || !isIpAddress(apn.mmsProxy)) { + EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS, + dnsServers[0]); + phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_FORCE_RETRY)); + return; } - - if (DBG) log("PDP setup on cid = " + cid); } } - break; - case EVENT_FORCE_RETRY: - if (receivedDisconnectReq) { - notifyDisconnect(onDisconnect); - } else { - ar = (AsyncResult) msg.obj; - notifyFail(PdpFailCause.RADIO_ERROR_RETRY, onConnectCompleted); - } - break; - case EVENT_GET_LAST_FAIL_DONE: - if (receivedDisconnectReq) { - // Don't bother reporting the error if there's already a - // pending disconnect request, since DataConnectionTracker - // has already updated its state. - notifyDisconnect(onDisconnect); - } else { - ar = (AsyncResult) msg.obj; - PdpFailCause cause = PdpFailCause.UNKNOWN; - if (ar.exception == null) { - int rilFailCause = ((int[]) (ar.result))[0]; - cause = getFailCauseFromRequest(rilFailCause); - } - notifyFail(cause, onConnectCompleted); + if (dataLink != null) { + dataLink.connect(); + } else { + onLinkStateChanged(DataLink.LinkState.LINK_UP); } - break; - case EVENT_LINK_STATE_CHANGED: - ar = (AsyncResult) msg.obj; - DataLink.LinkState ls = (DataLink.LinkState) ar.result; - onLinkStateChanged(ls); - break; - case EVENT_DEACTIVATE_DONE: - ar = (AsyncResult) msg.obj; - notifyDisconnect((Message) ar.userObj); - break; + if (DBG) log("PDP setup on cid = " + cid); + } } } @@ -488,4 +294,8 @@ public class PdpConnection extends Handler { return Regex.IP_ADDRESS_PATTERN.matcher(apn.mmsProxy).matches(); } + + public ApnSetting getApn() { + return this.apn; + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/PppLink.java b/telephony/java/com/android/internal/telephony/gsm/PppLink.java index 43d4f1f..9627696 100644 --- a/telephony/java/com/android/internal/telephony/gsm/PppLink.java +++ b/telephony/java/com/android/internal/telephony/gsm/PppLink.java @@ -16,28 +16,31 @@ package com.android.internal.telephony.gsm; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.RandomAccessFile; - import android.database.Cursor; import android.os.Message; import android.os.SystemProperties; import android.os.SystemService; -import com.android.internal.telephony.gsm.DataConnectionTracker.State; -import com.android.internal.util.ArrayUtils; 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 implements DataLinkInterface { +final class PppLink extends DataLink { private static final String LOG_TAG = "GSM"; static final String PATH_PPP_OPERSTATE = "/sys/class/net/ppp0/operstate"; @@ -69,11 +72,14 @@ final class PppLink extends DataLink implements DataLinkInterface { }; private final byte[] mCheckPPPBuffer = new byte[32]; + private PhoneBase phone; + int lastPppdExitCode = EXIT_OK; - PppLink(DataConnectionTracker dc) { + PppLink(GsmDataConnectionTracker dc, GSMPhone p) { super(dc); + this.phone = p; } public void connect() { @@ -131,7 +137,7 @@ final class PppLink extends DataLink implements DataLinkInterface { checkPPP(); // keep polling in case interface goes down - if (dataConnection.state != State.IDLE) { + if (dataConnection.getState() != State.IDLE) { Message poll = obtainMessage(); poll.what = EVENT_POLL_DATA_CONNECTION; sendMessageDelayed(poll, POLL_SYSFS_MILLIS); @@ -141,7 +147,7 @@ final class PppLink extends DataLink implements DataLinkInterface { } private void checkPPP() { - boolean connecting = (dataConnection.state == State.CONNECTING); + boolean connecting = (dataConnection.getState() == State.CONNECTING); try { RandomAccessFile file = new RandomAccessFile(PATH_PPP_OPERSTATE, "r"); @@ -152,10 +158,10 @@ final class PppLink extends DataLink implements DataLinkInterface { // "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.state == State.CONNECTING) { + UNKNOWN_ASCII_STRING.length) + && dataConnection.getState() == State.CONNECTING) { - Log.i(LOG_TAG, + Log.i(LOG_TAG, "found ppp interface. Notifying GPRS connected"); if (mLinkChangeRegistrant != null) { @@ -163,23 +169,23 @@ final class PppLink extends DataLink implements DataLinkInterface { } connecting = false; - } else if (dataConnection.state == State.CONNECTED + } else if (dataConnection.getState() == State.CONNECTED && ArrayUtils.equals(mCheckPPPBuffer, DOWN_ASCII_STRING, - DOWN_ASCII_STRING.length)) { + DOWN_ASCII_STRING.length)) { - Log.i(LOG_TAG, + 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.state == State.CONNECTED && + if (dataConnection.getState() == State.CONNECTED && mLinkChangeRegistrant != null) { mLinkChangeRegistrant.notifyResult(LinkState.LINK_DOWN); } @@ -206,4 +212,8 @@ final class PppLink extends DataLink implements DataLinkInterface { } } + + protected void log(String s) { + Log.d(LOG_TAG, "[PppLink] " + s); + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java b/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java index 81fc657..ead1327 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java +++ b/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java @@ -16,506 +16,54 @@ package com.android.internal.telephony.gsm; -import com.android.internal.telephony.*; -import com.android.internal.telephony.gsm.stk.ImageDescriptor; import android.os.*; import android.os.AsyncResult; -import android.os.RegistrantList; -import android.os.Registrant; import android.util.Log; + +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.IccException; +import com.android.internal.telephony.IccFileHandler; +import com.android.internal.telephony.IccFileTypeMismatch; +import com.android.internal.telephony.IccIoResult; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.PhoneProxy; + import java.util.ArrayList; /** * {@hide} */ -public final class SIMFileHandler extends Handler -{ +public final class SIMFileHandler extends IccFileHandler { static final String LOG_TAG = "GSM"; - //from TS 11.11 9.1 or elsewhere - static private final int COMMAND_READ_BINARY = 0xb0; - static private final int COMMAND_UPDATE_BINARY = 0xd6; - static private final int COMMAND_READ_RECORD = 0xb2; - static private final int COMMAND_UPDATE_RECORD = 0xdc; - static private final int COMMAND_SEEK = 0xa2; - static private final int COMMAND_GET_RESPONSE = 0xc0; - - // from TS 11.11 9.2.5 - static private final int READ_RECORD_MODE_ABSOLUTE = 4; - - //***** types of files TS 11.11 9.3 - static private final int EF_TYPE_TRANSPARENT = 0; - static private final int EF_TYPE_LINEAR_FIXED = 1; - static private final int EF_TYPE_CYCLIC = 3; - - //***** types of files TS 11.11 9.3 - static private final int TYPE_RFU = 0; - static private final int TYPE_MF = 1; - static private final int TYPE_DF = 2; - static private final int TYPE_EF = 4; - - // size of GET_RESPONSE for EF - static private final int GET_RESPONSE_EF_SIZE_BYTES = 15; - - // Byte order received in response to COMMAND_GET_RESPONSE - // Refer TS 51.011 Section 9.2.1 - static private final int RESPONSE_DATA_RFU_1 = 0; - static private final int RESPONSE_DATA_RFU_2 = 1; - - static private final int RESPONSE_DATA_FILE_SIZE_1 = 2; - static private final int RESPONSE_DATA_FILE_SIZE_2 = 3; - - static private final int RESPONSE_DATA_FILE_ID_1 = 4; - static private final int RESPONSE_DATA_FILE_ID_2 = 5; - static private final int RESPONSE_DATA_FILE_TYPE = 6; - static private final int RESPONSE_DATA_RFU_3 = 7; - static private final int RESPONSE_DATA_ACCESS_CONDITION_1 = 8; - static private final int RESPONSE_DATA_ACCESS_CONDITION_2 = 9; - static private final int RESPONSE_DATA_ACCESS_CONDITION_3 = 10; - static private final int RESPONSE_DATA_FILE_STATUS = 11; - static private final int RESPONSE_DATA_LENGTH = 12; - static private final int RESPONSE_DATA_STRUCTURE = 13; - static private final int RESPONSE_DATA_RECORD_LENGTH = 14; - - //***** Instance Variables - GSMPhone phone; - - //***** Events - - /** Finished retrieving size of transparent EF; start loading. */ - static private final int EVENT_GET_BINARY_SIZE_DONE = 4; - /** Finished loading contents of transparent EF; post result. */ - static private final int EVENT_READ_BINARY_DONE = 5; - /** Finished retrieving size of records for linear-fixed EF; now load. */ - static private final int EVENT_GET_RECORD_SIZE_DONE = 6; - /** Finished loading single record from a linear-fixed EF; post result. */ - static private final int EVENT_READ_RECORD_DONE = 7; - /** Finished retrieving record size; post result. */ - static private final int EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE = 8; - /** Finished retrieving image instance record; post result. */ - static private final int EVENT_READ_IMG_DONE = 9; - /** Finished retrieving icon data; post result. */ - static private final int EVENT_READ_ICON_DONE = 10; - - //***** Inner Classes - - static class LoadLinearFixedContext - { - - int efid; - int recordNum, recordSize, countRecords; - boolean loadAll; - - Message onLoaded; - - ArrayList<byte[]> results; - - LoadLinearFixedContext(int efid, int recordNum, Message onLoaded) - { - this.efid = efid; - this.recordNum = recordNum; - this.onLoaded = onLoaded; - this.loadAll = false; - } - - LoadLinearFixedContext(int efid, Message onLoaded) - { - this.efid = efid; - this.recordNum = 1; - this.loadAll = true; - this.onLoaded = onLoaded; - } - - } - //***** Constructor - SIMFileHandler(GSMPhone phone) - { - this.phone = phone; + SIMFileHandler(GSMPhone phone) { + super(phone); } - //***** Public Methods - - /** - * Load a record from a SIM Linear Fixed EF - * - * @param fileid EF id - * @param recordNum 1-based (not 0-based) record number - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is the byte[] - * - */ - void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded) - { - Message response - = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, - new LoadLinearFixedContext(fileid, recordNum, onLoaded)); - - phone.mCM.simIO(COMMAND_GET_RESPONSE, fileid, null, - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); - } - - /** - * Load a image instance record from a SIM Linear Fixed EF-IMG - * - * @param recordNum 1-based (not 0-based) record number - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is the byte[] - * - */ - public void loadEFImgLinearFixed(int recordNum, Message onLoaded) { - Message response = obtainMessage(EVENT_READ_IMG_DONE, - new LoadLinearFixedContext(SimConstants.EF_IMG, recordNum, - onLoaded)); - - phone.mCM.simIO(COMMAND_GET_RESPONSE, SimConstants.EF_IMG, "img", - recordNum, READ_RECORD_MODE_ABSOLUTE, - ImageDescriptor.ID_LENGTH, null, null, response); - } - - /** - * get record size for a linear fixed EF - * - * @param fileid EF id - * @param onLoaded ((AsnyncResult)(onLoaded.obj)).result is the recordSize[] - * int[0] is the record length int[1] is the total length of the EF - * file int[3] is the number of records in the EF file So int[0] * - * int[3] = int[1] - */ - void getEFLinearRecordSize(int fileid, Message onLoaded) - { - Message response - = obtainMessage(EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE, - new LoadLinearFixedContext(fileid, onLoaded)); - phone.mCM.simIO(COMMAND_GET_RESPONSE, fileid, null, - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); - } - - /** - * Load all records from a SIM Linear Fixed EF - * - * @param fileid EF id - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is an ArrayList<byte[]> - * - */ - void loadEFLinearFixedAll(int fileid, Message onLoaded) - { - Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, - new LoadLinearFixedContext(fileid,onLoaded)); - - phone.mCM.simIO(COMMAND_GET_RESPONSE, fileid, null, - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + public void dispose() { + super.dispose(); } - /** - * Load a SIM Transparent EF - * - * @param fileid EF id - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is the byte[] - * - */ - - void loadEFTransparent(int fileid, Message onLoaded) - { - Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE, - fileid, 0, onLoaded); - - phone.mCM.simIO(COMMAND_GET_RESPONSE, fileid, null, - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); - } - - /** - * Load a SIM Transparent EF-IMG. Used right after loadEFImgLinearFixed to - * retrive STK's icon data. - * - * @param fileid EF id - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is the byte[] - * - */ - public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset, - int length, Message onLoaded) { - Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0, - onLoaded); - - phone.mCM.simIO(COMMAND_READ_BINARY, fileid, "img", highOffset, lowOffset, - length, null, null, response); + protected void finalize() { + Log.d(LOG_TAG, "SIMFileHandler finalized"); } - /** - * Update a record in a linear fixed EF - * @param fileid EF id - * @param recordNum 1-based (not 0-based) record number - * @param data must be exactly as long as the record in the EF - * @param pin2 for CHV2 operations, otherwist must be null - * @param onComplete onComplete.obj will be an AsyncResult - * onComplete.obj.userObj will be a SimIoResult on success - */ - void updateEFLinearFixed(int fileid, int recordNum, byte[] data, - String pin2, Message onComplete) - { - phone.mCM.simIO(COMMAND_UPDATE_RECORD, fileid, null, - recordNum, READ_RECORD_MODE_ABSOLUTE, data.length, - SimUtils.bytesToHexString(data), pin2, onComplete); - } + //***** Overridden from IccFileHandler - /** - * Update a transparent EF - * @param fileid EF id - * @param data must be exactly as long as the EF - */ - void updateEFTransparent(int fileid, byte[] data, Message onComplete) - { - phone.mCM.simIO(COMMAND_UPDATE_BINARY, fileid, null, - 0, 0, data.length, - SimUtils.bytesToHexString(data), null, onComplete); + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); } - //***** Overridden from Handler - - public void handleMessage(Message msg) - { - AsyncResult ar; - SimIoResult result; - Message response = null; - String str; - LoadLinearFixedContext lc; - - SimException simException; - byte data[]; - int size; - int fileid; - int recordNum; - int recordSize[]; - - try { - switch (msg.what) { - case EVENT_READ_IMG_DONE: - ar = (AsyncResult) msg.obj; - lc = (LoadLinearFixedContext) ar.userObj; - result = (SimIoResult) ar.result; - response = lc.onLoaded; - - simException = result.getException(); - if (simException != null) { - sendResult(response, result.payload, ar.exception); - } - break; - case EVENT_READ_ICON_DONE: - ar = (AsyncResult) msg.obj; - response = (Message) ar.userObj; - result = (SimIoResult) ar.result; - - simException = result.getException(); - if (simException != null) { - sendResult(response, result.payload, ar.exception); - } - break; - case EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE: - ar = (AsyncResult)msg.obj; - lc = (LoadLinearFixedContext) ar.userObj; - result = (SimIoResult) ar.result; - response = lc.onLoaded; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - simException = result.getException(); - if (simException != null) { - sendResult(response, null, simException); - break; - } - - data = result.payload; - - if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] || - EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { - throw new SimFileTypeMismatch(); - } - - recordSize = new int[3]; - recordSize[0] = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; - recordSize[1] = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) - + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); - recordSize[2] = recordSize[1] / recordSize[0]; - - sendResult(response, recordSize, null); - break; - case EVENT_GET_RECORD_SIZE_DONE: - ar = (AsyncResult)msg.obj; - lc = (LoadLinearFixedContext) ar.userObj; - result = (SimIoResult) ar.result; - response = lc.onLoaded; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - simException = result.getException(); - - if (simException != null) { - sendResult(response, null, simException); - break; - } - - data = result.payload; - fileid = lc.efid; - recordNum = lc.recordNum; - - if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { - throw new SimFileTypeMismatch(); - } - - if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { - throw new SimFileTypeMismatch(); - } - - lc.recordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; - - size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) - + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); - - lc.countRecords = size / lc.recordSize; - - if (lc.loadAll) { - lc.results = new ArrayList<byte[]>(lc.countRecords); - } - - phone.mCM.simIO(COMMAND_READ_RECORD, lc.efid, null, - lc.recordNum, - READ_RECORD_MODE_ABSOLUTE, - lc.recordSize, null, null, - obtainMessage(EVENT_READ_RECORD_DONE, lc)); - break; - case EVENT_GET_BINARY_SIZE_DONE: - ar = (AsyncResult)msg.obj; - response = (Message) ar.userObj; - result = (SimIoResult) ar.result; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - simException = result.getException(); - - if (simException != null) { - sendResult(response, null, simException); - break; - } - - data = result.payload; - - fileid = msg.arg1; - - if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { - throw new SimFileTypeMismatch(); - } - - if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) { - throw new SimFileTypeMismatch(); - } - - size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) - + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); - - phone.mCM.simIO(COMMAND_READ_BINARY, fileid, null, - 0, 0, size, null, null, - obtainMessage(EVENT_READ_BINARY_DONE, - fileid, 0, response)); - break; - - case EVENT_READ_RECORD_DONE: - - ar = (AsyncResult)msg.obj; - lc = (LoadLinearFixedContext) ar.userObj; - result = (SimIoResult) ar.result; - response = lc.onLoaded; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - simException = result.getException(); - - if (simException != null) { - sendResult(response, null, simException); - break; - } - - if (!lc.loadAll) { - sendResult(response, result.payload, null); - } else { - lc.results.add(result.payload); - - lc.recordNum++; - - if (lc.recordNum > lc.countRecords) { - sendResult(response, lc.results, null); - } else { - phone.mCM.simIO(COMMAND_READ_RECORD, lc.efid, null, - lc.recordNum, - READ_RECORD_MODE_ABSOLUTE, - lc.recordSize, null, null, - obtainMessage(EVENT_READ_RECORD_DONE, lc)); - } - } - - break; - - case EVENT_READ_BINARY_DONE: - ar = (AsyncResult)msg.obj; - response = (Message) ar.userObj; - result = (SimIoResult) ar.result; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - simException = result.getException(); - - if (simException != null) { - sendResult(response, null, simException); - break; - } - - sendResult(response, result.payload, null); - break; - - }} catch (Exception exc) { - if (response != null) { - sendResult(response, null, exc); - } else { - Log.e(LOG_TAG, "uncaught exception", exc); - } - } + protected void logd(String msg) { + Log.d(LOG_TAG, "[SIMFileHandler] " + msg); } - //***** Private Methods - - private void sendResult(Message response, Object result, Throwable ex) - { - if (response == null) { - return; - } - - AsyncResult.forMessage(response, result, ex); - - response.sendToTarget(); + protected void loge(String msg) { + Log.e(LOG_TAG, "[SIMFileHandler] " + msg); } } diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java index 4467536..09a17f5 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java +++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java @@ -16,26 +16,45 @@ package com.android.internal.telephony.gsm; +import android.app.ActivityManagerNative; import android.app.AlarmManager; +import android.app.IActivityManager; import android.content.Context; +import android.content.res.Configuration; import android.os.AsyncResult; -import android.os.RegistrantList; -import android.os.Registrant; import android.os.Handler; import android.os.Message; import android.os.SystemProperties; -import android.telephony.gsm.SmsMessage; +import android.os.Registrant; import android.util.Log; import java.util.ArrayList; + import static com.android.internal.telephony.TelephonyProperties.*; -import com.android.internal.telephony.SimCard; + +import com.android.internal.telephony.AdnRecord; +import com.android.internal.telephony.AdnRecordCache; +import com.android.internal.telephony.AdnRecordLoader; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.gsm.SimCard; +import com.android.internal.telephony.gsm.SmsMessage; +import com.android.internal.telephony.IccFileHandler; +import com.android.internal.telephony.IccRecords; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.IccVmFixedException; +import com.android.internal.telephony.IccVmNotSupportedException; +import com.android.internal.telephony.PhoneProxy; + + + + + + /** * {@hide} */ -public final class SIMRecords extends Handler implements SimConstants -{ +public final class SIMRecords extends IccRecords { static final String LOG_TAG = "GSM"; private static final boolean CRASH_RIL = false; @@ -44,37 +63,19 @@ public final class SIMRecords extends Handler implements SimConstants //***** Instance Variables - GSMPhone phone; - RegistrantList recordsLoadedRegistrants = new RegistrantList(); - - int recordsToLoad; // number of pending load requests + VoiceMailConstants mVmConfig; - AdnRecordCache adnCache; - VoiceMailConstants mVmConfig; SpnOverride mSpnOverride; //***** Cached SIM State; cleared on channel close - boolean recordsRequested = false; // true if we've made requests for the sim records - String imsi; - String iccid; - String msisdn = null; // My mobile number - String msisdnTag = null; - String voiceMailNum = null; - String voiceMailTag = null; - String newVoiceMailNum = null; - String newVoiceMailTag = null; - boolean isVoiceMailFixed = false; - int countVoiceMessages = 0; boolean callForwardingEnabled; - int mncLength = 0; // 0 is used to indicate that the value - // is not initialized - int mailboxIndex = 0; // 0 is no mailbox dailing number associated + /** - * Sates only used by getSpnFsm FSM + * States only used by getSpnFsm FSM */ private Get_Spn_Fsm_State spnState; @@ -157,9 +158,8 @@ public final class SIMRecords extends Handler implements SimConstants //***** Constructor - SIMRecords(GSMPhone phone) - { - this.phone = phone; + SIMRecords(GSMPhone p) { + super(p); adnCache = new AdnRecordCache(phone); @@ -172,30 +172,35 @@ public final class SIMRecords extends Handler implements SimConstants recordsToLoad = 0; - phone.mCM.registerForSIMReady(this, EVENT_SIM_READY, null); - phone.mCM.registerForOffOrNotAvailable( + p.mCM.registerForSIMReady(this, EVENT_SIM_READY, null); + p.mCM.registerForOffOrNotAvailable( this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); - phone.mCM.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null); - phone.mCM.setOnSimRefresh(this, EVENT_SIM_REFRESH, null); + p.mCM.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null); + p.mCM.setOnIccRefresh(this, EVENT_SIM_REFRESH, null); // Start off by setting empty state - onRadioOffOrNotAvailable(); + onRadioOffOrNotAvailable(); } - AdnRecordCache getAdnCache() { - return adnCache; + public void dispose() { + //Unregister for all events + phone.mCM.unregisterForSIMReady(this); + phone.mCM.unregisterForOffOrNotAvailable( this); + phone.mCM.unSetOnIccRefresh(this); } - private void onRadioOffOrNotAvailable() - { + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "SIMRecords finalized"); + } + + protected void onRadioOffOrNotAvailable() { imsi = null; msisdn = null; voiceMailNum = null; countVoiceMessages = 0; mncLength = 0; iccid = null; - spn = null; // -1 means no EF_SPN found; treat accordingly. spnDisplayCondition = -1; efMWIS = null; @@ -205,9 +210,9 @@ public final class SIMRecords extends Handler implements SimConstants adnCache.reset(); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_NUMERIC, null); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, null); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ISO_COUNTRY, null); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, null); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, null); + phone.setSystemProperty(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 @@ -217,24 +222,13 @@ public final class SIMRecords extends Handler implements SimConstants //***** Public Methods - public void registerForRecordsLoaded(Handler h, int what, Object obj) - { - Registrant r = new Registrant(h, what, obj); - recordsLoadedRegistrants.add(r); - - if (recordsToLoad == 0 && recordsRequested == true) { - r.notifyRegistrant(new AsyncResult(null, null, null)); - } - } /** Returns null if SIM is not yet ready */ - public String getIMSI() - { + public String getIMSI() { return imsi; } - public String getMsisdnNumber() - { + public String getMsisdnNumber() { return msisdn; } @@ -272,28 +266,18 @@ public final class SIMRecords extends Handler implements SimConstants return msisdnTag; } - public String getVoiceMailNumber() - { + public String getVoiceMailNumber() { return voiceMailNum; } /** - * Return Service Provider Name stored in SIM - * @return null if SIM is not yet ready - */ - String getServiceProviderName() - { - return spn; - } - - /** * Set voice mail number to SIM record * * The voice mail number can be stored either in EF_MBDN (TS 51.011) or * EF_MAILBOX_CPHS (CPHS 4.2) * * If EF_MBDN is available, store the voice mail number to EF_MBDN - * + * * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS * * So the voice mail number will be stored in both EFs if both are available @@ -314,7 +298,7 @@ public final class SIMRecords extends Handler implements SimConstants Message onComplete) { if (isVoiceMailFixed) { AsyncResult.forMessage((onComplete)).exception = - new SimVmFixedException("Voicemail number is fixed by operator"); + new IccVmFixedException("Voicemail number is fixed by operator"); onComplete.sendToTarget(); return; } @@ -336,9 +320,9 @@ public final class SIMRecords extends Handler implements SimConstants EF_EXT1, 1, null, obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE, onComplete)); - }else { + } else { AsyncResult.forMessage((onComplete)).exception = - new SimVmNotSupportedException("Update SIM voice mailbox error"); + new IccVmNotSupportedException("Update SIM voice mailbox error"); onComplete.sendToTarget(); } } @@ -352,12 +336,11 @@ public final class SIMRecords extends Handler implements SimConstants * Sets the SIM voice message waiting indicator records * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported * @param countWaiting The number of messages waiting, if known. Use - * -1 to indicate that an unknown number of + * -1 to indicate that an unknown number of * messages are waiting */ public void - setVoiceMessageWaiting(int line, int countWaiting) - { + setVoiceMessageWaiting(int line, int countWaiting) { if (line != 1) { // only profile 1 is supported return; @@ -374,14 +357,14 @@ public final class SIMRecords extends Handler implements SimConstants countVoiceMessages = countWaiting; - phone.notifyMessageWaitingIndicator(); + ((GSMPhone) phone).notifyMessageWaitingIndicator(); try { if (efMWIS != null) { // TS 51.011 10.3.45 // lsb of byte 0 is 'voicemail' status - efMWIS[0] = (byte)((efMWIS[0] & 0xfe) + efMWIS[0] = (byte)((efMWIS[0] & 0xfe) | (countVoiceMessages == 0 ? 0 : 1)); // byte 1 is the number of voice messages waiting @@ -393,17 +376,17 @@ public final class SIMRecords extends Handler implements SimConstants efMWIS[1] = (byte) countWaiting; } - phone.mSIMFileHandler.updateEFLinearFixed( + phone.getIccFileHandler().updateEFLinearFixed( EF_MWIS, 1, efMWIS, null, obtainMessage (EVENT_UPDATE_DONE, EF_MWIS)); - } + } if (efCPHS_MWI != null) { // Refer CPHS4_2.WW6 B4.2.3 - efCPHS_MWI[0] = (byte)((efCPHS_MWI[0] & 0xf0) + efCPHS_MWI[0] = (byte)((efCPHS_MWI[0] & 0xf0) | (countVoiceMessages == 0 ? 0x5 : 0xa)); - phone.mSIMFileHandler.updateEFTransparent( + phone.getIccFileHandler().updateEFTransparent( EF_VOICE_MAIL_INDICATOR_CPHS, efCPHS_MWI, obtainMessage (EVENT_UPDATE_DONE, EF_VOICE_MAIL_INDICATOR_CPHS)); } @@ -413,22 +396,6 @@ public final class SIMRecords extends Handler implements SimConstants } } - /** @return true if there are messages waiting, false otherwise. */ - public boolean getVoiceMessageWaiting() - { - return countVoiceMessages != 0; - } - - /** - * Returns number of voice messages waiting, if available - * If not available (eg, on an older CPHS SIM) -1 is returned if - * getVoiceMessageWaiting() is true - */ - public int getCountVoiceMessages() - { - return countVoiceMessages; - } - public boolean getVoiceCallForwardingFlag() { return callForwardingEnabled; } @@ -439,7 +406,7 @@ public final class SIMRecords extends Handler implements SimConstants callForwardingEnabled = enable; - phone.notifyCallForwardingIndicator(); + ((GSMPhone) phone).notifyCallForwardingIndicator(); try { if (mEfCfis != null) { @@ -453,7 +420,7 @@ public final class SIMRecords extends Handler implements SimConstants // TODO: Should really update other fields in EF_CFIS, eg, // dialing number. We don't read or use it right now. - phone.mSIMFileHandler.updateEFLinearFixed( + phone.getIccFileHandler().updateEFLinearFixed( EF_CFIS, 1, mEfCfis, null, obtainMessage (EVENT_UPDATE_DONE, EF_CFIS)); } @@ -467,7 +434,7 @@ public final class SIMRecords extends Handler implements SimConstants | CFF_UNCONDITIONAL_DEACTIVE); } - phone.mSIMFileHandler.updateEFTransparent( + phone.getIccFileHandler().updateEFTransparent( EF_CFF_CPHS, mEfCff, obtainMessage (EVENT_UPDATE_DONE, EF_CFF_CPHS)); } @@ -496,8 +463,7 @@ public final class SIMRecords extends Handler implements SimConstants /** Returns the 5 or 6 digit MCC/MNC of the operator that * provided the SIM card. Returns null of SIM is not yet ready */ - String getSIMOperatorNumeric() - { + String getSIMOperatorNumeric() { if (imsi == null) { return null; } @@ -517,17 +483,8 @@ public final class SIMRecords extends Handler implements SimConstants return imsi.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc)); } - - boolean getRecordsLoaded() - { - if (recordsToLoad == 0 && recordsRequested == true) { - return true; - } else { - return false; - } - } - - /** + + /** * If the timezone is not already set, set it based on the MCC of the SIM. * @param mcc Mobile Country Code of the SIM */ @@ -557,8 +514,7 @@ public final class SIMRecords extends Handler implements SimConstants } //***** Overridden from Handler - public void handleMessage(Message msg) - { + public void handleMessage(Message msg) { AsyncResult ar; AdnRecord adn; @@ -573,19 +529,19 @@ public final class SIMRecords extends Handler implements SimConstants case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: onRadioOffOrNotAvailable(); - break; + break; /* IO events */ case EVENT_GET_IMSI_DONE: isRecordLoadResponse = true; - + ar = (AsyncResult)msg.obj; if (ar.exception != null) { Log.e(LOG_TAG, "Exception querying IMSI, Exception:" + ar.exception); break; - } - + } + imsi = (String) ar.result; // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more @@ -594,11 +550,11 @@ public final class SIMRecords extends Handler implements SimConstants Log.e(LOG_TAG, "invalid IMSI " + imsi); imsi = null; } - + Log.d(LOG_TAG, "IMSI: " + imsi.substring(0, 6) + "xxxxxxxxx"); - phone.mSimCard.updateImsiConfiguration(imsi); - phone.mSimCard.broadcastSimStateChangedIntent( - SimCard.INTENT_VALUE_SIM_IMSI, null); + ((GSMPhone) phone).mSimCard.updateImsiConfiguration(imsi); + ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent( + SimCard.INTENT_VALUE_ICC_IMSI, null); int mcc = Integer.parseInt(imsi.substring(0, 3)); setTimezoneFromMccIfNeeded(mcc); @@ -616,7 +572,7 @@ public final class SIMRecords extends Handler implements SimConstants if (ar.exception == null) { // Refer TS 51.011 Section 10.3.44 for content details Log.d(LOG_TAG, "EF_MBI: " + - SimUtils.bytesToHexString(data)); + IccUtils.bytesToHexString(data)); // Voice mail record number stored first mailboxIndex = (int)data[0] & 0xff; @@ -651,20 +607,20 @@ public final class SIMRecords extends Handler implements SimConstants ar = (AsyncResult)msg.obj; if (ar.exception != null) { - - Log.d(LOG_TAG, "Invalid or missing EF" + + Log.d(LOG_TAG, "Invalid or missing EF" + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? "[MAILBOX]" : "[MBDN]")); // Bug #645770 fall back to CPHS // FIXME should use SST to decide if (msg.what == EVENT_GET_MBDN_DONE) { - //load CPHS on fail... + //load CPHS on fail... // FIXME right now, only load line1's CPHS voice mail entry recordsToLoad += 1; new AdnRecordLoader(phone).loadFromEF( - EF_MAILBOX_CPHS, EF_EXT1, 1, + EF_MAILBOX_CPHS, EF_EXT1, 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); } break; @@ -672,7 +628,8 @@ public final class SIMRecords extends Handler implements SimConstants adn = (AdnRecord)ar.result; - Log.d(LOG_TAG, "VM: " + adn + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? " EF[MAILBOX]" : " EF[MBDN]")); + Log.d(LOG_TAG, "VM: " + adn + + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? " EF[MAILBOX]" : " EF[MBDN]")); if (adn.isEmpty() && msg.what == EVENT_GET_MBDN_DONE) { // Bug #645770 fall back to CPHS @@ -680,7 +637,7 @@ public final class SIMRecords extends Handler implements SimConstants // FIXME right now, only load line1's CPHS voice mail entry recordsToLoad += 1; new AdnRecordLoader(phone).loadFromEF( - EF_MAILBOX_CPHS, EF_EXT1, 1, + EF_MAILBOX_CPHS, EF_EXT1, 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); break; @@ -730,7 +687,7 @@ public final class SIMRecords extends Handler implements SimConstants } Log.d(LOG_TAG, "EF_MWIS: " + - SimUtils.bytesToHexString(data)); + IccUtils.bytesToHexString(data)); efMWIS = data; @@ -744,11 +701,11 @@ public final class SIMRecords extends Handler implements SimConstants countVoiceMessages = data[1] & 0xff; if (voiceMailWaiting && countVoiceMessages == 0) { - // Unknown count = -1 + // Unknown count = -1 countVoiceMessages = -1; } - phone.notifyMessageWaitingIndicator(); + ((GSMPhone) phone).notifyMessageWaitingIndicator(); break; case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE: @@ -777,7 +734,7 @@ public final class SIMRecords extends Handler implements SimConstants countVoiceMessages = 0; } - phone.notifyMessageWaitingIndicator(); + ((GSMPhone) phone).notifyMessageWaitingIndicator(); } break; @@ -786,13 +743,13 @@ public final class SIMRecords extends Handler implements SimConstants ar = (AsyncResult)msg.obj; data = (byte[])ar.result; - + if (ar.exception != null) { break; - } + } + + iccid = IccUtils.bcdToString(data, 0, data.length); - iccid = SimUtils.bcdToString(data, 0, data.length); - Log.d(LOG_TAG, "iccid: " + iccid); break; @@ -809,7 +766,7 @@ public final class SIMRecords extends Handler implements SimConstants } Log.d(LOG_TAG, "EF_AD: " + - SimUtils.bytesToHexString(data)); + IccUtils.bytesToHexString(data)); if (data.length < 3) { Log.d(LOG_TAG, "SIMRecords: Corrupt AD data on SIM"); @@ -851,14 +808,14 @@ public final class SIMRecords extends Handler implements SimConstants } Log.d(LOG_TAG, "EF_CFF_CPHS: " + - SimUtils.bytesToHexString(data)); + IccUtils.bytesToHexString(data)); mEfCff = data; if (mEfCfis == null) { callForwardingEnabled = ((data[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE); - phone.notifyCallForwardingIndicator(); + ((GSMPhone) phone).notifyCallForwardingIndicator(); } break; @@ -872,7 +829,7 @@ public final class SIMRecords extends Handler implements SimConstants break; } - parseEfSpdi(data); + parseEfSpdi(data); break; case EVENT_UPDATE_DONE: @@ -896,8 +853,8 @@ public final class SIMRecords extends Handler implements SimConstants for ( ; tlv.isValidObject() ; tlv.nextObject()) { if (tlv.getTag() == TAG_FULL_NETWORK_NAME) { - pnnHomeName - = SimUtils.networkNameToString( + pnnHomeName + = IccUtils.networkNameToString( tlv.getData(), 0, tlv.getData().length); break; } @@ -931,7 +888,8 @@ public final class SIMRecords extends Handler implements SimConstants + ar.exception + " length " + index.length); } else { Log.d(LOG_TAG, "READ EF_SMS RECORD index=" + index[0]); - phone.mSIMFileHandler.loadEFLinearFixed(EF_SMS,index[0],obtainMessage(EVENT_GET_SMS_DONE)); + phone.getIccFileHandler().loadEFLinearFixed(EF_SMS,index[0], + obtainMessage(EVENT_GET_SMS_DONE)); } break; @@ -955,7 +913,7 @@ public final class SIMRecords extends Handler implements SimConstants break; } - //Log.d(LOG_TAG, "SST: " + SimUtils.bytesToHexString(data)); + //Log.d(LOG_TAG, "SST: " + IccUtils.bytesToHexString(data)); break; case EVENT_GET_INFO_CPHS_DONE: @@ -969,7 +927,7 @@ public final class SIMRecords extends Handler implements SimConstants mCphsInfo = (byte[])ar.result; - if (DBG) log("iCPHS: " + SimUtils.bytesToHexString(mCphsInfo)); + if (DBG) log("iCPHS: " + IccUtils.bytesToHexString(mCphsInfo)); break; case EVENT_SET_MBDN_DONE: @@ -1050,20 +1008,20 @@ public final class SIMRecords extends Handler implements SimConstants } Log.d(LOG_TAG, "EF_CFIS: " + - SimUtils.bytesToHexString(data)); + IccUtils.bytesToHexString(data)); mEfCfis = data; // Refer TS 51.011 Section 10.3.46 for the content description callForwardingEnabled = ((data[1] & 0x01) != 0); - phone.notifyCallForwardingIndicator(); + ((GSMPhone) phone).notifyCallForwardingIndicator(); break; }}catch (RuntimeException exc) { // I don't want these exceptions to be fatal Log.w(LOG_TAG, "Exception parsing SIM record", exc); - } finally { + } finally { // Count up record load responses even if they are fails if (isRecordLoadResponse) { onRecordLoaded(); @@ -1076,12 +1034,12 @@ public final class SIMRecords extends Handler implements SimConstants case EF_MBDN: recordsToLoad++; new AdnRecordLoader(phone).loadFromEF(EF_MBDN, EF_EXT6, - mailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE)); + mailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE)); break; case EF_MAILBOX_CPHS: recordsToLoad++; new AdnRecordLoader(phone).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1, - 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); + 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); break; default: // For now, fetch all records if this is not a @@ -1093,7 +1051,7 @@ public final class SIMRecords extends Handler implements SimConstants } } - private void handleSimRefresh(int[] result) { + private void handleSimRefresh(int[] result) { if (result == null || result.length == 0) { if (DBG) log("handleSimRefresh without input"); return; @@ -1102,7 +1060,7 @@ public final class SIMRecords extends Handler implements SimConstants switch ((result[0])) { case CommandsInterface.SIM_REFRESH_FILE_UPDATED: if (DBG) log("handleSimRefresh with SIM_REFRESH_FILE_UPDATED"); - // result[1] contains the EFID of the updated file. + // result[1] contains the EFID of the updated file. int efid = result[1]; handleFileUpdate(efid); break; @@ -1130,8 +1088,7 @@ public final class SIMRecords extends Handler implements SimConstants } } - private void handleSms(byte[] ba) - { + private void handleSms(byte[] ba) { if (ba[0] != 0) Log.d("ENF", "status : " + ba[0]); @@ -1145,12 +1102,13 @@ public final class SIMRecords extends Handler implements SimConstants byte[] nba = new byte[n - 1]; System.arraycopy(ba, 1, nba, 0, n - 1); - String pdu = SimUtils.bytesToHexString(nba); + String pdu = IccUtils.bytesToHexString(nba); // XXX first line is bogus SmsMessage message = SmsMessage.newFromCMT( new String[] { "", pdu }); - phone.mSMS.dispatchMessage(message); + + ((GSMPhone) phone).mSMS.dispatchMessage(message); } } @@ -1175,12 +1133,13 @@ public final class SIMRecords extends Handler implements SimConstants byte[] nba = new byte[n - 1]; System.arraycopy(ba, 1, nba, 0, n - 1); - String pdu = SimUtils.bytesToHexString(nba); + String pdu = IccUtils.bytesToHexString(nba); // XXX first line is bogus SmsMessage message = SmsMessage.newFromCMT( new String[] { "", pdu }); - phone.mSMS.dispatchMessage(message); + + ((GSMPhone) phone).mSMS.dispatchMessage(message); // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 // 1 == "received by MS from network; message read" @@ -1188,18 +1147,14 @@ public final class SIMRecords extends Handler implements SimConstants ba[0] = 1; if (false) { // XXX writing seems to crash RdoServD - phone.mSIMFileHandler.updateEFLinearFixed(EF_SMS, i, ba, null, - obtainMessage(EVENT_MARK_SMS_READ_DONE, i)); + phone.getIccFileHandler().updateEFLinearFixed(EF_SMS, + i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i)); } } } } - - //***** Private Methods - - private void onRecordLoaded() - { + protected void onRecordLoaded() { // One record loaded successfully or failed, In either case // we need to update the recordsToLoad count recordsToLoad -= 1; @@ -1211,21 +1166,19 @@ public final class SIMRecords extends Handler implements SimConstants recordsToLoad = 0; } } - - private void onAllRecordsLoaded() - { + + protected void onAllRecordsLoaded() { Log.d(LOG_TAG, "SIMRecords: record load complete"); String operator = getSIMOperatorNumeric(); // Some fields require more than one SIM record to set - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_NUMERIC, operator); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operator); if (imsi != null) { - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ISO_COUNTRY, - MccTable.countryCodeForMcc( - Integer.parseInt(imsi.substring(0,3)))); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, + MccTable.countryCodeForMcc(Integer.parseInt(imsi.substring(0,3)))); } else { Log.e("SIM", "[SIMRecords] onAllRecordsLoaded: imsi is NULL!"); @@ -1236,16 +1189,19 @@ public final class SIMRecords extends Handler implements SimConstants recordsLoadedRegistrants.notifyRegistrants( new AsyncResult(null, null, null)); - phone.mSimCard.broadcastSimStateChangedIntent( - SimCard.INTENT_VALUE_SIM_LOADED, null); + ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent( + SimCard.INTENT_VALUE_ICC_LOADED, null); } + //***** Private methods + private void setSpnFromConfig(String carrier) { if (mSpnOverride.containsCarrier(carrier)) { spn = mSpnOverride.getSpn(carrier); } } + private void setVoiceMailByCountry (String spn) { if (mVmConfig.containsCarrier(spn)) { isVoiceMailFixed = true; @@ -1258,22 +1214,22 @@ public final class SIMRecords extends Handler implements SimConstants /* broadcast intent SIM_READY here so that we can make sure READY is sent before IMSI ready */ - phone.mSimCard.broadcastSimStateChangedIntent( - SimCard.INTENT_VALUE_SIM_READY, null); + ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent( + SimCard.INTENT_VALUE_ICC_READY, null); fetchSimRecords(); } private void fetchSimRecords() { recordsRequested = true; + IccFileHandler iccFh = phone.getIccFileHandler(); - Log.v(LOG_TAG, "SIMRecords:fetchSimRecords " + recordsToLoad); + Log.v(LOG_TAG, "SIMRecords:fetchSimRecords " + recordsToLoad); phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE)); recordsToLoad++; - phone.mSIMFileHandler.loadEFTransparent(EF_ICCID, - obtainMessage(EVENT_GET_ICCID_DONE)); + iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE)); recordsToLoad++; // FIXME should examine EF[MSISDN]'s capability configuration @@ -1283,17 +1239,14 @@ public final class SIMRecords extends Handler implements SimConstants recordsToLoad++; // Record number is subscriber profile - phone.mSIMFileHandler.loadEFLinearFixed(EF_MBI, 1, - obtainMessage(EVENT_GET_MBI_DONE)); + iccFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE)); recordsToLoad++; - phone.mSIMFileHandler.loadEFTransparent(EF_AD, - obtainMessage(EVENT_GET_AD_DONE)); + iccFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE)); recordsToLoad++; // Record number is subscriber profile - phone.mSIMFileHandler.loadEFLinearFixed(EF_MWIS, 1, - obtainMessage(EVENT_GET_MWIS_DONE)); + iccFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE)); recordsToLoad++; @@ -1301,50 +1254,49 @@ public final class SIMRecords extends Handler implements SimConstants // the same info as EF[MWIS]. If both exist, both are updated // but the EF[MWIS] data is preferred // Please note this must be loaded after EF[MWIS] - phone.mSIMFileHandler.loadEFTransparent( - EF_VOICE_MAIL_INDICATOR_CPHS, + iccFh.loadEFTransparent( + EF_VOICE_MAIL_INDICATOR_CPHS, obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE)); recordsToLoad++; // Same goes for Call Forward Status indicator: fetch both // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred. - phone.mSIMFileHandler.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE)); + iccFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE)); recordsToLoad++; - phone.mSIMFileHandler.loadEFTransparent(EF_CFF_CPHS, - obtainMessage(EVENT_GET_CFF_DONE)); + iccFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE)); recordsToLoad++; getSpnFsm(true, null); - phone.mSIMFileHandler.loadEFTransparent(EF_SPDI, - obtainMessage(EVENT_GET_SPDI_DONE)); + iccFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE)); recordsToLoad++; - phone.mSIMFileHandler.loadEFLinearFixed(EF_PNN, 1, - obtainMessage(EVENT_GET_PNN_DONE)); + iccFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE)); recordsToLoad++; - phone.mSIMFileHandler.loadEFTransparent(EF_SST, - obtainMessage(EVENT_GET_SST_DONE)); + iccFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE)); recordsToLoad++; - phone.mSIMFileHandler.loadEFTransparent(EF_INFO_CPHS, - obtainMessage(EVENT_GET_INFO_CPHS_DONE)); + iccFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE)); recordsToLoad++; // XXX should seek instead of examining them all if (false) { // XXX - phone.mSIMFileHandler.loadEFLinearFixedAll(EF_SMS, - obtainMessage(EVENT_GET_ALL_SMS_DONE)); + iccFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE)); recordsToLoad++; } if (CRASH_RIL) { - String sms = "0107912160130310f20404d0110041007030208054832b0120ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; - byte[] ba = SimUtils.hexStringToBytes(sms); - - phone.mSIMFileHandler.updateEFLinearFixed(EF_SMS, 1, ba, null, + String sms = "0107912160130310f20404d0110041007030208054832b0120" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffffffffffffffff"; + byte[] ba = IccUtils.hexStringToBytes(sms); + + iccFh.updateEFLinearFixed(EF_SMS, 1, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, 1)); } } @@ -1356,7 +1308,7 @@ public final class SIMRecords extends Handler implements SimConstants * * If the SPN is not found on the SIM, the rule is always PLMN_ONLY. */ - int getDisplayRule(String plmn) { + protected int getDisplayRule(String plmn) { int rule; if (spn == null || spnDisplayCondition == -1) { // EF_SPN was not found on the SIM, or not yet loaded. Just show ONS. @@ -1431,7 +1383,7 @@ public final class SIMRecords extends Handler implements SimConstants case INIT: spn = null; - phone.mSIMFileHandler.loadEFTransparent( EF_SPN, + phone.getIccFileHandler().loadEFTransparent( EF_SPN, obtainMessage(EVENT_GET_SPN_DONE)); recordsToLoad++; @@ -1441,20 +1393,20 @@ public final class SIMRecords extends Handler implements SimConstants if (ar != null && ar.exception == null) { data = (byte[]) ar.result; spnDisplayCondition = 0xff & data[0]; - spn = SimUtils.adnStringFieldToString(data, 1, data.length - 1); + spn = IccUtils.adnStringFieldToString(data, 1, data.length - 1); if (DBG) log("Load EF_SPN: " + spn + " spnDisplayCondition: " + spnDisplayCondition); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, spn); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn); spnState = Get_Spn_Fsm_State.IDLE; } else { - phone.mSIMFileHandler.loadEFTransparent( EF_SPN_CPHS, + phone.getIccFileHandler().loadEFTransparent( EF_SPN_CPHS, obtainMessage(EVENT_GET_SPN_DONE)); recordsToLoad++; spnState = Get_Spn_Fsm_State.READ_SPN_CPHS; - + // See TS 51.011 10.3.11. Basically, default to // show PLMN always, and SPN also if roaming. spnDisplayCondition = -1; @@ -1463,16 +1415,16 @@ public final class SIMRecords extends Handler implements SimConstants case READ_SPN_CPHS: if (ar != null && ar.exception == null) { data = (byte[]) ar.result; - spn = SimUtils.adnStringFieldToString( + spn = IccUtils.adnStringFieldToString( data, 0, data.length - 1 ); if (DBG) log("Load EF_SPN_CPHS: " + spn); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, spn); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn); spnState = Get_Spn_Fsm_State.IDLE; } else { - phone.mSIMFileHandler.loadEFTransparent( EF_SPN_SHORT_CPHS, - obtainMessage(EVENT_GET_SPN_DONE)); + phone.getIccFileHandler().loadEFTransparent( + EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE)); recordsToLoad++; spnState = Get_Spn_Fsm_State.READ_SPN_SHORT_CPHS; @@ -1481,11 +1433,11 @@ public final class SIMRecords extends Handler implements SimConstants case READ_SPN_SHORT_CPHS: if (ar != null && ar.exception == null) { data = (byte[]) ar.result; - spn = SimUtils.adnStringFieldToString( + spn = IccUtils.adnStringFieldToString( data, 0, data.length - 1); if (DBG) log("Load EF_SPN_SHORT_CPHS: " + spn); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, spn); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn); }else { if (DBG) log("No SPN loaded in either CHPS or 3GPP"); } @@ -1503,8 +1455,7 @@ public final class SIMRecords extends Handler implements SimConstants * are treated specially when determining SPN display */ private void - parseEfSpdi(byte[] data) - { + parseEfSpdi(byte[] data) { SimTlv tlv = new SimTlv(data, 0, data.length); byte[] plmnEntries = null; @@ -1524,8 +1475,8 @@ public final class SIMRecords extends Handler implements SimConstants spdiNetworks = new ArrayList<String>(plmnEntries.length / 3); for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) { - String plmnCode; - plmnCode = SimUtils.bcdToString(plmnEntries, i, 3); + String plmnCode; + plmnCode = IccUtils.bcdToString(plmnEntries, i, 3); // Valid operator codes are 5 or 6 digits if (plmnCode.length() >= 5) { @@ -1543,7 +1494,11 @@ public final class SIMRecords extends Handler implements SimConstants return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED ); } - private void log(String s) { + protected void log(String s) { Log.d(LOG_TAG, "[SIMRecords] " + s); } + } + + + diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java index a4cded9..9af3aa6 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmSimCard.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java @@ -16,6 +16,9 @@ package com.android.internal.telephony.gsm; +import android.app.ActivityManagerNative; +import android.content.Intent; +import android.content.res.Configuration; import android.os.AsyncResult; import android.os.RemoteException; import android.os.Handler; @@ -23,32 +26,34 @@ import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; import android.util.Log; -import com.android.internal.telephony.SimCard; -import com.android.internal.telephony.TelephonyProperties; + +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.IccCard; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.TelephonyIntents; -import android.content.Intent; -import android.content.res.Configuration; -import android.app.ActivityManagerNative; +import com.android.internal.telephony.TelephonyProperties; import static android.Manifest.permission.READ_PHONE_STATE; /** + * Note: this class shares common code with RuimCard, consider a base class to minimize code + * duplication. * {@hide} */ -public final class GsmSimCard extends Handler implements SimCard { +public final class SimCard extends Handler implements IccCard { static final String LOG_TAG="GSM"; - + //***** Instance Variables private static final boolean DBG = true; private GSMPhone phone; - private CommandsInterface.SimStatus status = null; + private CommandsInterface.IccStatus status = null; + private boolean mDesiredPinLocked; + private boolean mDesiredFdnEnabled; private boolean mSimPinLocked = true; // Default to locked private boolean mSimFdnEnabled = false; // Default to disabled. // Will be updated when SIM_READY. - private boolean mDesiredPinLocked; - private boolean mDesiredFdnEnabled; //***** Constants @@ -72,8 +77,7 @@ public final class GsmSimCard extends Handler implements SimCard { //***** Constructor - GsmSimCard(GSMPhone phone) - { + SimCard(GSMPhone phone) { this.phone = phone; phone.mCM.registerForSIMLockedOrAbsent( @@ -87,12 +91,22 @@ public final class GsmSimCard extends Handler implements SimCard { updateStateProperty(); } - + + public void dispose() { + //Unregister for all events + phone.mCM.unregisterForSIMLockedOrAbsent(this); + phone.mCM.unregisterForOffOrNotAvailable(this); + phone.mCM.unregisterForSIMReady(this); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "SimCard finalized"); + } + //***** SimCard implementation public State - getState() - { + getState() { if (status == null) { switch(phone.mCM.getRadioState()) { /* This switch block must not return anything in @@ -111,12 +125,12 @@ public final class GsmSimCard extends Handler implements SimCard { } } else { switch (status) { - case SIM_ABSENT: return State.ABSENT; - case SIM_NOT_READY: return State.UNKNOWN; - case SIM_READY: return State.READY; - case SIM_PIN: return State.PIN_REQUIRED; - case SIM_PUK: return State.PUK_REQUIRED; - case SIM_NETWORK_PERSONALIZATION: return State.NETWORK_LOCKED; + case ICC_ABSENT: return State.ABSENT; + case ICC_NOT_READY: return State.UNKNOWN; + case ICC_READY: return State.READY; + case ICC_PIN: return State.PIN_REQUIRED; + case ICC_PUK: return State.PUK_REQUIRED; + case ICC_NETWORK_PERSONALIZATION: return State.NETWORK_LOCKED; } } @@ -129,8 +143,7 @@ public final class GsmSimCard extends Handler implements SimCard { private RegistrantList networkLockedRegistrants = new RegistrantList(); - public void registerForAbsent(Handler h, int what, Object obj) - { + public void registerForAbsent(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); absentRegistrants.add(r); @@ -139,9 +152,9 @@ public final class GsmSimCard extends Handler implements SimCard { r.notifyRegistrant(); } } - + public void unregisterForAbsent(Handler h) { - absentRegistrants.remove(h); + absentRegistrants.remove(h); } public void registerForNetworkLocked(Handler h, int what, Object obj) { @@ -155,11 +168,10 @@ public final class GsmSimCard extends Handler implements SimCard { } public void unregisterForNetworkLocked(Handler h) { - networkLockedRegistrants.remove(h); + networkLockedRegistrants.remove(h); } - - public void registerForLocked(Handler h, int what, Object obj) - { + + public void registerForLocked(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); pinLockedRegistrants.add(r); @@ -169,50 +181,44 @@ public final class GsmSimCard extends Handler implements SimCard { } } - public void unregisterForLocked(Handler h) - { + public void unregisterForLocked(Handler h) { pinLockedRegistrants.remove(h); } - public void supplyPin (String pin, Message onComplete) - { - phone.mCM.supplySimPin(pin, + public void supplyPin (String pin, Message onComplete) { + phone.mCM.supplyIccPin(pin, obtainMessage(EVENT_PINPUK_DONE, onComplete)); } - public void supplyPuk (String puk, String newPin, Message onComplete) - { - phone.mCM.supplySimPuk(puk, newPin, + public void supplyPuk (String puk, String newPin, Message onComplete) { + phone.mCM.supplyIccPuk(puk, newPin, obtainMessage(EVENT_PINPUK_DONE, onComplete)); } - public void supplyPin2 (String pin2, Message onComplete) - { - phone.mCM.supplySimPin2(pin2, + public void supplyPin2 (String pin2, Message onComplete) { + phone.mCM.supplyIccPin2(pin2, obtainMessage(EVENT_PINPUK_DONE, onComplete)); } - public void supplyPuk2 (String puk2, String newPin2, Message onComplete) - { - phone.mCM.supplySimPuk2(puk2, newPin2, + public void supplyPuk2 (String puk2, String newPin2, Message onComplete) { + phone.mCM.supplyIccPuk2(puk2, newPin2, obtainMessage(EVENT_PINPUK_DONE, onComplete)); } - public void supplyNetworkDepersonalization (String pin, Message onComplete) - { + public void supplyNetworkDepersonalization (String pin, Message onComplete) { if(DBG) log("Network Despersonalization: " + pin); phone.mCM.supplyNetworkDepersonalization(pin, obtainMessage(EVENT_PINPUK_DONE, onComplete)); } - public boolean getSimLockEnabled() { + public boolean getIccLockEnabled() { return mSimPinLocked; } - public boolean getSimFdnEnabled() { + public boolean getIccFdnEnabled() { return mSimFdnEnabled; } - public void setSimLockEnabled (boolean enabled, + public void setIccLockEnabled (boolean enabled, String password, Message onComplete) { int serviceClassX; serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + @@ -226,7 +232,7 @@ public final class GsmSimCard extends Handler implements SimCard { obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete)); } - public void setSimFdnEnabled (boolean enabled, + public void setIccFdnEnabled (boolean enabled, String password, Message onComplete) { int serviceClassX; serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + @@ -241,18 +247,18 @@ public final class GsmSimCard extends Handler implements SimCard { obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete)); } - public void changeSimLockPassword(String oldPassword, String newPassword, + public void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete) { if(DBG) log("Change Pin1 old: " + oldPassword + " new: " + newPassword); - phone.mCM.changeSimPin(oldPassword, newPassword, + phone.mCM.changeIccPin(oldPassword, newPassword, obtainMessage(EVENT_CHANGE_SIM_PASSWORD_DONE, onComplete)); } - public void changeSimFdnPassword(String oldPassword, String newPassword, + public void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete) { if(DBG) log("Change Pin2 old: " + oldPassword + " new: " + newPassword); - phone.mCM.changeSimPin2(oldPassword, newPassword, + phone.mCM.changeIccPin2(oldPassword, newPassword, obtainMessage(EVENT_CHANGE_SIM_PASSWORD_DONE, onComplete)); } @@ -275,11 +281,11 @@ public final class GsmSimCard extends Handler implements SimCard { case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: status = null; updateStateProperty(); - broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_SIM_NOT_READY, null); + broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_NOT_READY, null); break; case EVENT_SIM_READY: //TODO: put facility read in SIM_READY now, maybe in REG_NW - phone.mCM.getSimStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE)); + phone.mCM.getIccStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE)); phone.mCM.queryFacilityLock ( CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); @@ -288,7 +294,7 @@ public final class GsmSimCard extends Handler implements SimCard { obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE)); break; case EVENT_SIM_LOCKED_OR_ABSENT: - phone.mCM.getSimStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE)); + phone.mCM.getIccStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE)); phone.mCM.queryFacilityLock ( CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); @@ -306,7 +312,7 @@ public final class GsmSimCard extends Handler implements SimCard { // TODO should abstract these exceptions AsyncResult.forMessage(((Message)ar.userObj)).exception = ar.exception; - phone.mCM.getSimStatus( + phone.mCM.getIccStatus( obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj)); break; case EVENT_REPOLL_STATUS_DONE: @@ -415,24 +421,24 @@ public final class GsmSimCard extends Handler implements SimCard { private void getSimStatusDone(AsyncResult ar) { if (ar.exception != null) { - Log.e(LOG_TAG,"Error getting SIM status. " - + "RIL_REQUEST_GET_SIM_STATUS should " + Log.e(LOG_TAG,"Error getting ICC status. " + + "RIL_REQUEST_GET_ICC_STATUS should " + "never return an error", ar.exception); return; } - CommandsInterface.SimStatus newStatus - = (CommandsInterface.SimStatus) ar.result; + CommandsInterface.IccStatus newStatus + = (CommandsInterface.IccStatus) ar.result; handleSimStatus(newStatus); } private void - handleSimStatus(CommandsInterface.SimStatus newStatus) { + handleSimStatus(CommandsInterface.IccStatus newStatus) { boolean transitionedIntoPinLocked; boolean transitionedIntoAbsent; boolean transitionedIntoNetworkLocked; - + SimCard.State oldState, newState; oldState = getState(); @@ -451,17 +457,17 @@ public final class GsmSimCard extends Handler implements SimCard { if (transitionedIntoPinLocked) { if(DBG) log("Notify SIM pin or puk locked."); pinLockedRegistrants.notifyRegistrants(); - broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_SIM_LOCKED, + broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_LOCKED, (newState == State.PIN_REQUIRED) ? INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK); } else if (transitionedIntoAbsent) { if(DBG) log("Notify SIM missing."); absentRegistrants.notifyRegistrants(); - broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_SIM_ABSENT, null); + broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_ABSENT, null); } else if (transitionedIntoNetworkLocked) { if(DBG) log("Notify SIM network locked."); networkLockedRegistrants.notifyRegistrants(); - broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_SIM_LOCKED, + broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_LOCKED, INTENT_VALUE_LOCKED_NETWORK); } } @@ -469,7 +475,7 @@ public final class GsmSimCard extends Handler implements SimCard { public void broadcastSimStateChangedIntent(String value, String reason) { Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); intent.putExtra(Phone.PHONE_NAME_KEY, phone.getPhoneName()); - intent.putExtra(SimCard.INTENT_KEY_SIM_STATE, value); + intent.putExtra(SimCard.INTENT_KEY_ICC_STATE, value); intent.putExtra(SimCard.INTENT_KEY_LOCKED_REASON, reason); if(DBG) log("Broadcasting intent SIM_STATE_CHANGED_ACTION " + value + " reason " + reason); diff --git a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java index 7cc9a80..076da6b 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java @@ -25,6 +25,11 @@ import android.os.ServiceManager; import android.telephony.PhoneNumberUtils; import android.util.Log; +import com.android.internal.telephony.AdnRecord; +import com.android.internal.telephony.AdnRecordCache; +import com.android.internal.telephony.IccPhoneBookInterfaceManager; +import com.android.internal.telephony.PhoneProxy; + import java.util.ArrayList; import java.util.List; @@ -32,247 +37,65 @@ import java.util.List; * SimPhoneBookInterfaceManager to provide an inter-process communication to * access ADN-like SIM records. */ -public class SimPhoneBookInterfaceManager extends ISimPhoneBook.Stub { - static final String LOG_TAG = "GSM"; - static final boolean DBG = false; - private GSMPhone phone; - private AdnRecordCache adnCache; - private final Object mLock = new Object(); - private int recordSize[]; - private boolean success; - private List<AdnRecord> records; - private static final boolean ALLOW_SIM_OP_IN_UI_THREAD = false; +public class SimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager { + static final String LOG_TAG = "GSM"; - private static final int EVENT_GET_SIZE_DONE = 1; - private static final int EVENT_LOAD_DONE = 2; - private static final int EVENT_UPDATE_DONE = 3; Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { AsyncResult ar; - switch (msg.what) { - case EVENT_GET_SIZE_DONE: - ar = (AsyncResult) msg.obj; - synchronized (mLock) { - if (ar.exception == null) { - recordSize = (int[])ar.result; - // recordSize[0] is the record length - // recordSize[1] is the total length of the EF file - // recordSize[2] is the number of records in the EF file - log("GET_RECORD_SIZE Size " + recordSize[0] + - " total " + recordSize[1] + - " #record " + recordSize[2]); - mLock.notifyAll(); - } - } - break; - case EVENT_UPDATE_DONE: - ar = (AsyncResult) msg.obj; - synchronized (mLock) { - success = (ar.exception == null); - mLock.notifyAll(); - } - break; - case EVENT_LOAD_DONE: - ar = (AsyncResult)msg.obj; - synchronized (mLock) { - if (ar.exception == null) { - records = (List<AdnRecord>) - ((ArrayList<AdnRecord>) ar.result); - } else { - if(DBG) log("Cannot load ADN records"); - if (records != null) { - records.clear(); - } - } - mLock.notifyAll(); - } + switch(msg.what) { + default: + mBaseHandler.handleMessage(msg); break; } } }; public SimPhoneBookInterfaceManager(GSMPhone phone) { - this.phone = phone; + super(phone); adnCache = phone.mSIMRecords.getAdnCache(); - publish(); + //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy } - private void publish() { - ServiceManager.addService("simphonebook", this); + public void dispose() { + super.dispose(); } - /** - * Replace oldAdn with newAdn in ADN-like record in EF - * - * getAdnRecordsInEf must be called at least once before this function, - * otherwise an error will be returned - * throws SecurityException if no WRITE_CONTACTS permission - * - * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN - * @param oldTag adn tag to be replaced - * @param oldPhoneNumber adn number to be replaced - * Set both oldTag and oldPhoneNubmer to "" means to replace an - * empty record, aka, insert new record - * @param newTag adn tag to be stored - * @param newPhoneNumber adn number ot be stored - * Set both newTag and newPhoneNubmer to "" means to replace the old - * record with empty one, aka, delete old record - * @param pin2 required to update EF_FDN, otherwise must be null - * @return true for success - */ - public boolean - updateAdnRecordsInEfBySearch (int efid, - String oldTag, String oldPhoneNumber, - String newTag, String newPhoneNumber, String pin2) { - - - if (phone.getContext().checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_CONTACTS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException( - "Requires android.permission.WRITE_CONTACTS permission"); - } - - - if (DBG) log("updateAdnRecordsInEfBySearch: efid=" + efid + - " ("+ oldTag + "," + oldPhoneNumber + ")"+ "==>" + - " ("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2); - synchronized(mLock) { - checkThread(); - success = false; - Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); - AdnRecord oldAdn = new AdnRecord(oldTag, oldPhoneNumber); - AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber); - adnCache.updateAdnBySearch(efid, oldAdn, newAdn, pin2, response); - try { - mLock.wait(); - } catch (InterruptedException e) { - log("interrupted while trying to update by search"); - } - } - return success; - } - - /** - * Update an ADN-like EF record by record index - * - * This is useful for iteration the whole ADN file, such as write the whole - * phone book or erase/format the whole phonebook - * throws SecurityException if no WRITE_CONTACTS permission - * - * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN - * @param newTag adn tag to be stored - * @param newPhoneNumber adn number to be stored - * Set both newTag and newPhoneNubmer to "" means to replace the old - * record with empty one, aka, delete old record - * @param index is 1-based adn record index to be updated - * @param pin2 required to update EF_FDN, otherwise must be null - * @return true for success - */ - public boolean - updateAdnRecordsInEfByIndex(int efid, String newTag, - String newPhoneNumber, int index, String pin2) { - - if (phone.getContext().checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_CONTACTS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException( - "Requires android.permission.WRITE_CONTACTS permission"); - } - - if (DBG) log("updateAdnRecordsInEfByIndex: efid=" + efid + - " Index=" + index + " ==> " + - "("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2); - synchronized(mLock) { - checkThread(); - success = false; - Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); - AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber); - adnCache.updateAdnByIndex(efid, newAdn, index, pin2, response); - try { - mLock.wait(); - } catch (InterruptedException e) { - log("interrupted while trying to update by index"); - } - } - return success; + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "SimPhoneBookInterfaceManager finalized"); } - /** - * Get the capacity of records in efid - * - * @param efid the EF id of a ADN-like SIM - * @return int[3] array - * recordSizes[0] is the single record length - * recordSizes[1] is the total length of the EF file - * recordSizes[2] is the number of records in the EF file - */ public int[] getAdnRecordsSize(int efid) { - if (DBG) log("getAdnRecordsSize: efid=" + efid); + if (DBG) logd("getAdnRecordsSize: efid=" + efid); synchronized(mLock) { checkThread(); recordSize = new int[3]; - Message response = mHandler.obtainMessage(EVENT_GET_SIZE_DONE); - phone.mSIMFileHandler.getEFLinearRecordSize(efid, response); - try { - mLock.wait(); - } catch (InterruptedException e) { - log("interrupted while trying to load from the SIM"); - } - } - return recordSize; - } + //Using mBaseHandler, no difference in EVENT_GET_SIZE_DONE handling + Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE); - /** - * Loads the AdnRecords in efid and returns them as a - * List of AdnRecords - * - * throws SecurityException if no READ_CONTACTS permission - * - * @param efid the EF id of a ADN-like SIM - * @return List of AdnRecord - */ - public List<AdnRecord> getAdnRecordsInEf(int efid) { - - if (phone.getContext().checkCallingOrSelfPermission( - android.Manifest.permission.READ_CONTACTS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException( - "Requires android.permission.READ_CONTACTS permission"); - } - - if (DBG) log("getAdnRecordsInEF: efid=" + efid); - - synchronized(mLock) { - checkThread(); - Message response = mHandler.obtainMessage(EVENT_LOAD_DONE); - adnCache.requestLoadAllAdnLike(efid, response); + phone.getIccFileHandler().getEFLinearRecordSize(efid, response); try { mLock.wait(); } catch (InterruptedException e) { - log("interrupted while trying to load from the SIM"); + logd("interrupted while trying to load from the SIM"); } } - return records; + + return recordSize; } - private void checkThread() { - if (!ALLOW_SIM_OP_IN_UI_THREAD) { - // Make sure this isn't the UI thread, since it will block - if (mHandler.getLooper().equals(Looper.myLooper())) { - Log.e(LOG_TAG, "query() called on the main UI thread!"); - throw new IllegalStateException("You cannot call query on this provder from the main UI thread."); - } - } + protected void logd(String msg) { + Log.d(LOG_TAG, "[SimPbInterfaceManager] " + msg); } - private void log(String msg) { - Log.d(LOG_TAG, "[SpbInterfaceManager] " + msg); + protected void loge(String msg) { + Log.e(LOG_TAG, "[SimPbInterfaceManager] " + msg); } } + diff --git a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java index c3df0d0..875d8d0 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java @@ -16,27 +16,31 @@ package com.android.internal.telephony.gsm; -import android.app.PendingIntent; import android.content.Context; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; -import android.os.ServiceManager; -import android.telephony.gsm.SmsManager; import android.util.Log; +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.IccSmsInterfaceManager; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.SmsRawData; + import java.util.ArrayList; import java.util.List; +import static android.telephony.SmsManager.STATUS_ON_ICC_FREE; + /** * SimSmsInterfaceManager to provide an inter-process communication to * access Sms in Sim. */ -public class SimSmsInterfaceManager extends ISms.Stub { +public class SimSmsInterfaceManager extends IccSmsInterfaceManager { static final String LOG_TAG = "GSM"; - static final boolean DBG = false; + static final boolean DBG = true; - private GSMPhone mPhone; private final Object mLock = new Object(); private boolean mSuccess; private List<SmsRawData> mSms; @@ -76,33 +80,31 @@ public class SimSmsInterfaceManager extends ISms.Stub { }; public SimSmsInterfaceManager(GSMPhone phone) { - this.mPhone = phone; - ServiceManager.addService("isms", this); + super(phone); + mDispatcher = new GsmSMSDispatcher(phone); } - private void enforceReceiveAndSend(String message) { - Context context = mPhone.getContext(); + public void dispose() { + } - context.enforceCallingPermission( - "android.permission.RECEIVE_SMS", message); - context.enforceCallingPermission( - "android.permission.SEND_SMS", message); + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "SimSmsInterfaceManager finalized"); } /** * Update the specified message on the SIM. * * @param index record index of message to update - * @param status new message status (STATUS_ON_SIM_READ, - * STATUS_ON_SIM_UNREAD, STATUS_ON_SIM_SENT, - * STATUS_ON_SIM_UNSENT, STATUS_ON_SIM_FREE) + * @param status new message status (STATUS_ON_ICC_READ, + * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, + * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) * @param pdu the raw PDU to store * @return success or not * */ public boolean - updateMessageOnSimEf(int index, int status, byte[] pdu) { - if (DBG) log("updateMessageOnSimEf: index=" + index + + updateMessageOnIccEf(int index, int status, byte[] pdu) { + if (DBG) log("updateMessageOnIccEf: index=" + index + " status=" + status + " ==> " + "("+ pdu + ")"); enforceReceiveAndSend("Updating message on SIM"); @@ -110,13 +112,14 @@ public class SimSmsInterfaceManager extends ISms.Stub { mSuccess = false; Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); - if (status == SmsManager.STATUS_ON_SIM_FREE) { + if (status == STATUS_ON_ICC_FREE) { // Special case FREE: call deleteSmsOnSim instead of // manipulating the SIM record mPhone.mCM.deleteSmsOnSim(index, response); } else { byte[] record = makeSmsRecordData(status, pdu); - mPhone.mSIMFileHandler.updateEFLinearFixed( SimConstants.EF_SMS, + ((SIMFileHandler)mPhone.getIccFileHandler()).updateEFLinearFixed( + IccConstants.EF_SMS, index, record, null, response); } try { @@ -132,21 +135,21 @@ public class SimSmsInterfaceManager extends ISms.Stub { * Copy a raw SMS PDU to the SIM. * * @param pdu the raw PDU to store - * @param status message status (STATUS_ON_SIM_READ, STATUS_ON_SIM_UNREAD, - * STATUS_ON_SIM_SENT, STATUS_ON_SIM_UNSENT) + * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, + * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) * @return success or not * */ - public boolean copyMessageToSimEf(int status, byte[] pdu, byte[] smsc) { - if (DBG) log("copyMessageToSimEf: status=" + status + " ==> " + + public boolean copyMessageToIccEf(int status, byte[] pdu, byte[] smsc) { + if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " + "pdu=("+ pdu + "), smsm=(" + smsc +")"); enforceReceiveAndSend("Copying message to SIM"); synchronized(mLock) { mSuccess = false; Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); - mPhone.mCM.writeSmsToSim(status, SimUtils.bytesToHexString(smsc), - SimUtils.bytesToHexString(pdu), response); + mPhone.mCM.writeSmsToSim(status, IccUtils.bytesToHexString(smsc), + IccUtils.bytesToHexString(pdu), response); try { mLock.wait(); @@ -158,11 +161,11 @@ public class SimSmsInterfaceManager extends ISms.Stub { } /** - * Retrieves all messages currently stored on SIM. + * Retrieves all messages currently stored on ICC. * - * @return list of SmsRawData of all sms on SIM + * @return list of SmsRawData of all sms on ICC */ - public List<SmsRawData> getAllMessagesFromSimEf() { + public List<SmsRawData> getAllMessagesFromIccEf() { if (DBG) log("getAllMessagesFromEF"); Context context = mPhone.getContext(); @@ -172,7 +175,7 @@ public class SimSmsInterfaceManager extends ISms.Stub { "Reading messages from SIM"); synchronized(mLock) { Message response = mHandler.obtainMessage(EVENT_LOAD_DONE); - mPhone.mSIMFileHandler.loadEFLinearFixedAll(SimConstants.EF_SMS, + ((SIMFileHandler)mPhone.getIccFileHandler()).loadEFLinearFixedAll(IccConstants.EF_SMS, response); try { @@ -184,119 +187,7 @@ public class SimSmsInterfaceManager extends ISms.Stub { return mSms; } - /** - * Send a Raw PDU SMS - * - * @param smsc the SMSC to send the message through, or NULL for the - * defatult SMSC - * @param pdu the raw PDU to send - * @param sentIntent if not NULL this <code>Intent</code> is - * broadcast when the message is sucessfully sent, or failed. - * The result code will be <code>Activity.RESULT_OK<code> for success, - * or one of these errors: - * <code>RESULT_ERROR_GENERIC_FAILURE</code> - * <code>RESULT_ERROR_RADIO_OFF</code> - * <code>RESULT_ERROR_NULL_PDU</code>. - * @param deliveryIntent if not NULL this <code>Intent</code> is - * broadcast when the message is delivered to the recipient. The - * raw pdu of the status report is in the extended data ("pdu"). - */ - public void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, - PendingIntent deliveryIntent) { - Context context = mPhone.getContext(); - - context.enforceCallingPermission( - "android.permission.SEND_SMS", - "Sending SMS message"); - if (DBG) log("sendRawPdu: smsc=" + smsc + - " pdu="+ pdu + " sentIntent" + sentIntent + - " deliveryIntent" + deliveryIntent); - mPhone.mSMS.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); - } - - /** - * Send a multi-part text based SMS. - * - * @param destinationAddress the address to send the message to - * @param scAddress is the service center address or null to use - * the current default SMSC - * @param parts an <code>ArrayList</code> of strings that, in order, - * comprise the original message - * @param sentIntents if not null, an <code>ArrayList</code> of - * <code>PendingIntent</code>s (one for each message part) that is - * broadcast when the corresponding message part has been sent. - * The result code will be <code>Activity.RESULT_OK<code> for success, - * or one of these errors: - * <code>RESULT_ERROR_GENERIC_FAILURE</code> - * <code>RESULT_ERROR_RADIO_OFF</code> - * <code>RESULT_ERROR_NULL_PDU</code>. - * @param deliveryIntents if not null, an <code>ArrayList</code> of - * <code>PendingIntent</code>s (one for each message part) that is - * broadcast when the corresponding message part has been delivered - * to the recipient. The raw pdu of the status report is in the - * extended data ("pdu"). - */ - public void sendMultipartText(String destinationAddress, String scAddress, List<String> parts, - List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) { - Context context = mPhone.getContext(); - - context.enforceCallingPermission( - "android.permission.SEND_SMS", - "Sending SMS message"); - if (DBG) log("sendMultipartText"); - mPhone.mSMS.sendMultipartText(destinationAddress, scAddress, (ArrayList<String>) parts, - (ArrayList<PendingIntent>) sentIntents, (ArrayList<PendingIntent>) deliveryIntents); - } - - /** - * Generates an EF_SMS record from status and raw PDU. - * - * @param status Message status. See TS 51.011 10.5.3. - * @param pdu Raw message PDU. - * @return byte array for the record. - */ - private byte[] makeSmsRecordData(int status, byte[] pdu) { - byte[] data = new byte[SimConstants.SMS_RECORD_LENGTH]; - - // Status bits for this record. See TS 51.011 10.5.3 - data[0] = (byte)(status & 7); - - System.arraycopy(pdu, 0, data, 1, pdu.length); - - // Pad out with 0xFF's. - for (int j = pdu.length+1; j < SimConstants.SMS_RECORD_LENGTH; j++) { - data[j] = -1; - } - - return data; - } - - /** - * create SmsRawData lists from all sms record byte[] - * Use null to indicate "free" record - * - * @param messages List of message records from EF_SMS. - * @return SmsRawData list of all in-used records - */ - private ArrayList<SmsRawData> buildValidRawData(ArrayList<byte[]> messages) { - int count = messages.size(); - ArrayList<SmsRawData> ret; - - ret = new ArrayList<SmsRawData>(count); - - for (int i = 0; i < count; i++) { - byte[] ba = messages.get(i); - if (ba[0] == 0) { - ret.add(null); - } else { - ret.add(new SmsRawData(messages.get(i))); - } - } - - return ret; - } - - private void log(String msg) { - Log.d(LOG_TAG, "[SmsInterfaceManager] " + msg); + protected void log(String msg) { + Log.d(LOG_TAG, "[SimSmsInterfaceManager] " + msg); } } diff --git a/telephony/java/com/android/internal/telephony/gsm/SimTlv.java b/telephony/java/com/android/internal/telephony/gsm/SimTlv.java index 00879ce..30543c7 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimTlv.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimTlv.java @@ -34,9 +34,8 @@ public class SimTlv int curDataOffset; int curDataLength; boolean hasValidTlvObject; - - public SimTlv(byte[] record, int offset, int length) - { + + public SimTlv(byte[] record, int offset, int length) { this.record = record; this.tlvOffset = offset; @@ -46,19 +45,15 @@ public class SimTlv hasValidTlvObject = parseCurrentTlvObject(); } - public boolean - nextObject() - { + public boolean nextObject() { if (!hasValidTlvObject) return false; curOffset = curDataOffset + curDataLength; - hasValidTlvObject = parseCurrentTlvObject(); + hasValidTlvObject = parseCurrentTlvObject(); return hasValidTlvObject; } - public boolean - isValidObject() - { + public boolean isValidObject() { return hasValidTlvObject; } @@ -68,9 +63,7 @@ public class SimTlv * 0 and 0xff are invalid tag values * valid tags range from 1 - 0xfe */ - public int - getTag() - { + public int getTag() { if (!hasValidTlvObject) return 0; return record[curOffset] & 0xff; } @@ -79,10 +72,8 @@ public class SimTlv * Returns data associated with current TLV object * returns null if !isValidObject() */ - - public byte[] - getData() - { + + public byte[] getData() { if (!hasValidTlvObject) return null; byte[] ret = new byte[curDataLength]; @@ -95,14 +86,12 @@ public class SimTlv * @return false on invalid record, true on valid record */ - private boolean - parseCurrentTlvObject() - { + private boolean parseCurrentTlvObject() { // 0x00 and 0xff are invalid tag values if (record[curOffset] == 0 || (record[curOffset] & 0xff) == 0xff) { return false; } - + try { if ((record[curOffset + 1] & 0xff) < 0x80) { // one byte length 0 - 0x7f diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java new file mode 100644 index 0000000..867b719 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java @@ -0,0 +1,1058 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.gsm; + +import android.os.Parcel; +import android.telephony.PhoneNumberUtils; +import android.text.format.Time; +import android.util.Config; +import android.util.Log; +import com.android.internal.telephony.IccUtils; +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 java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; + +import static android.telephony.SmsMessage.ENCODING_7BIT; +import static android.telephony.SmsMessage.ENCODING_8BIT; +import static android.telephony.SmsMessage.ENCODING_16BIT; +import static android.telephony.SmsMessage.ENCODING_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; +import static android.telephony.SmsMessage.MessageClass; + +/** + * A Short Message Service message. + * + */ +public class SmsMessage extends SmsMessageBase{ + static final String LOG_TAG = "GSM"; + + private MessageClass messageClass; + + /** + * TP-Message-Type-Indicator + * 9.2.3 + */ + private int mti; + + /** TP-Protocol-Identifier (TP-PID) */ + private int protocolIdentifier; + + // TP-Data-Coding-Scheme + // see TS 23.038 + private int dataCodingScheme; + + // TP-Reply-Path + // e.g. 23.040 9.2.2.1 + private boolean replyPathPresent = false; + + // "Message Marked for Automatic Deletion Group" + // 23.038 Section 4 + private boolean automaticDeletion; + + /** True if Status Report is for SMS-SUBMIT; false for SMS-COMMAND. */ + private boolean forSubmit; + + /** The address of the receiver. */ + private GsmSmsAddress recipientAddress; + + /** Time when SMS-SUBMIT was delivered from SC to MSE. */ + private long dischargeTimeMillis; + + /** + * TP-Status - status of a previously submitted SMS. + * This field applies to SMS-STATUS-REPORT messages. 0 indicates success; + * see TS 23.040, 9.2.3.15 for description of other possible values. + */ + private int status; + + /** + * TP-Status - status of a previously submitted SMS. + * This field is true iff the message is a SMS-STATUS-REPORT message. + */ + private boolean isStatusReportMessage = false; + + public static class SubmitPdu extends SubmitPduBase { + } + + /** + * Create an SmsMessage from a raw PDU. + */ + public static SmsMessage createFromPdu(byte[] pdu) { + try { + SmsMessage msg = new SmsMessage(); + msg.parsePdu(pdu); + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); + return null; + } + } + + /** + * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the + * +CMT unsolicited response (PDU mode, of course) + * +CMT: [<alpha>],<length><CR><LF><pdu> + * + * Only public for debugging + * + * {@hide} + */ + public static SmsMessage newFromCMT(String[] lines) { + try { + SmsMessage msg = new SmsMessage(); + msg.parsePdu(IccUtils.hexStringToBytes(lines[1])); + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); + return null; + } + } + + /** @hide */ + public static SmsMessage newFromCMTI(String line) { + // the thinking here is not to read the message immediately + // FTA test case + Log.e(LOG_TAG, "newFromCMTI: not yet supported"); + return null; + } + + /** @hide */ + public static SmsMessage newFromCDS(String line) { + try { + SmsMessage msg = new SmsMessage(); + msg.parsePdu(IccUtils.hexStringToBytes(line)); + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "CDS SMS PDU parsing failed: ", ex); + return null; + } + } + + /** + * Note: This functionality is currently not supported in GSM mode. + * @hide + */ + public static SmsMessageBase newFromParcel(Parcel p){ + Log.w(LOG_TAG, "newFromParcel: is not supported in GSM mode."); + return null; + } + + /** + * Create an SmsMessage from an SMS EF record. + * + * @param index Index of SMS record. This should be index in ArrayList + * returned by SmsManager.getAllMessagesFromSim + 1. + * @param data Record data. + * @return An SmsMessage representing the record. + * + * @hide + */ + public static SmsMessage createFromEfRecord(int index, byte[] data) { + try { + SmsMessage msg = new SmsMessage(); + + msg.indexOnIcc = index; + + // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT, + // or STORED_UNSENT + // See TS 51.011 10.5.3 + if ((data[0] & 1) == 0) { + Log.w(LOG_TAG, + "SMS parsing failed: Trying to parse a free record"); + return null; + } else { + msg.statusOnIcc = data[0] & 0x07; + } + + int size = data.length - 1; + + // Note: Data may include trailing FF's. That's OK; message + // should still parse correctly. + byte[] pdu = new byte[size]; + System.arraycopy(data, 1, pdu, 0, size); + msg.parsePdu(pdu); + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); + return null; + } + } + + /** + * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the + * length in bytes (not hex chars) less the SMSC header + */ + public static int getTPLayerLengthForPDU(String pdu) { + int len = pdu.length() / 2; + int smscLen = 0; + + smscLen = Integer.parseInt(pdu.substring(0, 2), 16); + + return len - smscLen - 1; + } + + /** + * 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. + * @hide + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, String message, + boolean statusReportRequested, byte[] header) { + + // Perform null parameter checks. + if (message == null || destinationAddress == null) { + return null; + } + + SubmitPdu ret = new SubmitPdu(); + // MTI = SMS-SUBMIT, UDHI = header != null + byte mtiByte = (byte)(0x01 | (header != null ? 0x40 : 0x00)); + ByteArrayOutputStream bo = getSubmitPduHead( + scAddress, destinationAddress, mtiByte, + statusReportRequested, ret); + + try { + // First, try encoding it with the GSM alphabet + + // User Data (and length) + byte[] userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header); + + if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) { + // Message too long + return null; + } + + // TP-Data-Coding-Scheme + // Default encoding, uncompressed + bo.write(0x00); + + // (no TP-Validity-Period) + + bo.write(userData, 0, userData.length); + } catch (EncodeException ex) { + byte[] userData, textPart; + // Encoding to the 7-bit alphabet failed. Let's see if we can + // send it as a UCS-2 encoded message + + try { + textPart = message.getBytes("utf-16be"); + } catch (UnsupportedEncodingException uex) { + Log.e(LOG_TAG, + "Implausible UnsupportedEncodingException ", + uex); + return null; + } + + if (header != null) { + userData = new byte[header.length + textPart.length]; + + System.arraycopy(header, 0, userData, 0, header.length); + System.arraycopy(textPart, 0, userData, header.length, textPart.length); + } + else { + userData = textPart; + } + + if (userData.length > MAX_USER_DATA_BYTES) { + // Message too long + return null; + } + + // TP-Data-Coding-Scheme + // Class 3, UCS-2 encoding, uncompressed + bo.write(0x0b); + + // (no TP-Validity-Period) + + // TP-UDL + bo.write(userData.length); + + bo.write(userData, 0, userData.length); + } + + ret.encodedMessage = bo.toByteArray(); + return ret; + } + + /** + * 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); + } + + /** + * 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 + * destination + * @param data the dat 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 destinationAddress, short destinationPort, byte[] data, + boolean statusReportRequested) { + if (data.length > (MAX_USER_DATA_BYTES - 7 /* UDH size */)) { + Log.e(LOG_TAG, "SMS data message may only contain " + + (MAX_USER_DATA_BYTES - 7) + " bytes"); + return null; + } + + SubmitPdu ret = new SubmitPdu(); + ByteArrayOutputStream bo = getSubmitPduHead( + scAddress, destinationAddress, (byte) 0x41, // MTI = SMS-SUBMIT, + // TP-UDHI = true + statusReportRequested, ret); + + // TP-Data-Coding-Scheme + // No class, 8 bit data + bo.write(0x04); + + // (no TP-Validity-Period) + + // User data size + bo.write(data.length + 7); + + // User data header size + bo.write(0x06); // header is 6 octets + + // 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 + bo.write(data, 0, data.length); + + ret.encodedMessage = bo.toByteArray(); + return ret; + } + + /** + * Create the beginning of a SUBMIT PDU. This is the part of the + * SUBMIT PDU that is common to the two versions of {@link #getSubmitPdu}, + * one of which takes a byte array and the other of which takes a + * <code>String</code>. + * + * @param scAddress Service Centre address. null == use default + * @param destinationAddress the address of the destination for the message + * @param mtiByte + * @param ret <code>SubmitPdu</code> containing the encoded SC + * address, if applicable, and the encoded message + */ + private static ByteArrayOutputStream getSubmitPduHead( + String scAddress, String destinationAddress, byte mtiByte, + boolean statusReportRequested, SubmitPdu ret) { + ByteArrayOutputStream bo = new ByteArrayOutputStream( + MAX_USER_DATA_BYTES + 40); + + // SMSC address with length octet, or 0 + if (scAddress == null) { + ret.encodedScAddress = null; + } else { + ret.encodedScAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength( + scAddress); + } + + // TP-Message-Type-Indicator (and friends) + if (statusReportRequested) { + // Set TP-Status-Report-Request bit. + mtiByte |= 0x20; + if (Config.LOGD) Log.d(LOG_TAG, "SMS status report requested"); + } + bo.write(mtiByte); + + // space for TP-Message-Reference + bo.write(0); + + byte[] daBytes; + + daBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(destinationAddress); + + // destination address length in BCD digits, ignoring TON byte and pad + // TODO Should be better. + bo.write((daBytes.length - 1) * 2 + - ((daBytes[daBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0)); + + // destination address + bo.write(daBytes, 0, daBytes.length); + + // TP-Protocol-Identifier + bo.write(0); + return bo; + } + + static class PduParser { + byte pdu[]; + int cur; + SmsHeader userDataHeader; + byte[] userData; + int mUserDataSeptetPadding; + int mUserDataSize; + + PduParser(String s) { + this(IccUtils.hexStringToBytes(s)); + } + + PduParser(byte[] pdu) { + this.pdu = pdu; + cur = 0; + mUserDataSeptetPadding = 0; + } + + /** + * Parse and return the SC address prepended to SMS messages coming via + * the TS 27.005 / AT interface. Returns null on invalid address + */ + String getSCAddress() { + int len; + String ret; + + // length of SC Address + len = getByte(); + + if (len == 0) { + // no SC address + ret = null; + } else { + // SC address + try { + ret = PhoneNumberUtils + .calledPartyBCDToString(pdu, cur, len); + } catch (RuntimeException tr) { + Log.d(LOG_TAG, "invalid SC address: ", tr); + ret = null; + } + } + + cur += len; + + return ret; + } + + /** + * returns non-sign-extended byte value + */ + int getByte() { + return pdu[cur++] & 0xff; + } + + /** + * Any address except the SC address (eg, originating address) See TS + * 23.040 9.1.2.5 + */ + GsmSmsAddress getAddress() { + GsmSmsAddress ret; + + // "The Address-Length field is an integer representation of + // the number field, i.e. excludes any semi octet containing only + // fill bits." + // The TOA field is not included as part of this + int addressLength = pdu[cur] & 0xff; + int lengthBytes = 2 + (addressLength + 1) / 2; + + ret = new GsmSmsAddress(pdu, cur, lengthBytes); + + cur += lengthBytes; + + return ret; + } + + /** + * Parses an SC timestamp and returns a currentTimeMillis()-style + * timestamp + */ + + long getSCTimestampMillis() { + // TP-Service-Centre-Time-Stamp + int year = IccUtils.bcdByteToInt(pdu[cur++]); + int month = IccUtils.bcdByteToInt(pdu[cur++]); + int day = IccUtils.bcdByteToInt(pdu[cur++]); + int hour = IccUtils.bcdByteToInt(pdu[cur++]); + int minute = IccUtils.bcdByteToInt(pdu[cur++]); + int second = IccUtils.bcdByteToInt(pdu[cur++]); + + // For the timezone, the most significant bit of the + // least signficant nibble is the sign byte + // (meaning the max range of this field is 79 quarter-hours, + // which is more than enough) + + byte tzByte = pdu[cur++]; + + // Mask out sign bit. + int timezoneOffset = IccUtils + .bcdByteToInt((byte) (tzByte & (~0x08))); + + timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset + : -timezoneOffset; + + Time time = new Time(Time.TIMEZONE_UTC); + + // It's 2006. Should I really support years < 2000? + time.year = year >= 90 ? year + 1900 : year + 2000; + time.month = month - 1; + time.monthDay = day; + time.hour = hour; + time.minute = minute; + time.second = second; + + // Timezone offset is in quarter hours. + return time.toMillis(true) - (timezoneOffset * 15 * 60 * 1000); + } + + /** + * Pulls the user data out of the PDU, and separates the payload from + * the header if there is one. + * + * @param hasUserDataHeader true if there is a user data header + * @param dataInSeptets true if the data payload is in septets instead + * of octets + * @return the number of septets or octets in the user data payload + */ + int constructUserData(boolean hasUserDataHeader, boolean dataInSeptets) { + int offset = cur; + int userDataLength = pdu[offset++] & 0xff; + int headerSeptets = 0; + + if (hasUserDataHeader) { + int userDataHeaderLength = pdu[offset++] & 0xff; + + byte[] udh = new byte[userDataHeaderLength]; + System.arraycopy(pdu, offset, udh, 0, userDataHeaderLength); + userDataHeader = SmsHeader.parse(udh); + offset += userDataHeaderLength; + + int headerBits = (userDataHeaderLength + 1) * 8; + headerSeptets = headerBits / 7; + headerSeptets += (headerBits % 7) > 0 ? 1 : 0; + 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]; + System.arraycopy(pdu, offset, userData, 0, userData.length); + cur = offset; + + if (dataInSeptets) { + // Return the number of septets + return userDataLength - headerSeptets; + } else { + // Return the number of octets + return userData.length; + } + } + + /** + * Returns the user data payload, not including the headers + * + * @return the user data payload, not including the headers + */ + byte[] getUserData() { + return userData; + } + + /** + * Returns the number of padding bits at the begining of the user data + * array before the start of the septets. + * + * @return the number of padding bits at the begining of the user data + * array before the start of the septets + */ + int getUserDataSeptetPadding() { + return mUserDataSeptetPadding; + } + + /** + * Returns an object representing the user data headers + * + * @return an object representing the user data headers + * + * {@hide} + */ + SmsHeader getUserDataHeader() { + return userDataHeader; + } + +/* + XXX Not sure what this one is supposed to be doing, and no one is using + it. + String getUserDataGSM8bit() { + // System.out.println("remainder of pud:" + + // HexDump.dumpHexString(pdu, cur, pdu.length - cur)); + int count = pdu[cur++] & 0xff; + int size = pdu[cur++]; + + // skip over header for now + cur += size; + + if (pdu[cur - 1] == 0x01) { + int tid = pdu[cur++] & 0xff; + int type = pdu[cur++] & 0xff; + + size = pdu[cur++] & 0xff; + + int i = cur; + + while (pdu[i++] != '\0') { + } + + int length = i - cur; + String mimeType = new String(pdu, cur, length); + + cur += length; + + if (false) { + System.out.println("tid = 0x" + HexDump.toHexString(tid)); + System.out.println("type = 0x" + HexDump.toHexString(type)); + System.out.println("header size = " + size); + System.out.println("mimeType = " + mimeType); + System.out.println("remainder of header:" + + HexDump.dumpHexString(pdu, cur, (size - mimeType.length()))); + } + + cur += size - mimeType.length(); + + // System.out.println("data count = " + count + " cur = " + cur + // + " :" + HexDump.dumpHexString(pdu, cur, pdu.length - cur)); + + MMSMessage msg = MMSMessage.parseEncoding(mContext, pdu, cur, + pdu.length - cur); + } else { + System.out.println(new String(pdu, cur, pdu.length - cur - 1)); + } + + return IccUtils.bytesToHexString(pdu); + } +*/ + + /** + * Interprets the user data payload as pack GSM 7bit characters, and + * decodes them into a String. + * + * @param septetCount the number of septets in the user data payload + * @return a String with the decoded characters + */ + String getUserDataGSM7Bit(int septetCount) { + String ret; + + ret = GsmAlphabet.gsm7BitPackedToString(pdu, cur, septetCount, + mUserDataSeptetPadding); + + cur += (septetCount * 7) / 8; + + return ret; + } + + /** + * Interprets the user data payload as UCS2 characters, and + * decodes them into a String. + * + * @param byteCount the number of bytes in the user data payload + * @return a String with the decoded characters + */ + String getUserDataUCS2(int byteCount) { + String ret; + + try { + ret = new String(pdu, cur, byteCount, "utf-16"); + } catch (UnsupportedEncodingException ex) { + ret = ""; + Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex); + } + + cur += byteCount; + return ret; + } + + boolean moreDataPresent() { + return (pdu.length > cur); + } + } + + /** {@inheritDoc} */ + public int getProtocolIdentifier() { + return protocolIdentifier; + } + + /** {@inheritDoc} */ + public boolean isReplace() { + return (protocolIdentifier & 0xc0) == 0x40 + && (protocolIdentifier & 0x3f) > 0 + && (protocolIdentifier & 0x3f) < 8; + } + + /** {@inheritDoc} */ + public boolean isCphsMwiMessage() { + return ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageClear() + || ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageSet(); + } + + /** {@inheritDoc} */ + public boolean isMWIClearMessage() { + if (isMwi && (mwiSense == false)) { + return true; + } + + return originatingAddress != null + && ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageClear(); + } + + /** {@inheritDoc} */ + public boolean isMWISetMessage() { + if (isMwi && (mwiSense == true)) { + return true; + } + + return originatingAddress != null + && ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageSet(); + } + + /** {@inheritDoc} */ + public boolean isMwiDontStore() { + if (isMwi && mwiDontStore) { + return true; + } + + if (isCphsMwiMessage()) { + // See CPHS 4.2 Section B.4.2.1 + // If the user data is a single space char, do not store + // the message. Otherwise, store and display as usual + if (" ".equals(getMessageBody())) { + ; + } + return true; + } + + return false; + } + + /** {@inheritDoc} */ + public int getStatus() { + return status; + } + + /** {@inheritDoc} */ + public boolean isStatusReportMessage() { + return isStatusReportMessage; + } + + /** {@inheritDoc} */ + public boolean isReplyPathPresent() { + return replyPathPresent; + } + + /** + * TS 27.005 3.1, <pdu> definition "In the case of SMS: 3GPP TS 24.011 [6] + * SC address followed by 3GPP TS 23.040 [3] TPDU in hexadecimal format: + * ME/TA converts each octet of TP data unit into two IRA character long + * hexad number (e.g. octet with integer value 42 is presented to TE as two + * characters 2A (IRA 50 and 65))" ...in the case of cell broadcast, + * something else... + */ + private void parsePdu(byte[] pdu) { + mPdu = pdu; + // Log.d(LOG_TAG, "raw sms mesage:"); + // Log.d(LOG_TAG, s); + + PduParser p = new PduParser(pdu); + + scAddress = p.getSCAddress(); + + if (scAddress != null) { + if (Config.LOGD) Log.d(LOG_TAG, "SMS SC address: " + scAddress); + } + + // TODO(mkf) support reply path, user data header indicator + + // TP-Message-Type-Indicator + // 9.2.3 + int firstByte = p.getByte(); + + mti = firstByte & 0x3; + switch (mti) { + // TP-Message-Type-Indicator + // 9.2.3 + case 0: + parseSmsDeliver(p, firstByte); + break; + case 2: + parseSmsStatusReport(p, firstByte); + break; + default: + // TODO(mkf) the rest of these + throw new RuntimeException("Unsupported message type"); + } + } + + /** + * Parses a SMS-STATUS-REPORT message. + * + * @param p A PduParser, cued past the first byte. + * @param firstByte The first byte of the PDU, which contains MTI, etc. + */ + private void parseSmsStatusReport(PduParser p, int firstByte) { + isStatusReportMessage = true; + + // TP-Status-Report-Qualifier bit == 0 for SUBMIT + forSubmit = (firstByte & 0x20) == 0x00; + // TP-Message-Reference + messageRef = p.getByte(); + // TP-Recipient-Address + recipientAddress = p.getAddress(); + // TP-Service-Centre-Time-Stamp + scTimeMillis = p.getSCTimestampMillis(); + // TP-Discharge-Time + dischargeTimeMillis = p.getSCTimestampMillis(); + // TP-Status + status = p.getByte(); + + // The following are optional fields that may or may not be present. + if (p.moreDataPresent()) { + // TP-Parameter-Indicator + int extraParams = p.getByte(); + int moreExtraParams = extraParams; + while ((moreExtraParams & 0x80) != 0) { + // We only know how to parse a few extra parameters, all + // indicated in the first TP-PI octet, so skip over any + // additional TP-PI octets. + moreExtraParams = p.getByte(); + } + // TP-Protocol-Identifier + if ((extraParams & 0x01) != 0) { + protocolIdentifier = p.getByte(); + } + // TP-Data-Coding-Scheme + if ((extraParams & 0x02) != 0) { + dataCodingScheme = p.getByte(); + } + // TP-User-Data-Length (implies existence of TP-User-Data) + if ((extraParams & 0x04) != 0) { + boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; + parseUserData(p, hasUserDataHeader); + } + } + } + + private void parseSmsDeliver(PduParser p, int firstByte) { + replyPathPresent = (firstByte & 0x80) == 0x80; + + originatingAddress = p.getAddress(); + + if (originatingAddress != null) { + if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: " + + originatingAddress.address); + } + + // TP-Protocol-Identifier (TP-PID) + // TS 23.040 9.2.3.9 + protocolIdentifier = p.getByte(); + + // TP-Data-Coding-Scheme + // see TS 23.038 + dataCodingScheme = p.getByte(); + + if (Config.LOGV) { + Log.v(LOG_TAG, "SMS TP-PID:" + protocolIdentifier + + " data coding scheme: " + dataCodingScheme); + } + + scTimeMillis = p.getSCTimestampMillis(); + + if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis); + + boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; + + parseUserData(p, hasUserDataHeader); + } + + /** + * Parses the User Data of an SMS. + * + * @param p The current PduParser. + * @param hasUserDataHeader Indicates whether a header is present in the + * User Data. + */ + private void parseUserData(PduParser p, boolean hasUserDataHeader) { + boolean hasMessageClass = false; + boolean userDataCompressed = false; + + int encodingType = ENCODING_UNKNOWN; + + // Look up the data encoding scheme + if ((dataCodingScheme & 0x80) == 0) { + // Bits 7..4 == 0xxx + automaticDeletion = (0 != (dataCodingScheme & 0x40)); + userDataCompressed = (0 != (dataCodingScheme & 0x20)); + hasMessageClass = (0 != (dataCodingScheme & 0x10)); + + if (userDataCompressed) { + Log.w(LOG_TAG, "4 - Unsupported SMS data coding scheme " + + "(compression) " + (dataCodingScheme & 0xff)); + } else { + switch ((dataCodingScheme >> 2) & 0x3) { + case 0: // GSM 7 bit default alphabet + encodingType = ENCODING_7BIT; + break; + + case 2: // UCS 2 (16bit) + encodingType = ENCODING_16BIT; + break; + + case 1: // 8 bit data + case 3: // reserved + Log.w(LOG_TAG, "1 - Unsupported SMS data coding scheme " + + (dataCodingScheme & 0xff)); + encodingType = ENCODING_8BIT; + break; + } + } + } else if ((dataCodingScheme & 0xf0) == 0xf0) { + automaticDeletion = false; + hasMessageClass = true; + userDataCompressed = false; + + if (0 == (dataCodingScheme & 0x04)) { + // GSM 7 bit default alphabet + encodingType = ENCODING_7BIT; + } else { + // 8 bit data + encodingType = ENCODING_8BIT; + } + } else if ((dataCodingScheme & 0xF0) == 0xC0 + || (dataCodingScheme & 0xF0) == 0xD0 + || (dataCodingScheme & 0xF0) == 0xE0) { + // 3GPP TS 23.038 V7.0.0 (2006-03) section 4 + + // 0xC0 == 7 bit, don't store + // 0xD0 == 7 bit, store + // 0xE0 == UCS-2, store + + if ((dataCodingScheme & 0xF0) == 0xE0) { + encodingType = ENCODING_16BIT; + } else { + encodingType = ENCODING_7BIT; + } + + userDataCompressed = false; + boolean active = ((dataCodingScheme & 0x08) == 0x08); + + // bit 0x04 reserved + + if ((dataCodingScheme & 0x03) == 0x00) { + isMwi = true; + mwiSense = active; + mwiDontStore = ((dataCodingScheme & 0xF0) == 0xC0); + } else { + isMwi = false; + + Log.w(LOG_TAG, "MWI for fax, email, or other " + + (dataCodingScheme & 0xff)); + } + } else { + Log.w(LOG_TAG, "3 - Unsupported SMS data coding scheme " + + (dataCodingScheme & 0xff)); + } + + // set both the user data and the user data header. + int count = p.constructUserData(hasUserDataHeader, + encodingType == ENCODING_7BIT); + this.userData = p.getUserData(); + this.userDataHeader = p.getUserDataHeader(); + + switch (encodingType) { + case ENCODING_UNKNOWN: + case ENCODING_8BIT: + messageBody = null; + break; + + case ENCODING_7BIT: + messageBody = p.getUserDataGSM7Bit(count); + break; + + case ENCODING_16BIT: + messageBody = p.getUserDataUCS2(count); + break; + } + + if (Config.LOGV) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'"); + + if (messageBody != null) { + parseMessageBody(); + } + + if (!hasMessageClass) { + messageClass = MessageClass.UNKNOWN; + } else { + switch (dataCodingScheme & 0x3) { + case 0: + messageClass = MessageClass.CLASS_0; + break; + case 1: + messageClass = MessageClass.CLASS_1; + break; + case 2: + messageClass = MessageClass.CLASS_2; + break; + case 3: + messageClass = MessageClass.CLASS_3; + break; + } + } + } + + /** + * {@inheritDoc} + */ + public MessageClass getMessageClass() { + return messageClass; + } + +} diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java b/telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java index 26c2175..19d3279 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java @@ -20,9 +20,9 @@ import java.util.List; /** * Class for representing BER-TLV objects. - * + * * @see "ETSI TS 102 223 Annex C" for more information. - * + * * {@hide} */ class BerTlv { @@ -41,16 +41,16 @@ class BerTlv { /** * Gets a list of ComprehensionTlv objects contained in this BER-TLV object. - * + * * @return A list of COMPREHENSION-TLV object */ public List<ComprehensionTlv> getComprehensionTlvs() { return mCompTlvs; } - + /** * Gets a tag id of the BER-TLV object. - * + * * @return A tag integer. */ public int getTag() { @@ -59,7 +59,7 @@ class BerTlv { /** * Decodes a BER-TLV object from a byte array. - * + * * @param data A byte array to decode from * @return A BER-TLV object decoded * @throws ResultException 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 60e8148..a27c582 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java @@ -19,7 +19,7 @@ package com.android.internal.telephony.gsm.stk; import android.graphics.Bitmap; /** - * Container class for proactive command parameters. + * Container class for proactive command parameters. * */ class CommandParams { 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 eb354e9..06b36a4 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java @@ -20,7 +20,7 @@ import android.graphics.Bitmap; import android.os.Handler; import android.os.Message; -import com.android.internal.telephony.gsm.GsmAlphabet; +import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.gsm.SIMFileHandler; import java.util.Iterator; 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 833ff3c..4f746ac 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java @@ -22,9 +22,9 @@ import java.util.List; /** * Class for representing COMPREHENSION-TLV objects. - * + * * @see "ETSI TS 101 220 subsection 7.1.1" - * + * * {@hide} */ class ComprehensionTlv { @@ -38,7 +38,7 @@ class ComprehensionTlv { * Constructor. Private on purpose. Use * {@link #decodeMany(byte[], int) decodeMany} or * {@link #decode(byte[], int) decode} method. - * + * * @param tag The tag for this object * @param cr Comprehension Required flag * @param length Length of the value @@ -76,7 +76,7 @@ class ComprehensionTlv { /** * Parses a list of COMPREHENSION-TLV objects from a byte array. - * + * * @param data A byte array containing data to be parsed * @param startIndex Index in data at which to start parsing * @return A list of COMPREHENSION-TLV objects parsed @@ -97,7 +97,7 @@ class ComprehensionTlv { /** * Parses an COMPREHENSION-TLV object from a byte array. - * + * * @param data A byte array containing data to be parsed * @param startIndex Index in data at which to start parsing * @return A COMPREHENSION-TLV object parsed diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java b/telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java index a63d1ca..fc02d2a 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java @@ -30,9 +30,9 @@ import android.util.Log; import java.util.HashMap; /** - * Class for loading icons from the SIM card. Has two states: single, for loading + * Class for loading icons from the SIM card. Has two states: single, for loading * one icon. Multi, for loading icons list. - * + * */ class IconLoader extends Handler { // members @@ -51,13 +51,13 @@ class IconLoader extends Handler { private static IconLoader sLoader = null; - // Loader state values. + // Loader state values. private static final int STATE_SINGLE_ICON = 1; private static final int STATE_MULTI_ICONS = 2; - // Finished loading single record from a linear-fixed EF-IMG. + // Finished loading single record from a linear-fixed EF-IMG. private static final int EVENT_READ_EF_IMG_RECOED_DONE = 1; - // Finished loading single icon from a Transparent DF-Graphics. + // Finished loading single icon from a Transparent DF-Graphics. private static final int EVENT_READ_ICON_DONE = 2; // Finished loading single colour icon lookup table. private static final int EVENT_READ_CLUT_DONE = 3; @@ -170,10 +170,10 @@ class IconLoader extends Handler { } /** - * Handles Image descriptor parsing and required processing. This is the + * Handles Image descriptor parsing and required processing. This is the * first step required to handle retrieving icons from the SIM. - * - * @param data byte [] containing Image Instance descriptor as defined in + * + * @param data byte [] containing Image Instance descriptor as defined in * TS 51.011. */ private boolean handleImageDescriptor(byte[] rawData) { @@ -232,7 +232,7 @@ class IconLoader extends Handler { * @param data The raw data * @param length The length of image body * @return The bitmap - */ + */ public static Bitmap parseToBnW(byte[] data, int length){ int valueIndex = 0; int width = data[valueIndex++] & 0xFF; @@ -264,7 +264,7 @@ class IconLoader extends Handler { * 0 is black * 1 is white * @param bit to decode - * @return RGB color + * @return RGB color */ private static int bitToBnW(int bit){ if(bit == 1){ @@ -276,11 +276,11 @@ class IconLoader extends Handler { /** * a TS 131.102 image instance of code scheme '11' into color Bitmap - * + * * @param data The raw data * @param length the length of image body * @param transparency with or without transparency - * @param clut coulor lookup table + * @param clut coulor lookup table * @return The color bitmap */ public static Bitmap parseToRGB(byte[] data, int length, @@ -321,9 +321,9 @@ class IconLoader extends Handler { return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888); } - + /** - * Calculate bit mask for a given number of bits. The mask should enable to + * Calculate bit mask for a given number of bits. The mask should enable to * make a bitwise and to the given number of bits. * @param numOfBits number of bits to calculate mask for. * @return bit mask diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ImageDescriptor.java b/telephony/java/com/android/internal/telephony/gsm/stk/ImageDescriptor.java index 7120a37..880b9e5 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/ImageDescriptor.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ImageDescriptor.java @@ -33,7 +33,8 @@ public class ImageDescriptor { static final int CODING_SCHEME_BASIC = 0x11; static final int CODING_SCHEME_COLOUR = 0x21; - public static final int ID_LENGTH = 9; + // public static final int ID_LENGTH = 9; + // ID_LENGTH substituted by IccFileHandlerBase.GET_RESPONSE_EF_IMG_SIZE_BYTES ImageDescriptor() { width = 0; @@ -47,7 +48,7 @@ public class ImageDescriptor { /** * Extract descriptor information about image instance. - * + * * @param rawData * @param valueIndex * @return ImageDescriptor 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 9afa063..810afd2 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/ResponseData.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ResponseData.java @@ -16,8 +16,8 @@ package com.android.internal.telephony.gsm.stk; -import com.android.internal.telephony.gsm.EncodeException; -import com.android.internal.telephony.gsm.GsmAlphabet; +import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.GsmAlphabet; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java b/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java index 5d82473..1cf38ed 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java @@ -17,7 +17,7 @@ package com.android.internal.telephony.gsm.stk; import com.android.internal.telephony.gsm.SIMFileHandler; -import com.android.internal.telephony.gsm.SimUtils; +import com.android.internal.telephony.IccUtils; import android.os.Handler; import android.os.HandlerState; @@ -142,7 +142,7 @@ class RilMessageDecoder extends HandlerStateMachine { case StkService.MSG_ID_REFRESH: byte[] rawData = null; try { - rawData = SimUtils.hexStringToBytes((String) rilMsg.mData); + rawData = IccUtils.hexStringToBytes((String) rilMsg.mData); } catch (Exception e) { // zombie messages are dropped StkLog.d(this, "decodeMessageParams dropping zombie messages"); 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 c0c4ceb..3de14f0 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java @@ -23,11 +23,13 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Message; -import com.android.internal.telephony.gsm.CommandsInterface; -import com.android.internal.telephony.gsm.GsmSimCard; +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; -import com.android.internal.telephony.gsm.SimUtils; import android.util.Config; @@ -115,10 +117,12 @@ class RilMessage { */ public class StkService extends Handler implements AppInterface { + // Class members + private static SIMRecords mSimRecords; + // Service members. private static StkService sInstance; private CommandsInterface mCmdIf; - private SIMRecords mSimRecords; private Context mContext; private StkCmdMessage mCurrntCmd = null; private StkCmdMessage mMenuCmd = null; @@ -147,7 +151,7 @@ public class StkService extends Handler implements AppInterface { /* Intentionally private for singleton */ private StkService(CommandsInterface ci, SIMRecords sr, Context context, - SIMFileHandler fh, GsmSimCard sc) { + SIMFileHandler fh, SimCard sc) { if (ci == null || sr == null || context == null || fh == null || sc == null) { throw new NullPointerException( @@ -172,6 +176,23 @@ public class StkService extends Handler implements AppInterface { mSimRecords.registerForRecordsLoaded(this, MSG_ID_SIM_LOADED, null); } + public void dispose() { + mSimRecords.unregisterForRecordsLoaded(this); + mCmdIf.unSetOnStkSessionEnd(this); + mCmdIf.unSetOnStkProactiveCmd(this); + mCmdIf.unSetOnStkEvent(this); + mCmdIf.unSetOnStkCallSetUp(this); + + this.removeCallbacksAndMessages(null); + + //removing instance + sInstance = null; + } + + protected void finalize() { + StkLog.d(this, "Service finalized"); + } + private void handleRilMsg(RilMessage rilMsg) { if (rilMsg == null) { return; @@ -334,7 +355,7 @@ public class StkService extends Handler implements AppInterface { } byte[] rawData = buf.toByteArray(); - String hexString = SimUtils.bytesToHexString(rawData); + String hexString = IccUtils.bytesToHexString(rawData); if (Config.LOGD) { StkLog.d(this, "TERMINAL RESPONSE: " + hexString); } @@ -380,7 +401,7 @@ public class StkService extends Handler implements AppInterface { int len = rawData.length - 2; // minus (tag + length) rawData[1] = (byte) len; - String hexString = SimUtils.bytesToHexString(rawData); + String hexString = IccUtils.bytesToHexString(rawData); mCmdIf.sendEnvelope(hexString, null); } @@ -423,7 +444,7 @@ public class StkService extends Handler implements AppInterface { int len = rawData.length - 2; // minus (tag + length) rawData[1] = (byte) len; - String hexString = SimUtils.bytesToHexString(rawData); + String hexString = IccUtils.bytesToHexString(rawData); mCmdIf.sendEnvelope(hexString, null); } @@ -439,7 +460,7 @@ public class StkService extends Handler implements AppInterface { * @return The only Service object in the system */ public static StkService getInstance(CommandsInterface ci, SIMRecords sr, - Context context, SIMFileHandler fh, GsmSimCard sc) { + Context context, SIMFileHandler fh, SimCard sc) { if (sInstance == null) { if (ci == null || sr == null || context == null || fh == null || sc == null) { @@ -448,6 +469,17 @@ public class StkService extends Handler implements AppInterface { HandlerThread thread = new HandlerThread("Stk Telephony service"); thread.start(); sInstance = new StkService(ci, sr, context, fh, sc); + StkLog.d(sInstance, "NEW sInstance"); + } else if ((sr != null) && (mSimRecords != sr)) { + StkLog.d(sInstance, String.format( + "Reinitialize the Service with SIMRecords sr=0x%x.", sr)); + mSimRecords = sr; + + // re-Register for SIM ready event. + mSimRecords.registerForRecordsLoaded(sInstance, MSG_ID_SIM_LOADED, null); + StkLog.d(sInstance, "sr changed reinitialize and return current sInstance"); + } else { + StkLog.d(sInstance, "Return current sInstance"); } return sInstance; } 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 2cf87ba..8c8f977 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/ValueParser.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ValueParser.java @@ -16,8 +16,8 @@ package com.android.internal.telephony.gsm.stk; -import com.android.internal.telephony.gsm.GsmAlphabet; -import com.android.internal.telephony.gsm.SimUtils; +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.gsm.stk.Duration.TimeUnit; import java.io.UnsupportedEncodingException; @@ -117,7 +117,7 @@ abstract class ValueParser { try { int id = rawValue[valueIndex] & 0xff; - String text = SimUtils.adnStringFieldToString(rawValue, + String text = IccUtils.adnStringFieldToString(rawValue, valueIndex + 1, textLen); item = new Item(id, text); } catch (IndexOutOfBoundsException e) { @@ -278,7 +278,7 @@ abstract class ValueParser { int length = ctlv.getLength(); if (length != 0) { try { - return SimUtils.adnStringFieldToString(rawValue, valueIndex, + return IccUtils.adnStringFieldToString(rawValue, valueIndex, length); } catch (IndexOutOfBoundsException e) { throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java index 33c1679..3e53654 100644 --- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java +++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java @@ -23,19 +23,18 @@ import android.os.Looper; import android.os.Message; import android.util.Log; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.gsm.BaseCommands; +import com.android.internal.telephony.BaseCommands; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.gsm.CallFailCause; -import com.android.internal.telephony.gsm.CommandException; -import com.android.internal.telephony.gsm.CommandsInterface; import com.android.internal.telephony.gsm.PDPContextState; import com.android.internal.telephony.gsm.SuppServiceNotification; +import com.android.internal.telephony.Phone; import java.util.ArrayList; public final class SimulatedCommands extends BaseCommands - implements CommandsInterface, SimulatedRadioControl -{ + implements CommandsInterface, SimulatedRadioControl { private final static String LOG_TAG = "SIM"; private enum SimLockState { @@ -43,14 +42,14 @@ public final class SimulatedCommands extends BaseCommands REQUIRE_PIN, REQUIRE_PUK, SIM_PERM_LOCKED - }; + } private enum SimFdnState { NONE, REQUIRE_PIN2, REQUIRE_PUK2, SIM_PERM_LOCKED - }; + } private final static SimLockState INITIAL_LOCK_STATE = SimLockState.NONE; private final static String DEFAULT_SIM_PIN_CODE = "1234"; @@ -103,11 +102,10 @@ public final class SimulatedCommands extends BaseCommands //***** CommandsInterface implementation - public void getSimStatus(Message result) - { + public void getIccStatus(Message result) { switch (mState) { case SIM_READY: - resultSuccess(result, SimStatus.SIM_READY); + resultSuccess(result, IccStatus.ICC_READY); break; case SIM_LOCKED_OR_ABSENT: @@ -115,7 +113,7 @@ public final class SimulatedCommands extends BaseCommands break; default: - resultSuccess(result, SimStatus.SIM_NOT_READY); + resultSuccess(result, IccStatus.ICC_NOT_READY); break; } } @@ -123,13 +121,13 @@ public final class SimulatedCommands extends BaseCommands private void returnSimLockedStatus(Message result) { switch (mSimLockedState) { case REQUIRE_PIN: - Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: SIM_PIN"); - resultSuccess(result, SimStatus.SIM_PIN); + Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: ICC_PIN"); + resultSuccess(result, IccStatus.ICC_PIN); break; case REQUIRE_PUK: - Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: SIM_PUK"); - resultSuccess(result, SimStatus.SIM_PUK); + Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: ICC_PUK"); + resultSuccess(result, IccStatus.ICC_PUK); break; default: @@ -139,9 +137,9 @@ public final class SimulatedCommands extends BaseCommands } } - public void supplySimPin(String pin, Message result) { + public void supplyIccPin(String pin, Message result) { if (mSimLockedState != SimLockState.REQUIRE_PIN) { - Log.i(LOG_TAG, "[SimCmd] supplySimPin: wrong state, state=" + + Log.i(LOG_TAG, "[SimCmd] supplyIccPin: wrong state, state=" + mSimLockedState); CommandException ex = new CommandException( CommandException.Error.PASSWORD_INCORRECT); @@ -151,7 +149,7 @@ public final class SimulatedCommands extends BaseCommands } if (pin != null && pin.equals(mPinCode)) { - Log.i(LOG_TAG, "[SimCmd] supplySimPin: success!"); + Log.i(LOG_TAG, "[SimCmd] supplyIccPin: success!"); setRadioState(RadioState.SIM_READY); mPinUnlockAttempts = 0; mSimLockedState = SimLockState.NONE; @@ -167,10 +165,10 @@ public final class SimulatedCommands extends BaseCommands if (result != null) { mPinUnlockAttempts ++; - Log.i(LOG_TAG, "[SimCmd] supplySimPin: failed! attempt=" + + Log.i(LOG_TAG, "[SimCmd] supplyIccPin: failed! attempt=" + mPinUnlockAttempts); if (mPinUnlockAttempts >= 3) { - Log.i(LOG_TAG, "[SimCmd] supplySimPin: set state to REQUIRE_PUK"); + Log.i(LOG_TAG, "[SimCmd] supplyIccPin: set state to REQUIRE_PUK"); mSimLockedState = SimLockState.REQUIRE_PUK; } @@ -181,9 +179,9 @@ public final class SimulatedCommands extends BaseCommands } } - public void supplySimPuk(String puk, String newPin, Message result) { + public void supplyIccPuk(String puk, String newPin, Message result) { if (mSimLockedState != SimLockState.REQUIRE_PUK) { - Log.i(LOG_TAG, "[SimCmd] supplySimPuk: wrong state, state=" + + Log.i(LOG_TAG, "[SimCmd] supplyIccPuk: wrong state, state=" + mSimLockedState); CommandException ex = new CommandException( CommandException.Error.PASSWORD_INCORRECT); @@ -193,7 +191,7 @@ public final class SimulatedCommands extends BaseCommands } if (puk != null && puk.equals(SIM_PUK_CODE)) { - Log.i(LOG_TAG, "[SimCmd] supplySimPuk: success!"); + Log.i(LOG_TAG, "[SimCmd] supplyIccPuk: success!"); setRadioState(RadioState.SIM_READY); mSimLockedState = SimLockState.NONE; mPukUnlockAttempts = 0; @@ -209,10 +207,10 @@ public final class SimulatedCommands extends BaseCommands if (result != null) { mPukUnlockAttempts ++; - Log.i(LOG_TAG, "[SimCmd] supplySimPuk: failed! attempt=" + + Log.i(LOG_TAG, "[SimCmd] supplyIccPuk: failed! attempt=" + mPukUnlockAttempts); if (mPukUnlockAttempts >= 10) { - Log.i(LOG_TAG, "[SimCmd] supplySimPuk: set state to SIM_PERM_LOCKED"); + Log.i(LOG_TAG, "[SimCmd] supplyIccPuk: set state to SIM_PERM_LOCKED"); mSimLockedState = SimLockState.SIM_PERM_LOCKED; } @@ -223,9 +221,9 @@ public final class SimulatedCommands extends BaseCommands } } - public void supplySimPin2(String pin2, Message result) { + public void supplyIccPin2(String pin2, Message result) { if (mSimFdnEnabledState != SimFdnState.REQUIRE_PIN2) { - Log.i(LOG_TAG, "[SimCmd] supplySimPin2: wrong state, state=" + + Log.i(LOG_TAG, "[SimCmd] supplyIccPin2: wrong state, state=" + mSimFdnEnabledState); CommandException ex = new CommandException( CommandException.Error.PASSWORD_INCORRECT); @@ -235,7 +233,7 @@ public final class SimulatedCommands extends BaseCommands } if (pin2 != null && pin2.equals(mPin2Code)) { - Log.i(LOG_TAG, "[SimCmd] supplySimPin2: success!"); + Log.i(LOG_TAG, "[SimCmd] supplyIccPin2: success!"); mPin2UnlockAttempts = 0; mSimFdnEnabledState = SimFdnState.NONE; @@ -250,10 +248,10 @@ public final class SimulatedCommands extends BaseCommands if (result != null) { mPin2UnlockAttempts ++; - Log.i(LOG_TAG, "[SimCmd] supplySimPin2: failed! attempt=" + + Log.i(LOG_TAG, "[SimCmd] supplyIccPin2: failed! attempt=" + mPin2UnlockAttempts); if (mPin2UnlockAttempts >= 3) { - Log.i(LOG_TAG, "[SimCmd] supplySimPin2: set state to REQUIRE_PUK2"); + Log.i(LOG_TAG, "[SimCmd] supplyIccPin2: set state to REQUIRE_PUK2"); mSimFdnEnabledState = SimFdnState.REQUIRE_PUK2; } @@ -264,9 +262,9 @@ public final class SimulatedCommands extends BaseCommands } } - public void supplySimPuk2(String puk2, String newPin2, Message result) { + public void supplyIccPuk2(String puk2, String newPin2, Message result) { if (mSimFdnEnabledState != SimFdnState.REQUIRE_PUK2) { - Log.i(LOG_TAG, "[SimCmd] supplySimPuk2: wrong state, state=" + + Log.i(LOG_TAG, "[SimCmd] supplyIccPuk2: wrong state, state=" + mSimLockedState); CommandException ex = new CommandException( CommandException.Error.PASSWORD_INCORRECT); @@ -276,7 +274,7 @@ public final class SimulatedCommands extends BaseCommands } if (puk2 != null && puk2.equals(SIM_PUK2_CODE)) { - Log.i(LOG_TAG, "[SimCmd] supplySimPuk2: success!"); + Log.i(LOG_TAG, "[SimCmd] supplyIccPuk2: success!"); mSimFdnEnabledState = SimFdnState.NONE; mPuk2UnlockAttempts = 0; @@ -291,10 +289,10 @@ public final class SimulatedCommands extends BaseCommands if (result != null) { mPuk2UnlockAttempts ++; - Log.i(LOG_TAG, "[SimCmd] supplySimPuk2: failed! attempt=" + + Log.i(LOG_TAG, "[SimCmd] supplyIccPuk2: failed! attempt=" + mPuk2UnlockAttempts); if (mPuk2UnlockAttempts >= 10) { - Log.i(LOG_TAG, "[SimCmd] supplySimPuk2: set state to SIM_PERM_LOCKED"); + Log.i(LOG_TAG, "[SimCmd] supplyIccPuk2: set state to SIM_PERM_LOCKED"); mSimFdnEnabledState = SimFdnState.SIM_PERM_LOCKED; } @@ -305,7 +303,7 @@ public final class SimulatedCommands extends BaseCommands } } - public void changeSimPin(String oldPin, String newPin, Message result) { + public void changeIccPin(String oldPin, String newPin, Message result) { if (oldPin != null && oldPin.equals(mPinCode)) { mPinCode = newPin; if (result != null) { @@ -317,7 +315,7 @@ public final class SimulatedCommands extends BaseCommands } if (result != null) { - Log.i(LOG_TAG, "[SimCmd] changeSimPin: pin failed!"); + Log.i(LOG_TAG, "[SimCmd] changeIccPin: pin failed!"); CommandException ex = new CommandException( CommandException.Error.PASSWORD_INCORRECT); @@ -326,7 +324,7 @@ public final class SimulatedCommands extends BaseCommands } } - public void changeSimPin2(String oldPin2, String newPin2, Message result) { + public void changeIccPin2(String oldPin2, String newPin2, Message result) { if (oldPin2 != null && oldPin2.equals(mPin2Code)) { mPin2Code = newPin2; if (result != null) { @@ -338,7 +336,7 @@ public final class SimulatedCommands extends BaseCommands } if (result != null) { - Log.i(LOG_TAG, "[SimCmd] changeSimPin: pin2 failed!"); + Log.i(LOG_TAG, "[SimCmd] changeIccPin2: pin2 failed!"); CommandException ex = new CommandException( CommandException.Error.PASSWORD_INCORRECT); @@ -348,14 +346,12 @@ public final class SimulatedCommands extends BaseCommands } public void - changeBarringPassword(String facility, String oldPwd, String newPwd, Message result) - { + changeBarringPassword(String facility, String oldPwd, String newPwd, Message result) { unimplemented(result); } public void - setSuppServiceNotifications(boolean enable, Message result) - { + setSuppServiceNotifications(boolean enable, Message result) { resultSuccess(result, null); if (enable && mSsnNotifyOn) { @@ -477,8 +473,7 @@ public final class SimulatedCommands extends BaseCommands * ar.result contains a List of DriverCall * The ar.result List is sorted by DriverCall.index */ - public void getCurrentCalls (Message result) - { + public void getCurrentCalls (Message result) { if (mState == RadioState.SIM_READY) { //Log.i("GSM", "[SimCmds] getCurrentCalls"); resultSuccess(result, simulatedCallState.getDriverCalls()); @@ -491,14 +486,20 @@ public final class SimulatedCommands extends BaseCommands } /** + * @deprecated + */ + public void getPDPContextList(Message result) { + getDataCallList(result); + } + + /** * returned message * 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 */ - public void getPDPContextList(Message result) - { + public void getDataCallList(Message result) { resultSuccess(result, new ArrayList<PDPContextState>(0)); } @@ -513,8 +514,7 @@ public final class SimulatedCommands extends BaseCommands * CLIR_SUPPRESSION == on "CLIR suppression" (allow CLI presentation) * CLIR_INVOCATION == on "CLIR invocation" (restrict CLI presentation) */ - public void dial (String address, int clirMode, Message result) - { + public void dial (String address, int clirMode, Message result) { simulatedCallState.onDial(address); resultSuccess(result, null); @@ -527,8 +527,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is String containing IMSI on success */ - public void getIMSI(Message result) - { + public void getIMSI(Message result) { resultSuccess(result, "012345678901234"); } @@ -539,8 +538,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is String containing IMEI on success */ - public void getIMEI(Message result) - { + public void getIMEI(Message result) { resultSuccess(result, "012345678901234"); } @@ -551,8 +549,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is String containing IMEISV on success */ - public void getIMEISV(Message result) - { + public void getIMEISV(Message result) { resultSuccess(result, "99"); } @@ -567,8 +564,7 @@ public final class SimulatedCommands extends BaseCommands * 3GPP 22.030 6.5.5 * "Releases a specific active call X" */ - public void hangupConnection (int gsmIndex, Message result) - { + public void hangupConnection (int gsmIndex, Message result) { boolean success; success = simulatedCallState.onChld('1', (char)('0'+gsmIndex)); @@ -590,8 +586,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void hangupWaitingOrBackground (Message result) - { + public void hangupWaitingOrBackground (Message result) { boolean success; success = simulatedCallState.onChld('0', '\0'); @@ -612,8 +607,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void hangupForegroundResumeBackground (Message result) - { + public void hangupForegroundResumeBackground (Message result) { boolean success; success = simulatedCallState.onChld('1', '\0'); @@ -634,8 +628,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void switchWaitingOrHoldingAndActive (Message result) - { + public void switchWaitingOrHoldingAndActive (Message result) { boolean success; success = simulatedCallState.onChld('2', '\0'); @@ -655,8 +648,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void conference (Message result) - { + public void conference (Message result) { boolean success; success = simulatedCallState.onChld('3', '\0'); @@ -676,8 +668,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void explicitCallTransfer (Message result) - { + public void explicitCallTransfer (Message result) { boolean success; success = simulatedCallState.onChld('4', '\0'); @@ -694,8 +685,7 @@ public final class SimulatedCommands extends BaseCommands * "Places all active calls on hold except call X with which * communication shall be supported." */ - public void separateConnection (int gsmIndex, Message result) - { + public void separateConnection (int gsmIndex, Message result) { boolean success; char ch = (char)(gsmIndex + '0'); @@ -714,8 +704,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void acceptCall (Message result) - { + public void acceptCall (Message result) { boolean success; success = simulatedCallState.onAnswer(); @@ -733,8 +722,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void rejectCall (Message result) - { + public void rejectCall (Message result) { boolean success; success = simulatedCallState.onChld('0', '\0'); @@ -754,17 +742,22 @@ public final class SimulatedCommands extends BaseCommands * - Any defined in 22.001 F.4 (for generating busy/congestion) * - Cause 68: ACM >= ACMMax */ - public void getLastCallFailCause (Message result) - { + public void getLastCallFailCause (Message result) { int[] ret = new int[1]; ret[0] = nextCallFailCause; resultSuccess(result, ret); } - public void - getLastPdpFailCause (Message result) - { + /** + * @deprecated + */ + public void getLastPdpFailCause (Message result) { + unimplemented(result); + } + + public void getLastDataCallFailCause(Message result) { + // unimplemented(result); } @@ -779,8 +772,7 @@ public final class SimulatedCommands extends BaseCommands * response.obj.result[1] is bit error rate (0-7, 99) * as defined in TS 27.007 8.5 */ - public void getSignalStrength (Message result) - { + public void getSignalStrength (Message result) { int ret[] = new int[2]; ret[0] = 23; @@ -850,8 +842,7 @@ public final class SimulatedCommands extends BaseCommands * Please note that registration state 4 ("unknown") is treated * as "out of service" above */ - public void getRegistrationState (Message result) - { + public void getRegistrationState (Message result) { String ret[] = new String[3]; ret[0] = "5"; // registered roam @@ -878,8 +869,7 @@ public final class SimulatedCommands extends BaseCommands * Please note that registration state 4 ("unknown") is treated * as "out of service" in the Android telephony system */ - public void getGPRSRegistrationState (Message result) - { + public void getGPRSRegistrationState (Message result) { String ret[] = new String[4]; ret[0] = "5"; // registered roam @@ -896,8 +886,7 @@ public final class SimulatedCommands extends BaseCommands * 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) - { + public void getOperator(Message result) { String[] ret = new String[3]; ret[0] = "El Telco Loco"; @@ -912,8 +901,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void sendDtmf(char c, Message result) - { + public void sendDtmf(char c, Message result) { resultSuccess(result, null); } @@ -922,8 +910,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void startDtmf(char c, Message result) - { + public void startDtmf(char c, Message result) { resultSuccess(result, null); } @@ -932,8 +919,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void stopDtmf(Message result) - { + public void stopDtmf(Message result) { resultSuccess(result, null); } @@ -950,16 +936,35 @@ public final class SimulatedCommands extends BaseCommands unimplemented(response); } + public void deleteSmsOnRuim(int index, Message response) { + Log.d(LOG_TAG, "Delete RUIM message at index " + index); + unimplemented(response); + } + public void writeSmsToSim(int status, String smsc, String pdu, Message response) { Log.d(LOG_TAG, "Write SMS to SIM with status " + status); unimplemented(response); } + public void writeSmsToRuim(int status, String pdu, Message response) { + Log.d(LOG_TAG, "Write SMS to RUIM with status " + status); + unimplemented(response); + } public void setupDefaultPDP(String apn, String user, String password, Message result) { unimplemented(result); } + public void setupDataCall(String radioTechnology, String profile, String apn, String user, + String password, Message result) { + unimplemented(result); + } + + public void deactivateDataCall(int cid, Message result) {unimplemented(result);} + + /** + * @deprecated + */ public void deactivateDefaultPDP(int cid, Message result) {unimplemented(result);} public void setPreferredNetworkType(int networkType , Message result) { @@ -994,9 +999,8 @@ public final class SimulatedCommands extends BaseCommands } return false; } - - public void setRadioPower(boolean on, Message result) - { + + public void setRadioPower(boolean on, Message result) { if(on) { if (isSimLocked()) { Log.i("SIM", "[SimCmd] setRadioPower: SIM locked! state=" + @@ -1016,12 +1020,16 @@ public final class SimulatedCommands extends BaseCommands unimplemented(result); } + public void acknowledgeLastIncomingCdmaSms(boolean success, Message result) { + unimplemented(result); + } + /** * parameters equivilient to 27.007 AT+CRSM command * response.obj will be an AsyncResult * response.obj.userObj will be a SimIoResult on success */ - public void simIO (int command, int fileid, String path, int p1, int p2, + public void iccIO (int command, int fileid, String path, int p1, int p2, int p3, String data, String pin2, Message result) { unimplemented(result); } @@ -1069,8 +1077,7 @@ public final class SimulatedCommands extends BaseCommands * @param response is callback message */ - public void queryCallWaiting(int serviceClass, Message response) - { + public void queryCallWaiting(int serviceClass, Message response) { unimplemented(response); } @@ -1081,8 +1088,7 @@ public final class SimulatedCommands extends BaseCommands */ public void setCallWaiting(boolean enable, int serviceClass, - Message response) - { + Message response) { unimplemented(response); } @@ -1092,7 +1098,7 @@ public final class SimulatedCommands extends BaseCommands * @param serviceClass is a sum of SERVICE_CLASSS_* */ public void setCallForward(int action, int cfReason, int serviceClass, - String number, int timeSeconds, Message result) {unimplemented(result);} + String number, int timeSeconds, Message result) {unimplemented(result);} /** * cfReason is one of CF_REASON_* @@ -1103,11 +1109,12 @@ public final class SimulatedCommands extends BaseCommands * An array of length 0 means "disabled for all codes" */ public void queryCallForwardStatus(int cfReason, int serviceClass, - String number, Message result) {unimplemented(result);} + String number, Message result) {unimplemented(result);} public void setNetworkSelectionModeAutomatic(Message result) {unimplemented(result);} - public void setNetworkSelectionModeManual(String operatorNumeric, Message result) {unimplemented(result);} + public void setNetworkSelectionModeManual( + String operatorNumeric, Message result) {unimplemented(result);} /** * Queries whether the current network selection mode is automatic @@ -1117,8 +1124,7 @@ public final class SimulatedCommands extends BaseCommands * a 0 for automatic selection and a 1 for manual selection */ - public void getNetworkSelectionMode(Message result) - { + public void getNetworkSelectionMode(Message result) { int ret[] = new int[1]; ret[0] = 0; @@ -1132,8 +1138,7 @@ public final class SimulatedCommands extends BaseCommands */ public void getAvailableNetworks(Message result) {unimplemented(result);} - public void getBasebandVersion (Message result) - { + public void getBasebandVersion (Message result) { resultSuccess(result, "SimulatedCommands"); } @@ -1172,13 +1177,11 @@ public final class SimulatedCommands extends BaseCommands } - public void resetRadio(Message result) - { + public void resetRadio(Message result) { unimplemented(result); } - public void invokeOemRilRequestRaw(byte[] data, Message response) - { + public void invokeOemRilRequestRaw(byte[] data, Message response) { // Just echo back data if (response != null) { AsyncResult.forMessage(response).result = data; @@ -1186,8 +1189,7 @@ public final class SimulatedCommands extends BaseCommands } } - public void invokeOemRilRequestStrings(String[] strings, Message response) - { + public void invokeOemRilRequestStrings(String[] strings, Message response) { // Just echo back data if (response != null) { AsyncResult.forMessage(response).result = strings; @@ -1200,23 +1202,20 @@ public final class SimulatedCommands extends BaseCommands /** Start the simulated phone ringing */ public void - triggerRing(String number) - { + triggerRing(String number) { simulatedCallState.triggerRing(number); mCallStateRegistrants.notifyRegistrants(); } public void - progressConnectingCallState() - { + progressConnectingCallState() { simulatedCallState.progressConnectingCallState(); mCallStateRegistrants.notifyRegistrants(); } /** If a call is DIALING or ALERTING, progress it all the way to ACTIVE */ public void - progressConnectingToActive() - { + progressConnectingToActive() { simulatedCallState.progressConnectingToActive(); mCallStateRegistrants.notifyRegistrants(); } @@ -1225,40 +1224,34 @@ public final class SimulatedCommands extends BaseCommands * default to true */ public void - setAutoProgressConnectingCall(boolean b) - { + setAutoProgressConnectingCall(boolean b) { simulatedCallState.setAutoProgressConnectingCall(b); } public void - setNextDialFailImmediately(boolean b) - { + setNextDialFailImmediately(boolean b) { simulatedCallState.setNextDialFailImmediately(b); } public void - setNextCallFailCause(int gsmCause) - { + setNextCallFailCause(int gsmCause) { nextCallFailCause = gsmCause; } public void - triggerHangupForeground() - { + triggerHangupForeground() { simulatedCallState.triggerHangupForeground(); mCallStateRegistrants.notifyRegistrants(); } /** hangup holding calls */ public void - triggerHangupBackground() - { + triggerHangupBackground() { simulatedCallState.triggerHangupBackground(); mCallStateRegistrants.notifyRegistrants(); } - public void triggerSsn(int type, int code) - { + public void triggerSsn(int type, int code) { SuppServiceNotification not = new SuppServiceNotification(); not.notificationType = type; not.code = code; @@ -1266,8 +1259,7 @@ public final class SimulatedCommands extends BaseCommands } public void - shutdown() - { + shutdown() { setRadioState(RadioState.RADIO_UNAVAILABLE); Looper looper = mHandlerThread.getLooper(); if (looper != null) { @@ -1278,27 +1270,23 @@ public final class SimulatedCommands extends BaseCommands /** hangup all */ public void - triggerHangupAll() - { + triggerHangupAll() { simulatedCallState.triggerHangupAll(); mCallStateRegistrants.notifyRegistrants(); } public void - triggerIncomingSMS(String message) - { + triggerIncomingSMS(String message) { //TODO } public void - pauseResponses() - { + pauseResponses() { pausedResponseCount++; } public void - resumeResponses() - { + resumeResponses() { pausedResponseCount--; if (pausedResponseCount == 0) { @@ -1313,8 +1301,7 @@ public final class SimulatedCommands extends BaseCommands //***** Private Methods - private void unimplemented(Message result) - { + private void unimplemented(Message result) { if (result != null) { AsyncResult.forMessage(result).exception = new RuntimeException("Unimplemented"); @@ -1327,8 +1314,7 @@ public final class SimulatedCommands extends BaseCommands } } - private void resultSuccess(Message result, Object ret) - { + private void resultSuccess(Message result, Object ret) { if (result != null) { AsyncResult.forMessage(result).result = ret; if (pausedResponseCount > 0) { @@ -1339,8 +1325,7 @@ public final class SimulatedCommands extends BaseCommands } } - private void resultFail(Message result, Throwable tr) - { + private void resultFail(Message result, Throwable tr) { if (result != null) { AsyncResult.forMessage(result).exception = tr; if (pausedResponseCount > 0) { @@ -1351,4 +1336,103 @@ public final class SimulatedCommands extends BaseCommands } } + // ***** Methods for CDMA support + public void + getDeviceIdentity(Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + public void + getCDMASubscription(Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + public void + setCdmaSubscription(int cdmaSubscriptionType, Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + public void queryCdmaRoamingPreference(Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + public void + setPhoneType(int phoneType) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + } + + public void getPreferredVoicePrivacy(Message result) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(result); + } + + public void setPreferredVoicePrivacy(boolean enable, Message result) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(result); + } + + /** + * Set the TTY mode for the CDMA phone + * + * @param enable is true to enable, false to disable + * @param serviceClass is a sum of SERVICE_CLASS_* + * @param response is callback message + */ + public void setTTYModeEnabled(boolean enable, Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + /** + * 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. + * + * @param serviceClass is a sum of SERVICE_CLASS_* + * @param response is callback message + */ + public void queryTTYModeEnabled(Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + /** + * {@inheritDoc} + */ + public void sendCDMAFeatureCode(String FeatureCode, Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + /** + * {@inheritDoc} + */ + public void sendCdmaSms(byte[] pdu, Message response){ + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + } + + public void activateCdmaBroadcastSms(int activate, Message result) { + // TODO Auto-generated method stub + + } + + public void getCdmaBroadcastConfig(Message result) { + // TODO Auto-generated method stub + + } + + public void setCdmaBroadcastConfig(int[] configValuesArray, Message result) { + // TODO Auto-generated method stub + + } + } diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedGsmCallState.java b/telephony/java/com/android/internal/telephony/test/SimulatedGsmCallState.java index 340d788..803735c 100644 --- a/telephony/java/com/android/internal/telephony/test/SimulatedGsmCallState.java +++ b/telephony/java/com/android/internal/telephony/test/SimulatedGsmCallState.java @@ -21,14 +21,13 @@ import android.os.Message; import android.os.Handler; import android.telephony.PhoneNumberUtils; import com.android.internal.telephony.ATParseEx; -import com.android.internal.telephony.gsm.DriverCall; +import com.android.internal.telephony.DriverCall; import java.util.List; import java.util.ArrayList; import android.util.Log; -class CallInfo -{ +class CallInfo { enum State { ACTIVE(0), HOLDING(1), @@ -49,8 +48,7 @@ class CallInfo String number; int TOA; - CallInfo (boolean isMT, State state, boolean isMpty, String number) - { + CallInfo (boolean isMT, State state, boolean isMpty, String number) { this.isMT = isMT; this.state = state; this.isMpty = isMpty; @@ -64,20 +62,17 @@ class CallInfo } static CallInfo - createOutgoingCall(String number) - { + createOutgoingCall(String number) { return new CallInfo (false, State.DIALING, false, number); } static CallInfo - createIncomingCall(String number) - { + createIncomingCall(String number) { return new CallInfo (true, State.INCOMING, false, number); } String - toCLCCLine(int index) - { + toCLCCLine(int index) { return "+CLCC: " + index + "," + (isMT ? "1" : "0") +"," @@ -86,8 +81,7 @@ class CallInfo } DriverCall - toDriverCall(int index) - { + toDriverCall(int index) { DriverCall ret; ret = new DriverCall(); @@ -112,36 +106,30 @@ class CallInfo boolean - isActiveOrHeld() - { + isActiveOrHeld() { return state == State.ACTIVE || state == State.HOLDING; } boolean - isConnecting() - { + isConnecting() { return state == State.DIALING || state == State.ALERTING; } boolean - isRinging() - { + isRinging() { return state == State.INCOMING || state == State.WAITING; } } -class InvalidStateEx extends Exception -{ - InvalidStateEx() - { +class InvalidStateEx extends Exception { + InvalidStateEx() { } } -class SimulatedGsmCallState extends Handler -{ +class SimulatedGsmCallState extends Handler { //***** Instance Variables CallInfo calls[] = new CallInfo[MAX_CALLS]; @@ -168,8 +156,7 @@ class SimulatedGsmCallState extends Handler } public void - handleMessage(Message msg) - { + handleMessage(Message msg) { synchronized(this) { switch (msg.what) { // PLEASE REMEMBER // calls may have hung up by the time delayed events happen @@ -181,15 +168,13 @@ class SimulatedGsmCallState extends Handler } //***** Public Methods - - + /** * Start the simulated phone ringing * true if succeeded, false if failed */ public boolean - triggerRing(String number) - { + triggerRing(String number) { synchronized (this) { int empty = -1; boolean isCallWaiting = false; @@ -230,8 +215,7 @@ class SimulatedGsmCallState extends Handler /** If a call is DIALING or ALERTING, progress it to the next state */ public void - progressConnectingCallState() - { + progressConnectingCallState() { synchronized (this) { for (int i = 0 ; i < calls.length ; i++) { CallInfo call = calls[i]; @@ -257,8 +241,7 @@ class SimulatedGsmCallState extends Handler /** If a call is DIALING or ALERTING, progress it all the way to ACTIVE */ public void - progressConnectingToActive() - { + progressConnectingToActive() { synchronized (this) { for (int i = 0 ; i < calls.length ; i++) { CallInfo call = calls[i]; @@ -277,14 +260,12 @@ class SimulatedGsmCallState extends Handler * default to true */ public void - setAutoProgressConnectingCall(boolean b) - { + setAutoProgressConnectingCall(boolean b) { autoProgressConnecting = b; } public void - setNextDialFailImmediately(boolean b) - { + setNextDialFailImmediately(boolean b) { nextDialFailImmediately = b; } @@ -293,8 +274,7 @@ class SimulatedGsmCallState extends Handler * returns true if call was hung up, false if not */ public boolean - triggerHangupForeground() - { + triggerHangupForeground() { synchronized (this) { boolean found; @@ -333,8 +313,7 @@ class SimulatedGsmCallState extends Handler * returns true if call was hung up, false if not */ public boolean - triggerHangupBackground() - { + triggerHangupBackground() { synchronized (this) { boolean found = false; @@ -356,8 +335,7 @@ class SimulatedGsmCallState extends Handler * returns true if call was hung up, false if not */ public boolean - triggerHangupAll() - { + triggerHangupAll() { synchronized(this) { boolean found = false; @@ -376,8 +354,7 @@ class SimulatedGsmCallState extends Handler } public boolean - onAnswer() - { + onAnswer() { synchronized (this) { for (int i = 0 ; i < calls.length ; i++) { CallInfo call = calls[i]; @@ -395,8 +372,7 @@ class SimulatedGsmCallState extends Handler } public boolean - onHangup() - { + onHangup() { boolean found = false; for (int i = 0 ; i < calls.length ; i++) { @@ -412,8 +388,7 @@ class SimulatedGsmCallState extends Handler } public boolean - onChld(char c0, char c1) - { + onChld(char c0, char c1) { boolean ret; int callIndex = 0; @@ -499,8 +474,7 @@ class SimulatedGsmCallState extends Handler public boolean - releaseActiveAcceptHeldOrWaiting() - { + releaseActiveAcceptHeldOrWaiting() { boolean foundHeld = false; boolean foundActive = false; @@ -555,8 +529,7 @@ class SimulatedGsmCallState extends Handler } public boolean - switchActiveAndHeldOrWaiting() - { + switchActiveAndHeldOrWaiting() { boolean hasHeld = false; // first, are there held calls? @@ -589,8 +562,7 @@ class SimulatedGsmCallState extends Handler public boolean - separateCall(int index) - { + separateCall(int index) { try { CallInfo c; @@ -631,8 +603,7 @@ class SimulatedGsmCallState extends Handler public boolean - conference() - { + conference() { int countCalls = 0; // if there's connecting calls, we can't do this yet @@ -662,8 +633,7 @@ class SimulatedGsmCallState extends Handler } public boolean - explicitCallTransfer() - { + explicitCallTransfer() { int countCalls = 0; // if there's connecting calls, we can't do this yet @@ -684,8 +654,7 @@ class SimulatedGsmCallState extends Handler } public boolean - onDial(String address) - { + onDial(String address) { CallInfo call; int freeSlot = -1; @@ -758,8 +727,7 @@ class SimulatedGsmCallState extends Handler } public List<DriverCall> - getDriverCalls() - { + getDriverCalls() { ArrayList<DriverCall> ret = new ArrayList<DriverCall>(calls.length); for (int i = 0 ; i < calls.length ; i++) { @@ -779,8 +747,7 @@ class SimulatedGsmCallState extends Handler } public List<String> - getClccLines() - { + getClccLines() { ArrayList<String> ret = new ArrayList<String>(calls.length); for (int i = 0 ; i < calls.length ; i++) { @@ -795,8 +762,7 @@ class SimulatedGsmCallState extends Handler } private int - countActiveLines() throws InvalidStateEx - { + countActiveLines() throws InvalidStateEx { boolean hasMpty = false; boolean hasHeld = false; boolean hasActive = false; |