From 95a1d1a89e383dab893750638c2393dec54833ff Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Tue, 18 Aug 2009 12:08:59 -0700 Subject: E911 call fix in ECM Based on the VZW requirement, phone should be still in ECM mode in 2nd emergency call. but in the current phone call, if a 2nd emergency call is originated, ECM mode will exit. For fixing this problem, the coding design is as below: 1. In framework, canceling the first ECM timer immediately upon the origination of the 2nd E911 call, and restarting a new timer when the 2nd E911 ends. 2. Framework needs to syncronize the timer with phone app by sending notification to phone app to inform timer is canceled or re-started, since phone app needs to show how much ECM time left on the status bar. 3. In phone app's emergency callback mode service, the timer in this service will be canceled when it receives the timer cancel notification from framework; the timer will be restarted once it receives timer restart notification from framework. --- .../java/com/android/internal/telephony/Phone.java | 14 +++ .../com/android/internal/telephony/PhoneBase.java | 10 ++ .../com/android/internal/telephony/PhoneProxy.java | 8 ++ .../android/internal/telephony/cdma/CDMAPhone.java | 107 ++++++++++++++++----- .../internal/telephony/cdma/CdmaCallTracker.java | 49 ++++++++-- 5 files changed, 158 insertions(+), 30 deletions(-) mode change 100644 => 100755 telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java (limited to 'telephony/java') diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java index 622b47d..3f9744f 100644 --- a/telephony/java/com/android/internal/telephony/Phone.java +++ b/telephony/java/com/android/internal/telephony/Phone.java @@ -434,6 +434,20 @@ public interface Phone { void unregisterForMmiComplete(Handler h); /** + * Registration point for Ecm timer reset + * @param h handler to notify + * @param what user-defined message code + * @param obj placed in Message.obj + */ + public void registerForEcmTimerReset(Handler h, int what, Object obj); + + /** + * Unregister for notification for Ecm timer reset + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForEcmTimerReset(Handler h); + + /** * Returns a list of MMI codes that are pending. (They have initiated * but have not yet completed). * Presently there is only ever one. diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index 6f4aef9..04a3749 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -760,6 +760,16 @@ public abstract class PhoneBase implements Phone { Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); } + public void registerForEcmTimerReset(Handler h, int what, Object obj) { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + } + + public void unregisterForEcmTimerReset(Handler h) { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + } + public void registerForSignalInfo(Handler h, int what, Object obj) { mCM.registerForSignalInfo(h, what, obj); } diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java index f2568c1..8683278 100644 --- a/telephony/java/com/android/internal/telephony/PhoneProxy.java +++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java @@ -323,6 +323,14 @@ public class PhoneProxy extends Handler implements Phone { mActivePhone.unregisterForSubscriptionInfoReady(h); } + public void registerForEcmTimerReset(Handler h, int what, Object obj) { + mActivePhone.registerForEcmTimerReset(h,what,obj); + } + + public void unregisterForEcmTimerReset(Handler h) { + mActivePhone.unregisterForEcmTimerReset(h); + } + public boolean getIccRecordsLoaded() { return mActivePhone.getIccRecordsLoaded(); } diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java index f0c0ea2..237d533 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java +++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java @@ -28,6 +28,8 @@ import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; import android.os.Registrant; import android.os.RegistrantList; import android.os.RemoteException; @@ -72,8 +74,7 @@ import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OP import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY; import java.util.List; -import java.util.Timer; -import java.util.TimerTask; + import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -87,10 +88,14 @@ public class CDMAPhone extends PhoneBase { // Default Emergency Callback Mode exit timer 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; + static final int RESTART_ECM_TIMER = 0; // restart Ecm timer + static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer + //***** Instance Variables CdmaCallTracker mCT; CdmaSMSDispatcher mSMS; @@ -103,6 +108,7 @@ public class CDMAPhone extends PhoneBase { RuimSmsInterfaceManager mRuimSmsInterfaceManager; PhoneSubInfo mSubInfo; EriManager mEriManager; + WakeLock mWakeLock; // mNvLoadedRegistrants are informed after the EVENT_NV_READY private RegistrantList mNvLoadedRegistrants = new RegistrantList(); @@ -110,17 +116,20 @@ public class CDMAPhone extends PhoneBase { // mEriFileLoadedRegistrants are informed after the ERI text has been loaded private RegistrantList mEriFileLoadedRegistrants = new RegistrantList(); - // mECMExitRespRegistrant is informed after the phone has been exited + // mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started + private RegistrantList mEcmTimerResetRegistrants = new RegistrantList(); + + // mEcmExitRespRegistrant is informed after the phone has been exited //the emergency callback mode //keep track of if phone is in emergency callback mode - private boolean mIsPhoneInECMState; - private Registrant mECMExitRespRegistrant; + private boolean mIsPhoneInEcmState; + 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. + // A runnable which is used to automatically exit from Ecm after a period of time. private Runnable mExitEcmRunnable = new Runnable() { public void run() { exitEmergencyCallbackMode(); @@ -165,6 +174,9 @@ public class CDMAPhone extends PhoneBase { mCM.registerForNVReady(h, EVENT_NV_READY, null); mCM.setEmergencyCallbackMode(h, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null); + PowerManager pm + = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,LOG_TAG); //Change the system setting SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE, @@ -172,7 +184,7 @@ public class CDMAPhone extends PhoneBase { // This is needed to handle phone process crashes String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); - mIsPhoneInECMState = inEcm.equals("true"); + mIsPhoneInEcmState = inEcm.equals("true"); // get the string that specifies the carrier OTA Sp number mCarrierOtaSpNumSchema = SystemProperties.get( @@ -244,6 +256,10 @@ public class CDMAPhone extends PhoneBase { protected void finalize() { if(DBG) Log.d(LOG_TAG, "CDMAPhone finalized"); + if (mWakeLock.isHeld()) { + Log.e(LOG_TAG, "UNEXPECTED; mWakeLock is held when finalizing."); + mWakeLock.release(); + } } @@ -525,11 +541,11 @@ public class CDMAPhone extends PhoneBase { } public void setOnEcbModeExitResponse(Handler h, int what, Object obj) { - mECMExitRespRegistrant = new Registrant (h, what, obj); + mEcmExitRespRegistrant = new Registrant (h, what, obj); } public void unsetOnEcbModeExitResponse(Handler h) { - mECMExitRespRegistrant.clear(); + mEcmExitRespRegistrant.clear(); } public void registerForCallWaiting(Handler h, int what, Object obj) { @@ -729,7 +745,7 @@ public class CDMAPhone extends PhoneBase { public boolean enableDataConnectivity() { // block data activities when phone is in emergency callback mode - if (mIsPhoneInECMState) { + if (mIsPhoneInEcmState) { Intent intent = new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS); ActivityManagerNative.broadcastStickyIntent(intent, null); return false; @@ -826,8 +842,9 @@ public class CDMAPhone extends PhoneBase { void sendEmergencyCallbackModeChange(){ //Send an Intent Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); - intent.putExtra(PHONE_IN_ECM_STATE, mIsPhoneInECMState); + intent.putExtra(PHONE_IN_ECM_STATE, mIsPhoneInEcmState); ActivityManagerNative.broadcastStickyIntent(intent,null); + if (DBG) Log.d(LOG_TAG, "sendEmergencyCallbackModeChange"); } /*package*/ void @@ -859,15 +876,21 @@ public class CDMAPhone extends PhoneBase { @Override public void exitEmergencyCallbackMode() { + if (mWakeLock.isHeld()) { + mWakeLock.release(); + } // Send a message which will invoke handleExitEmergencyCallbackMode mCM.exitEmergencyCallbackMode(h.obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE)); } private void handleEnterEmergencyCallbackMode(Message msg) { - Log.d(LOG_TAG, "Event EVENT_EMERGENCY_CALLBACK_MODE Received"); - // if phone is not in ECM mode, and it's changed to ECM mode - if (mIsPhoneInECMState == false) { - mIsPhoneInECMState = true; + if (DBG) { + Log.d(LOG_TAG, "handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= " + + mIsPhoneInEcmState); + } + // if phone is not in Ecm mode, and it's changed to Ecm mode + if (mIsPhoneInEcmState == false) { + mIsPhoneInEcmState = true; // notify change sendEmergencyCallbackModeChange(); setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true"); @@ -877,23 +900,27 @@ public class CDMAPhone extends PhoneBase { long delayInMillis = SystemProperties.getLong( TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE); h.postDelayed(mExitEcmRunnable, delayInMillis); + // We don't want to go to sleep while in Ecm + mWakeLock.acquire(); } } private void handleExitEmergencyCallbackMode(Message msg) { - Log.d(LOG_TAG, "Event EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE Received"); AsyncResult ar = (AsyncResult)msg.obj; - - // Remove pending exit ECM runnable, if any + if (DBG) { + Log.d(LOG_TAG, "handleExitEmergencyCallbackMode,ar.exception , mIsPhoneInEcmState " + + ar.exception + mIsPhoneInEcmState); + } + // Remove pending exit Ecm runnable, if any h.removeCallbacks(mExitEcmRunnable); - if (mECMExitRespRegistrant != null) { - mECMExitRespRegistrant.notifyRegistrant(ar); + if (mEcmExitRespRegistrant != null) { + mEcmExitRespRegistrant.notifyRegistrant(ar); } // if exiting ecm success if (ar.exception == null) { - if (mIsPhoneInECMState) { - mIsPhoneInECMState = false; + if (mIsPhoneInEcmState) { + mIsPhoneInEcmState = false; setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false"); } // send an Intent @@ -903,6 +930,42 @@ public class CDMAPhone extends PhoneBase { } } + /** + * Handle to cancel or restart Ecm timer in emergency call back mode + * if action is CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled; + * otherwise, restart Ecm timer and notify apps the timer is restarted. + */ + void handleTimerInEmergencyCallbackMode(int action) { + switch(action) { + case CANCEL_ECM_TIMER: + h.removeCallbacks(mExitEcmRunnable); + mEcmTimerResetRegistrants.notifyResult(new Boolean(true)); + break; + case RESTART_ECM_TIMER: + long delayInMillis = SystemProperties.getLong( + TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE); + h.postDelayed(mExitEcmRunnable, delayInMillis); + mEcmTimerResetRegistrants.notifyResult(new Boolean(false)); + break; + default: + Log.e(LOG_TAG, "handleTimerInEmergencyCallbackMode, unsupported action " + action); + } + } + + /** + * Registration point for Ecm timer reset + * @param h handler to notify + * @param what User-defined message code + * @param obj placed in Message.obj + */ + public void registerForEcmTimerReset(Handler h, int what, Object obj) { + mEcmTimerResetRegistrants.addUnique(h, what, obj); + } + + public void unregisterForEcmTimerReset(Handler h) { + mEcmTimerResetRegistrants.remove(h); + } + //***** Inner Classes class MyHandler extends Handler { MyHandler() { diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java old mode 100644 new mode 100755 index be4763c..7bbf91d --- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java @@ -72,7 +72,7 @@ public final class CdmaCallTracker extends CallTracker { CdmaConnection pendingMO; boolean hangupPendingMO; - boolean pendingCallInECM=false; + boolean pendingCallInEcm=false; CDMAPhone phone; boolean desiredMute = false; // false = mute off @@ -80,6 +80,7 @@ public final class CdmaCallTracker extends CallTracker { int pendingCallClirMode; Phone.State state = Phone.State.IDLE; + private boolean mIsEcmTimerCanceled = false; // boolean needsPoll; @@ -182,6 +183,14 @@ public final class CdmaCallTracker extends CallTracker { throw new CallStateException("cannot dial in current state"); } + String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); + boolean isPhoneInEcmMode = inEcm.equals("true"); + boolean isEmergencyCall = PhoneNumberUtils.isEmergencyNumber(dialString); + + // Cancel Ecm timer if a second emergency call is originating in Ecm mode + if (isPhoneInEcmMode && isEmergencyCall) { + handleEcmTimer(phone.CANCEL_ECM_TIMER); + } // We are initiating a call therefore even if we previously // didn't know the state (i.e. Generic was true) we now know @@ -210,14 +219,14 @@ public final class CdmaCallTracker extends CallTracker { // Always unmute when initiating a new call setMute(false); - String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); - if(inEcm.equals("false")) { + // In Ecm mode, if another emergency call is dialed, Ecm mode will not exit. + if(!isPhoneInEcmMode || (isPhoneInEcmMode && isEmergencyCall)) { cm.dial(pendingMO.address, clirMode, obtainCompleteMessage()); } else { phone.exitEmergencyCallbackMode(); phone.setOnEcbModeExitResponse(this,EVENT_EXIT_ECM_RESPONSE_CDMA, null); pendingCallClirMode=clirMode; - pendingCallInECM=true; + pendingCallInEcm=true; } } @@ -479,6 +488,11 @@ public final class CdmaCallTracker extends CallTracker { // Someone has already asked to hangup this call if (hangupPendingMO) { hangupPendingMO = false; + // Re-start Ecm timer when an uncompleted emergency call ends + if (mIsEcmTimerCanceled) { + handleEcmTimer(phone.RESTART_ECM_TIMER); + } + try { if (Phone.DEBUG_PHONE) log( "poll: hangupPendingMO, hangup conn " + i); @@ -532,6 +546,12 @@ public final class CdmaCallTracker extends CallTracker { } } foregroundCall.setGeneric(false); + + // Re-start Ecm timer when the connected emergency call ends + if (mIsEcmTimerCanceled) { + handleEcmTimer(phone.RESTART_ECM_TIMER); + } + // Dropped connections are removed from the CallTracker // list but kept in the Call list connections[i] = null; @@ -571,8 +591,8 @@ public final class CdmaCallTracker extends CallTracker { droppedDuringPoll.add(pendingMO); pendingMO = null; hangupPendingMO = false; - if( pendingCallInECM) { - pendingCallInECM = false; + if( pendingCallInEcm) { + pendingCallInEcm = false; } } @@ -941,9 +961,9 @@ public final class CdmaCallTracker extends CallTracker { case EVENT_EXIT_ECM_RESPONSE_CDMA: //no matter the result, we still do the same here - if (pendingCallInECM) { + if (pendingCallInEcm) { cm.dial(pendingMO.address, pendingCallClirMode, obtainCompleteMessage()); - pendingCallInECM = false; + pendingCallInEcm = false; } phone.unsetOnEcbModeExitResponse(this); break; @@ -971,6 +991,19 @@ public final class CdmaCallTracker extends CallTracker { } } + /** + * Handle Ecm timer to be canceled or re-started + */ + private void handleEcmTimer(int action) { + phone.handleTimerInEmergencyCallbackMode(action); + switch(action) { + case CDMAPhone.CANCEL_ECM_TIMER: mIsEcmTimerCanceled = true; break; + case CDMAPhone.RESTART_ECM_TIMER: mIsEcmTimerCanceled = false; break; + default: + Log.e(LOG_TAG, "handleEcmTimer, unsupported action " + action); + } + } + protected void log(String msg) { Log.d(LOG_TAG, "[CdmaCallTracker] " + msg); } -- cgit v1.1