diff options
Diffstat (limited to 'telephony/java/com/android/internal')
26 files changed, 1163 insertions, 1454 deletions
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java index e583110..a7ac2bc 100644 --- a/telephony/java/com/android/internal/telephony/CommandsInterface.java +++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java @@ -82,15 +82,6 @@ public interface CommandsInterface { } } - enum IccStatus { - ICC_ABSENT, - ICC_NOT_READY, - ICC_READY, - ICC_PIN, - ICC_PUK, - ICC_NETWORK_PERSONALIZATION - } - //***** Constants // Used as parameter to dial() and setCLIR() below @@ -534,15 +525,6 @@ public interface CommandsInterface { void unregisterForCdmaOtaProvision(Handler h); /** - * Returns current ICC status. - * - * AsyncResult.result is IccStatus - * - */ - - void getIccStatus(Message result); - - /** * Supply the ICC PIN to the ICC card * * returned message @@ -1366,4 +1348,12 @@ public interface CommandsInterface { * @param response callback message */ public void exitEmergencyCallbackMode(Message response); + + /** + * Request the status of the ICC and UICC cards. + * + * @param response + * Callback message containing {@link IccCardStatus} structure for the card. + */ + public void getIccCardStatus(Message result); } diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java index d7ad492..c2bed88 100644 --- a/telephony/java/com/android/internal/telephony/IccCard.java +++ b/telephony/java/com/android/internal/telephony/IccCard.java @@ -16,13 +16,40 @@ package com.android.internal.telephony; -import android.os.Message; +import static android.Manifest.permission.READ_PHONE_STATE; +import android.app.ActivityManagerNative; +import android.content.Intent; +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 com.android.internal.telephony.PhoneBase; +import com.android.internal.telephony.CommandsInterface.RadioState; /** * {@hide} */ -public interface IccCard { +public abstract class IccCard { + protected String mLogTag; + protected boolean mDbg; + + private IccCardStatus mIccCardStatus = null; + protected State mState = null; + protected PhoneBase mPhone; + private RegistrantList mAbsentRegistrants = new RegistrantList(); + private RegistrantList mPinLockedRegistrants = new RegistrantList(); + private RegistrantList mNetworkLockedRegistrants = new RegistrantList(); + + private boolean mDesiredPinLocked; + private boolean mDesiredFdnEnabled; + private boolean mIccPinLocked = true; // Default to locked + private boolean mIccFdnEnabled = false; // Default to disabled. + // Will be updated when SIM_READY. + + /* 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) */ @@ -46,6 +73,17 @@ public interface IccCard { /* NETWORK means ICC is locked on NETWORK PERSONALIZATION */ static public final String INTENT_VALUE_LOCKED_NETWORK = "NETWORK"; + protected static final int EVENT_ICC_LOCKED_OR_ABSENT = 1; + private static final int EVENT_GET_ICC_STATUS_DONE = 2; + protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3; + private static final int EVENT_PINPUK_DONE = 4; + private static final int EVENT_REPOLL_STATUS_DONE = 5; + protected static final int EVENT_ICC_READY = 6; + private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7; + private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8; + private static final int EVENT_CHANGE_ICC_PASSWORD_DONE = 9; + private static final int EVENT_QUERY_FACILITY_FDN_DONE = 10; + private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11; /* UNKNOWN is a transient state, for example, after uesr inputs ICC pin under @@ -58,33 +96,108 @@ public interface IccCard { PIN_REQUIRED, PUK_REQUIRED, NETWORK_LOCKED, - READY; + READY, + NOT_READY; public boolean isPinLocked() { return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED)); } } - State getState(); + public State getState() { + if (mState == null) { + switch(mPhone.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 SIM_NOT_READY: + case RUIM_NOT_READY: + return State.UNKNOWN; + case SIM_LOCKED_OR_ABSENT: + case RUIM_LOCKED_OR_ABSENT: + //this should be transient-only + return State.UNKNOWN; + case SIM_READY: + case RUIM_READY: + case NV_READY: + return State.READY; + case NV_NOT_READY: + return State.ABSENT; + } + } else { + return mState; + } + + Log.e(mLogTag, "IccCard.getState(): case should never be reached"); + return State.UNKNOWN; + } + + public IccCard(PhoneBase phone, String logTag, Boolean dbg) { + mPhone = phone; + mLogTag = logTag; + mDbg = dbg; + } + + abstract public void dispose(); + protected void finalize() { + if(mDbg) Log.d(mLogTag, "IccCard finalized"); + } /** * Notifies handler of any transition into State.ABSENT */ - void registerForAbsent(Handler h, int what, Object obj); - void unregisterForAbsent(Handler h); + public void registerForAbsent(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + mAbsentRegistrants.add(r); + + if (getState() == State.ABSENT) { + r.notifyRegistrant(); + } + } + + public void unregisterForAbsent(Handler h) { + mAbsentRegistrants.remove(h); + } /** - * Notifies handler of any transition into State.isPinLocked() + * Notifies handler of any transition into State.NETWORK_LOCKED */ - void registerForLocked(Handler h, int what, Object obj); - void unregisterForLocked(Handler h); + public void registerForNetworkLocked(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + mNetworkLockedRegistrants.add(r); + + if (getState() == State.NETWORK_LOCKED) { + r.notifyRegistrant(); + } + } + + public void unregisterForNetworkLocked(Handler h) { + mNetworkLockedRegistrants.remove(h); + } /** - * Notifies handler of any transition into State.NETWORK_LOCKED + * Notifies handler of any transition into State.isPinLocked() */ - void registerForNetworkLocked(Handler h, int what, Object obj); - void unregisterForNetworkLocked(Handler h); + public void registerForLocked(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + mPinLockedRegistrants.add(r); + + if (getState().isPinLocked()) { + r.notifyRegistrant(); + } + } + + public void unregisterForLocked(Handler h) { + mPinLockedRegistrants.remove(h); + } + /** * Supply the ICC PIN to the ICC @@ -107,10 +220,30 @@ public interface IccCard { * */ - void supplyPin (String pin, Message onComplete); - void supplyPuk (String puk, String newPin, Message onComplete); - void supplyPin2 (String pin2, Message onComplete); - void supplyPuk2 (String puk2, String newPin2, Message onComplete); + public void supplyPin (String pin, Message onComplete) { + mPhone.mCM.supplyIccPin(pin, mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public void supplyPuk (String puk, String newPin, Message onComplete) { + mPhone.mCM.supplyIccPuk(puk, newPin, + mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public void supplyPin2 (String pin2, Message onComplete) { + mPhone.mCM.supplyIccPin2(pin2, + mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public void supplyPuk2 (String puk2, String newPin2, Message onComplete) { + mPhone.mCM.supplyIccPuk2(puk2, newPin2, + mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public void supplyNetworkDepersonalization (String pin, Message onComplete) { + if(mDbg) log("Network Despersonalization: " + pin); + mPhone.mCM.supplyNetworkDepersonalization(pin, + mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } /** * Check whether ICC pin lock is enabled @@ -119,35 +252,9 @@ public interface IccCard { * @return true for ICC locked enabled * false for ICC locked disabled */ - boolean getIccLockEnabled (); - - /** - * 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 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 setIccLockEnabled(boolean enabled, String password, Message onComplete); - - - /** - * 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 - * @param newPassword is the new password - * @param onComplete - * onComplete.obj will be an AsyncResult - * ((AsyncResult)onComplete.obj).exception == null on success - * ((AsyncResult)onComplete.obj).exception != null on fail - */ - void changeIccLockPassword(String oldPassword, String newPassword, - Message onComplete); + public boolean getIccLockEnabled() { + return mIccPinLocked; + } /** * Check whether ICC fdn (fixed dialing number) is enabled @@ -156,36 +263,99 @@ public interface IccCard { * @return true for ICC fdn enabled * false for ICC fdn disabled */ - boolean getIccFdnEnabled (); + public boolean getIccFdnEnabled() { + return mIccFdnEnabled; + } - /** - * 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 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 setIccFdnEnabled(boolean enabled, String password, Message onComplete); + /** + * 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 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 + */ + public void setIccLockEnabled (boolean enabled, + String password, Message onComplete) { + int serviceClassX; + serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + + CommandsInterface.SERVICE_CLASS_DATA + + CommandsInterface.SERVICE_CLASS_FAX; - /** - * 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 - * @param newPassword is the new password - * @param onComplete - * onComplete.obj will be an AsyncResult - * ((AsyncResult)onComplete.obj).exception == null on success - * ((AsyncResult)onComplete.obj).exception != null on fail - */ - void changeIccFdnPassword(String oldPassword, String newPassword, - Message onComplete); + mDesiredPinLocked = enabled; + + mPhone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM, + enabled, password, serviceClassX, + mHandler.obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete)); + } + + /** + * 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 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 + */ + 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; + + mPhone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD, + enabled, password, serviceClassX, + mHandler.obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete)); + } + + /** + * 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 + * @param newPassword is the new password + * @param onComplete + * onComplete.obj will be an AsyncResult + * ((AsyncResult)onComplete.obj).exception == null on success + * ((AsyncResult)onComplete.obj).exception != null on fail + */ + public void changeIccLockPassword(String oldPassword, String newPassword, + Message onComplete) { + if(mDbg) log("Change Pin1 old: " + oldPassword + " new: " + newPassword); + mPhone.mCM.changeIccPin(oldPassword, newPassword, + mHandler.obtainMessage(EVENT_CHANGE_ICC_PASSWORD_DONE, onComplete)); + + } + + /** + * 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 + * @param newPassword is the new password + * @param onComplete + * onComplete.obj will be an AsyncResult + * ((AsyncResult)onComplete.obj).exception == null on success + * ((AsyncResult)onComplete.obj).exception != null on fail + */ + public void changeIccFdnPassword(String oldPassword, String newPassword, + Message onComplete) { + if(mDbg) log("Change Pin2 old: " + oldPassword + " new: " + newPassword); + mPhone.mCM.changeIccPin2(oldPassword, newPassword, + mHandler.obtainMessage(EVENT_CHANGE_ICC_PASSWORD_DONE, onComplete)); + + } - void supplyNetworkDepersonalization (String pin, Message onComplete); /** * Returns service provider name stored in ICC card. @@ -203,5 +373,301 @@ public interface IccCard { * yet available * */ - String getServiceProviderName(); + public abstract String getServiceProviderName(); + + protected void updateStateProperty() { + mPhone.setSystemProperty(TelephonyProperties.PROPERTY_SIM_STATE, getState().toString()); + } + + private void getIccCardStatusDone(AsyncResult ar) { + if (ar.exception != null) { + Log.e(mLogTag,"Error getting ICC status. " + + "RIL_REQUEST_GET_ICC_STATUS should " + + "never return an error", ar.exception); + return; + } + handleIccCardStatus((IccCardStatus) ar.result); + } + + private void handleIccCardStatus(IccCardStatus newCardStatus) { + boolean transitionedIntoPinLocked; + boolean transitionedIntoAbsent; + boolean transitionedIntoNetworkLocked; + + State oldState, newState; + + oldState = mState; + mIccCardStatus = newCardStatus; + newState = getIccCardState(); + mState = newState; + + 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(mDbg) log("Notify SIM pin or puk locked."); + mPinLockedRegistrants.notifyRegistrants(); + broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED, + (newState == State.PIN_REQUIRED) ? + INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK); + } else if (transitionedIntoAbsent) { + if(mDbg) log("Notify SIM missing."); + mAbsentRegistrants.notifyRegistrants(); + broadcastIccStateChangedIntent(INTENT_VALUE_ICC_ABSENT, null); + } else if (transitionedIntoNetworkLocked) { + if(mDbg) log("Notify SIM network locked."); + mNetworkLockedRegistrants.notifyRegistrants(); + broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED, + INTENT_VALUE_LOCKED_NETWORK); + } + } + + /** + * Interperate EVENT_QUERY_FACILITY_LOCK_DONE + * @param ar is asyncResult of Query_Facility_Locked + */ + private void onQueryFdnEnabled(AsyncResult ar) { + if(ar.exception != null) { + if(mDbg) log("Error in querying facility lock:" + ar.exception); + return; + } + + int[] ints = (int[])ar.result; + if(ints.length != 0) { + mIccFdnEnabled = (0!=ints[0]); + if(mDbg) log("Query facility lock : " + mIccFdnEnabled); + } else { + Log.e(mLogTag, "[IccCard] Bogus facility lock response"); + } + } + + /** + * Interperate EVENT_QUERY_FACILITY_LOCK_DONE + * @param ar is asyncResult of Query_Facility_Locked + */ + private void onQueryFacilityLock(AsyncResult ar) { + if(ar.exception != null) { + if (mDbg) log("Error in querying facility lock:" + ar.exception); + return; + } + + int[] ints = (int[])ar.result; + if(ints.length != 0) { + mIccPinLocked = (0!=ints[0]); + if(mDbg) log("Query facility lock : " + mIccPinLocked); + } else { + Log.e(mLogTag, "[IccCard] Bogus facility lock response"); + } + } + + public void broadcastIccStateChangedIntent(String value, String reason) { + Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); + intent.putExtra(Phone.PHONE_NAME_KEY, mPhone.getPhoneName()); + intent.putExtra(INTENT_KEY_ICC_STATE, value); + intent.putExtra(INTENT_KEY_LOCKED_REASON, reason); + if(mDbg) log("Broadcasting intent ACTION_SIM_STATE_CHANGED " + value + + " reason " + reason); + ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE); + } + + protected Handler mHandler = new Handler() { + @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: + mState = null; + updateStateProperty(); + broadcastIccStateChangedIntent(INTENT_VALUE_ICC_NOT_READY, null); + break; + case EVENT_ICC_READY: + //TODO: put facility read in SIM_READY now, maybe in REG_NW + mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE)); + mPhone.mCM.queryFacilityLock ( + CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, + obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); + mPhone.mCM.queryFacilityLock ( + CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX, + obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE)); + break; + case EVENT_ICC_LOCKED_OR_ABSENT: + mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE)); + mPhone.mCM.queryFacilityLock ( + CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, + obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); + break; + case EVENT_GET_ICC_STATUS_DONE: + ar = (AsyncResult)msg.obj; + + getIccCardStatusDone(ar); + break; + case EVENT_PINPUK_DONE: + // 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; + mPhone.mCM.getIccCardStatus( + obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj)); + break; + case EVENT_REPOLL_STATUS_DONE: + // 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; + getIccCardStatusDone(ar); + ((Message)ar.userObj).sendToTarget(); + break; + case EVENT_QUERY_FACILITY_LOCK_DONE: + ar = (AsyncResult)msg.obj; + onQueryFacilityLock(ar); + break; + case EVENT_QUERY_FACILITY_FDN_DONE: + ar = (AsyncResult)msg.obj; + onQueryFdnEnabled(ar); + break; + case EVENT_CHANGE_FACILITY_LOCK_DONE: + ar = (AsyncResult)msg.obj; + if (ar.exception == null) { + mIccPinLocked = mDesiredPinLocked; + if (mDbg) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " + + "mIccPinLocked= " + mIccPinLocked); + } else { + Log.e(mLogTag, "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: + ar = (AsyncResult)msg.obj; + + if (ar.exception == null) { + mIccFdnEnabled = mDesiredFdnEnabled; + if (mDbg) log("EVENT_CHANGE_FACILITY_FDN_DONE: " + + "mIccFdnEnabled=" + mIccFdnEnabled); + } else { + Log.e(mLogTag, "Error change facility fdn with exception " + + ar.exception); + } + AsyncResult.forMessage(((Message)ar.userObj)).exception + = ar.exception; + ((Message)ar.userObj).sendToTarget(); + break; + case EVENT_CHANGE_ICC_PASSWORD_DONE: + ar = (AsyncResult)msg.obj; + if(ar.exception != null) { + Log.e(mLogTag, "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(mLogTag, "[IccCard] Unknown Event " + msg.what); + } + } + }; + + public State getIccCardState() { + if (mIccCardStatus == null) { + Log.e(mLogTag, "[IccCard] IccCardStatus is null"); + return IccCard.State.ABSENT; + } + + // this is common for all radio technologies + if (!mIccCardStatus.getCardState().isCardPresent()) { + return IccCard.State.NOT_READY; + } + + RadioState currentRadioState = mPhone.mCM.getRadioState(); + // 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 IccCard.State.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 = mIccCardStatus.getCdmaSubscriptionAppIndex(); + } + else { + index = mIccCardStatus.getGsmUmtsSubscriptionAppIndex(); + } + + IccCardApplication app = mIccCardStatus.getApplication(index); + + if (app == null) { + Log.e(mLogTag, "[IccCard] Subscription Application in not present"); + return IccCard.State.ABSENT; + } + + // check if PIN required + if (app.app_state.isPinRequired()) { + return IccCard.State.PIN_REQUIRED; + } + if (app.app_state.isPukRequired()) { + return IccCard.State.PUK_REQUIRED; + } + if (app.app_state.isSubscriptionPersoEnabled()) { + return IccCard.State.NETWORK_LOCKED; + } + if (app.app_state.isAppReady()) { + return IccCard.State.READY; + } + if (app.app_state.isAppNotReady()) { + return IccCard.State.NOT_READY; + } + return IccCard.State.NOT_READY; + } + + return IccCard.State.ABSENT; + } + + + public boolean hasApplicationType(IccCardApplication.AppType type) { + if (mIccCardStatus == null) return false; + + for (int i = 0 ; i < mIccCardStatus.getNumApplications(); i++) { + IccCardApplication app = mIccCardStatus.getApplication(i); + if (app != null && app.app_type == type) { + return true; + } + } + return false; + } + + private void log(String msg) { + Log.d(mLogTag, "[IccCard] " + msg); + } } diff --git a/telephony/java/com/android/internal/telephony/IccCardStatus.java b/telephony/java/com/android/internal/telephony/IccCardStatus.java index b602b1c..0e7bad7 100644 --- a/telephony/java/com/android/internal/telephony/IccCardStatus.java +++ b/telephony/java/com/android/internal/telephony/IccCardStatus.java @@ -45,42 +45,89 @@ public class IccCardStatus { 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; + private CardState mCardState; + private PinState mUniversalPinState; + private int mGsmUmtsSubscriptionAppIndex; + private int mCdmaSubscriptionAppIndex; + private int mNumApplications; - ArrayList<IccCardApplication> application = new ArrayList<IccCardApplication>(CARD_MAX_APPS); + private ArrayList<IccCardApplication> mApplications = + new ArrayList<IccCardApplication>(CARD_MAX_APPS); - CardState CardStateFromRILInt(int state) { - CardState newState; - /* RIL_CardState ril.h */ + public CardState getCardState() { + return mCardState; + } + + public void setCardState(int state) { 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); + case 0: + mCardState = CardState.CARDSTATE_ABSENT; + break; + case 1: + mCardState = CardState.CARDSTATE_PRESENT; + break; + case 2: + mCardState = CardState.CARDSTATE_ERROR; + break; + default: + throw new RuntimeException("Unrecognized RIL_CardState: " + state); } - return newState; } - PinState PinStateFromRILInt(int state) { - PinState newState; - /* RIL_PinState ril.h */ + public void setUniversalPinState(int state) { 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); + case 0: + mUniversalPinState = PinState.PINSTATE_UNKNOWN; + break; + case 1: + mUniversalPinState = PinState.PINSTATE_ENABLED_NOT_VERIFIED; + break; + case 2: + mUniversalPinState = PinState.PINSTATE_ENABLED_VERIFIED; + break; + case 3: + mUniversalPinState = PinState.PINSTATE_DISABLED; + break; + case 4: + mUniversalPinState = PinState.PINSTATE_ENABLED_BLOCKED; + break; + case 5: + mUniversalPinState = PinState.PINSTATE_ENABLED_PERM_BLOCKED; + break; + default: + throw new RuntimeException("Unrecognized RIL_PinState: " + state); } - return newState; + } + + public int getGsmUmtsSubscriptionAppIndex() { + return mGsmUmtsSubscriptionAppIndex; + } + + public void setGsmUmtsSubscriptionAppIndex(int gsmUmtsSubscriptionAppIndex) { + mGsmUmtsSubscriptionAppIndex = gsmUmtsSubscriptionAppIndex; + } + + public int getCdmaSubscriptionAppIndex() { + return mCdmaSubscriptionAppIndex; + } + + public void setCdmaSubscriptionAppIndex(int cdmaSubscriptionAppIndex) { + mCdmaSubscriptionAppIndex = cdmaSubscriptionAppIndex; + } + + public int getNumApplications() { + return mNumApplications; + } + + public void setNumApplications(int numApplications) { + mNumApplications = numApplications; + } + + public void addApplication(IccCardApplication application) { + mApplications.add(application); + } + + public IccCardApplication getApplication(int index) { + return mApplications.get(index); } } diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java index 7f2b849..0bb2df1 100644 --- a/telephony/java/com/android/internal/telephony/Phone.java +++ b/telephony/java/com/android/internal/telephony/Phone.java @@ -22,6 +22,7 @@ import android.os.Handler; import android.os.Message; import android.preference.PreferenceManager; import android.telephony.CellLocation; +import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SignalStrength; @@ -260,8 +261,8 @@ public interface Phone { /** * Get current coarse-grained voice call state. - * Use {@link #registerForPhoneStateChanged(Handler, int, Object) - * registerForPhoneStateChanged()} for change notification. <p> + * Use {@link #registerForPreciseCallStateChanged(Handler, int, Object) + * registerForPreciseCallStateChanged()} 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> @@ -315,18 +316,21 @@ public interface Phone { void unregisterForUnknownConnection(Handler h); /** - * Notifies when any aspect of the voice call state changes. + * Register for getting notifications for change in the Call State {@link Call.State} + * This is called PreciseCallState because the call state is more precise than the + * {@link Phone.State} which can be obtained using the {@link PhoneStateListener} + * * Resulting events will have an AsyncResult in <code>Message.obj</code>. * AsyncResult.userData will be set to the obj argument here. * The <em>h</em> parameter is held only by a weak reference. */ - void registerForPhoneStateChanged(Handler h, int what, Object obj); + void registerForPreciseCallStateChanged(Handler h, int what, Object obj); /** * Unregisters for voice call state change notifications. * Extraneous calls are tolerated silently. */ - void unregisterForPhoneStateChanged(Handler h); + void unregisterForPreciseCallStateChanged(Handler h); /** @@ -556,8 +560,8 @@ public interface Phone { /** * 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, - * java.lang.Object) registerForPhoneStateChanged()}. + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()}. * * @exception CallStateException when no call is ringing or waiting */ @@ -567,8 +571,8 @@ public interface Phone { * 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()}. + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()}. * * @exception CallStateException when no call is ringing or waiting */ @@ -578,8 +582,8 @@ public interface Phone { * 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, - * java.lang.Object) registerForPhoneStateChanged()}. + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()}. * * @exception CallStateException if a call is ringing, waiting, or * dialing/alerting. In these cases, this operation may not be performed. @@ -596,8 +600,8 @@ public interface Phone { /** * Conferences holding and active. Conference occurs asynchronously * and may fail. Final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()}. + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()}. * * @exception CallStateException if canConference() would return false. * In these cases, this operation may not be performed. @@ -631,8 +635,8 @@ public interface Phone { * Connects the two calls and disconnects the subscriber from both calls * Explicit Call Transfer occurs asynchronously * and may fail. Final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()}. + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()}. * * @exception CallStateException if canTransfer() would return false. * In these cases, this operation may not be performed. @@ -659,8 +663,8 @@ public interface Phone { * IDLE, ACTIVE, DIALING, ALERTING, or DISCONNECTED. * * State change notification is available via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()}. + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()}. */ Call getForegroundCall(); @@ -676,8 +680,8 @@ public interface Phone { * IDLE, HOLDING or DISCONNECTED. * * State change notification is available via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()}. + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()}. */ Call getBackgroundCall(); @@ -693,8 +697,8 @@ public interface Phone { * IDLE, INCOMING, WAITING or DISCONNECTED. * * State change notification is available via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()}. + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()}. */ Call getRingingCall(); @@ -1067,8 +1071,8 @@ public interface Phone { /** * Gets current mute status. Use - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()} + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()} * as a change notifcation, although presently phone state changed is not * fired when setMute() is called. * diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index bcb1ccc..fbda221 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -21,6 +21,7 @@ import android.app.IActivityManager; import android.content.Context; import android.content.res.Configuration; import android.content.SharedPreferences; +import android.net.wifi.WifiManager; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; @@ -28,6 +29,7 @@ import android.os.Message; import android.os.RegistrantList; import android.os.SystemProperties; import android.preference.PreferenceManager; +import android.provider.Settings; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.text.TextUtils; @@ -117,7 +119,7 @@ public abstract class PhoneBase implements Phone { } - protected final RegistrantList mPhoneStateRegistrants + protected final RegistrantList mPreciseCallStateRegistrants = new RegistrantList(); protected final RegistrantList mNewRingingConnectionRegistrants @@ -185,7 +187,7 @@ public abstract class PhoneBase implements Phone { this.mContext = context; mLooper = Looper.myLooper(); - setLocaleByCarrier(); + setPropertiesByCarrier(); setUnitTestMode(unitTestMode); @@ -219,25 +221,24 @@ public abstract class PhoneBase implements Phone { } // Inherited documentation suffices. - public void registerForPhoneStateChanged(Handler h, int what, Object obj) { + public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) { checkCorrectThread(h); - mPhoneStateRegistrants.addUnique(h, what, obj); + mPreciseCallStateRegistrants.addUnique(h, what, obj); } // Inherited documentation suffices. - public void unregisterForPhoneStateChanged(Handler h) { - mPhoneStateRegistrants.remove(h); + public void unregisterForPreciseCallStateChanged(Handler h) { + mPreciseCallStateRegistrants.remove(h); } /** - * Notify registrants of a PhoneStateChanged. * Subclasses of Phone probably want to replace this with a * version scoped to their packages */ - protected void notifyCallStateChangedP() { + protected void notifyPreciseCallStateChangedP() { AsyncResult ar = new AsyncResult(null, this, null); - mPhoneStateRegistrants.notifyRegistrants(ar); + mPreciseCallStateRegistrants.notifyRegistrants(ar); } // Inherited documentation suffices. @@ -450,10 +451,10 @@ public abstract class PhoneBase implements Phone { } /** - * Set the locale by matching the carrier string in + * Set the properties by matching the carrier string in * a string-array resource */ - private void setLocaleByCarrier() { + private void setPropertiesByCarrier() { String carrier = SystemProperties.get("ro.carrier"); if (null == carrier || 0 == carrier.length()) { @@ -461,18 +462,36 @@ public abstract class PhoneBase implements Phone { } CharSequence[] carrierLocales = mContext. - getResources().getTextArray(R.array.carrier_locales); + getResources().getTextArray(R.array.carrier_properties); - for (int i = 0; i < carrierLocales.length-1; i+=2) { + for (int i = 0; i < carrierLocales.length; i+=3) { String c = carrierLocales[i].toString(); - String l = carrierLocales[i+1].toString(); if (carrier.equals(c)) { + String l = carrierLocales[i+1].toString(); + int wifiChannels = 0; + try { + wifiChannels = Integer.parseInt( + carrierLocales[i+2].toString()); + } catch (NumberFormatException e) { } + String language = l.substring(0, 2); String country = ""; if (l.length() >=5) { country = l.substring(3, 5); } setSystemLocale(language, country); + + if (wifiChannels != 0) { + try { + Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS); + } catch (Settings.SettingNotFoundException e) { + // note this is not persisting + WifiManager wM = (WifiManager) + mContext.getSystemService(Context.WIFI_SERVICE); + wM.setNumAllowedChannels(wifiChannels, false); + } + } return; } } diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java index da00268..979f0cd 100644 --- a/telephony/java/com/android/internal/telephony/PhoneProxy.java +++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java @@ -25,6 +25,7 @@ import android.os.Handler; import android.os.Message; import android.preference.PreferenceManager; import android.telephony.CellLocation; +import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.util.Log; @@ -210,12 +211,12 @@ public class PhoneProxy extends Handler implements Phone { mActivePhone.unregisterForUnknownConnection(h); } - public void registerForPhoneStateChanged(Handler h, int what, Object obj) { - mActivePhone.registerForPhoneStateChanged(h, what, obj); + public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) { + mActivePhone.registerForPreciseCallStateChanged(h, what, obj); } - public void unregisterForPhoneStateChanged(Handler h) { - mActivePhone.unregisterForPhoneStateChanged(h); + public void unregisterForPreciseCallStateChanged(Handler h) { + mActivePhone.unregisterForPreciseCallStateChanged(h); } public void registerForNewRingingConnection(Handler h, int what, Object obj) { diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java index 690b38a..2bec9bc 100644 --- a/telephony/java/com/android/internal/telephony/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -630,7 +630,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { } public void - getIccStatus(Message result) { + getIccCardStatus(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); @@ -2735,24 +2735,22 @@ public final class RIL extends BaseCommands implements CommandsInterface { private Object 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(); + status.setCardState(p.readInt()); + status.setUniversalPinState(p.readInt()); + status.setGsmUmtsSubscriptionAppIndex(p.readInt()); + status.setCdmaSubscriptionAppIndex(p.readInt()); + int numApplications = p.readInt(); // limit to maximum allowed applications - if (status.num_applications > IccCardStatus.CARD_MAX_APPS) { - status.num_applications = IccCardStatus.CARD_MAX_APPS; + if (numApplications > IccCardStatus.CARD_MAX_APPS) { + numApplications = IccCardStatus.CARD_MAX_APPS; } + status.setNumApplications(numApplications); - for (int i = 0 ; i < status.num_applications ; i++) { + for (int i = 0 ; i < numApplications ; i++) { ca = new IccCardApplication(); ca.app_type = ca.AppTypeFromRILInt(p.readInt()); ca.app_state = ca.AppStateFromRILInt(p.readInt()); @@ -2762,62 +2760,9 @@ public final class RIL extends BaseCommands implements CommandsInterface { 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; + status.addApplication(ca); } - - // 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; + return status; } private Object diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java index bdcf3f7..8e76cd2 100644 --- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java @@ -116,6 +116,7 @@ public abstract class ServiceStateTracker extends Handler { protected static final int EVENT_POLL_STATE_CDMA_SUBSCRIPTION = 34; protected static final int EVENT_NV_READY = 35; protected static final int EVENT_ERI_FILE_LOADED = 36; + protected static final int EVENT_OTA_PROVISION_STATUS_CHANGE = 37; //***** Time Zones protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java index 3c7dd45..9c78b98 100644 --- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java +++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java @@ -352,60 +352,36 @@ public abstract class SmsMessageBase { } /** - * 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 + * Try to parse this message as an email gateway message + * There are two ways specified in TS 23.040 Section 3.8 : + * - SMS message "may have its TP-PID set for internet electronic mail - MT * SMS 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 + * address is added at the beginning as shown above." (which is supported here) + * - Multiple addreses separated by commas, no spaces, Subject field delimited + * by '()' or '##' and '#' Section 9.2.3.24.11 (which are NOT supported here) */ protected void extractEmailAddressFromMessageBody() { - /* - * a little guesswork here. I haven't found doc for this. - * the format could be either + /* Some carriers may use " /" delimiter as below * * 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); - } + String[] parts = messageBody.split("( /)|( )", 3); + if (parts.length < 2 || parts[0].indexOf('@') == -1) return; + emailFrom = parts[0]; + if (parts.length == 3) { + pseudoSubject = parts[1]; + emailBody = parts[2]; + } else { + pseudoSubject = null; + emailBody = parts[1]; + } + isEmail = true; } } diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index 02e9800..2216ec4 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -220,28 +220,4 @@ public class TelephonyIntents { */ public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS = "android.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS"; - - /** - * Broadcast Action: The MDN changed during the CDMA OTA Process - * The intent will have the following extra values:</p> - * <ul> - * <li><em>mdn</em> - An Integer of the updated MDN number.</li> - * </ul> - * - * <p class="note">This is a protected intent that can only be sent - * by the system. - * - * <p class="note"> - */ - // TODO(Moto): Generally broadcast intents are for use to allow entities which - // may not know about each other to "communicate". This seems quite specific - // and maybe using the registrant style would be better. - - // Moto: Since this is used for apps not in the same process of phone, can the - // registrant style be used? (Ling Li says: Maybe the "app" can request rather - // than save the MDN each time and this intent would not be necessary?) - // Moto response: Moto internal discussion is on-going. - public static final String ACTION_CDMA_OTA_MDN_CHANGED - = "android.intent.action.ACTION_MDN_STATE_CHANGED"; - } diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java index 5ec4020..8a1e928 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java +++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java @@ -109,4 +109,10 @@ public interface TelephonyProperties /** The international dialing prefix conversion string */ static final String PROPERTY_IDP_STRING = "ro.cdma.idpstring"; + + /** + * Defines the schema for the carrier specified OTASP number + */ + static final String PROPERTY_OTASP_NUM_SCHEMA = "ro.cdma.otaspnumschema"; + } diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java index 23eedfe..bdcea92 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java +++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java @@ -42,6 +42,7 @@ import android.telephony.SignalStrength; import android.text.TextUtils; import android.util.Log; +import com.android.internal.telephony.Call; import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; @@ -73,15 +74,19 @@ import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OP import java.util.List; import java.util.Timer; import java.util.TimerTask; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * {@hide} */ public class CDMAPhone extends PhoneBase { static final String LOG_TAG = "CDMA"; - private static final boolean LOCAL_DEBUG = true; + private static final boolean DBG = true; // Default Emergency Callback Mode exit timer - private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 30000; + private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000; static final String VM_COUNT_CDMA = "vm_count_key_cdma"; private static final String VM_NUMBER_CDMA = "vm_number_key_cdma"; private String mVmNumber = null; @@ -113,6 +118,8 @@ public class CDMAPhone extends PhoneBase { private Registrant mECMExitRespRegistrant; private String mEsn; private String mMeid; + // string to define how the carrier specifies its own ota sp number + private String mCarrierOtaSpNumSchema; // A runnable which is used to automatically exit from ECM after a period of time. private Runnable mExitEcmRunnable = new Runnable() { @@ -168,6 +175,10 @@ public class CDMAPhone extends PhoneBase { String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); mIsPhoneInECMState = inEcm.equals("true"); + // get the string that specifies the carrier OTA Sp number + mCarrierOtaSpNumSchema = SystemProperties.get( + TelephonyProperties.PROPERTY_OTASP_NUM_SCHEMA,""); + // Sets operator alpha property by retrieving from build-time system property String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha"); setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, operatorAlpha); @@ -233,7 +244,7 @@ public class CDMAPhone extends PhoneBase { } protected void finalize() { - if(LOCAL_DEBUG) Log.d(LOG_TAG, "CDMAPhone finalized"); + if(DBG) Log.d(LOG_TAG, "CDMAPhone finalized"); } @@ -423,10 +434,10 @@ public class CDMAPhone extends PhoneBase { } public String getCdmaPrlVersion(){ - return mRuimRecords.getPrlVersion(); + return mSST.getPrlVersion(); } - public String getCdmaMIN() { + public String getCdmaMin() { return mSST.getCdmaMin(); } @@ -808,19 +819,19 @@ public class CDMAPhone extends PhoneBase { } /** - * Notify any interested party of a Phone state change. + * Notify any interested party of a Phone state change {@link Phone.State} */ /*package*/ void notifyPhoneStateChanged() { mNotifier.notifyPhoneState(this); } /** - * Notifies registrants (ie, activities in the Phone app) about - * changes to call state (including Phone and Connection changes). + * Notify registrants of a change in the call state. This notifies changes in {@link Call.State} + * Use this when changes in the precise call state are needed, else use notifyPhoneStateChanged. */ - /*package*/ void notifyCallStateChanged() { + /*package*/ void notifyPreciseCallStateChanged() { /* we'd love it if this was package-scoped*/ - super.notifyCallStateChangedP(); + super.notifyPreciseCallStateChangedP(); } void notifyServiceStateChanged(ServiceState ss) { @@ -959,7 +970,7 @@ public class CDMAPhone extends PhoneBase { break; } - if (LOCAL_DEBUG) Log.d(LOG_TAG, "Baseband version: " + ar.result); + if (DBG) Log.d(LOG_TAG, "Baseband version: " + ar.result); setSystemProperty(TelephonyProperties.PROPERTY_BASEBAND_VERSION, (String)ar.result); } break; @@ -1153,10 +1164,10 @@ public class CDMAPhone extends PhoneBase { mSMS.setCellBroadcastConfig(configValuesArray, response); } - public static final String IS683A_FEATURE_CODE = "*228" ; - public static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4 ; - public static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2 ; - public static final int IS683A_SYS_SEL_CODE_OFFSET = 4; + private static final String IS683A_FEATURE_CODE = "*228"; + private static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4; + private static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2; + private static final int IS683A_SYS_SEL_CODE_OFFSET = 4; private static final int IS683_CONST_800MHZ_A_BAND = 0; private static final int IS683_CONST_800MHZ_B_BAND = 1; @@ -1166,6 +1177,7 @@ public class CDMAPhone extends PhoneBase { private static final int IS683_CONST_1900MHZ_D_BLOCK = 5; private static final int IS683_CONST_1900MHZ_E_BLOCK = 6; private static final int IS683_CONST_1900MHZ_F_BLOCK = 7; + private static final int INVALID_SYSTEM_SELECTION_CODE = -1; private boolean isIs683OtaSpDialStr(String dialStr) { int sysSelCodeInt; @@ -1176,38 +1188,146 @@ public class CDMAPhone extends PhoneBase { if (dialStr.equals(IS683A_FEATURE_CODE)) { isOtaspDialString = true; } - } else if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE, 0, - IS683A_FEATURE_CODE_NUM_DIGITS) == true) - && (dialStrLen >= - (IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS))) { - StringBuilder sb = new StringBuilder(dialStr); - // Separate the System Selection Code into its own string - char[] sysSel = new char[2]; - sb.delete(0, IS683A_SYS_SEL_CODE_OFFSET); - sb.getChars(0, IS683A_SYS_SEL_CODE_NUM_DIGITS, sysSel, 0); - - if ((PhoneNumberUtils.isISODigit(sysSel[0])) - && (PhoneNumberUtils.isISODigit(sysSel[1]))) { - String sysSelCode = new String(sysSel); - sysSelCodeInt = Integer.parseInt((String)sysSelCode); - switch (sysSelCodeInt) { - case IS683_CONST_800MHZ_A_BAND: - case IS683_CONST_800MHZ_B_BAND: - case IS683_CONST_1900MHZ_A_BLOCK: - case IS683_CONST_1900MHZ_B_BLOCK: - case IS683_CONST_1900MHZ_C_BLOCK: - case IS683_CONST_1900MHZ_D_BLOCK: - case IS683_CONST_1900MHZ_E_BLOCK: - case IS683_CONST_1900MHZ_F_BLOCK: - isOtaspDialString = true; - break; + } else { + sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr); + switch (sysSelCodeInt) { + case IS683_CONST_800MHZ_A_BAND: + case IS683_CONST_800MHZ_B_BAND: + case IS683_CONST_1900MHZ_A_BLOCK: + case IS683_CONST_1900MHZ_B_BLOCK: + case IS683_CONST_1900MHZ_C_BLOCK: + case IS683_CONST_1900MHZ_D_BLOCK: + case IS683_CONST_1900MHZ_E_BLOCK: + case IS683_CONST_1900MHZ_F_BLOCK: + isOtaspDialString = true; + break; + default: + break; + } + } + return isOtaspDialString; + } + /** + * This function extracts the system selection code from the dial string. + */ + private int extractSelCodeFromOtaSpNum(String dialStr) { + int dialStrLen = dialStr.length(); + int sysSelCodeInt = INVALID_SYSTEM_SELECTION_CODE; + + if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE, + 0, IS683A_FEATURE_CODE_NUM_DIGITS)) && + (dialStrLen >= (IS683A_FEATURE_CODE_NUM_DIGITS + + IS683A_SYS_SEL_CODE_NUM_DIGITS))) { + // Since we checked the condition above, the system selection code + // extracted from dialStr will not cause any exception + sysSelCodeInt = Integer.parseInt ( + dialStr.substring (IS683A_FEATURE_CODE_NUM_DIGITS, + IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS)); + } + if (DBG) Log.d(LOG_TAG, "extractSelCodeFromOtaSpNum " + sysSelCodeInt); + return sysSelCodeInt; + } - default: + /** + * This function checks if the system selection code extracted from + * the dial string "sysSelCodeInt' is the system selection code specified + * in the carrier ota sp number schema "sch". + */ + private boolean + checkOtaSpNumBasedOnSysSelCode (int sysSelCodeInt, String sch[]) { + boolean isOtaSpNum = false; + try { + // Get how many number of system selection code ranges + int selRc = Integer.parseInt((String)sch[1]); + for (int i = 0; i < selRc; i++) { + if (!TextUtils.isEmpty(sch[i+2]) && !TextUtils.isEmpty(sch[i+3])) { + int selMin = Integer.parseInt((String)sch[i+2]); + int selMax = Integer.parseInt((String)sch[i+3]); + // Check if the selection code extracted from the dial string falls + // within any of the range pairs specified in the schema. + if ((sysSelCodeInt >= selMin) && (sysSelCodeInt <= selMax)) { + isOtaSpNum = true; break; + } } } + } catch (NumberFormatException ex) { + // If the carrier ota sp number schema is not correct, we still allow dial + // and only log the error: + Log.e(LOG_TAG, "checkOtaSpNumBasedOnSysSelCode, error", ex); } - return isOtaspDialString; + return isOtaSpNum; + } + + // Define the pattern/format for carrier specified OTASP number schema. + // It separates by comma and/or whitespace. + private static Pattern pOtaSpNumSchema = Pattern.compile("[,\\s]+"); + + /** + * The following function checks if a dial string is a carrier specified + * OTASP number or not by checking against the OTASP number schema stored + * in PROPERTY_OTASP_NUM_SCHEMA. + * + * Currently, there are 2 schemas for carriers to specify the OTASP number: + * 1) Use system selection code: + * The schema is: + * SELC,the # of code pairs,min1,max1,min2,max2,... + * e.g "SELC,3,10,20,30,40,60,70" indicates that there are 3 pairs of + * selection codes, and they are {10,20}, {30,40} and {60,70} respectively. + * + * 2) Use feature code: + * The schema is: + * "FC,length of feature code,feature code". + * e.g "FC,2,*2" indicates that the length of the feature code is 2, + * and the code itself is "*2". + */ + private boolean isCarrierOtaSpNum(String dialStr) { + boolean isOtaSpNum = false; + int sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr); + if (sysSelCodeInt == INVALID_SYSTEM_SELECTION_CODE) { + return isOtaSpNum; + } + // mCarrierOtaSpNumSchema is retrieved from PROPERTY_OTASP_NUM_SCHEMA: + if (!TextUtils.isEmpty(mCarrierOtaSpNumSchema)) { + Matcher m = pOtaSpNumSchema.matcher(mCarrierOtaSpNumSchema); + if (DBG) { + Log.d(LOG_TAG, "isCarrierOtaSpNum,schema" + mCarrierOtaSpNumSchema); + } + + if (m.find()) { + String sch[] = pOtaSpNumSchema.split(mCarrierOtaSpNumSchema); + // If carrier uses system selection code mechanism + if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("SELC")) { + if (sysSelCodeInt!=INVALID_SYSTEM_SELECTION_CODE) { + isOtaSpNum=checkOtaSpNumBasedOnSysSelCode(sysSelCodeInt,sch); + } else { + if (DBG) { + Log.d(LOG_TAG, "isCarrierOtaSpNum,sysSelCodeInt is invalid"); + } + } + } else if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("FC")) { + int fcLen = Integer.parseInt((String)sch[1]); + String fc = (String)sch[2]; + if (dialStr.regionMatches(0,fc,0,fcLen)) { + isOtaSpNum = true; + } else { + if (DBG) Log.d(LOG_TAG, "isCarrierOtaSpNum,not otasp number"); + } + } else { + if (DBG) { + Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema not supported" + sch[0]); + } + } + } else { + if (DBG) { + Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern not right" + + mCarrierOtaSpNumSchema); + } + } + } else { + if (DBG) Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern empty"); + } + return isOtaSpNum; } /** @@ -1220,12 +1340,13 @@ public class CDMAPhone extends PhoneBase { @Override public boolean isOtaSpNumber(String dialStr){ boolean isOtaSpNum = false; - if(dialStr != null){ - isOtaSpNum=isIs683OtaSpDialStr(dialStr); + if (dialStr != null) { + isOtaSpNum = isIs683OtaSpDialStr(dialStr); if(isOtaSpNum == false){ - //TO DO:Add carrier specific OTASP number detection here. + isOtaSpNum = isCarrierOtaSpNum(dialStr); } } + if (DBG) Log.d(LOG_TAG, "isOtaSpNumber " + isOtaSpNum); return isOtaSpNum; } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java index ed2ea90..cc456c5 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java @@ -222,7 +222,7 @@ public final class CdmaCallTracker extends CallTracker { } updatePhoneState(); - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); return pendingMO; } @@ -262,6 +262,7 @@ public final class CdmaCallTracker extends CallTracker { // triggered by updateParent. cwConn.updateParent(ringingCall, foregroundCall); cwConn.onConnectedInOrOut(); + updatePhoneState(); switchWaitingOrHoldingAndActive(); } else { throw new CallStateException("phone not ringing"); @@ -305,7 +306,7 @@ public final class CdmaCallTracker extends CallTracker { internalClearDisconnected(); updatePhoneState(); - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); } boolean @@ -531,17 +532,6 @@ public final class CdmaCallTracker extends CallTracker { // 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); @@ -644,7 +634,7 @@ public final class CdmaCallTracker extends CallTracker { } if (hasNonHangupStateChanged || newRinging != null) { - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); } //dumpState(); @@ -678,7 +668,8 @@ public final class CdmaCallTracker extends CallTracker { // the hangup reason is user ignoring or timing out. So conn.onDisconnect() // is not called here. Instead, conn.onLocalDisconnect() is called. conn.onLocalDisconnect(); - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); + updatePhoneState(); return; } else { try { @@ -821,7 +812,7 @@ public final class CdmaCallTracker extends CallTracker { // the status of the call is after a call waiting is answered, // 3 way call merged or a switch between calls. foregroundCall.setGeneric(true); - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); } private Phone.SuppService getFailedService(int what) { @@ -865,6 +856,7 @@ public final class CdmaCallTracker extends CallTracker { // Create a new CdmaConnection which attaches itself to ringingCall. ringingCall.setGeneric(false); new CdmaConnection(phone.getContext(), cw, this, ringingCall); + updatePhoneState(); // Finally notify application notifyCallWaitingInfo(cw); @@ -926,7 +918,7 @@ public final class CdmaCallTracker extends CallTracker { updatePhoneState(); - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); droppedDuringPoll.clear(); break; diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java index ecdc8f6..c4db609 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java @@ -25,12 +25,14 @@ import android.database.Cursor; import android.database.SQLException; import android.os.AsyncResult; import android.os.Message; +import android.os.SystemProperties; import android.provider.Telephony; import android.provider.Telephony.Sms.Intents; import android.preference.PreferenceManager; import android.util.Config; import android.util.Log; +import com.android.internal.telephony.TelephonyProperties; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; @@ -75,6 +77,11 @@ final class CdmaSMSDispatcher extends SMSDispatcher { return Intents.RESULT_SMS_GENERIC_ERROR; } + String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); + if (inEcm.equals("true")) { + return Intents.RESULT_SMS_GENERIC_ERROR; + } + // Decode BD stream and set sms variables. SmsMessage sms = (SmsMessage) smsb; sms.parseSms(); @@ -343,6 +350,12 @@ final class CdmaSMSDispatcher extends SMSDispatcher { /** {@inheritDoc} */ protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){ // FIXME unit test leaves cm == null. this should change + + String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); + if (inEcm.equals("true")) { + return; + } + if (mCm != null) { mCm.acknowledgeLastIncomingCdmaSms(success, resultToCause(result), response); } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java index 23a0520..e785709 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java @@ -124,6 +124,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { private int mHomeSystemId; private int mHomeNetworkId; private String mMin; + private String mPrlVersion; private boolean isEriTextLoaded = false; private boolean isSubscriptionFromRuim = false; @@ -175,6 +176,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { cm.registerForNVReady(this, EVENT_NV_READY, null); phone.registerForEriFileLoaded(this, EVENT_ERI_FILE_LOADED, null); + cm.registerForCdmaOtaProvision(this,EVENT_OTA_PROVISION_STATUS_CHANGE, null); // system setting property AIRPLANE_MODE_ON is set in Settings. int airplaneMode = Settings.System.getInt( @@ -198,6 +200,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { cm.unregisterForNetworkStateChanged(this); cm.unregisterForRUIMReady(this); cm.unregisterForNVReady(this); + cm.unregisterForCdmaOtaProvision(this); phone.unregisterForEriFileLoaded(this); phone.mRuimRecords.unregisterForRecordsLoaded(this); cm.unSetOnSignalStrengthUpdate(this); @@ -290,6 +293,10 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { EVENT_RUIM_RECORDS_LOADED, null); mNeedToRegForRuimLoaded = false; } + + cm.getCDMASubscription(obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION)); + if (DBG) log("Receive EVENT_RUIM_READY and Send Request getCDMASubscription."); + // restore the previous network selection. pollState(); @@ -299,6 +306,10 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { case EVENT_NV_READY: isSubscriptionFromRuim = false; + // For Non-RUIM phones, the subscription information is stored in + // Non Volatile. Here when Non-Volatile is ready, we can poll the CDMA + // subscription info. + cm.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION)); pollState(); // Signal strength polling stops when radio is off queueNextSignalStrengthPoll(); @@ -376,11 +387,36 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { case EVENT_POLL_STATE_REGISTRATION_CDMA: case EVENT_POLL_STATE_OPERATOR_CDMA: - case EVENT_POLL_STATE_CDMA_SUBSCRIPTION: ar = (AsyncResult) msg.obj; handlePollStateResult(msg.what, ar); break; + case EVENT_POLL_STATE_CDMA_SUBSCRIPTION: // Handle RIL_CDMA_SUBSCRIPTION + ar = (AsyncResult) msg.obj; + + if (ar.exception == null) { + String cdmaSubscription[] = (String[])ar.result; + if (cdmaSubscription != null && cdmaSubscription.length >= 5) { + mMdn = cdmaSubscription[0]; + // TODO: Only grabbing the first SID/NID for now. + if (cdmaSubscription[1] != null) { + String[] sid = cdmaSubscription[1].split(","); + mHomeSystemId = sid.length > 0 ? Integer.parseInt(sid[0]) : 0; + } + if (cdmaSubscription[2] != null) { + String[] nid = cdmaSubscription[2].split(","); + mHomeNetworkId = nid.length > 0 ? Integer.parseInt(nid[0]) : 0; + } + mMin = cdmaSubscription[3]; + mPrlVersion = cdmaSubscription[4]; + Log.d(LOG_TAG,"GET_CDMA_SUBSCRIPTION MDN=" + mMdn); + } else { + Log.w(LOG_TAG,"error parsing cdmaSubscription params num=" + + cdmaSubscription.length); + } + } + break; + case EVENT_POLL_SIGNAL_STRENGTH: // Just poll signal strength...not part of pollState() @@ -427,6 +463,19 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { pollState(); break; + case EVENT_OTA_PROVISION_STATUS_CHANGE: + ar = (AsyncResult)msg.obj; + if (ar.exception == null) { + ints = (int[]) ar.result; + int otaStatus = ints[0]; + if (otaStatus == phone.CDMA_OTA_PROVISION_STATUS_COMMITTED + || otaStatus == phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED) { + Log.d(LOG_TAG, "Received OTA_PROGRAMMING Complete,Reload MDN "); + cm.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION)); + } + } + break; + default: Log.e(LOG_TAG, "Unhandled message with number: " + msg.what); break; @@ -589,7 +638,10 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } mRegistrationState = registrationState; - mCdmaRoaming = regCodeIsRoaming(registrationState); + // mCdmaRoaming is true when registration state is roaming and TSB58 roaming + // indicator is not in the carrier-specified list of ERIs for home system + mCdmaRoaming = + regCodeIsRoaming(registrationState) && !isRoamIndForHomeSystem(states[10]); newSS.setState (regCodeToServiceState(registrationState)); this.newCdmaDataConnectionState = radioTechnologyToDataServiceState(radioTechnology); @@ -636,27 +688,6 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } break; - case EVENT_POLL_STATE_CDMA_SUBSCRIPTION: // Handle RIL_CDMA_SUBSCRIPTION - String cdmaSubscription[] = (String[])ar.result; - - if (cdmaSubscription != null && cdmaSubscription.length >= 4) { - mMdn = cdmaSubscription[0]; - // TODO: Only grabbing the first SID/NID for now. - if (cdmaSubscription[1] != null) { - String[] sid = cdmaSubscription[1].split(","); - mHomeSystemId = sid.length > 0 ? Integer.parseInt(sid[0]) : 0; - } - if (cdmaSubscription[2] != null) { - String[] nid = cdmaSubscription[2].split(","); - mHomeNetworkId = nid.length > 0 ? Integer.parseInt(nid[0]) : 0; - } - mMin = cdmaSubscription[3]; - - } else { - Log.w(LOG_TAG, "error parsing cdmaSubscription"); - } - break; - default: Log.e(LOG_TAG, "RIL response handle in wrong phone!" + " Expected CDMA RIL request and get GSM RIL request."); @@ -773,11 +804,6 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { // are allowed to arrive out-of-order pollingContext[0]++; - // RIL_REQUEST_CDMA_SUBSCRIPTION is necessary for CDMA - cm.getCDMASubscription( - obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION, pollingContext)); - - pollingContext[0]++; // RIL_REQUEST_OPERATOR is necessary for CDMA cm.getOperator( obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext)); @@ -1152,6 +1178,33 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } /** + * Determine whether a roaming indicator is in the carrier-specified list of ERIs for + * home system + * + * @param roamInd roaming indicator in String + * @return true if the roamInd is in the carrier-specified list of ERIs for home network + */ + private boolean isRoamIndForHomeSystem(String roamInd) { + // retrieve the carrier-specified list of ERIs for home system + String homeRoamIndcators = SystemProperties.get("ro.cdma.homesystem"); + + if (!TextUtils.isEmpty(homeRoamIndcators)) { + // searches through the comma-separated list for a match, + // return true if one is found. + for (String homeRoamInd : homeRoamIndcators.split(",")) { + if (homeRoamInd.equals(roamInd)) { + return true; + } + } + // no matches found against the list! + return false; + } + + // no system property found for the roaming indicators for home system + return false; + } + + /** * 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 @@ -1420,6 +1473,11 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { return mMin; } + /** Returns null if NV is not yet ready */ + public String getPrlVersion() { + return mPrlVersion; + } + /** * Returns IMSI as MCC + MNC + MIN */ diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java index 9d9f479..734badd 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java @@ -16,507 +16,34 @@ 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 +public final class RuimCard extends IccCard { 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); - + super(phone, "CDMA", true); + mPhone.mCM.registerForRUIMLockedOrAbsent(mHandler, EVENT_ICC_LOCKED_OR_ABSENT, null); + mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + mPhone.mCM.registerForRUIMReady(mHandler, EVENT_ICC_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; - } - + @Override 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)); + mPhone.mCM.unregisterForRUIMLockedOrAbsent(mHandler); + mPhone.mCM.unregisterForOffOrNotAvailable(mHandler); + mPhone.mCM.unregisterForRUIMReady(mHandler); } - 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); + public String getServiceProviderName () { + return ((CDMAPhone)mPhone).mRuimRecords.getServiceProviderName(); } -} + } diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java index 55f48b1..7c74314 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java @@ -37,10 +37,6 @@ import com.android.internal.telephony.IccRecords; import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.PhoneProxy; -import com.android.internal.telephony.TelephonyIntents; -import android.app.ActivityManagerNative; -import android.content.Intent; - /** * {@hide} @@ -65,7 +61,6 @@ public final class RuimRecords extends IccRecords { private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2; private static final int EVENT_GET_DEVICE_IDENTITY_DONE = 4; private static final int EVENT_GET_ICCID_DONE = 5; - private static final int EVENT_NV_READY = 9; private static final int EVENT_GET_CDMA_SUBSCRIPTION_DONE = 10; private static final int EVENT_UPDATE_DONE = 14; private static final int EVENT_GET_SST_DONE = 17; @@ -76,7 +71,7 @@ public final class RuimRecords extends IccRecords { private static final int EVENT_GET_SMS_DONE = 22; private static final int EVENT_RUIM_REFRESH = 31; - private static final int EVENT_OTA_PROVISION_STATUS_CHANGE = 32; + RuimRecords(CDMAPhone p) { super(p); @@ -90,14 +85,12 @@ public final class RuimRecords extends IccRecords { p.mCM.registerForRUIMReady(this, EVENT_RUIM_READY, null); - p.mCM.registerForNVReady(this, EVENT_NV_READY, null); p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); // NOTE the EVENT_SMS_ON_RUIM is not registered p.mCM.setOnIccRefresh(this, EVENT_RUIM_REFRESH, null); // Start off by setting empty state onRadioOffOrNotAvailable(); - p.mCM.registerForCdmaOtaProvision(this,EVENT_OTA_PROVISION_STATUS_CHANGE, null); } @@ -106,8 +99,6 @@ public final class RuimRecords extends IccRecords { phone.mCM.unregisterForRUIMReady(this); phone.mCM.unregisterForOffOrNotAvailable( this); phone.mCM.unSetOnIccRefresh(this); - phone.mCM.unregisterForNVReady(this); - phone.mCM.unregisterForCdmaOtaProvision(this); } @Override @@ -202,9 +193,7 @@ public final class RuimRecords extends IccRecords { case EVENT_RUIM_READY: onRuimReady(); break; - case EVENT_NV_READY: - onNvReady(); - break; + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: onRadioOffOrNotAvailable(); break; @@ -221,15 +210,7 @@ public final class RuimRecords extends IccRecords { if (ar.exception != null) { break; } - if (m_ota_commited) { - if (mMyMobileNumber != localTemp[0]) { - Intent intent = new Intent(TelephonyIntents.ACTION_CDMA_OTA_MDN_CHANGED); - intent.putExtra("mdn", localTemp[0]); - Log.d(LOG_TAG,"Broadcasting intent MDN Change in OTA "); - ActivityManagerNative.broadcastStickyIntent(intent, null); - } - m_ota_commited = false; - } + mMyMobileNumber = localTemp[0]; mMin2Min1 = localTemp[3]; mPrlVersion = localTemp[4]; @@ -281,21 +262,6 @@ public final class RuimRecords extends IccRecords { } break; - case EVENT_OTA_PROVISION_STATUS_CHANGE: - m_ota_commited=false; - ar = (AsyncResult)msg.obj; - if (ar.exception == null) { - int[] ints = (int[]) ar.result; - int otaStatus = ints[0]; - if (otaStatus == phone.CDMA_OTA_PROVISION_STATUS_COMMITTED) { - m_ota_commited=true; - phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE)); - } else if (otaStatus == phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED) { - phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE)); - } - } - break; - }}catch (RuntimeException exc) { // I don't want these exceptions to be fatal Log.w(LOG_TAG, "Exception parsing RUIM record", exc); @@ -329,7 +295,7 @@ public final class RuimRecords extends IccRecords { recordsLoadedRegistrants.notifyRegistrants( new AsyncResult(null, null, null)); - ((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent( + ((CDMAPhone) phone).mRuimCard.broadcastIccStateChangedIntent( RuimCard.INTENT_VALUE_ICC_LOADED, null); } @@ -338,7 +304,7 @@ public final class RuimRecords extends IccRecords { READY is sent before IMSI ready */ - ((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent( + ((CDMAPhone) phone).mRuimCard.broadcastIccStateChangedIntent( RuimCard.INTENT_VALUE_ICC_READY, null); fetchRuimRecords(); @@ -347,10 +313,6 @@ public final class RuimRecords extends IccRecords { } - private void onNvReady() { - phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE)); - - } private void fetchRuimRecords() { recordsRequested = true; diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java index 3a92064..c085739 100644..100755 --- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java @@ -518,6 +518,7 @@ public class SmsMessage extends SmsMessageBase { originatingAddress = addr; env.origAddress = addr; mEnvelope = env; + mPdu = pdu; parseSms(); } @@ -586,9 +587,24 @@ public class SmsMessage extends SmsMessageBase { private static CdmaSmsAddress parseCdmaSmsAddr(String addrStr) { // see C.S0015-B, v2.0, 3.4.3.3 CdmaSmsAddress addr = new CdmaSmsAddress(); - addr.digitMode = CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR; + addr.digitMode = CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF; try { addr.origBytes = addrStr.getBytes("UTF-8"); + for (int index = 0; index < addr.origBytes.length; index++) { + if (addr.origBytes[index] >= '0' && addr.origBytes[index] <= '9') { + if (addr.origBytes[index] == '0') { + addr.origBytes[index] = 10; + } else { + addr.origBytes[index] -= '0'; + } + } else if (addr.origBytes[index] == '*') { + addr.origBytes[index] = 11; + } else if (addr.origBytes[index] == '#') { + addr.origBytes[index] = 12; + } else { + return null; + } + } } catch (java.io.UnsupportedEncodingException ex) { Log.e(LOG_TAG, "CDMA address parsing failed: " + ex); return null; @@ -596,7 +612,7 @@ public class SmsMessage extends SmsMessageBase { addr.numberOfDigits = (byte)addr.origBytes.length; addr.numberMode = CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK; addr.numberPlan = CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY; - addr.ton = CdmaSmsAddress.TON_INTERNATIONAL_OR_IP; + addr.ton = CdmaSmsAddress.TON_UNKNOWN; return addr; } @@ -728,9 +744,8 @@ public class SmsMessage extends SmsMessageBase { dos.close(); /** - * TODO(cleanup) -- This is the only place where mPdu is - * defined, and this is not obviously the only place where - * it needs to be defined. It would be much nicer if + * TODO(cleanup) -- The mPdu field is managed in + * a fragile manner, and it would be much nicer if * accessing the serialized representation used a less * fragile mechanism. Maybe the getPdu method could * generate a representation if there was not yet one? diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java index ef3afff..2b32872 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java @@ -901,6 +901,16 @@ public final class BearerData { return result; } + private static String decodeLatin(byte[] data, int offset, int numFields) + throws CodingException + { + try { + return new String(data, offset, numFields - offset, "ISO-8859-1"); + } catch (java.io.UnsupportedEncodingException ex) { + throw new CodingException("ISO-8859-1 decode failed: " + ex); + } + } + private static void decodeUserDataPayload(UserData userData, boolean hasUserDataHeader) throws CodingException { @@ -914,6 +924,19 @@ public final class BearerData { } switch (userData.msgEncoding) { case UserData.ENCODING_OCTET: + // Strip off any padding bytes, meaning any differences between the length of the + // array and the target length specified by numFields. This is to avoid any confusion + // by code elsewhere that only considers the payload array length. + byte[] payload = new byte[userData.numFields]; + int copyLen = userData.numFields < userData.payload.length + ? userData.numFields : userData.payload.length; + + System.arraycopy(userData.payload, 0, payload, 0, copyLen); + userData.payload = payload; + + // There are many devices in the market that send 8bit text sms (latin encoded) as + // octet encoded. + userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields); break; case UserData.ENCODING_7BIT_ASCII: userData.payloadStr = decode7bitAscii(userData.payload, offset, userData.numFields); @@ -927,6 +950,9 @@ public final class BearerData { case UserData.ENCODING_GSM_7BIT_ALPHABET: userData.payloadStr = decode7bitGsm(userData.payload, offset, userData.numFields); break; + case UserData.ENCODING_LATIN: + userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields); + break; default: throw new CodingException("unsupported user data encoding (" + userData.msgEncoding + ")"); diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java index 34cbbfa..04796b8 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java @@ -35,7 +35,7 @@ public class UserData { //public static final int ENCODING_SHIFT_JIS = 0x05; //public static final int ENCODING_KOREAN = 0x06; //public static final int ENCODING_LATIN_HEBREW = 0x07; - //public static final int ENCODING_LATIN = 0x08; + public static final int ENCODING_LATIN = 0x08; public static final int ENCODING_GSM_7BIT_ALPHABET = 0x09; public static final int ENCODING_GSM_DCS = 0x0A; diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java index d1e4b4f..ebbf096 100755 --- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java @@ -51,6 +51,7 @@ import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDI 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.Call; import com.android.internal.telephony.CallForwardInfo; import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.CommandsInterface; @@ -378,20 +379,19 @@ public class GSMPhone extends PhoneBase { } /** - * Notify any interested party of a Phone state change. + * Notify any interested party of a Phone state change {@link Phone.State} */ /*package*/ void notifyPhoneStateChanged() { mNotifier.notifyPhoneState(this); } /** - * Notifies registrants (ie, activities in the Phone app) about - * changes to call state (including Phone and Connection changes). + * Notify registrants of a change in the call state. This notifies changes in {@link Call.State} + * Use this when changes in the precise call state are needed, else use notifyPhoneStateChanged. */ - /*package*/ void - notifyCallStateChanged() { + /*package*/ void notifyPreciseCallStateChanged() { /* we'd love it if this was package-scoped*/ - super.notifyCallStateChangedP(); + super.notifyPreciseCallStateChangedP(); } /*package*/ void diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java index 5c5090f..f3b7596 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java @@ -212,7 +212,7 @@ public final class GsmCallTracker extends CallTracker { } updatePhoneState(); - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); return pendingMO; } @@ -279,7 +279,7 @@ public final class GsmCallTracker extends CallTracker { internalClearDisconnected(); updatePhoneState(); - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); } boolean @@ -600,7 +600,7 @@ public final class GsmCallTracker extends CallTracker { } if (hasNonHangupStateChanged || newRinging != null) { - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); } //dumpState(); @@ -883,7 +883,7 @@ public final class GsmCallTracker extends CallTracker { updatePhoneState(); - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); droppedDuringPoll.clear(); break; diff --git a/telephony/java/com/android/internal/telephony/gsm/MccTable.java b/telephony/java/com/android/internal/telephony/gsm/MccTable.java index e18da56..22b1f4f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/MccTable.java +++ b/telephony/java/com/android/internal/telephony/gsm/MccTable.java @@ -35,6 +35,7 @@ public final class MccTable int smallestDigitsMnc; String timezone; String language; + int wifiChannelsAllowed; MccEntry(int mnc, String iso, int smallestDigitsMCC) { this(mnc, iso, smallestDigitsMCC, null); @@ -45,11 +46,16 @@ public final class MccTable } MccEntry(int mnc, String iso, int smallestDigitsMCC, String timezone, String language) { + this(mnc, iso, smallestDigitsMCC, timezone, language, 0); + } + + MccEntry(int mnc, String iso, int smallestDigitsMCC, String timezone, String language, int wifiChannels) { this.mcc = mnc; this.iso = iso; this.smallestDigitsMnc = smallestDigitsMCC; this.timezone = timezone; this.language = language; + this.wifiChannelsAllowed = wifiChannels; } public int compareTo(MccEntry o) @@ -148,6 +154,23 @@ public final class MccTable } } + /** + * Given a GSM Mobile Country Code, returns + * the number of wifi channels allowed in that country. + * Returns 0 if unavailable + */ + public static int wifiChannelsForMcc(int mcc) { + MccEntry entry; + + entry = entryForMcc(mcc); + + if (entry == null) { + return 0; + } else { + return entry.wifiChannelsAllowed; + } + } + static { table = new ArrayList<MccEntry>(240); @@ -169,7 +192,7 @@ public final class MccTable */ table.add(new MccEntry(202,"gr",2)); //Greece - table.add(new MccEntry(204,"nl",2,"Europe/Amsterdam","nl")); //Netherlands (Kingdom of the) + table.add(new MccEntry(204,"nl",2,"Europe/Amsterdam","nl",13)); //Netherlands (Kingdom of the) table.add(new MccEntry(206,"be",2)); //Belgium table.add(new MccEntry(208,"fr",2,"Europe/Paris","fr")); //France table.add(new MccEntry(212,"mc",2)); //Monaco (Principality of) @@ -183,11 +206,11 @@ public final class MccTable table.add(new MccEntry(225,"va",2,"Europe/Rome","it")); //Vatican City State table.add(new MccEntry(226,"ro",2)); //Romania table.add(new MccEntry(228,"ch",2,"Europe/Zurich","de")); //Switzerland (Confederation of) - table.add(new MccEntry(230,"cz",2,"Europe/Prague","cs")); //Czech Republic + table.add(new MccEntry(230,"cz",2,"Europe/Prague","cs", 13)); //Czech Republic table.add(new MccEntry(231,"sk",2)); //Slovak Republic - table.add(new MccEntry(232,"at",2,"Europe/Vienna","de")); //Austria - table.add(new MccEntry(234,"gb",2,"Europe/London","en")); //United Kingdom of Great Britain and Northern Ireland - table.add(new MccEntry(235,"gb",2,"Europe/London","en")); //United Kingdom of Great Britain and Northern Ireland + table.add(new MccEntry(232,"at",2,"Europe/Vienna","de", 13)); //Austria + table.add(new MccEntry(234,"gb",2,"Europe/London","en", 13)); //United Kingdom of Great Britain and Northern Ireland + table.add(new MccEntry(235,"gb",2,"Europe/London","en", 13)); //United Kingdom of Great Britain and Northern Ireland table.add(new MccEntry(238,"dk",2)); //Denmark table.add(new MccEntry(240,"se",2)); //Sweden table.add(new MccEntry(242,"no",2)); //Norway @@ -200,7 +223,7 @@ public final class MccTable table.add(new MccEntry(257,"by",2)); //Belarus (Republic of) table.add(new MccEntry(259,"md",2)); //Moldova (Republic of) table.add(new MccEntry(260,"pl",2,"Europe/Warsaw")); //Poland (Republic of) - table.add(new MccEntry(262,"de",2,"Europe/Berlin","de")); //Germany (Federal Republic of) + table.add(new MccEntry(262,"de",2,"Europe/Berlin","de", 13)); //Germany (Federal Republic of) table.add(new MccEntry(266,"gi",2)); //Gibraltar table.add(new MccEntry(268,"pt",2)); //Portugal table.add(new MccEntry(270,"lu",2)); //Luxembourg @@ -219,15 +242,15 @@ public final class MccTable table.add(new MccEntry(293,"sl",2)); //Slovenia (Republic of) table.add(new MccEntry(294,"mk",2)); //The Former Yugoslav Republic of Macedonia table.add(new MccEntry(295,"li",2)); //Liechtenstein (Principality of) - table.add(new MccEntry(302,"ca",2)); //Canada + table.add(new MccEntry(302,"ca",2, "", "", 11)); //Canada table.add(new MccEntry(308,"pm",2)); //Saint Pierre and Miquelon (Collectivit territoriale de la Rpublique franaise) - table.add(new MccEntry(310,"us",3,"","en")); //United States of America - table.add(new MccEntry(311,"us",3,"","en")); //United States of America - table.add(new MccEntry(312,"us",3,"","en")); //United States of America - table.add(new MccEntry(313,"us",3,"","en")); //United States of America - table.add(new MccEntry(314,"us",3,"","en")); //United States of America - table.add(new MccEntry(315,"us",3,"","en")); //United States of America - table.add(new MccEntry(316,"us",3,"","en")); //United States of America + table.add(new MccEntry(310,"us",3,"","en", 11)); //United States of America + table.add(new MccEntry(311,"us",3,"","en", 11)); //United States of America + table.add(new MccEntry(312,"us",3,"","en", 11)); //United States of America + table.add(new MccEntry(313,"us",3,"","en", 11)); //United States of America + table.add(new MccEntry(314,"us",3,"","en", 11)); //United States of America + table.add(new MccEntry(315,"us",3,"","en", 11)); //United States of America + table.add(new MccEntry(316,"us",3,"","en", 11)); //United States of America table.add(new MccEntry(330,"pr",2)); //Puerto Rico table.add(new MccEntry(332,"vi",2)); //United States Virgin Islands table.add(new MccEntry(334,"mx",3)); //Mexico @@ -283,8 +306,8 @@ public final class MccTable table.add(new MccEntry(436,"tj",2)); //Tajikistan (Republic of) table.add(new MccEntry(437,"kg",2)); //Kyrgyz Republic table.add(new MccEntry(438,"tm",2)); //Turkmenistan - table.add(new MccEntry(440,"jp",2,"Asia/Tokyo","ja")); //Japan - table.add(new MccEntry(441,"jp",2,"Asia/Tokyo","ja")); //Japan + table.add(new MccEntry(440,"jp",2,"Asia/Tokyo","ja", 14)); //Japan + table.add(new MccEntry(441,"jp",2,"Asia/Tokyo","ja", 14)); //Japan table.add(new MccEntry(450,"kr",2)); //Korea (Republic of) table.add(new MccEntry(452,"vn",2)); //Viet Nam (Socialist Republic of) table.add(new MccEntry(454,"hk",2)); //"Hong Kong, China" @@ -298,12 +321,12 @@ public final class MccTable table.add(new MccEntry(470,"bd",2)); //Bangladesh (People's Republic of) table.add(new MccEntry(472,"mv",2)); //Maldives (Republic of) table.add(new MccEntry(502,"my",2)); //Malaysia - table.add(new MccEntry(505,"au",2,"Australia/Sydney","en")); //Australia + table.add(new MccEntry(505,"au",2,"Australia/Sydney","en", 11)); //Australia table.add(new MccEntry(510,"id",2)); //Indonesia (Republic of) table.add(new MccEntry(514,"tl",2)); //Democratic Republic of Timor-Leste table.add(new MccEntry(515,"ph",2)); //Philippines (Republic of the) table.add(new MccEntry(520,"th",2)); //Thailand - table.add(new MccEntry(525,"sg",2,"Singapore","en")); //Singapore (Republic of) + table.add(new MccEntry(525,"sg",2,"Singapore","en", 11)); //Singapore (Republic of) table.add(new MccEntry(528,"bn",2)); //Brunei Darussalam table.add(new MccEntry(530,"nz",2,"Pacific/Auckland", "en")); //New Zealand table.add(new MccEntry(534,"mp",2)); //Northern Mariana Islands (Commonwealth of the) diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java index e25de81..4272faa 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java +++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java @@ -16,39 +16,29 @@ package com.android.internal.telephony.gsm; -import android.app.ActivityManagerNative; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA; +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.app.AlarmManager; -import android.app.IActivityManager; import android.content.Context; -import android.content.res.Configuration; +import android.net.wifi.WifiManager; import android.os.AsyncResult; -import android.os.Handler; import android.os.Message; import android.os.SystemProperties; -import android.os.Registrant; +import android.provider.Settings; import android.util.Log; -import java.util.ArrayList; - - -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.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; - - - - +import java.util.ArrayList; /** @@ -512,6 +502,29 @@ public final class SIMRecords extends IccRecords { phone.setSystemLocale(language, country); } + /** + * If the number of allowed wifi channels has not been set, set it based on + * the MCC of the SIM. + * @param mcc Mobile Country Code of the SIM + */ + private void setWifiChannelsFromMccIfNeeded(int mcc) { + int wifiChannels = MccTable.wifiChannelsForMcc(mcc); + + if (wifiChannels != 0) { + Context context = phone.getContext(); + // only set to this default if the user hasn't manually set it + try { + Settings.Secure.getInt(context.getContentResolver(), + Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS); + } catch (Settings.SettingNotFoundException e) { + WifiManager wM = (WifiManager) + context.getSystemService(Context.WIFI_SERVICE); + // don't persist + wM.setNumAllowedChannels(wifiChannels, false); + } + } + } + //***** Overridden from Handler public void handleMessage(Message msg) { AsyncResult ar; @@ -552,12 +565,13 @@ public final class SIMRecords extends IccRecords { Log.d(LOG_TAG, "IMSI: " + imsi.substring(0, 6) + "xxxxxxxxx"); ((GSMPhone) phone).mSimCard.updateImsiConfiguration(imsi); - ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent( + ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent( SimCard.INTENT_VALUE_ICC_IMSI, null); int mcc = Integer.parseInt(imsi.substring(0, 3)); setTimezoneFromMccIfNeeded(mcc); setLocaleFromMccIfNeeded(mcc); + setWifiChannelsFromMccIfNeeded(mcc); break; case EVENT_GET_MBI_DONE: @@ -1178,7 +1192,7 @@ public final class SIMRecords extends IccRecords { recordsLoadedRegistrants.notifyRegistrants( new AsyncResult(null, null, null)); - ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent( + ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent( SimCard.INTENT_VALUE_ICC_LOADED, null); } @@ -1203,7 +1217,7 @@ public final class SIMRecords extends IccRecords { /* broadcast intent SIM_READY here so that we can make sure READY is sent before IMSI ready */ - ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent( + ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent( SimCard.INTENT_VALUE_ICC_READY, null); fetchSimRecords(); diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java index 9af3aa6..6c56682 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java @@ -17,469 +17,37 @@ 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; -import android.os.Message; -import android.os.Registrant; -import android.os.RegistrantList; 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 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 SimCard extends Handler implements IccCard { - static final String LOG_TAG="GSM"; - - //***** Instance Variables - private static final boolean DBG = true; - - private GSMPhone phone; - 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. - - //***** Constants - - // FIXME I hope this doesn't conflict with the Dialer's notifications - static final int NOTIFICATION_ID_SIM_STATUS = 33456; - - //***** Event Constants - - static final int EVENT_SIM_LOCKED_OR_ABSENT = 1; - static final int EVENT_GET_SIM_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_SIM_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_SIM_PASSWORD_DONE = 9; - static final int EVENT_QUERY_FACILITY_FDN_DONE = 10; - static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11; - - - //***** Constructor +public final class SimCard extends IccCard { SimCard(GSMPhone phone) { - this.phone = phone; - - phone.mCM.registerForSIMLockedOrAbsent( - this, EVENT_SIM_LOCKED_OR_ABSENT, null); - - phone.mCM.registerForOffOrNotAvailable( - this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); - - phone.mCM.registerForSIMReady( - this, EVENT_SIM_READY, null); + super(phone, "GSM", true); + mPhone.mCM.registerForSIMLockedOrAbsent(mHandler, EVENT_ICC_LOCKED_OR_ABSENT, null); + mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + mPhone.mCM.registerForSIMReady(mHandler, EVENT_ICC_READY, null); updateStateProperty(); } + @Override 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() { - 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 SIM_NOT_READY: - return State.UNKNOWN; - case SIM_LOCKED_OR_ABSENT: - //this should be transient-only - return State.UNKNOWN; - case SIM_READY: - return State.READY; - } - } 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, "GsmSimCard.getState(): case should never be reached"); - return State.UNKNOWN; - } - - 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 mSimPinLocked; - } - - public boolean getIccFdnEnabled() { - return mSimFdnEnabled; + mPhone.mCM.unregisterForSIMLockedOrAbsent(mHandler); + mPhone.mCM.unregisterForOffOrNotAvailable(mHandler); + mPhone.mCM.unregisterForSIMReady(mHandler); } - 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_SIM_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_SIM_PASSWORD_DONE, onComplete)); - - } - - public String getServiceProviderName () { - return phone.mSIMRecords.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: - status = null; - updateStateProperty(); - 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.getIccStatus(obtainMessage(EVENT_GET_SIM_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_SIM_LOCKED_OR_ABSENT: - phone.mCM.getIccStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE)); - phone.mCM.queryFacilityLock ( - CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, - obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); - break; - case EVENT_GET_SIM_STATUS_DONE: - ar = (AsyncResult)msg.obj; - - getSimStatusDone(ar); - break; - case EVENT_PINPUK_DONE: - // 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: - // 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; - getSimStatusDone(ar); - ((Message)ar.userObj).sendToTarget(); - break; - case EVENT_QUERY_FACILITY_LOCK_DONE: - ar = (AsyncResult)msg.obj; - onQueryFacilityLock(ar); - break; - case EVENT_QUERY_FACILITY_FDN_DONE: - ar = (AsyncResult)msg.obj; - onQueryFdnEnabled(ar); - break; - case EVENT_CHANGE_FACILITY_LOCK_DONE: - ar = (AsyncResult)msg.obj; - if (ar.exception == null) { - mSimPinLocked = mDesiredPinLocked; - if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " + - "mSimPinLocked= " + mSimPinLocked); - } 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: - ar = (AsyncResult)msg.obj; - - if (ar.exception == null) { - mSimFdnEnabled = mDesiredFdnEnabled; - if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " + - "mSimFdnEnabled=" + mSimFdnEnabled); - } 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_SIM_PASSWORD_DONE: - 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, "[GsmSimCard] Unknown Event " + msg.what); - } - } - - - //***** Private methods - - /** - * Interperate 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) { - mSimPinLocked = (0!=ints[0]); - if(DBG) log("Query facility lock : " + mSimPinLocked); - } else { - Log.e(LOG_TAG, "[GsmSimCard] Bogus facility lock response"); - } - } - - /** - * Interperate 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) { - mSimFdnEnabled = (0!=ints[0]); - if(DBG) log("Query facility lock : " + mSimFdnEnabled); - } else { - Log.e(LOG_TAG, "[GsmSimCard] Bogus facility lock response"); - } - } - - private void - getSimStatusDone(AsyncResult ar) { - if (ar.exception != null) { - Log.e(LOG_TAG,"Error getting ICC status. " - + "RIL_REQUEST_GET_ICC_STATUS should " - + "never return an error", ar.exception); - return; - } - - CommandsInterface.IccStatus newStatus - = (CommandsInterface.IccStatus) ar.result; - - handleSimStatus(newStatus); - } - - private void - handleSimStatus(CommandsInterface.IccStatus newStatus) { - boolean transitionedIntoPinLocked; - boolean transitionedIntoAbsent; - boolean transitionedIntoNetworkLocked; - - SimCard.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 SIM pin or puk locked."); - pinLockedRegistrants.notifyRegistrants(); - 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_ICC_ABSENT, null); - } else if (transitionedIntoNetworkLocked) { - if(DBG) log("Notify SIM network locked."); - networkLockedRegistrants.notifyRegistrants(); - broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_LOCKED, - INTENT_VALUE_LOCKED_NETWORK); - } - } - - 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_ICC_STATE, value); - intent.putExtra(SimCard.INTENT_KEY_LOCKED_REASON, reason); - if(DBG) log("Broadcasting intent SIM_STATE_CHANGED_ACTION " + value - + " reason " + reason); - ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE); + public String getServiceProviderName () { + return ((GSMPhone)mPhone).mSIMRecords.getServiceProviderName(); } public void updateImsiConfiguration(String imsi) { @@ -494,19 +62,8 @@ public final class SimCard extends Handler implements IccCard { try { ActivityManagerNative.getDefault().updateConfiguration(config); } catch (RemoteException e) { + Log.e(mLogTag, "[SimCard] Remote Exception when updating imsi configuration"); } } } - - private void - updateStateProperty() { - phone.setSystemProperty( - TelephonyProperties.PROPERTY_SIM_STATE, - getState().toString()); - } - - private void log(String msg) { - Log.d(LOG_TAG, "[GsmSimCard] " + msg); - } } - diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java index f71ea48..be5b842 100644 --- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java +++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java @@ -27,10 +27,11 @@ import com.android.internal.telephony.BaseCommands; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.DataCallState; +import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.Phone; import com.android.internal.telephony.gsm.CallFailCause; import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; import com.android.internal.telephony.gsm.SuppServiceNotification; -import com.android.internal.telephony.Phone; import java.util.ArrayList; @@ -103,39 +104,8 @@ public final class SimulatedCommands extends BaseCommands //***** CommandsInterface implementation - public void getIccStatus(Message result) { - switch (mState) { - case SIM_READY: - resultSuccess(result, IccStatus.ICC_READY); - break; - - case SIM_LOCKED_OR_ABSENT: - returnSimLockedStatus(result); - break; - - default: - resultSuccess(result, IccStatus.ICC_NOT_READY); - break; - } - } - - private void returnSimLockedStatus(Message result) { - switch (mSimLockedState) { - case REQUIRE_PIN: - Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: ICC_PIN"); - resultSuccess(result, IccStatus.ICC_PIN); - break; - - case REQUIRE_PUK: - Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: ICC_PUK"); - resultSuccess(result, IccStatus.ICC_PUK); - break; - - default: - Log.i(LOG_TAG, - "[SimCmd] returnSimLockedStatus: mSimLockedState==NONE !?"); - break; - } + public void getIccCardStatus(Message result) { + unimplemented(result); } public void supplyIccPin(String pin, Message result) { |