GsmCdmaConnection.java revision 74c8509aede6fe748904e75c156049b4f1ba5e28
188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project/*
288b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project * Copyright (C) 2015 The Android Open Source Project
388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project *
488b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
588b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project * you may not use this file except in compliance with the License.
688b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project * You may obtain a copy of the License at
788b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project *
888b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
988b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project *
1088b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1288b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project * See the License for the specific language governing permissions and
1488b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project * limitations under the License.
1588b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project */
1688b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
1788b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectpackage com.android.internal.telephony;
1888b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport android.content.Context;
1988b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport android.os.AsyncResult;
2088b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport android.os.Handler;
2188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport android.os.Looper;
2288b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport android.os.Message;
2388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport android.os.PersistableBundle;
2488b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport android.os.PowerManager;
2588b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport android.os.Registrant;
2688b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport android.os.SystemClock;
2788b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport android.telephony.CarrierConfigManager;
2888b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport android.telephony.DisconnectCause;
2988b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport android.telephony.PhoneNumberUtils;
3088b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport android.telephony.Rlog;
3188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport android.telephony.ServiceState;
3288b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport android.text.TextUtils;
3388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
3488b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
3588b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
3688b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
3788b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectimport com.android.internal.telephony.uicc.UiccCardApplication;
3888b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
3988b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project/**
4088b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project * {@hide}
4188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project */
4288b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Projectpublic class GsmCdmaConnection extends Connection {
4388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    private static final String LOG_TAG = "GsmCdmaConnection";
4488b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    private static final boolean DBG = true;
4588b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    private static final boolean VDBG = false;
4688b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
4788b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    //***** Instance Variables
4888b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
4988b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    GsmCdmaCallTracker mOwner;
5088b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    GsmCdmaCall mParent;
5188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
528539929a12f135f45de9cd99f9502431f7d2de85Mike Lockwood    boolean mDisconnected;
538539929a12f135f45de9cd99f9502431f7d2de85Mike Lockwood
548539929a12f135f45de9cd99f9502431f7d2de85Mike Lockwood    int mIndex;          // index in GsmCdmaCallTracker.connections[], -1 if unassigned
558539929a12f135f45de9cd99f9502431f7d2de85Mike Lockwood                        // The GsmCdma index is 1 + this
568539929a12f135f45de9cd99f9502431f7d2de85Mike Lockwood
578539929a12f135f45de9cd99f9502431f7d2de85Mike Lockwood    /*
588539929a12f135f45de9cd99f9502431f7d2de85Mike Lockwood     * These time/timespan values are based on System.currentTimeMillis(),
598539929a12f135f45de9cd99f9502431f7d2de85Mike Lockwood     * i.e., "wall clock" time.
608539929a12f135f45de9cd99f9502431f7d2de85Mike Lockwood     */
618539929a12f135f45de9cd99f9502431f7d2de85Mike Lockwood    long mDisconnectTime;
628539929a12f135f45de9cd99f9502431f7d2de85Mike Lockwood
638539929a12f135f45de9cd99f9502431f7d2de85Mike Lockwood    UUSInfo mUusInfo;
648539929a12f135f45de9cd99f9502431f7d2de85Mike Lockwood    int mPreciseCause = 0;
658539929a12f135f45de9cd99f9502431f7d2de85Mike Lockwood    String mVendorCause;
6664d85d0d827489c514f6aec075482563c80cda73Joe Onorato
6764d85d0d827489c514f6aec075482563c80cda73Joe Onorato    Connection mOrigConnection;
6864d85d0d827489c514f6aec075482563c80cda73Joe Onorato
6964d85d0d827489c514f6aec075482563c80cda73Joe Onorato    Handler mHandler;
7064d85d0d827489c514f6aec075482563c80cda73Joe Onorato
7164d85d0d827489c514f6aec075482563c80cda73Joe Onorato    private PowerManager.WakeLock mPartialWakeLock;
7264d85d0d827489c514f6aec075482563c80cda73Joe Onorato
7364d85d0d827489c514f6aec075482563c80cda73Joe Onorato    private boolean mIsEmergencyCall = false;
7464d85d0d827489c514f6aec075482563c80cda73Joe Onorato
7564d85d0d827489c514f6aec075482563c80cda73Joe Onorato    // The cached delay to be used between DTMF tones fetched from carrier config.
7664d85d0d827489c514f6aec075482563c80cda73Joe Onorato    private int mDtmfToneDelay = 0;
77f23e6bfda08cc629cded7c1ef4b24eb8a0365403Dan Willemsen
7864d85d0d827489c514f6aec075482563c80cda73Joe Onorato    //***** Event Constants
7964d85d0d827489c514f6aec075482563c80cda73Joe Onorato    static final int EVENT_DTMF_DONE = 1;
8064d85d0d827489c514f6aec075482563c80cda73Joe Onorato    static final int EVENT_PAUSE_DONE = 2;
8188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    static final int EVENT_NEXT_POST_DIAL = 3;
822f31293ba78695cb48ac5a1cab835197ace58d47The Android Open Source Project    static final int EVENT_WAKE_LOCK_TIMEOUT = 4;
832f31293ba78695cb48ac5a1cab835197ace58d47The Android Open Source Project    static final int EVENT_DTMF_DELAY_DONE = 5;
842f31293ba78695cb48ac5a1cab835197ace58d47The Android Open Source Project
85d0244b395a583804137cd1fe2bff4f86d66b396bYing Wang    //***** Constants
862f31293ba78695cb48ac5a1cab835197ace58d47The Android Open Source Project    static final int PAUSE_DELAY_MILLIS_GSM = 3 * 1000;
8788b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    static final int PAUSE_DELAY_MILLIS_CDMA = 2 * 1000;
8888b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    static final int WAKE_LOCK_TIMEOUT_MILLIS = 60*1000;
8988b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
9088b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    //***** Inner Classes
9120f99a60eabe1ae79c90263df85ed5f15f6f9bdeDan Willemsen
9288b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    class MyHandler extends Handler {
9388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        MyHandler(Looper l) {super(l);}
9488b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
9588b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        @Override
9688b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        public void
9788b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        handleMessage(Message msg) {
9888b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
9988b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project            switch (msg.what) {
10088b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                case EVENT_NEXT_POST_DIAL:
10188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                case EVENT_DTMF_DELAY_DONE:
10288b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                case EVENT_PAUSE_DONE:
10388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                    processNextPostDialChar();
10488b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                    break;
10588b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                case EVENT_WAKE_LOCK_TIMEOUT:
10688b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                    releaseWakeLock();
10788b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                    break;
10888b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                case EVENT_DTMF_DONE:
10988b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                    // We may need to add a delay specified by carrier between DTMF tones that are
11088b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                    // sent out.
11188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                    mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_DTMF_DELAY_DONE),
11288b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                            mDtmfToneDelay);
113d0244b395a583804137cd1fe2bff4f86d66b396bYing Wang                    break;
114d0244b395a583804137cd1fe2bff4f86d66b396bYing Wang            }
115d0244b395a583804137cd1fe2bff4f86d66b396bYing Wang        }
116d0244b395a583804137cd1fe2bff4f86d66b396bYing Wang    }
1179bfcbc8a716303ceb39c59afff13e509af6e18bbDan Willemsen
1189bfcbc8a716303ceb39c59afff13e509af6e18bbDan Willemsen    //***** Constructors
1192f31293ba78695cb48ac5a1cab835197ace58d47The Android Open Source Project
1209bfcbc8a716303ceb39c59afff13e509af6e18bbDan Willemsen    /** This is probably an MT call that we first saw in a CLCC response or a hand over. */
121ba740ff57fd314d0ad649c252841ab834e96fdaaVince Harron    public GsmCdmaConnection (GsmCdmaPhone phone, DriverCall dc, GsmCdmaCallTracker ct, int index) {
12217c83cf22c426c628b4b21bc65128a0d80866d31Doug Zongker        super(phone.getPhoneType());
12388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        createWakeLock(phone.getContext());
1249bfcbc8a716303ceb39c59afff13e509af6e18bbDan Willemsen        acquireWakeLock();
12588b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
12688b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        mOwner = ct;
12788b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        mHandler = new MyHandler(mOwner.getLooper());
12888b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
12988b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        mAddress = dc.number;
1309bfcbc8a716303ceb39c59afff13e509af6e18bbDan Willemsen        mIsEmergencyCall = PhoneNumberUtils.isLocalEmergencyNumber(phone.getContext(), mAddress);
13188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        mIsIncoming = dc.isMT;
13220f99a60eabe1ae79c90263df85ed5f15f6f9bdeDan Willemsen        mCreateTime = System.currentTimeMillis();
13388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        mCnapName = dc.name;
13488b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        mCnapNamePresentation = dc.namePresentation;
13588b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        mNumberPresentation = dc.numberPresentation;
136529113098350c026ec521258d4c6fba51f285a48Ying Wang        mUusInfo = dc.uusInfo;
137529113098350c026ec521258d4c6fba51f285a48Ying Wang
138529113098350c026ec521258d4c6fba51f285a48Ying Wang        mIndex = index;
13920f99a60eabe1ae79c90263df85ed5f15f6f9bdeDan Willemsen
140529113098350c026ec521258d4c6fba51f285a48Ying Wang        mParent = parentFromDCState(dc.state);
141529113098350c026ec521258d4c6fba51f285a48Ying Wang        mParent.attach(this, dc);
142529113098350c026ec521258d4c6fba51f285a48Ying Wang
1431d97b9013c24e93442416d77426561ede54fb692Shinichiro Hamaji        fetchDtmfToneDelay(phone);
144529113098350c026ec521258d4c6fba51f285a48Ying Wang    }
14516fa4b290e8ce76652c9ba0ba16b80578456ab95Joe Onorato
1469bfcbc8a716303ceb39c59afff13e509af6e18bbDan Willemsen    /** This is an MO call, created when dialing */
1479bfcbc8a716303ceb39c59afff13e509af6e18bbDan Willemsen    public GsmCdmaConnection (GsmCdmaPhone phone, String dialString, GsmCdmaCallTracker ct,
148529113098350c026ec521258d4c6fba51f285a48Ying Wang                              GsmCdmaCall parent, boolean isEmergencyCall) {
1499bfcbc8a716303ceb39c59afff13e509af6e18bbDan Willemsen        super(phone.getPhoneType());
150529113098350c026ec521258d4c6fba51f285a48Ying Wang        createWakeLock(phone.getContext());
151529113098350c026ec521258d4c6fba51f285a48Ying Wang        acquireWakeLock();
1529bfcbc8a716303ceb39c59afff13e509af6e18bbDan Willemsen
153529113098350c026ec521258d4c6fba51f285a48Ying Wang        mOwner = ct;
1542c3f8366e2c6479f75266a98204d02b313891a78Dan Willemsen        mHandler = new MyHandler(mOwner.getLooper());
1552c3f8366e2c6479f75266a98204d02b313891a78Dan Willemsen
1562c3f8366e2c6479f75266a98204d02b313891a78Dan Willemsen        if (isPhoneTypeGsm()) {
1572c3f8366e2c6479f75266a98204d02b313891a78Dan Willemsen            mDialString = dialString;
1582c3f8366e2c6479f75266a98204d02b313891a78Dan Willemsen        } else {
1592c3f8366e2c6479f75266a98204d02b313891a78Dan Willemsen            Rlog.d(LOG_TAG, "[GsmCdmaConn] GsmCdmaConnection: dialString=" +
1602c3f8366e2c6479f75266a98204d02b313891a78Dan Willemsen                    maskDialString(dialString));
161cbb3266b4712fe0aa82d80d9d6db0974be9eea3fRyo Fujii            dialString = formatDialString(dialString);
162cbb3266b4712fe0aa82d80d9d6db0974be9eea3fRyo Fujii            Rlog.d(LOG_TAG,
163cbb3266b4712fe0aa82d80d9d6db0974be9eea3fRyo Fujii                    "[GsmCdmaConn] GsmCdmaConnection:formated dialString=" +
164cbb3266b4712fe0aa82d80d9d6db0974be9eea3fRyo Fujii                            maskDialString(dialString));
165cf5da40e5295f28f84e760dccfb02278c55dfc10Ying Wang        }
166cbb3266b4712fe0aa82d80d9d6db0974be9eea3fRyo Fujii
167cbb3266b4712fe0aa82d80d9d6db0974be9eea3fRyo Fujii        mAddress = PhoneNumberUtils.extractNetworkPortionAlt(dialString);
168cbb3266b4712fe0aa82d80d9d6db0974be9eea3fRyo Fujii        mIsEmergencyCall = isEmergencyCall;
169cbb3266b4712fe0aa82d80d9d6db0974be9eea3fRyo Fujii        mPostDialString = PhoneNumberUtils.extractPostDialPortion(dialString);
17088b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
17188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        mIndex = -1;
17288b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
17388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        mIsIncoming = false;
17488b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        mCnapName = null;
17588b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        mCnapNamePresentation = PhoneConstants.PRESENTATION_ALLOWED;
17688b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        mNumberPresentation = PhoneConstants.PRESENTATION_ALLOWED;
17788b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        mCreateTime = System.currentTimeMillis();
17816fa4b290e8ce76652c9ba0ba16b80578456ab95Joe Onorato
179157a5e1695593f935c3223430f4530e21f990378Ying Wang        if (parent != null) {
180157a5e1695593f935c3223430f4530e21f990378Ying Wang            mParent = parent;
181157a5e1695593f935c3223430f4530e21f990378Ying Wang            if (isPhoneTypeGsm()) {
182529113098350c026ec521258d4c6fba51f285a48Ying Wang                parent.attachFake(this, GsmCdmaCall.State.DIALING);
183157a5e1695593f935c3223430f4530e21f990378Ying Wang            } else {
184157a5e1695593f935c3223430f4530e21f990378Ying Wang                //for the three way call case, not change parent state
185157a5e1695593f935c3223430f4530e21f990378Ying Wang                if (parent.mState == GsmCdmaCall.State.ACTIVE) {
186157a5e1695593f935c3223430f4530e21f990378Ying Wang                    parent.attachFake(this, GsmCdmaCall.State.ACTIVE);
187157a5e1695593f935c3223430f4530e21f990378Ying Wang                } else {
1884c364620ac81a01dc2c9d6aac7cad3e4dbc6b52bDan Willemsen                    parent.attachFake(this, GsmCdmaCall.State.DIALING);
1894c364620ac81a01dc2c9d6aac7cad3e4dbc6b52bDan Willemsen                }
190157a5e1695593f935c3223430f4530e21f990378Ying Wang
191157a5e1695593f935c3223430f4530e21f990378Ying Wang            }
192157a5e1695593f935c3223430f4530e21f990378Ying Wang        }
193157a5e1695593f935c3223430f4530e21f990378Ying Wang
194157a5e1695593f935c3223430f4530e21f990378Ying Wang        fetchDtmfToneDelay(phone);
195157a5e1695593f935c3223430f4530e21f990378Ying Wang    }
196157a5e1695593f935c3223430f4530e21f990378Ying Wang
197157a5e1695593f935c3223430f4530e21f990378Ying Wang    //CDMA
198157a5e1695593f935c3223430f4530e21f990378Ying Wang    /** This is a Call waiting call*/
199157a5e1695593f935c3223430f4530e21f990378Ying Wang    public GsmCdmaConnection(Context context, CdmaCallWaitingNotification cw, GsmCdmaCallTracker ct,
200157a5e1695593f935c3223430f4530e21f990378Ying Wang                             GsmCdmaCall parent) {
201157a5e1695593f935c3223430f4530e21f990378Ying Wang        super(parent.getPhone().getPhoneType());
202157a5e1695593f935c3223430f4530e21f990378Ying Wang        createWakeLock(context);
203594c3fc3d795b1ef776c352314d26a079c118f4eDan Willemsen        acquireWakeLock();
204157a5e1695593f935c3223430f4530e21f990378Ying Wang
205157a5e1695593f935c3223430f4530e21f990378Ying Wang        mOwner = ct;
206157a5e1695593f935c3223430f4530e21f990378Ying Wang        mHandler = new MyHandler(mOwner.getLooper());
2074c364620ac81a01dc2c9d6aac7cad3e4dbc6b52bDan Willemsen        mAddress = cw.number;
208157a5e1695593f935c3223430f4530e21f990378Ying Wang        mNumberPresentation = cw.numberPresentation;
209157a5e1695593f935c3223430f4530e21f990378Ying Wang        mCnapName = cw.name;
210157a5e1695593f935c3223430f4530e21f990378Ying Wang        mCnapNamePresentation = cw.namePresentation;
211157a5e1695593f935c3223430f4530e21f990378Ying Wang        mIndex = -1;
212157a5e1695593f935c3223430f4530e21f990378Ying Wang        mIsIncoming = true;
213157a5e1695593f935c3223430f4530e21f990378Ying Wang        mCreateTime = System.currentTimeMillis();
214157a5e1695593f935c3223430f4530e21f990378Ying Wang        mConnectTime = 0;
215157a5e1695593f935c3223430f4530e21f990378Ying Wang        mParent = parent;
21667132baa4d11917030c5156f507a50110c4cd935Ying Wang        parent.attachFake(this, GsmCdmaCall.State.WAITING);
21767132baa4d11917030c5156f507a50110c4cd935Ying Wang    }
21867132baa4d11917030c5156f507a50110c4cd935Ying Wang
21967132baa4d11917030c5156f507a50110c4cd935Ying Wang
22067132baa4d11917030c5156f507a50110c4cd935Ying Wang    public void dispose() {
22167132baa4d11917030c5156f507a50110c4cd935Ying Wang        clearPostDialListeners();
22267132baa4d11917030c5156f507a50110c4cd935Ying Wang        if (mParent != null) {
22367132baa4d11917030c5156f507a50110c4cd935Ying Wang            mParent.detach(this);
22467132baa4d11917030c5156f507a50110c4cd935Ying Wang        }
22567132baa4d11917030c5156f507a50110c4cd935Ying Wang        releaseAllWakeLocks();
22667132baa4d11917030c5156f507a50110c4cd935Ying Wang    }
22767132baa4d11917030c5156f507a50110c4cd935Ying Wang
22867132baa4d11917030c5156f507a50110c4cd935Ying Wang    static boolean
229157a5e1695593f935c3223430f4530e21f990378Ying Wang    equalsHandlesNulls (Object a, Object b) {
230157a5e1695593f935c3223430f4530e21f990378Ying Wang        return (a == null) ? (b == null) : a.equals (b);
231157a5e1695593f935c3223430f4530e21f990378Ying Wang    }
232157a5e1695593f935c3223430f4530e21f990378Ying Wang
233157a5e1695593f935c3223430f4530e21f990378Ying Wang    static boolean
2340c4eb4188553fc06049834111416067da53ac605Ying Wang    equalsBaseDialString (String a, String b) {
235157a5e1695593f935c3223430f4530e21f990378Ying Wang        return (a == null) ? (b == null) : (b != null && a.startsWith (b));
236157a5e1695593f935c3223430f4530e21f990378Ying Wang    }
237157a5e1695593f935c3223430f4530e21f990378Ying Wang
238157a5e1695593f935c3223430f4530e21f990378Ying Wang    //CDMA
239157a5e1695593f935c3223430f4530e21f990378Ying Wang    /**
240157a5e1695593f935c3223430f4530e21f990378Ying Wang     * format original dial string
241157a5e1695593f935c3223430f4530e21f990378Ying Wang     * 1) convert international dialing prefix "+" to
242157a5e1695593f935c3223430f4530e21f990378Ying Wang     *    string specified per region
24388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project     *
244cae4d12fd114babec4249123c56110b8e247fda1Ying Wang     * 2) handle corner cases for PAUSE/WAIT dialing:
245cae4d12fd114babec4249123c56110b8e247fda1Ying Wang     *
246cae4d12fd114babec4249123c56110b8e247fda1Ying Wang     *    If PAUSE/WAIT sequence at the end, ignore them.
247cae4d12fd114babec4249123c56110b8e247fda1Ying Wang     *
248cae4d12fd114babec4249123c56110b8e247fda1Ying Wang     *    If consecutive PAUSE/WAIT sequence in the middle of the string,
24988b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project     *    and if there is any WAIT in PAUSE/WAIT sequence, treat them like WAIT.
25088b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project     */
25188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    public static String formatDialString(String phoneNumber) {
25288b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        /**
25388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project         * TODO(cleanup): This function should move to PhoneNumberUtils, and
254157a5e1695593f935c3223430f4530e21f990378Ying Wang         * tests should be added.
255157a5e1695593f935c3223430f4530e21f990378Ying Wang         */
256157a5e1695593f935c3223430f4530e21f990378Ying Wang
257157a5e1695593f935c3223430f4530e21f990378Ying Wang        if (phoneNumber == null) {
258157a5e1695593f935c3223430f4530e21f990378Ying Wang            return null;
259157a5e1695593f935c3223430f4530e21f990378Ying Wang        }
26088b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        int length = phoneNumber.length();
26122ef79850e92ae3fd7dc039014446f60de43850aYing Wang        StringBuilder ret = new StringBuilder();
26222ef79850e92ae3fd7dc039014446f60de43850aYing Wang        char c;
26322ef79850e92ae3fd7dc039014446f60de43850aYing Wang        int currIndex = 0;
2640650d1503d89f1563978f6006a2f904da7140027Ying Wang
265ad6674cd6003b78ef8ba101eb8a6b3c889ae4b0dYing Wang        while (currIndex < length) {
26689ec496f989c44315b25ec08915d847edd322739Narayan Kamath            c = phoneNumber.charAt(currIndex);
267cdd4343bb2e2dfc9c1886ab2749394861110848aNicolas Geoffray            if (isPause(c) || isWait(c)) {
2684a0ad4ac61081f56c4aab50a2aed3001e51f9126Nicolas Geoffray                if (currIndex < length - 1) {
269a95fbd1ed57c7261788a354d1ca18821d1df483cNicolas Geoffray                    // if PW not at the end
2700650d1503d89f1563978f6006a2f904da7140027Ying Wang                    int nextIndex = findNextPCharOrNonPOrNonWCharIndex(phoneNumber, currIndex);
27155eabd5511c5cabd2eb4851e04e993b9a99d370dMathieu Chartier                    // If there is non PW char following PW sequence
27255eabd5511c5cabd2eb4851e04e993b9a99d370dMathieu Chartier                    if (nextIndex < length) {
27355eabd5511c5cabd2eb4851e04e993b9a99d370dMathieu Chartier                        char pC = findPOrWCharToAppend(phoneNumber, currIndex, nextIndex);
27488b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                        ret.append(pC);
27588b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                        // If PW char sequence has more than 2 PW characters,
27688b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                        // skip to the last PW character since the sequence already be
27788b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                        // converted to WAIT character
27888b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                        if (nextIndex > (currIndex + 1)) {
27988b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                            currIndex = nextIndex - 1;
28088b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                        }
28188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                    } else if (nextIndex == length) {
28288b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                        // It means PW characters at the end, ignore
28388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                        currIndex = length - 1;
28488b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                    }
28588b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project                }
286d14f6d92d4284ea54520bb29f21411e892ba43edDave Bort            } else {
287d14f6d92d4284ea54520bb29f21411e892ba43edDave Bort                ret.append(c);
288d14f6d92d4284ea54520bb29f21411e892ba43edDave Bort            }
289d14f6d92d4284ea54520bb29f21411e892ba43edDave Bort            currIndex++;
29088b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        }
29188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        return PhoneNumberUtils.cdmaCheckAndProcessPlusCode(ret.toString());
29288b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    }
29388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
2944f1ab92aac00a73276793ed25af669d112618a32Ying Wang    /*package*/ boolean
29583ee6d790f007beaefcc5f997b15952ed6d7d840Adam Lesinski    compareTo(DriverCall c) {
296a0f464a8e7f006177db084df7e925bbb8e5ffed3Dianne Hackborn        // On mobile originated (MO) calls, the phone number may have changed
29760686586a5f9c8f78b9ad16e19782da85e89a760Ying Wang        // due to a SIM Toolkit call control modification.
2984f1ab92aac00a73276793ed25af669d112618a32Ying Wang        //
29991341e5283661befaf029caec9383e2dba7941baYing Wang        // We assume we know when MO calls are created (since we created them)
30091341e5283661befaf029caec9383e2dba7941baYing Wang        // and therefore don't need to compare the phone number anyway.
30191341e5283661befaf029caec9383e2dba7941baYing Wang        if (! (mIsIncoming || c.isMT)) return true;
30288b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
30388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        // A new call appearing by SRVCC may have invalid number
3043c21fe5b12d95fe374b9b8c874dc4c48b7f9fce1Ying Wang        //  if IMS service is not tightly coupled with cellular modem stack.
30588b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        // Thus we prefer the preexisting handover connection instance.
30688b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        if (isPhoneTypeGsm() && mOrigConnection != null) return true;
30788b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
30888b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        // ... but we can compare phone numbers on MT calls, and we have
30988b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        // no control over when they begin, so we might as well
31017c83cf22c426c628b4b21bc65128a0d80866d31Doug Zongker
31188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        String cAddress = PhoneNumberUtils.stringFromStringAndTOA(c.number, c.TOA);
31288b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        return mIsIncoming == c.isMT && equalsHandlesNulls(mAddress, cAddress);
31388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    }
3143c21fe5b12d95fe374b9b8c874dc4c48b7f9fce1Ying Wang
31588b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    @Override
31688b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    public String getOrigDialString(){
31788b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        return mDialString;
31888b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    }
319700b88e1451f216d137d8a356496bf51712512c6Joe Onorato
320700b88e1451f216d137d8a356496bf51712512c6Joe Onorato    @Override
321700b88e1451f216d137d8a356496bf51712512c6Joe Onorato    public GsmCdmaCall getCall() {
322700b88e1451f216d137d8a356496bf51712512c6Joe Onorato        return mParent;
323700b88e1451f216d137d8a356496bf51712512c6Joe Onorato    }
324700b88e1451f216d137d8a356496bf51712512c6Joe Onorato
325fbd10d940d9dca8aba940f91fceade4098c6cb92Robert Greenwalt    @Override
3263c21fe5b12d95fe374b9b8c874dc4c48b7f9fce1Ying Wang    public long getDisconnectTime() {
3273c21fe5b12d95fe374b9b8c874dc4c48b7f9fce1Ying Wang        return mDisconnectTime;
3283c21fe5b12d95fe374b9b8c874dc4c48b7f9fce1Ying Wang    }
3293c21fe5b12d95fe374b9b8c874dc4c48b7f9fce1Ying Wang
3303c21fe5b12d95fe374b9b8c874dc4c48b7f9fce1Ying Wang    @Override
3313c21fe5b12d95fe374b9b8c874dc4c48b7f9fce1Ying Wang    public long getHoldDurationMillis() {
3323c21fe5b12d95fe374b9b8c874dc4c48b7f9fce1Ying Wang        if (getState() != GsmCdmaCall.State.HOLDING) {
3333c21fe5b12d95fe374b9b8c874dc4c48b7f9fce1Ying Wang            // If not holding, return 0
3343c21fe5b12d95fe374b9b8c874dc4c48b7f9fce1Ying Wang            return 0;
3353c21fe5b12d95fe374b9b8c874dc4c48b7f9fce1Ying Wang        } else {
336fbd10d940d9dca8aba940f91fceade4098c6cb92Robert Greenwalt            return SystemClock.elapsedRealtime() - mHoldingStartTime;
3374b0486b4a6108ea863da6232cc376cd1edc55640Ying Wang        }
3384b0486b4a6108ea863da6232cc376cd1edc55640Ying Wang    }
3394b0486b4a6108ea863da6232cc376cd1edc55640Ying Wang
3404b0486b4a6108ea863da6232cc376cd1edc55640Ying Wang    @Override
3416cdc5d20f346187a9926a7e9a2ccb07efc4ed3ffColin Cross    public GsmCdmaCall.State getState() {
3424b0486b4a6108ea863da6232cc376cd1edc55640Ying Wang        if (mDisconnected) {
34388b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project            return GsmCdmaCall.State.DISCONNECTED;
3443c21fe5b12d95fe374b9b8c874dc4c48b7f9fce1Ying Wang        } else {
34588b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project            return super.getState();
34688b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        }
34788b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    }
34888b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
3493c21fe5b12d95fe374b9b8c874dc4c48b7f9fce1Ying Wang    @Override
3507ace0d60ef59bb5d5ff0b22d51d3a85b626eaa0cJaekyun Seok    public void hangup() throws CallStateException {
35188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        if (!mDisconnected) {
35281ee18670d9c0745aabc2453e049142269504e2dGustav Sennton            mOwner.hangup(this);
35381ee18670d9c0745aabc2453e049142269504e2dGustav Sennton        } else {
3540d23fec792d2bc92417d2b2e716be73704efc240Mike Lockwood            throw new CallStateException ("disconnected");
3550d23fec792d2bc92417d2b2e716be73704efc240Mike Lockwood        }
3560d23fec792d2bc92417d2b2e716be73704efc240Mike Lockwood    }
3570d23fec792d2bc92417d2b2e716be73704efc240Mike Lockwood
3583c21fe5b12d95fe374b9b8c874dc4c48b7f9fce1Ying Wang    @Override
3597ace0d60ef59bb5d5ff0b22d51d3a85b626eaa0cJaekyun Seok    public void separate() throws CallStateException {
3600d23fec792d2bc92417d2b2e716be73704efc240Mike Lockwood        if (!mDisconnected) {
361b31b9bad6697cf81647703332ebd844c743fd241Jaekyun Seok            mOwner.separate(this);
362b31b9bad6697cf81647703332ebd844c743fd241Jaekyun Seok        } else {
363b31b9bad6697cf81647703332ebd844c743fd241Jaekyun Seok            throw new CallStateException ("disconnected");
364b31b9bad6697cf81647703332ebd844c743fd241Jaekyun Seok        }
365b31b9bad6697cf81647703332ebd844c743fd241Jaekyun Seok    }
366b31b9bad6697cf81647703332ebd844c743fd241Jaekyun Seok
367b31b9bad6697cf81647703332ebd844c743fd241Jaekyun Seok    @Override
368b7735d81054002961b681f4bdf296d4de2701135Jaekyun Seok    public void proceedAfterWaitChar() {
369b7735d81054002961b681f4bdf296d4de2701135Jaekyun Seok        if (mPostDialState != PostDialState.WAIT) {
370b7735d81054002961b681f4bdf296d4de2701135Jaekyun Seok            Rlog.w(LOG_TAG, "GsmCdmaConnection.proceedAfterWaitChar(): Expected "
371b7735d81054002961b681f4bdf296d4de2701135Jaekyun Seok                    + "getPostDialState() to be WAIT but was " + mPostDialState);
372b7735d81054002961b681f4bdf296d4de2701135Jaekyun Seok            return;
373b7735d81054002961b681f4bdf296d4de2701135Jaekyun Seok        }
374b7735d81054002961b681f4bdf296d4de2701135Jaekyun Seok
37588b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        setPostDialState(PostDialState.STARTED);
37688b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
3773c21fe5b12d95fe374b9b8c874dc4c48b7f9fce1Ying Wang        processNextPostDialChar();
37888b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    }
37988b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project
38088b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project    @Override
381f926990ba3f04c03037b838cd5fe8f33c21e8013Dima Zavin    public void proceedAfterWildChar(String str) {
382f926990ba3f04c03037b838cd5fe8f33c21e8013Dima Zavin        if (mPostDialState != PostDialState.WILD) {
383f926990ba3f04c03037b838cd5fe8f33c21e8013Dima Zavin            Rlog.w(LOG_TAG, "GsmCdmaConnection.proceedAfterWaitChar(): Expected "
384f926990ba3f04c03037b838cd5fe8f33c21e8013Dima Zavin                + "getPostDialState() to be WILD but was " + mPostDialState);
38517c83cf22c426c628b4b21bc65128a0d80866d31Doug Zongker            return;
38617c83cf22c426c628b4b21bc65128a0d80866d31Doug Zongker        }
38717c83cf22c426c628b4b21bc65128a0d80866d31Doug Zongker
38817c83cf22c426c628b4b21bc65128a0d80866d31Doug Zongker        setPostDialState(PostDialState.STARTED);
38917c83cf22c426c628b4b21bc65128a0d80866d31Doug Zongker
39017c83cf22c426c628b4b21bc65128a0d80866d31Doug Zongker        // make a new postDialString, with the wild char replacement string
39188b607994a148f4af5bffee163e39ce8296750c6The Android Open Source Project        // at the beginning, followed by the remaining postDialString.
3925d4808db1630048f6eb0610b75af01c9fc877412Doug Zongker
3935d4808db1630048f6eb0610b75af01c9fc877412Doug Zongker        StringBuilder buf = new StringBuilder(str);
3948fb5dfc5c716f823b48617fa35a486b2bc696731Brian Carlstrom        buf.append(mPostDialString.substring(mNextPostDialChar));
395e8fb7cf87b8525629efbff823b4a870f8c4d1c5aMathieu Chartier        mPostDialString = buf.toString();
396e8fb7cf87b8525629efbff823b4a870f8c4d1c5aMathieu Chartier        mNextPostDialChar = 0;
39770d617aaf57c636ca7b6aedee5b009a7c46bdd3aYing Wang        if (Phone.DEBUG_PHONE) {
39870d617aaf57c636ca7b6aedee5b009a7c46bdd3aYing Wang            log("proceedAfterWildChar: new postDialString is " +
3995c658ac3a978648e8501a55b0f0eeb004026f1a4Mathieu Chartier                    mPostDialString);
4005c658ac3a978648e8501a55b0f0eeb004026f1a4Mathieu Chartier        }
40170d617aaf57c636ca7b6aedee5b009a7c46bdd3aYing Wang
40270d617aaf57c636ca7b6aedee5b009a7c46bdd3aYing Wang        processNextPostDialChar();
403fcc8d8b26d9ea3a94796aa181d4d4919de259123Mathieu Chartier    }
404fcc8d8b26d9ea3a94796aa181d4d4919de259123Mathieu Chartier
405fcc8d8b26d9ea3a94796aa181d4d4919de259123Mathieu Chartier    @Override
406a61acf62c95adba6b6aeea6fdb4d24fe8ba5fb1aMathieu Chartier    public void cancelPostDial() {
407a61acf62c95adba6b6aeea6fdb4d24fe8ba5fb1aMathieu Chartier        setPostDialState(PostDialState.CANCELLED);
408a61acf62c95adba6b6aeea6fdb4d24fe8ba5fb1aMathieu Chartier    }
409a61acf62c95adba6b6aeea6fdb4d24fe8ba5fb1aMathieu Chartier
410a61acf62c95adba6b6aeea6fdb4d24fe8ba5fb1aMathieu Chartier    /**
411a61acf62c95adba6b6aeea6fdb4d24fe8ba5fb1aMathieu Chartier     * Called when this Connection is being hung up locally (eg, user pressed "end")
4126228ec2d0768ffd25f7e60e70b82d8b5a067e9f9Mathieu Chartier     * Note that at this point, the hangup request has been dispatched to the radio
4136228ec2d0768ffd25f7e60e70b82d8b5a067e9f9Mathieu Chartier     * but no response has yet been received so update() has not yet been called
414f0db908ea755e564a090a6966883bba17b4f1004Mathieu Chartier     */
415f0db908ea755e564a090a6966883bba17b4f1004Mathieu Chartier    void
416cdfe46b5a78b82e095d9f61345196ce9444e1ac6Andreas Gampe    onHangupLocal() {
417cdfe46b5a78b82e095d9f61345196ce9444e1ac6Andreas Gampe        mCause = DisconnectCause.LOCAL;
4186228ec2d0768ffd25f7e60e70b82d8b5a067e9f9Mathieu Chartier        mPreciseCause = 0;
419bb5454b6db5770f0b0275424148b2d7d3c52a56dAndreas Gampe        mVendorCause = null;
42070d617aaf57c636ca7b6aedee5b009a7c46bdd3aYing Wang    }
42170d617aaf57c636ca7b6aedee5b009a7c46bdd3aYing Wang
42270d617aaf57c636ca7b6aedee5b009a7c46bdd3aYing Wang    /**
42370d617aaf57c636ca7b6aedee5b009a7c46bdd3aYing Wang     * Maps RIL call disconnect code to {@link DisconnectCause}.
42470d617aaf57c636ca7b6aedee5b009a7c46bdd3aYing Wang     * @param causeCode RIL disconnect code
42570d617aaf57c636ca7b6aedee5b009a7c46bdd3aYing Wang     * @return the corresponding value from {@link DisconnectCause}
42670d617aaf57c636ca7b6aedee5b009a7c46bdd3aYing Wang     */
42770d617aaf57c636ca7b6aedee5b009a7c46bdd3aYing Wang    int disconnectCauseFromCode(int causeCode) {
42870d617aaf57c636ca7b6aedee5b009a7c46bdd3aYing Wang        /**
42970d617aaf57c636ca7b6aedee5b009a7c46bdd3aYing Wang         * See 22.001 Annex F.4 for mapping of cause codes
43070d617aaf57c636ca7b6aedee5b009a7c46bdd3aYing Wang         * to local tones
43170d617aaf57c636ca7b6aedee5b009a7c46bdd3aYing Wang         */
432bb5454b6db5770f0b0275424148b2d7d3c52a56dAndreas Gampe
433bb5454b6db5770f0b0275424148b2d7d3c52a56dAndreas Gampe        switch (causeCode) {
434bb5454b6db5770f0b0275424148b2d7d3c52a56dAndreas Gampe            case CallFailCause.USER_BUSY:
435bb5454b6db5770f0b0275424148b2d7d3c52a56dAndreas Gampe                return DisconnectCause.BUSY;
436bb5454b6db5770f0b0275424148b2d7d3c52a56dAndreas Gampe
437bb5454b6db5770f0b0275424148b2d7d3c52a56dAndreas Gampe            case CallFailCause.NO_CIRCUIT_AVAIL:
438bb5454b6db5770f0b0275424148b2d7d3c52a56dAndreas Gampe            case CallFailCause.TEMPORARY_FAILURE:
439bb5454b6db5770f0b0275424148b2d7d3c52a56dAndreas Gampe            case CallFailCause.SWITCHING_CONGESTION:
440bb5454b6db5770f0b0275424148b2d7d3c52a56dAndreas Gampe            case CallFailCause.CHANNEL_NOT_AVAIL:
441bb5454b6db5770f0b0275424148b2d7d3c52a56dAndreas Gampe            case CallFailCause.QOS_NOT_AVAIL:
442bb5454b6db5770f0b0275424148b2d7d3c52a56dAndreas Gampe            case CallFailCause.BEARER_NOT_AVAIL:
443bb5454b6db5770f0b0275424148b2d7d3c52a56dAndreas Gampe                return DisconnectCause.CONGESTION;
444bb5454b6db5770f0b0275424148b2d7d3c52a56dAndreas Gampe
445bb5454b6db5770f0b0275424148b2d7d3c52a56dAndreas Gampe            case CallFailCause.ACM_LIMIT_EXCEEDED:
44664594c4f53357a5037cf026387f8b5ab2e24bafeHiroshi Yamauchi                return DisconnectCause.LIMIT_EXCEEDED;
447831fc713f82b90cb3f5864c9412e6e82a4b8d12dAndreas Gampe
448831fc713f82b90cb3f5864c9412e6e82a4b8d12dAndreas Gampe            case CallFailCause.CALL_BARRED:
449831fc713f82b90cb3f5864c9412e6e82a4b8d12dAndreas Gampe                return DisconnectCause.CALL_BARRED;
450831fc713f82b90cb3f5864c9412e6e82a4b8d12dAndreas Gampe
45164594c4f53357a5037cf026387f8b5ab2e24bafeHiroshi Yamauchi            case CallFailCause.FDN_BLOCKED:
45264594c4f53357a5037cf026387f8b5ab2e24bafeHiroshi Yamauchi                return DisconnectCause.FDN_BLOCKED;
45364594c4f53357a5037cf026387f8b5ab2e24bafeHiroshi Yamauchi
4548fe63c3899cbdad9de50a7f1ec8802388c26a82aAlex Deymo            case CallFailCause.IMEI_NOT_ACCEPTED:
4558fe63c3899cbdad9de50a7f1ec8802388c26a82aAlex Deymo                return DisconnectCause.IMEI_NOT_ACCEPTED;
4568fe63c3899cbdad9de50a7f1ec8802388c26a82aAlex Deymo
4578fe63c3899cbdad9de50a7f1ec8802388c26a82aAlex Deymo            case CallFailCause.UNOBTAINABLE_NUMBER:
4581b2242895ea1538b094a54be3100880f92bd2bb2Jaekyun Seok                return DisconnectCause.UNOBTAINABLE_NUMBER;
459ccee95e6ec94196bfca775e526e27276a09856aeJaekyun Seok
460ccee95e6ec94196bfca775e526e27276a09856aeJaekyun Seok            case CallFailCause.DIAL_MODIFIED_TO_USSD:
461ccee95e6ec94196bfca775e526e27276a09856aeJaekyun Seok                return DisconnectCause.DIAL_MODIFIED_TO_USSD;
462ccee95e6ec94196bfca775e526e27276a09856aeJaekyun Seok
4631b2242895ea1538b094a54be3100880f92bd2bb2Jaekyun Seok            case CallFailCause.DIAL_MODIFIED_TO_SS:
4641b2242895ea1538b094a54be3100880f92bd2bb2Jaekyun Seok                return DisconnectCause.DIAL_MODIFIED_TO_SS;
4651b2242895ea1538b094a54be3100880f92bd2bb2Jaekyun Seok
466001c676b81f22bc2b5d690e54324d5b99c53c003Julius D'souza            case CallFailCause.DIAL_MODIFIED_TO_DIAL:
467001c676b81f22bc2b5d690e54324d5b99c53c003Julius D'souza                return DisconnectCause.DIAL_MODIFIED_TO_DIAL;
468001c676b81f22bc2b5d690e54324d5b99c53c003Julius D'souza
469001c676b81f22bc2b5d690e54324d5b99c53c003Julius D'souza            case CallFailCause.CDMA_LOCKED_UNTIL_POWER_CYCLE:
4702e81b3c49f51384beb0e9035ae283f9b0fbc6cacPrzemyslaw Szczepaniak                return DisconnectCause.CDMA_LOCKED_UNTIL_POWER_CYCLE;
4712e81b3c49f51384beb0e9035ae283f9b0fbc6cacPrzemyslaw Szczepaniak
4722e81b3c49f51384beb0e9035ae283f9b0fbc6cacPrzemyslaw Szczepaniak            case CallFailCause.CDMA_DROP:
4732e81b3c49f51384beb0e9035ae283f9b0fbc6cacPrzemyslaw Szczepaniak                return DisconnectCause.CDMA_DROP;
4749a82bfdc68b437d80c0b3802a097a29dc301b22dIvan Lozano
4759a82bfdc68b437d80c0b3802a097a29dc301b22dIvan Lozano            case CallFailCause.CDMA_INTERCEPT:
4769a82bfdc68b437d80c0b3802a097a29dc301b22dIvan Lozano                return DisconnectCause.CDMA_INTERCEPT;
4779a82bfdc68b437d80c0b3802a097a29dc301b22dIvan Lozano
4780bd793815e8c1d7830c6753e399b70d4bfb4a88bDan Willemsen            case CallFailCause.CDMA_REORDER:
4790bd793815e8c1d7830c6753e399b70d4bfb4a88bDan Willemsen                return DisconnectCause.CDMA_REORDER;
4800bd793815e8c1d7830c6753e399b70d4bfb4a88bDan Willemsen
4810bd793815e8c1d7830c6753e399b70d4bfb4a88bDan Willemsen            case CallFailCause.CDMA_SO_REJECT:
4820bd793815e8c1d7830c6753e399b70d4bfb4a88bDan Willemsen                return DisconnectCause.CDMA_SO_REJECT;
4830bd793815e8c1d7830c6753e399b70d4bfb4a88bDan Willemsen
4840bd793815e8c1d7830c6753e399b70d4bfb4a88bDan Willemsen            case CallFailCause.CDMA_RETRY_ORDER:
4850bd793815e8c1d7830c6753e399b70d4bfb4a88bDan Willemsen                return DisconnectCause.CDMA_RETRY_ORDER;
4860bd793815e8c1d7830c6753e399b70d4bfb4a88bDan Willemsen
4870bd793815e8c1d7830c6753e399b70d4bfb4a88bDan Willemsen            case CallFailCause.CDMA_ACCESS_FAILURE:
48823b2d2e5312dbe5b361c848766ba8af62649d2f5Vishwath Mohan                return DisconnectCause.CDMA_ACCESS_FAILURE;
48923b2d2e5312dbe5b361c848766ba8af62649d2f5Vishwath Mohan
49023b2d2e5312dbe5b361c848766ba8af62649d2f5Vishwath Mohan            case CallFailCause.CDMA_PREEMPTED:
49123b2d2e5312dbe5b361c848766ba8af62649d2f5Vishwath Mohan                return DisconnectCause.CDMA_PREEMPTED;
49223b2d2e5312dbe5b361c848766ba8af62649d2f5Vishwath Mohan
49323b2d2e5312dbe5b361c848766ba8af62649d2f5Vishwath Mohan            case CallFailCause.CDMA_NOT_EMERGENCY:
49423b2d2e5312dbe5b361c848766ba8af62649d2f5Vishwath Mohan                return DisconnectCause.CDMA_NOT_EMERGENCY;
49523b2d2e5312dbe5b361c848766ba8af62649d2f5Vishwath Mohan
4961fe28d332e032bb1bce455b92dc0d41beda43e57Jeff Gaston            case CallFailCause.CDMA_ACCESS_BLOCKED:
4971fe28d332e032bb1bce455b92dc0d41beda43e57Jeff Gaston                return DisconnectCause.CDMA_ACCESS_BLOCKED;
498ea55e8c86c4d995752c3d648e8bdc7fb62de492bAlexey Polyudov
4991fe28d332e032bb1bce455b92dc0d41beda43e57Jeff Gaston            case CallFailCause.ERROR_UNSPECIFIED:
5000538ff796f1d17c084bc0b54cb2177faacda8919Jaekyun Seok            case CallFailCause.NORMAL_CLEARING:
5010538ff796f1d17c084bc0b54cb2177faacda8919Jaekyun Seok            default:
5020538ff796f1d17c084bc0b54cb2177faacda8919Jaekyun Seok                GsmCdmaPhone phone = mOwner.getPhone();
5030538ff796f1d17c084bc0b54cb2177faacda8919Jaekyun Seok                int serviceState = phone.getServiceState().getState();
5040538ff796f1d17c084bc0b54cb2177faacda8919Jaekyun Seok                UiccCardApplication cardApp = phone.getUiccCardApplication();
5050538ff796f1d17c084bc0b54cb2177faacda8919Jaekyun Seok                AppState uiccAppState = (cardApp != null) ? cardApp.getState() :
5060538ff796f1d17c084bc0b54cb2177faacda8919Jaekyun Seok                        AppState.APPSTATE_UNKNOWN;
5070538ff796f1d17c084bc0b54cb2177faacda8919Jaekyun Seok                if (serviceState == ServiceState.STATE_POWER_OFF) {
508                    return DisconnectCause.POWER_OFF;
509                }
510                if (!mIsEmergencyCall) {
511                    // Only send OUT_OF_SERVICE if it is not an emergency call. We can still
512                    // technically be in STATE_OUT_OF_SERVICE or STATE_EMERGENCY_ONLY during
513                    // an emergency call and when it ends, we do not want to mistakenly generate
514                    // an OUT_OF_SERVICE disconnect cause during normal call ending.
515                    if ((serviceState == ServiceState.STATE_OUT_OF_SERVICE
516                            || serviceState == ServiceState.STATE_EMERGENCY_ONLY)) {
517                        return DisconnectCause.OUT_OF_SERVICE;
518                    }
519                    // If we are placing an emergency call and the SIM is currently PIN/PUK
520                    // locked the AppState will always not be equal to APPSTATE_READY.
521                    if (uiccAppState != AppState.APPSTATE_READY) {
522                        if (isPhoneTypeGsm()) {
523                            return DisconnectCause.ICC_ERROR;
524                        } else { // CDMA
525                            if (phone.mCdmaSubscriptionSource ==
526                                    CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_RUIM) {
527                                return DisconnectCause.ICC_ERROR;
528                            }
529                        }
530                    }
531                }
532                if (isPhoneTypeGsm()) {
533                    if (causeCode == CallFailCause.ERROR_UNSPECIFIED) {
534                        if (phone.mSST.mRestrictedState.isCsRestricted()) {
535                            return DisconnectCause.CS_RESTRICTED;
536                        } else if (phone.mSST.mRestrictedState.isCsEmergencyRestricted()) {
537                            return DisconnectCause.CS_RESTRICTED_EMERGENCY;
538                        } else if (phone.mSST.mRestrictedState.isCsNormalRestricted()) {
539                            return DisconnectCause.CS_RESTRICTED_NORMAL;
540                        }
541                    }
542                }
543                if (causeCode == CallFailCause.NORMAL_CLEARING) {
544                    return DisconnectCause.NORMAL;
545                }
546                // If nothing else matches, report unknown call drop reason
547                // to app, not NORMAL call end.
548                return DisconnectCause.ERROR_UNSPECIFIED;
549        }
550    }
551
552    /*package*/ void
553    onRemoteDisconnect(int causeCode, String vendorCause) {
554        this.mPreciseCause = causeCode;
555        this.mVendorCause = vendorCause;
556        onDisconnect(disconnectCauseFromCode(causeCode));
557    }
558
559    /**
560     * Called when the radio indicates the connection has been disconnected.
561     * @param cause call disconnect cause; values are defined in {@link DisconnectCause}
562     */
563    @Override
564    public boolean onDisconnect(int cause) {
565        boolean changed = false;
566
567        mCause = cause;
568
569        if (!mDisconnected) {
570            doDisconnect();
571
572            if (DBG) Rlog.d(LOG_TAG, "onDisconnect: cause=" + cause);
573
574            mOwner.getPhone().notifyDisconnect(this);
575
576            if (mParent != null) {
577                changed = mParent.connectionDisconnected(this);
578            }
579
580            mOrigConnection = null;
581        }
582        clearPostDialListeners();
583        releaseWakeLock();
584        return changed;
585    }
586
587    //CDMA
588    /** Called when the call waiting connection has been hung up */
589    /*package*/ void
590    onLocalDisconnect() {
591        if (!mDisconnected) {
592            doDisconnect();
593            if (VDBG) Rlog.d(LOG_TAG, "onLoalDisconnect" );
594
595            if (mParent != null) {
596                mParent.detach(this);
597            }
598        }
599        releaseWakeLock();
600    }
601
602    // Returns true if state has changed, false if nothing changed
603    public boolean
604    update (DriverCall dc) {
605        GsmCdmaCall newParent;
606        boolean changed = false;
607        boolean wasConnectingInOrOut = isConnectingInOrOut();
608        boolean wasHolding = (getState() == GsmCdmaCall.State.HOLDING);
609
610        newParent = parentFromDCState(dc.state);
611
612        if (Phone.DEBUG_PHONE) log("parent= " +mParent +", newParent= " + newParent);
613
614        //Ignore dc.number and dc.name in case of a handover connection
615        if (isPhoneTypeGsm() && mOrigConnection != null) {
616            if (Phone.DEBUG_PHONE) log("update: mOrigConnection is not null");
617        } else {
618            log(" mNumberConverted " + mNumberConverted);
619            if (!equalsBaseDialString(mAddress, dc.number) && (!mNumberConverted
620                    || !equalsBaseDialString(mConvertedNumber, dc.number))) {
621                if (Phone.DEBUG_PHONE) log("update: phone # changed!");
622                mAddress = dc.number;
623                changed = true;
624            }
625        }
626
627        // A null cnapName should be the same as ""
628        if (TextUtils.isEmpty(dc.name)) {
629            if (!TextUtils.isEmpty(mCnapName)) {
630                changed = true;
631                mCnapName = "";
632            }
633        } else if (!dc.name.equals(mCnapName)) {
634            changed = true;
635            mCnapName = dc.name;
636        }
637
638        if (Phone.DEBUG_PHONE) log("--dssds----"+mCnapName);
639        mCnapNamePresentation = dc.namePresentation;
640        mNumberPresentation = dc.numberPresentation;
641
642        if (newParent != mParent) {
643            if (mParent != null) {
644                mParent.detach(this);
645            }
646            newParent.attach(this, dc);
647            mParent = newParent;
648            changed = true;
649        } else {
650            boolean parentStateChange;
651            parentStateChange = mParent.update (this, dc);
652            changed = changed || parentStateChange;
653        }
654
655        /** Some state-transition events */
656
657        if (Phone.DEBUG_PHONE) log(
658                "update: parent=" + mParent +
659                ", hasNewParent=" + (newParent != mParent) +
660                ", wasConnectingInOrOut=" + wasConnectingInOrOut +
661                ", wasHolding=" + wasHolding +
662                ", isConnectingInOrOut=" + isConnectingInOrOut() +
663                ", changed=" + changed);
664
665
666        if (wasConnectingInOrOut && !isConnectingInOrOut()) {
667            onConnectedInOrOut();
668        }
669
670        if (changed && !wasHolding && (getState() == GsmCdmaCall.State.HOLDING)) {
671            // We've transitioned into HOLDING
672            onStartedHolding();
673        }
674
675        return changed;
676    }
677
678    /**
679     * Called when this Connection is in the foregroundCall
680     * when a dial is initiated.
681     * We know we're ACTIVE, and we know we're going to end up
682     * HOLDING in the backgroundCall
683     */
684    void
685    fakeHoldBeforeDial() {
686        if (mParent != null) {
687            mParent.detach(this);
688        }
689
690        mParent = mOwner.mBackgroundCall;
691        mParent.attachFake(this, GsmCdmaCall.State.HOLDING);
692
693        onStartedHolding();
694    }
695
696    /*package*/ int
697    getGsmCdmaIndex() throws CallStateException {
698        if (mIndex >= 0) {
699            return mIndex + 1;
700        } else {
701            throw new CallStateException ("GsmCdma index not yet assigned");
702        }
703    }
704
705    /**
706     * An incoming or outgoing call has connected
707     */
708    void
709    onConnectedInOrOut() {
710        mConnectTime = System.currentTimeMillis();
711        mConnectTimeReal = SystemClock.elapsedRealtime();
712        mDuration = 0;
713
714        // bug #678474: incoming call interpreted as missed call, even though
715        // it sounds like the user has picked up the call.
716        if (Phone.DEBUG_PHONE) {
717            log("onConnectedInOrOut: connectTime=" + mConnectTime);
718        }
719
720        if (!mIsIncoming) {
721            // outgoing calls only
722            processNextPostDialChar();
723        } else {
724            // Only release wake lock for incoming calls, for outgoing calls the wake lock
725            // will be released after any pause-dial is completed
726            releaseWakeLock();
727        }
728    }
729
730    private void
731    doDisconnect() {
732        mIndex = -1;
733        mDisconnectTime = System.currentTimeMillis();
734        mDuration = SystemClock.elapsedRealtime() - mConnectTimeReal;
735        mDisconnected = true;
736        clearPostDialListeners();
737    }
738
739    /*package*/ void
740    onStartedHolding() {
741        mHoldingStartTime = SystemClock.elapsedRealtime();
742    }
743
744    /**
745     * Performs the appropriate action for a post-dial char, but does not
746     * notify application. returns false if the character is invalid and
747     * should be ignored
748     */
749    private boolean
750    processPostDialChar(char c) {
751        if (PhoneNumberUtils.is12Key(c)) {
752            mOwner.mCi.sendDtmf(c, mHandler.obtainMessage(EVENT_DTMF_DONE));
753        } else if (isPause(c)) {
754            if (!isPhoneTypeGsm()) {
755                setPostDialState(PostDialState.PAUSE);
756            }
757            // From TS 22.101:
758            // It continues...
759            // Upon the called party answering the UE shall send the DTMF digits
760            // automatically to the network after a delay of 3 seconds( 20 ).
761            // The digits shall be sent according to the procedures and timing
762            // specified in 3GPP TS 24.008 [13]. The first occurrence of the
763            // "DTMF Control Digits Separator" shall be used by the ME to
764            // distinguish between the addressing digits (i.e. the phone number)
765            // and the DTMF digits. Upon subsequent occurrences of the
766            // separator,
767            // the UE shall pause again for 3 seconds ( 20 ) before sending
768            // any further DTMF digits.
769            mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_PAUSE_DONE),
770                    isPhoneTypeGsm() ? PAUSE_DELAY_MILLIS_GSM: PAUSE_DELAY_MILLIS_CDMA);
771        } else if (isWait(c)) {
772            setPostDialState(PostDialState.WAIT);
773        } else if (isWild(c)) {
774            setPostDialState(PostDialState.WILD);
775        } else {
776            return false;
777        }
778
779        return true;
780    }
781
782    @Override
783    public String
784    getRemainingPostDialString() {
785        String subStr = super.getRemainingPostDialString();
786        if (!isPhoneTypeGsm() && !TextUtils.isEmpty(subStr)) {
787            int wIndex = subStr.indexOf(PhoneNumberUtils.WAIT);
788            int pIndex = subStr.indexOf(PhoneNumberUtils.PAUSE);
789
790            if (wIndex > 0 && (wIndex < pIndex || pIndex <= 0)) {
791                subStr = subStr.substring(0, wIndex);
792            } else if (pIndex > 0) {
793                subStr = subStr.substring(0, pIndex);
794            }
795        }
796        return subStr;
797    }
798
799    //CDMA
800    public void updateParent(GsmCdmaCall oldParent, GsmCdmaCall newParent){
801        if (newParent != oldParent) {
802            if (oldParent != null) {
803                oldParent.detach(this);
804            }
805            newParent.attachFake(this, GsmCdmaCall.State.ACTIVE);
806            mParent = newParent;
807        }
808    }
809
810    @Override
811    protected void finalize()
812    {
813        /**
814         * It is understood that This finializer is not guaranteed
815         * to be called and the release lock call is here just in
816         * case there is some path that doesn't call onDisconnect
817         * and or onConnectedInOrOut.
818         */
819        if (mPartialWakeLock.isHeld()) {
820            Rlog.e(LOG_TAG, "[GsmCdmaConn] UNEXPECTED; mPartialWakeLock is held when finalizing.");
821        }
822        clearPostDialListeners();
823        releaseWakeLock();
824    }
825
826    private void
827    processNextPostDialChar() {
828        char c = 0;
829        Registrant postDialHandler;
830
831        if (mPostDialState == PostDialState.CANCELLED) {
832            releaseWakeLock();
833            return;
834        }
835
836        if (mPostDialString == null ||
837                mPostDialString.length() <= mNextPostDialChar) {
838            setPostDialState(PostDialState.COMPLETE);
839
840            // We were holding a wake lock until pause-dial was complete, so give it up now
841            releaseWakeLock();
842
843            // notifyMessage.arg1 is 0 on complete
844            c = 0;
845        } else {
846            boolean isValid;
847
848            setPostDialState(PostDialState.STARTED);
849
850            c = mPostDialString.charAt(mNextPostDialChar++);
851
852            isValid = processPostDialChar(c);
853
854            if (!isValid) {
855                // Will call processNextPostDialChar
856                mHandler.obtainMessage(EVENT_NEXT_POST_DIAL).sendToTarget();
857                // Don't notify application
858                Rlog.e(LOG_TAG, "processNextPostDialChar: c=" + c + " isn't valid!");
859                return;
860            }
861        }
862
863        notifyPostDialListenersNextChar(c);
864
865        // TODO: remove the following code since the handler no longer executes anything.
866        postDialHandler = mOwner.getPhone().getPostDialHandler();
867
868        Message notifyMessage;
869
870        if (postDialHandler != null
871                && (notifyMessage = postDialHandler.messageForRegistrant()) != null) {
872            // The AsyncResult.result is the Connection object
873            PostDialState state = mPostDialState;
874            AsyncResult ar = AsyncResult.forMessage(notifyMessage);
875            ar.result = this;
876            ar.userObj = state;
877
878            // arg1 is the character that was/is being processed
879            notifyMessage.arg1 = c;
880
881            //Rlog.v("GsmCdma", "##### processNextPostDialChar: send msg to postDialHandler, arg1=" + c);
882            notifyMessage.sendToTarget();
883        }
884    }
885
886    /** "connecting" means "has never been ACTIVE" for both incoming
887     *  and outgoing calls
888     */
889    private boolean
890    isConnectingInOrOut() {
891        return mParent == null || mParent == mOwner.mRingingCall
892            || mParent.mState == GsmCdmaCall.State.DIALING
893            || mParent.mState == GsmCdmaCall.State.ALERTING;
894    }
895
896    private GsmCdmaCall
897    parentFromDCState (DriverCall.State state) {
898        switch (state) {
899            case ACTIVE:
900            case DIALING:
901            case ALERTING:
902                return mOwner.mForegroundCall;
903            //break;
904
905            case HOLDING:
906                return mOwner.mBackgroundCall;
907            //break;
908
909            case INCOMING:
910            case WAITING:
911                return mOwner.mRingingCall;
912            //break;
913
914            default:
915                throw new RuntimeException("illegal call state: " + state);
916        }
917    }
918
919    /**
920     * Set post dial state and acquire wake lock while switching to "started" or "pause"
921     * state, the wake lock will be released if state switches out of "started" or "pause"
922     * state or after WAKE_LOCK_TIMEOUT_MILLIS.
923     * @param s new PostDialState
924     */
925    private void setPostDialState(PostDialState s) {
926        if (s == PostDialState.STARTED ||
927                s == PostDialState.PAUSE) {
928            synchronized (mPartialWakeLock) {
929                if (mPartialWakeLock.isHeld()) {
930                    mHandler.removeMessages(EVENT_WAKE_LOCK_TIMEOUT);
931                } else {
932                    acquireWakeLock();
933                }
934                Message msg = mHandler.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT);
935                mHandler.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT_MILLIS);
936            }
937        } else {
938            mHandler.removeMessages(EVENT_WAKE_LOCK_TIMEOUT);
939            releaseWakeLock();
940        }
941        mPostDialState = s;
942        notifyPostDialListeners();
943    }
944
945    private void
946    createWakeLock(Context context) {
947        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
948        mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
949    }
950
951    private void
952    acquireWakeLock() {
953        log("acquireWakeLock");
954        mPartialWakeLock.acquire();
955    }
956
957    private void
958    releaseWakeLock() {
959        synchronized(mPartialWakeLock) {
960            if (mPartialWakeLock.isHeld()) {
961                log("releaseWakeLock");
962                mPartialWakeLock.release();
963            }
964        }
965    }
966
967    private void
968    releaseAllWakeLocks() {
969        synchronized(mPartialWakeLock) {
970            while (mPartialWakeLock.isHeld()) {
971                mPartialWakeLock.release();
972            }
973        }
974    }
975
976    private static boolean isPause(char c) {
977        return c == PhoneNumberUtils.PAUSE;
978    }
979
980    private static boolean isWait(char c) {
981        return c == PhoneNumberUtils.WAIT;
982    }
983
984    private static boolean isWild(char c) {
985        return c == PhoneNumberUtils.WILD;
986    }
987
988    //CDMA
989    // This function is to find the next PAUSE character index if
990    // multiple pauses in a row. Otherwise it finds the next non PAUSE or
991    // non WAIT character index.
992    private static int
993    findNextPCharOrNonPOrNonWCharIndex(String phoneNumber, int currIndex) {
994        boolean wMatched = isWait(phoneNumber.charAt(currIndex));
995        int index = currIndex + 1;
996        int length = phoneNumber.length();
997        while (index < length) {
998            char cNext = phoneNumber.charAt(index);
999            // if there is any W inside P/W sequence,mark it
1000            if (isWait(cNext)) {
1001                wMatched = true;
1002            }
1003            // if any characters other than P/W chars after P/W sequence
1004            // we break out the loop and append the correct
1005            if (!isWait(cNext) && !isPause(cNext)) {
1006                break;
1007            }
1008            index++;
1009        }
1010
1011        // It means the PAUSE character(s) is in the middle of dial string
1012        // and it needs to be handled one by one.
1013        if ((index < length) && (index > (currIndex + 1))  &&
1014                ((wMatched == false) && isPause(phoneNumber.charAt(currIndex)))) {
1015            return (currIndex + 1);
1016        }
1017        return index;
1018    }
1019
1020    //CDMA
1021    // This function returns either PAUSE or WAIT character to append.
1022    // It is based on the next non PAUSE/WAIT character in the phoneNumber and the
1023    // index for the current PAUSE/WAIT character
1024    private static char
1025    findPOrWCharToAppend(String phoneNumber, int currPwIndex, int nextNonPwCharIndex) {
1026        char c = phoneNumber.charAt(currPwIndex);
1027        char ret;
1028
1029        // Append the PW char
1030        ret = (isPause(c)) ? PhoneNumberUtils.PAUSE : PhoneNumberUtils.WAIT;
1031
1032        // If the nextNonPwCharIndex is greater than currPwIndex + 1,
1033        // it means the PW sequence contains not only P characters.
1034        // Since for the sequence that only contains P character,
1035        // the P character is handled one by one, the nextNonPwCharIndex
1036        // equals to currPwIndex + 1.
1037        // In this case, skip P, append W.
1038        if (nextNonPwCharIndex > (currPwIndex + 1)) {
1039            ret = PhoneNumberUtils.WAIT;
1040        }
1041        return ret;
1042    }
1043
1044    private String maskDialString(String dialString) {
1045        if (VDBG) {
1046            return dialString;
1047        }
1048
1049        return "<MASKED>";
1050    }
1051
1052    private void fetchDtmfToneDelay(GsmCdmaPhone phone) {
1053        CarrierConfigManager configMgr = (CarrierConfigManager)
1054                phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
1055        PersistableBundle b = configMgr.getConfigForSubId(phone.getSubId());
1056        if (b != null) {
1057            mDtmfToneDelay = b.getInt(phone.getDtmfToneDelayKey());
1058        }
1059    }
1060
1061    private boolean isPhoneTypeGsm() {
1062        return mOwner.getPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_GSM;
1063    }
1064
1065    private void log(String msg) {
1066        Rlog.d(LOG_TAG, "[GsmCdmaConn] " + msg);
1067    }
1068
1069    @Override
1070    public int getNumberPresentation() {
1071        return mNumberPresentation;
1072    }
1073
1074    @Override
1075    public UUSInfo getUUSInfo() {
1076        return mUusInfo;
1077    }
1078
1079    public int getPreciseDisconnectCause() {
1080        return mPreciseCause;
1081    }
1082
1083    @Override
1084    public String getVendorDisconnectCause() {
1085        return mVendorCause;
1086    }
1087
1088    @Override
1089    public void migrateFrom(Connection c) {
1090        if (c == null) return;
1091
1092        super.migrateFrom(c);
1093
1094        this.mUusInfo = c.getUUSInfo();
1095
1096        this.setUserData(c.getUserData());
1097    }
1098
1099    @Override
1100    public Connection getOrigConnection() {
1101        return mOrigConnection;
1102    }
1103
1104    @Override
1105    public boolean isMultiparty() {
1106        if (mOrigConnection != null) {
1107            return mOrigConnection.isMultiparty();
1108        }
1109
1110        return false;
1111    }
1112}
1113