Revert "Revert "Move SIP telephony related codes to framework.""

This reverts commit cde66df44240cfe5a7bec12ac52464c3bf26c14f.

Change-Id: I87da883b45350ec8f7da71e9bd392b075ea30ca7
diff --git a/telephony/java/com/android/internal/telephony/SipPhoneNotifier.java b/telephony/java/com/android/internal/telephony/SipPhoneNotifier.java
new file mode 100644
index 0000000..81e151e
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/SipPhoneNotifier.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import com.android.internal.telephony.ITelephonyRegistry;
+
+/**
+ * Temporary. Will be removed after integrating with CallManager.
+ * 100% copy from DefaultPhoneNotifier. Cannot access its package level
+ * constructor; thus the copy.
+ * @hide
+ */
+public class SipPhoneNotifier implements PhoneNotifier {
+
+    static final String LOG_TAG = "GSM";
+    private static final boolean DBG = true;
+    private ITelephonyRegistry mRegistry;
+
+    public SipPhoneNotifier() {
+        mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
+                    "telephony.registry"));
+    }
+
+    public void notifyPhoneState(Phone sender) {
+        Call ringingCall = sender.getRingingCall();
+        String incomingNumber = "";
+        if (ringingCall != null && ringingCall.getEarliestConnection() != null){
+            incomingNumber = ringingCall.getEarliestConnection().getAddress();
+        }
+        try {
+            mRegistry.notifyCallState(convertCallState(sender.getState()), incomingNumber);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    public void notifyServiceState(Phone sender) {
+        try {
+            mRegistry.notifyServiceState(sender.getServiceState());
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    public void notifySignalStrength(Phone sender) {
+        try {
+            mRegistry.notifySignalStrength(sender.getSignalStrength());
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    public void notifyMessageWaitingChanged(Phone sender) {
+        try {
+            mRegistry.notifyMessageWaitingChanged(sender.getMessageWaitingIndicator());
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    public void notifyCallForwardingChanged(Phone sender) {
+        try {
+            mRegistry.notifyCallForwardingChanged(sender.getCallForwardingIndicator());
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    public void notifyDataActivity(Phone sender) {
+        try {
+            mRegistry.notifyDataActivity(convertDataActivityState(sender.getDataActivityState()));
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    public void notifyDataConnection(Phone sender, String reason) {
+        TelephonyManager telephony = TelephonyManager.getDefault();
+        try {
+            mRegistry.notifyDataConnection(
+                    convertDataState(sender.getDataConnectionState()),
+                    sender.isDataConnectivityPossible(), reason,
+                    sender.getActiveApn(),
+                    sender.getActiveApnTypes(),
+                    sender.getInterfaceName(null),
+                    ((telephony!=null) ? telephony.getNetworkType() :
+                    TelephonyManager.NETWORK_TYPE_UNKNOWN));
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    public void notifyDataConnectionFailed(Phone sender, String reason) {
+        try {
+            mRegistry.notifyDataConnectionFailed(reason);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    public void notifyCellLocation(Phone sender) {
+        Bundle data = new Bundle();
+        sender.getCellLocation().fillInNotifierBundle(data);
+        try {
+            mRegistry.notifyCellLocation(data);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    private void log(String s) {
+        Log.d(LOG_TAG, "[PhoneNotifier] " + s);
+    }
+
+    /**
+     * Convert the {@link State} enum into the TelephonyManager.CALL_STATE_* constants
+     * for the public API.
+     */
+    public static int convertCallState(Phone.State state) {
+        switch (state) {
+            case RINGING:
+                return TelephonyManager.CALL_STATE_RINGING;
+            case OFFHOOK:
+                return TelephonyManager.CALL_STATE_OFFHOOK;
+            default:
+                return TelephonyManager.CALL_STATE_IDLE;
+        }
+    }
+
+    /**
+     * Convert the TelephonyManager.CALL_STATE_* constants into the {@link State} enum
+     * for the public API.
+     */
+    public static Phone.State convertCallState(int state) {
+        switch (state) {
+            case TelephonyManager.CALL_STATE_RINGING:
+                return Phone.State.RINGING;
+            case TelephonyManager.CALL_STATE_OFFHOOK:
+                return Phone.State.OFFHOOK;
+            default:
+                return Phone.State.IDLE;
+        }
+    }
+
+    /**
+     * Convert the {@link DataState} enum into the TelephonyManager.DATA_* constants
+     * for the public API.
+     */
+    public static int convertDataState(Phone.DataState state) {
+        switch (state) {
+            case CONNECTING:
+                return TelephonyManager.DATA_CONNECTING;
+            case CONNECTED:
+                return TelephonyManager.DATA_CONNECTED;
+            case SUSPENDED:
+                return TelephonyManager.DATA_SUSPENDED;
+            default:
+                return TelephonyManager.DATA_DISCONNECTED;
+        }
+    }
+
+    /**
+     * Convert the TelephonyManager.DATA_* constants into {@link DataState} enum
+     * for the public API.
+     */
+    public static Phone.DataState convertDataState(int state) {
+        switch (state) {
+            case TelephonyManager.DATA_CONNECTING:
+                return Phone.DataState.CONNECTING;
+            case TelephonyManager.DATA_CONNECTED:
+                return Phone.DataState.CONNECTED;
+            case TelephonyManager.DATA_SUSPENDED:
+                return Phone.DataState.SUSPENDED;
+            default:
+                return Phone.DataState.DISCONNECTED;
+        }
+    }
+
+    /**
+     * Convert the {@link DataState} enum into the TelephonyManager.DATA_* constants
+     * for the public API.
+     */
+    public static int convertDataActivityState(Phone.DataActivityState state) {
+        switch (state) {
+            case DATAIN:
+                return TelephonyManager.DATA_ACTIVITY_IN;
+            case DATAOUT:
+                return TelephonyManager.DATA_ACTIVITY_OUT;
+            case DATAINANDOUT:
+                return TelephonyManager.DATA_ACTIVITY_INOUT;
+            case DORMANT:
+                return TelephonyManager.DATA_ACTIVITY_DORMANT;
+            default:
+                return TelephonyManager.DATA_ACTIVITY_NONE;
+        }
+    }
+
+    /**
+     * Convert the TelephonyManager.DATA_* constants into the {@link DataState} enum
+     * for the public API.
+     */
+    public static Phone.DataActivityState convertDataActivityState(int state) {
+        switch (state) {
+            case TelephonyManager.DATA_ACTIVITY_IN:
+                return Phone.DataActivityState.DATAIN;
+            case TelephonyManager.DATA_ACTIVITY_OUT:
+                return Phone.DataActivityState.DATAOUT;
+            case TelephonyManager.DATA_ACTIVITY_INOUT:
+                return Phone.DataActivityState.DATAINANDOUT;
+            case TelephonyManager.DATA_ACTIVITY_DORMANT:
+                return Phone.DataActivityState.DORMANT;
+            default:
+                return Phone.DataActivityState.NONE;
+        }
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/CallFailCause.java b/telephony/java/com/android/internal/telephony/sip/CallFailCause.java
new file mode 100644
index 0000000..58fb408
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/CallFailCause.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.sip;
+
+/**
+ * Call fail causes from TS 24.008 .
+ * These are mostly the cause codes we need to distinguish for the UI.
+ * See 22.001 Annex F.4 for mapping of cause codes to local tones.
+ *
+ * {@hide}
+ *
+ */
+public interface CallFailCause {
+    static final int NORMAL_CLEARING     = 16;
+    // Busy Tone
+    static final int USER_BUSY           = 17;
+
+    // No Tone
+    static final int NUMBER_CHANGED      = 22;
+    static final int STATUS_ENQUIRY      = 30;
+    static final int NORMAL_UNSPECIFIED  = 31;
+
+    // Congestion Tone
+    static final int NO_CIRCUIT_AVAIL    = 34;
+    static final int TEMPORARY_FAILURE   = 41;
+    static final int SWITCHING_CONGESTION    = 42;
+    static final int CHANNEL_NOT_AVAIL   = 44;
+    static final int QOS_NOT_AVAIL       = 49;
+    static final int BEARER_NOT_AVAIL    = 58;
+
+    // others
+    static final int ACM_LIMIT_EXCEEDED = 68;
+    static final int CALL_BARRED        = 240;
+    static final int FDN_BLOCKED        = 241;
+    static final int ERROR_UNSPECIFIED = 0xffff;
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/CallProxy.java b/telephony/java/com/android/internal/telephony/sip/CallProxy.java
new file mode 100644
index 0000000..fad9663
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/CallProxy.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.sip;
+
+import com.android.internal.telephony.*;
+import java.util.List;
+
+// TODO: remove this class after integrating with CallManager
+class CallProxy extends Call {
+    private Call mTarget;
+
+    void setTarget(Call target) {
+        mTarget = target;
+    }
+
+    @Override
+    public List<Connection> getConnections() {
+        return mTarget.getConnections();
+    }
+
+    @Override
+    public Phone getPhone() {
+        return mTarget.getPhone();
+    }
+
+    @Override
+    public boolean isMultiparty() {
+        return mTarget.isMultiparty();
+    }
+
+    @Override
+    public void hangup() throws CallStateException {
+        mTarget.hangup();
+    }
+
+    @Override
+    public boolean hasConnection(Connection c) {
+        return mTarget.hasConnection(c);
+    }
+
+    @Override
+    public boolean hasConnections() {
+        return mTarget.hasConnections();
+    }
+
+    @Override
+    public State getState() {
+        return mTarget.getState();
+    }
+
+    @Override
+    public boolean isIdle() {
+        return mTarget.isIdle();
+    }
+
+    @Override
+    public Connection getEarliestConnection() {
+        return mTarget.getEarliestConnection();
+    }
+
+    @Override
+    public long getEarliestCreateTime() {
+        return mTarget.getEarliestCreateTime();
+    }
+
+    @Override
+    public long getEarliestConnectTime() {
+        return mTarget.getEarliestConnectTime();
+    }
+
+    @Override
+    public boolean isDialingOrAlerting() {
+        return mTarget.isDialingOrAlerting();
+    }
+
+    @Override
+    public boolean isRinging() {
+        return mTarget.isRinging();
+    }
+
+    @Override
+    public Connection getLatestConnection() {
+        return mTarget.getLatestConnection();
+    }
+
+    @Override
+    public boolean isGeneric() {
+        return mTarget.isGeneric();
+    }
+
+    @Override
+    public void setGeneric(boolean generic) {
+        mTarget.setGeneric(generic);
+    }
+
+    @Override
+    public void hangupIfAlive() {
+        mTarget.hangupIfAlive();
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipCallBase.java b/telephony/java/com/android/internal/telephony/sip/SipCallBase.java
new file mode 100644
index 0000000..e7eda4f
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/SipCallBase.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.sip;
+
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.CallStateException;
+import com.android.internal.telephony.Connection;
+import com.android.internal.telephony.DriverCall;
+import com.android.internal.telephony.Phone;
+
+import android.net.sip.SipManager;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.sip.SipException;
+
+abstract class SipCallBase extends Call {
+    private static final int MAX_CONNECTIONS_PER_CALL = 5;
+
+    protected List<Connection> connections = new ArrayList<Connection>();
+
+    protected abstract void setState(State newState);
+
+    public void dispose() {
+    }
+
+    public List<Connection> getConnections() {
+        // FIXME should return Collections.unmodifiableList();
+        return connections;
+    }
+
+    public boolean isMultiparty() {
+        return connections.size() > 1;
+    }
+
+    public String toString() {
+        return state.toString();
+    }
+
+    /**
+     * Called by SipConnection when it has disconnected
+     */
+    void connectionDisconnected(Connection conn) {
+        if (state != State.DISCONNECTED) {
+            /* If only disconnected connections remain, we are disconnected*/
+
+            boolean hasOnlyDisconnectedConnections = true;
+
+            for (int i = 0, s = connections.size()  ; i < s; i ++) {
+                if (connections.get(i).getState()
+                    != State.DISCONNECTED
+                ) {
+                    hasOnlyDisconnectedConnections = false;
+                    break;
+                }
+            }
+
+            if (hasOnlyDisconnectedConnections) {
+                state = State.DISCONNECTED;
+            }
+        }
+    }
+
+
+    /*package*/ void detach(Connection conn) {
+        connections.remove(conn);
+
+        if (connections.size() == 0) {
+            state = State.IDLE;
+        }
+    }
+
+    /**
+     * @return true if there's no space in this call for additional
+     * connections to be added via "conference"
+     */
+    /*package*/ boolean isFull() {
+        return connections.size() == MAX_CONNECTIONS_PER_CALL;
+    }
+
+    void clearDisconnected() {
+        for (Iterator<Connection> it = connections.iterator(); it.hasNext(); ) {
+            Connection c = it.next();
+            if (c.getState() == State.DISCONNECTED) it.remove();
+        }
+
+        if (connections.isEmpty()) setState(State.IDLE);
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
new file mode 100644
index 0000000..33c89f8
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.sip;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+
+import com.android.internal.telephony.BaseCommands;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.UUSInfo;
+import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
+
+/**
+ * SIP doesn't need CommandsInterface. The class does nothing but made to work
+ * with PhoneBase's constructor.
+ */
+class SipCommandInterface extends BaseCommands implements CommandsInterface {
+    SipCommandInterface(Context context) {
+        super(context);
+    }
+
+    @Override public void setOnNITZTime(Handler h, int what, Object obj) {
+    }
+
+    public void getIccCardStatus(Message result) {
+    }
+
+    public void supplyIccPin(String pin, Message result) {
+    }
+
+    public void supplyIccPuk(String puk, String newPin, Message result) {
+    }
+
+    public void supplyIccPin2(String pin, Message result) {
+    }
+
+    public void supplyIccPuk2(String puk, String newPin2, Message result) {
+    }
+
+    public void changeIccPin(String oldPin, String newPin, Message result) {
+    }
+
+    public void changeIccPin2(String oldPin2, String newPin2, Message result) {
+    }
+
+    public void changeBarringPassword(String facility, String oldPwd,
+            String newPwd, Message result) {
+    }
+
+    public void supplyNetworkDepersonalization(String netpin, Message result) {
+    }
+
+    public void getCurrentCalls(Message result) {
+    }
+
+    @Deprecated public void getPDPContextList(Message result) {
+    }
+
+    public void getDataCallList(Message result) {
+    }
+
+    public void dial(String address, int clirMode, Message result) {
+    }
+
+    public void dial(String address, int clirMode, UUSInfo uusInfo,
+            Message result) {
+    }
+
+    public void getIMSI(Message result) {
+    }
+
+    public void getIMEI(Message result) {
+    }
+
+    public void getIMEISV(Message result) {
+    }
+
+
+    public void hangupConnection (int gsmIndex, Message result) {
+    }
+
+    public void hangupWaitingOrBackground (Message result) {
+    }
+
+    public void hangupForegroundResumeBackground (Message result) {
+    }
+
+    public void switchWaitingOrHoldingAndActive (Message result) {
+    }
+
+    public void conference (Message result) {
+    }
+
+
+    public void setPreferredVoicePrivacy(boolean enable, Message result) {
+    }
+
+    public void getPreferredVoicePrivacy(Message result) {
+    }
+
+    public void separateConnection (int gsmIndex, Message result) {
+    }
+
+    public void acceptCall (Message result) {
+    }
+
+    public void rejectCall (Message result) {
+    }
+
+    public void explicitCallTransfer (Message result) {
+    }
+
+    public void getLastCallFailCause (Message result) {
+    }
+
+    /** @deprecated */
+    public void getLastPdpFailCause (Message result) {
+    }
+
+    public void getLastDataCallFailCause (Message result) {
+    }
+
+    public void setMute (boolean enableMute, Message response) {
+    }
+
+    public void getMute (Message response) {
+    }
+
+    public void getSignalStrength (Message result) {
+    }
+
+    public void getRegistrationState (Message result) {
+    }
+
+    public void getGPRSRegistrationState (Message result) {
+    }
+
+    public void getOperator(Message result) {
+    }
+
+    public void sendDtmf(char c, Message result) {
+    }
+
+    public void startDtmf(char c, Message result) {
+    }
+
+    public void stopDtmf(Message result) {
+    }
+
+    public void sendBurstDtmf(String dtmfString, int on, int off,
+            Message result) {
+    }
+
+    public void sendSMS (String smscPDU, String pdu, Message result) {
+    }
+
+    public void sendCdmaSms(byte[] pdu, Message result) {
+    }
+
+    public void deleteSmsOnSim(int index, Message response) {
+    }
+
+    public void deleteSmsOnRuim(int index, Message response) {
+    }
+
+    public void writeSmsToSim(int status, String smsc, String pdu, Message response) {
+    }
+
+    public void writeSmsToRuim(int status, String pdu, Message response) {
+    }
+
+    public void setupDefaultPDP(String apn, String user, String password,
+            Message result) {
+    }
+
+    public void deactivateDefaultPDP(int cid, Message result) {
+    }
+
+    public void setupDataCall(String radioTechnology, String profile,
+            String apn, String user, String password, String authType,
+            Message result) {
+    }
+
+    public void deactivateDataCall(int cid, Message result) {
+    }
+
+    public void setRadioPower(boolean on, Message result) {
+    }
+
+    public void setSuppServiceNotifications(boolean enable, Message result) {
+    }
+
+    public void acknowledgeLastIncomingGsmSms(boolean success, int cause,
+            Message result) {
+    }
+
+    public void acknowledgeLastIncomingCdmaSms(boolean success, int cause,
+            Message result) {
+    }
+
+
+    public void iccIO (int command, int fileid, String path, int p1, int p2,
+            int p3, String data, String pin2, Message result) {
+    }
+
+    public void getCLIR(Message result) {
+    }
+
+    public void setCLIR(int clirMode, Message result) {
+    }
+
+    public void queryCallWaiting(int serviceClass, Message response) {
+    }
+
+    public void setCallWaiting(boolean enable, int serviceClass,
+            Message response) {
+    }
+
+    public void setNetworkSelectionModeAutomatic(Message response) {
+    }
+
+    public void setNetworkSelectionModeManual(
+            String operatorNumeric, Message response) {
+    }
+
+    public void getNetworkSelectionMode(Message response) {
+    }
+
+    public void getAvailableNetworks(Message response) {
+    }
+
+    public void setCallForward(int action, int cfReason, int serviceClass,
+                String number, int timeSeconds, Message response) {
+    }
+
+    public void queryCallForwardStatus(int cfReason, int serviceClass,
+            String number, Message response) {
+    }
+
+    public void queryCLIP(Message response) {
+    }
+
+    public void getBasebandVersion (Message response) {
+    }
+
+    public void queryFacilityLock (String facility, String password,
+            int serviceClass, Message response) {
+    }
+
+    public void setFacilityLock (String facility, boolean lockState,
+            String password, int serviceClass, Message response) {
+    }
+
+    public void sendUSSD (String ussdString, Message response) {
+    }
+
+    public void cancelPendingUssd (Message response) {
+    }
+
+    public void resetRadio(Message result) {
+    }
+
+    public void invokeOemRilRequestRaw(byte[] data, Message response) {
+    }
+
+    public void invokeOemRilRequestStrings(String[] strings, Message response) {
+    }
+
+    public void setBandMode (int bandMode, Message response) {
+    }
+
+    public void queryAvailableBandMode (Message response) {
+    }
+
+    public void sendTerminalResponse(String contents, Message response) {
+    }
+
+    public void sendEnvelope(String contents, Message response) {
+    }
+
+    public void handleCallSetupRequestFromSim(
+            boolean accept, Message response) {
+    }
+
+    public void setPreferredNetworkType(int networkType , Message response) {
+    }
+
+    public void getPreferredNetworkType(Message response) {
+    }
+
+    public void getNeighboringCids(Message response) {
+    }
+
+    public void setLocationUpdates(boolean enable, Message response) {
+    }
+
+    public void getSmscAddress(Message result) {
+    }
+
+    public void setSmscAddress(String address, Message result) {
+    }
+
+    public void reportSmsMemoryStatus(boolean available, Message result) {
+    }
+
+    public void reportStkServiceIsRunning(Message result) {
+    }
+
+    public void getGsmBroadcastConfig(Message response) {
+    }
+
+    public void setGsmBroadcastConfig(SmsBroadcastConfigInfo[] config, Message response) {
+    }
+
+    public void setGsmBroadcastActivation(boolean activate, Message response) {
+    }
+
+
+    // ***** Methods for CDMA support
+    public void getDeviceIdentity(Message response) {
+    }
+
+    public void getCDMASubscription(Message response) {
+    }
+
+    public void setPhoneType(int phoneType) { //Set by CDMAPhone and GSMPhone constructor
+    }
+
+    public void queryCdmaRoamingPreference(Message response) {
+    }
+
+    public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) {
+    }
+
+    public void setCdmaSubscription(int cdmaSubscription , Message response) {
+    }
+
+    public void queryTTYMode(Message response) {
+    }
+
+    public void setTTYMode(int ttyMode, Message response) {
+    }
+
+    public void sendCDMAFeatureCode(String FeatureCode, Message response) {
+    }
+
+    public void getCdmaBroadcastConfig(Message response) {
+    }
+
+    public void setCdmaBroadcastConfig(int[] configValuesArray, Message response) {
+    }
+
+    public void setCdmaBroadcastActivation(boolean activate, Message response) {
+    }
+
+    public void exitEmergencyCallbackMode(Message response) {
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java b/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java
new file mode 100644
index 0000000..d48f94a
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.sip;
+
+import android.content.Context;
+import android.net.sip.SipAudioCall;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.SystemClock;
+import android.util.Log;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.ServiceState;
+
+import com.android.internal.telephony.*;
+
+abstract class SipConnectionBase extends Connection {
+    //***** Event Constants
+    private static final int EVENT_DTMF_DONE = 1;
+    private static final int EVENT_PAUSE_DONE = 2;
+    private static final int EVENT_NEXT_POST_DIAL = 3;
+    private static final int EVENT_WAKE_LOCK_TIMEOUT = 4;
+
+    //***** Constants
+    private static final int PAUSE_DELAY_FIRST_MILLIS = 100;
+    private static final int PAUSE_DELAY_MILLIS = 3 * 1000;
+    private static final int WAKE_LOCK_TIMEOUT_MILLIS = 60*1000;
+
+    private static final String LOG_TAG = "SIP_CONN";
+
+    private SipAudioCall mSipAudioCall;
+
+    private String dialString;          // outgoing calls only
+    private String postDialString;      // outgoing calls only
+    private int nextPostDialChar;       // index into postDialString
+    private boolean isIncoming;
+    private boolean disconnected;
+
+    int index;          // index in SipCallTracker.connections[], -1 if unassigned
+                        // The Sip index is 1 + this
+
+    /*
+     * These time/timespan values are based on System.currentTimeMillis(),
+     * i.e., "wall clock" time.
+     */
+    private long createTime;
+    private long connectTime;
+    private long disconnectTime;
+
+    /*
+     * These time/timespan values are based on SystemClock.elapsedRealTime(),
+     * i.e., time since boot.  They are appropriate for comparison and
+     * calculating deltas.
+     */
+    private long connectTimeReal;
+    private long duration;
+    private long holdingStartTime;  // The time when the Connection last transitioned
+                            // into HOLDING
+
+    private DisconnectCause mCause = DisconnectCause.NOT_DISCONNECTED;
+    private PostDialState postDialState = PostDialState.NOT_STARTED;
+
+    SipConnectionBase(String calleeSipUri) {
+        dialString = calleeSipUri;
+
+        postDialString = PhoneNumberUtils.extractPostDialPortion(dialString);
+
+        isIncoming = false;
+        createTime = System.currentTimeMillis();
+    }
+
+    protected void setState(Call.State state) {
+        switch (state) {
+            case ACTIVE:
+                connectTimeReal = SystemClock.elapsedRealtime();
+                connectTime = System.currentTimeMillis();
+                break;
+            case DISCONNECTED:
+                duration = SystemClock.elapsedRealtime() - connectTimeReal;
+                disconnectTime = System.currentTimeMillis();
+                break;
+            case HOLDING:
+                holdingStartTime = SystemClock.elapsedRealtime();
+                break;
+        }
+    }
+
+    @Override
+    public long getCreateTime() {
+        return createTime;
+    }
+
+    @Override
+    public long getConnectTime() {
+        return connectTime;
+    }
+
+    @Override
+    public long getDisconnectTime() {
+        return disconnectTime;
+    }
+
+    @Override
+    public long getDurationMillis() {
+        if (connectTimeReal == 0) {
+            return 0;
+        } else if (duration == 0) {
+            return SystemClock.elapsedRealtime() - connectTimeReal;
+        } else {
+            return duration;
+        }
+    }
+
+    @Override
+    public long getHoldDurationMillis() {
+        if (getState() != Call.State.HOLDING) {
+            // If not holding, return 0
+            return 0;
+        } else {
+            return SystemClock.elapsedRealtime() - holdingStartTime;
+        }
+    }
+
+    @Override
+    public DisconnectCause getDisconnectCause() {
+        return mCause;
+    }
+
+    void setDisconnectCause(DisconnectCause cause) {
+        mCause = cause;
+    }
+
+    @Override
+    public PostDialState getPostDialState() {
+        return postDialState;
+    }
+
+    @Override
+    public void proceedAfterWaitChar() {
+        // TODO
+    }
+
+    @Override
+    public void proceedAfterWildChar(String str) {
+        // TODO
+    }
+
+    @Override
+    public void cancelPostDial() {
+        // TODO
+    }
+
+    protected abstract Phone getPhone();
+
+    DisconnectCause disconnectCauseFromCode(int causeCode) {
+        /**
+         * See 22.001 Annex F.4 for mapping of cause codes
+         * to local tones
+         */
+
+        switch (causeCode) {
+            case CallFailCause.USER_BUSY:
+                return DisconnectCause.BUSY;
+
+            case CallFailCause.NO_CIRCUIT_AVAIL:
+            case CallFailCause.TEMPORARY_FAILURE:
+            case CallFailCause.SWITCHING_CONGESTION:
+            case CallFailCause.CHANNEL_NOT_AVAIL:
+            case CallFailCause.QOS_NOT_AVAIL:
+            case CallFailCause.BEARER_NOT_AVAIL:
+                return DisconnectCause.CONGESTION;
+
+            case CallFailCause.ACM_LIMIT_EXCEEDED:
+                return DisconnectCause.LIMIT_EXCEEDED;
+
+            case CallFailCause.CALL_BARRED:
+                return DisconnectCause.CALL_BARRED;
+
+            case CallFailCause.FDN_BLOCKED:
+                return DisconnectCause.FDN_BLOCKED;
+
+            case CallFailCause.ERROR_UNSPECIFIED:
+            case CallFailCause.NORMAL_CLEARING:
+            default:
+                Phone phone = getPhone();
+                int serviceState = phone.getServiceState().getState();
+                if (serviceState == ServiceState.STATE_POWER_OFF) {
+                    return DisconnectCause.POWER_OFF;
+                } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE
+                        || serviceState == ServiceState.STATE_EMERGENCY_ONLY ) {
+                    return DisconnectCause.OUT_OF_SERVICE;
+                } else if (causeCode == CallFailCause.ERROR_UNSPECIFIED) {
+                    return DisconnectCause.ERROR_UNSPECIFIED;
+                } else if (causeCode == CallFailCause.NORMAL_CLEARING) {
+                    return DisconnectCause.NORMAL;
+                } else {
+                    // If nothing else matches, report unknown call drop reason
+                    // to app, not NORMAL call end.
+                    return DisconnectCause.ERROR_UNSPECIFIED;
+                }
+        }
+    }
+
+    @Override
+    public String getRemainingPostDialString() {
+        if (postDialState == PostDialState.CANCELLED
+            || postDialState == PostDialState.COMPLETE
+            || postDialString == null
+            || postDialString.length() <= nextPostDialChar) {
+            return "";
+        }
+
+        return postDialString.substring(nextPostDialChar);
+    }
+
+    private void log(String msg) {
+        Log.d(LOG_TAG, "[SipConn] " + msg);
+    }
+
+    @Override
+    public int getNumberPresentation() {
+        // TODO: add PRESENTATION_URL
+        return Connection.PRESENTATION_ALLOWED;
+    }
+
+    /*
+    @Override
+    public UUSInfo getUUSInfo() {
+        // FIXME: what's this for SIP?
+        return null;
+    }
+    */
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
new file mode 100755
index 0000000..4e61d30
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -0,0 +1,760 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.sip;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.net.rtp.AudioGroup;
+import android.net.sip.SipAudioCall;
+import android.net.sip.SipManager;
+import android.net.sip.SipProfile;
+import android.net.sip.SipSessionState;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.RegistrantList;
+import android.os.SystemProperties;
+import android.preference.PreferenceManager;
+import android.provider.Telephony;
+import android.telephony.CellLocation;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.CallerInfo;
+import com.android.internal.telephony.CallStateException;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.Connection;
+import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.IccFileHandler;
+import com.android.internal.telephony.IccPhoneBookInterfaceManager;
+import com.android.internal.telephony.IccSmsInterfaceManager;
+import com.android.internal.telephony.MmiCode;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneBase;
+import com.android.internal.telephony.PhoneNotifier;
+import com.android.internal.telephony.PhoneProxy;
+import com.android.internal.telephony.PhoneSubInfo;
+import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.telephony.UUSInfo;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.sip.SipException;
+
+/**
+ * {@hide}
+ */
+public class SipPhone extends SipPhoneBase {
+    private static final String LOG_TAG = "SipPhone";
+    private static final boolean LOCAL_DEBUG = true;
+
+    //private List<SipConnection> connections = new ArrayList<SipConnection>();
+
+    // A call that is ringing or (call) waiting
+    private SipCall ringingCall = new SipCall();
+    private SipCall foregroundCall = new SipCall();
+    private SipCall backgroundCall = new SipCall();
+
+    private SipManager mSipManager;
+    private SipProfile mProfile;
+
+    SipPhone (Context context, PhoneNotifier notifier, SipProfile profile) {
+        super(context, notifier);
+
+        Log.v(LOG_TAG, "  +++++++++++++++++++++ new SipPhone: " + profile.getUriString());
+        ringingCall = new SipCall();
+        foregroundCall = new SipCall();
+        backgroundCall = new SipCall();
+        mProfile = profile;
+        mSipManager = SipManager.getInstance(context);
+
+        // FIXME: what's this for SIP?
+        //Change the system property
+        //SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
+        //        new Integer(Phone.PHONE_TYPE_GSM).toString());
+    }
+
+    public String getPhoneName() {
+        return mProfile.getProfileName();
+    }
+
+    public boolean canTake(Object incomingCall) {
+        synchronized (SipPhone.class) {
+            if (!(incomingCall instanceof SipAudioCall)) return false;
+            if (ringingCall.getState().isAlive()) return false;
+
+            // FIXME: is it true that we cannot take any incoming call if
+            // both foreground and background are active
+            if (foregroundCall.getState().isAlive()
+                    && backgroundCall.getState().isAlive()) {
+                return false;
+            }
+
+            SipAudioCall sipAudioCall = (SipAudioCall) incomingCall;
+            Log.v(LOG_TAG, "  ++++++ taking call from: "
+                    + sipAudioCall.getPeerProfile().getUriString());
+            String localUri = sipAudioCall.getLocalProfile().getUriString();
+            if (localUri.equals(mProfile.getUriString())) {
+                boolean makeCallWait = foregroundCall.getState().isAlive();
+                ringingCall.initIncomingCall(sipAudioCall, makeCallWait);
+                return true;
+            }
+            return false;
+        }
+    }
+
+    public void acceptCall() throws CallStateException {
+        synchronized (SipPhone.class) {
+            // FIXME if SWITCH fails, should retry with ANSWER
+            // in case the active/holding call disappeared and this
+            // is no longer call waiting
+
+            if (ringingCall.getState() == Call.State.INCOMING) {
+                Log.v(LOG_TAG, "acceptCall");
+                // Always unmute when answering a new call
+                setMute(false);
+                // make ringingCall foreground
+                foregroundCall.switchWith(ringingCall);
+                foregroundCall.acceptCall();
+            } else if (ringingCall.getState() == Call.State.WAITING) {
+                setMute(false);
+                switchHoldingAndActive();
+                // make ringingCall foreground
+                foregroundCall.switchWith(ringingCall);
+                foregroundCall.acceptCall();
+            } else {
+                throw new CallStateException("phone not ringing");
+            }
+        }
+    }
+
+    public void rejectCall() throws CallStateException {
+        synchronized (SipPhone.class) {
+            if (ringingCall.getState().isRinging()) {
+                Log.v(LOG_TAG, "rejectCall");
+                ringingCall.rejectCall();
+            } else {
+                throw new CallStateException("phone not ringing");
+            }
+        }
+    }
+
+    public Connection dial(String dialString, UUSInfo uusinfo) throws CallStateException {
+        return dial(dialString);
+    }
+
+    public Connection dial(String dialString) throws CallStateException {
+        synchronized (SipPhone.class) {
+            return dialInternal(dialString);
+        }
+    }
+
+    private Connection dialInternal(String dialString)
+            throws CallStateException {
+        // TODO: parse SIP URL?
+        // Need to make sure dialString gets parsed properly
+        //String newDialString = PhoneNumberUtils.stripSeparators(dialString);
+        //return mCT.dial(newDialString);
+        clearDisconnected();
+
+        if (!canDial()) {
+            throw new CallStateException("cannot dial in current state");
+        }
+        if (foregroundCall.getState() == SipCall.State.ACTIVE) {
+            switchHoldingAndActive();
+        }
+        if (foregroundCall.getState() != SipCall.State.IDLE) {
+            //we should have failed in !canDial() above before we get here
+            throw new CallStateException("cannot dial in current state");
+        }
+
+        setMute(false);
+        //cm.dial(pendingMO.address, clirMode, obtainCompleteMessage());
+        try {
+            Connection c = foregroundCall.dial(dialString);
+            return c;
+        } catch (SipException e) {
+            Log.e(LOG_TAG, "dial()", e);
+            throw new CallStateException("dial error: " + e);
+        }
+    }
+
+    public void switchHoldingAndActive() throws CallStateException {
+        Log.v(LOG_TAG, " ~~~~~~  switch fg and bg");
+        synchronized (SipPhone.class) {
+            foregroundCall.switchWith(backgroundCall);
+            if (backgroundCall.getState().isAlive()) backgroundCall.hold();
+            if (foregroundCall.getState().isAlive()) foregroundCall.unhold();
+        }
+    }
+
+    public boolean canConference() {
+        return true;
+    }
+
+    public void conference() throws CallStateException {
+        // TODO
+    }
+
+    public boolean canTransfer() {
+        return false;
+    }
+
+    public void explicitCallTransfer() throws CallStateException {
+        //mCT.explicitCallTransfer();
+    }
+
+    public void clearDisconnected() {
+        ringingCall.clearDisconnected();
+        foregroundCall.clearDisconnected();
+        backgroundCall.clearDisconnected();
+
+        updatePhoneState();
+        notifyPreciseCallStateChanged();
+    }
+
+    public void sendDtmf(char c) {
+        if (!PhoneNumberUtils.is12Key(c)) {
+            Log.e(LOG_TAG,
+                    "sendDtmf called with invalid character '" + c + "'");
+        } else if (foregroundCall.getState().isAlive()) {
+            foregroundCall.sendDtmf(c);
+        }
+    }
+
+    public void startDtmf(char c) {
+        if (!PhoneNumberUtils.is12Key(c)) {
+            Log.e(LOG_TAG,
+                "startDtmf called with invalid character '" + c + "'");
+        } else {
+            sendDtmf(c);
+        }
+    }
+
+    public void stopDtmf() {
+        // no op
+    }
+
+    public void sendBurstDtmf(String dtmfString) {
+        Log.e(LOG_TAG, "[SipPhone] sendBurstDtmf() is a CDMA method");
+    }
+
+    public void getOutgoingCallerIdDisplay(Message onComplete) {
+        // FIXME: what to reply?
+        AsyncResult.forMessage(onComplete, null, null);
+        onComplete.sendToTarget();
+    }
+
+    public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode,
+                                           Message onComplete) {
+        // FIXME: what's this for SIP?
+        AsyncResult.forMessage(onComplete, null, null);
+        onComplete.sendToTarget();
+    }
+
+    public void getCallWaiting(Message onComplete) {
+        // FIXME: what to reply?
+        AsyncResult.forMessage(onComplete, null, null);
+        onComplete.sendToTarget();
+    }
+
+    public void setCallWaiting(boolean enable, Message onComplete) {
+        // FIXME: what to reply?
+        Log.e(LOG_TAG, "call waiting not supported");
+    }
+
+    public void setMute(boolean muted) {
+        foregroundCall.setMute(muted);
+    }
+
+    public boolean getMute() {
+        return foregroundCall.getMute();
+    }
+
+    public Call getForegroundCall() {
+        return foregroundCall;
+    }
+
+    public Call getBackgroundCall() {
+        return backgroundCall;
+    }
+
+    public Call getRingingCall() {
+        return ringingCall;
+    }
+
+    public ServiceState getServiceState() {
+        // FIXME: we may need to provide this when data connectivity is lost
+        // or when server is down
+        return super.getServiceState();
+    }
+
+    private String getUriString(SipProfile p) {
+        // SipProfile.getUriString() may contain "SIP:" and port
+        return p.getUserName() + "@" + getSipDomain(p);
+    }
+
+    private String getSipDomain(SipProfile p) {
+        String domain = p.getSipDomain();
+        // TODO: move this to SipProfile
+        if (domain.endsWith(":5060")) {
+            return domain.substring(0, domain.length() - 5);
+        } else {
+            return domain;
+        }
+    }
+
+    private class SipCall extends SipCallBase {
+        void switchWith(SipCall that) {
+            synchronized (SipPhone.class) {
+                SipCall tmp = new SipCall();
+                tmp.takeOver(this);
+                this.takeOver(that);
+                that.takeOver(tmp);
+            }
+        }
+
+        private void takeOver(SipCall that) {
+            connections = that.connections;
+            state = that.state;
+            for (Connection c : connections) {
+                ((SipConnection) c).changeOwner(this);
+            }
+        }
+
+        @Override
+        public Phone getPhone() {
+            return SipPhone.this;
+        }
+
+        @Override
+        public List<Connection> getConnections() {
+            synchronized (SipPhone.class) {
+                // FIXME should return Collections.unmodifiableList();
+                return connections;
+            }
+        }
+
+        private CallerInfo getCallerInfo(String number) {
+            CallerInfo info = CallerInfo.getCallerInfo(mContext, number);
+            if ((info == null) || (info.name == null)) return null;
+            Log.v(LOG_TAG, "++******++ got info from contact:");
+            Log.v(LOG_TAG, "     name: " + info.name);
+            Log.v(LOG_TAG, "     numb: " + info.phoneNumber);
+            Log.v(LOG_TAG, "     pres: " + info.numberPresentation);
+            return info;
+        }
+
+        Connection dial(String calleeSipUri) throws SipException {
+            CallerInfo info = getCallerInfo(calleeSipUri);
+            if (!calleeSipUri.contains("@")) {
+                calleeSipUri += "@" + getSipDomain(mProfile);
+                if (info != null) info.phoneNumber = calleeSipUri;
+            }
+            try {
+                SipProfile callee =
+                        new SipProfile.Builder(calleeSipUri).build();
+                SipConnection c = new SipConnection(this, callee, info);
+                connections.add(c);
+                c.dial();
+                setState(Call.State.DIALING);
+                return c;
+            } catch (ParseException e) {
+                // TODO: notify someone
+                throw new SipException("dial", e);
+            }
+        }
+
+        @Override
+        public void hangup() throws CallStateException {
+            Log.v(LOG_TAG, "hang up call: " + getState() + ": " + this
+                    + " on phone " + getPhone());
+            CallStateException excp = null;
+            for (Connection c : connections) {
+                try {
+                    c.hangup();
+                } catch (CallStateException e) {
+                    excp = e;
+                }
+            }
+            if (excp != null) throw excp;
+            setState(State.DISCONNECTING);
+        }
+
+        void initIncomingCall(SipAudioCall sipAudioCall, boolean makeCallWait) {
+            SipProfile callee = sipAudioCall.getPeerProfile();
+            CallerInfo info = getCallerInfo(getUriString(callee));
+            if (info == null) info = getCallerInfo(callee.getUserName());
+            if (info == null) info = getCallerInfo(callee.getDisplayName());
+            SipConnection c = new SipConnection(this, callee, info);
+            connections.add(c);
+
+            Call.State newState = makeCallWait ? State.WAITING : State.INCOMING;
+            c.initIncomingCall(sipAudioCall, newState);
+
+            setState(newState);
+            notifyNewRingingConnectionP(c);
+        }
+
+        void rejectCall() throws CallStateException {
+            hangup();
+        }
+
+        void acceptCall() throws CallStateException {
+            if (this != foregroundCall) {
+                throw new CallStateException("acceptCall() in a non-fg call");
+            }
+            if (connections.size() != 1) {
+                throw new CallStateException("acceptCall() in a conf call");
+            }
+            ((SipConnection) connections.get(0)).acceptCall();
+        }
+
+        void hold() throws CallStateException {
+            AudioGroup audioGroup = getAudioGroup();
+            if (audioGroup == null) return;
+            audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
+            setState(State.HOLDING);
+            for (Connection c : connections) ((SipConnection) c).hold();
+        }
+
+        void unhold() throws CallStateException {
+            AudioGroup audioGroup = getAudioGroup();
+            if (audioGroup == null) return;
+            audioGroup.setMode(AudioGroup.MODE_NORMAL);
+            setState(State.ACTIVE);
+            for (Connection c : connections) ((SipConnection) c).unhold();
+        }
+
+        void setMute(boolean muted) {
+            AudioGroup audioGroup = getAudioGroup();
+            if (audioGroup == null) return;
+            audioGroup.setMode(
+                    muted ? AudioGroup.MODE_MUTED : AudioGroup.MODE_NORMAL);
+        }
+
+        boolean getMute() {
+            AudioGroup audioGroup = getAudioGroup();
+            if (audioGroup == null) return false;
+            return (audioGroup.getMode() == AudioGroup.MODE_MUTED);
+        }
+
+        void sendDtmf(char c) {
+            AudioGroup audioGroup = getAudioGroup();
+            if (audioGroup == null) return;
+            audioGroup.sendDtmf(convertDtmf(c));
+        }
+
+        private int convertDtmf(char c) {
+            int code = c - '0';
+            if ((code < 0) || (code > 9)) {
+                switch (c) {
+                    case '*': return 10;
+                    case '#': return 11;
+                    case 'A': return 12;
+                    case 'B': return 13;
+                    case 'C': return 14;
+                    case 'D': return 15;
+                    default:
+                        throw new IllegalArgumentException(
+                                "invalid DTMF char: " + (int) c);
+                }
+            }
+            return code;
+        }
+
+        @Override
+        protected void setState(State newState) {
+            if (state != newState) {
+                Log.v(LOG_TAG, "++******++ call state changed: " + state
+                        + " --> " + newState + ": " + this + ": on phone "
+                        + getPhone() + " " + connections.size());
+
+                if (newState == Call.State.ALERTING) {
+                    state = newState; // need in ALERTING to enable ringback
+                    SipPhone.this.startRingbackTone();
+                } else if (state == Call.State.ALERTING) {
+                    SipPhone.this.stopRingbackTone();
+                }
+                state = newState;
+                updatePhoneState();
+                notifyPreciseCallStateChanged();
+            }
+        }
+
+        void onConnectionStateChanged(SipConnection conn) {
+            // this can be called back when a conf call is formed
+            if (state != State.ACTIVE) {
+                setState(conn.getState());
+            }
+        }
+
+        void onConnectionEnded(SipConnection conn) {
+            // set state to DISCONNECTED only when all conns are disconnected
+            if (state != State.DISCONNECTED) {
+                boolean allConnectionsDisconnected = true;
+                for (Connection c : connections) {
+                    if (c.getState() != State.DISCONNECTED) {
+                        allConnectionsDisconnected = false;
+                        break;
+                    }
+                }
+                if (allConnectionsDisconnected) setState(State.DISCONNECTED);
+            }
+            notifyDisconnectP(conn);
+        }
+
+        private AudioGroup getAudioGroup() {
+            if (connections.isEmpty()) return null;
+            return ((SipConnection) connections.get(0)).getAudioGroup();
+        }
+    }
+
+    private class SipConnection extends SipConnectionBase {
+        private SipCall mOwner;
+        private SipAudioCall mSipAudioCall;
+        private Call.State mState = Call.State.IDLE;
+        private SipProfile mPeer;
+        private boolean mIncoming = false;
+
+        private SipAudioCallAdapter mAdapter = new SipAudioCallAdapter() {
+            @Override
+            protected void onCallEnded(DisconnectCause cause) {
+                if (getDisconnectCause() != DisconnectCause.LOCAL) {
+                    setDisconnectCause(cause);
+                }
+                synchronized (SipPhone.class) {
+                    setState(Call.State.DISCONNECTED);
+                    mOwner.onConnectionEnded(SipConnection.this);
+                    Log.v(LOG_TAG, "-------- connection ended: "
+                            + mPeer.getUriString() + ": "
+                            + mSipAudioCall.getState() + ", cause: "
+                            + getDisconnectCause() + ", on phone "
+                            + getPhone());
+                }
+            }
+
+            @Override
+            public void onChanged(SipAudioCall call) {
+                synchronized (SipPhone.class) {
+                    Call.State newState = getCallStateFrom(call);
+                    if (mState == newState) return;
+                    if (newState == Call.State.INCOMING) {
+                        setState(mOwner.getState()); // INCOMING or WAITING
+                    } else {
+                        setState(newState);
+                    }
+                    mOwner.onConnectionStateChanged(SipConnection.this);
+                    Log.v(LOG_TAG, "++******++ connection state changed: "
+                            + mPeer.getUriString() + ": " + mState
+                            + " on phone " + getPhone());
+                }
+            }
+
+            @Override
+            protected void onError(String errorMessage) {
+                Log.w(LOG_TAG, "SIP error: " + errorMessage);
+                if (mSipAudioCall.isInCall()) {
+                    // Don't end the call when in call.
+                    // TODO: how to deliver the error to PhoneApp
+                    return;
+                }
+
+                // FIXME: specify error
+                onCallEnded(DisconnectCause.ERROR_UNSPECIFIED);
+            }
+        };
+
+        public SipConnection(SipCall owner, SipProfile callee,
+                CallerInfo info) {
+            super(getUriString(callee));
+            mOwner = owner;
+            mPeer = callee;
+            if (info == null) info = createCallerInfo();
+            setUserData(info);
+        }
+
+        private CallerInfo createCallerInfo() {
+            SipProfile p = mPeer;
+            String name = p.getDisplayName();
+            if (TextUtils.isEmpty(name)) name = p.getUserName();
+            CallerInfo info = new CallerInfo();
+            info.name = name;
+            info.phoneNumber = getUriString(p);
+            return info;
+        }
+
+        void initIncomingCall(SipAudioCall sipAudioCall, Call.State newState) {
+            setState(newState);
+            mSipAudioCall = sipAudioCall;
+            sipAudioCall.setListener(mAdapter); // call back to set state
+            mIncoming = true;
+        }
+
+        void acceptCall() throws CallStateException {
+            try {
+                mSipAudioCall.answerCall();
+            } catch (SipException e) {
+                throw new CallStateException("acceptCall(): " + e);
+            }
+        }
+
+        void changeOwner(SipCall owner) {
+            mOwner = owner;
+        }
+
+        AudioGroup getAudioGroup() {
+            if (mSipAudioCall == null) return null;
+            return mSipAudioCall.getAudioGroup();
+        }
+
+        void dial() throws SipException {
+            setState(Call.State.DIALING);
+            mSipAudioCall = mSipManager.makeAudioCall(mContext, mProfile,
+                    mPeer, null);
+            mSipAudioCall.setRingbackToneEnabled(false);
+            mSipAudioCall.setListener(mAdapter);
+        }
+
+        void hold() throws CallStateException {
+            try {
+                mSipAudioCall.holdCall();
+            } catch (SipException e) {
+                throw new CallStateException("hold(): " + e);
+            }
+        }
+
+        void unhold() throws CallStateException {
+            try {
+                mSipAudioCall.continueCall();
+            } catch (SipException e) {
+                throw new CallStateException("unhold(): " + e);
+            }
+        }
+
+        @Override
+        protected void setState(Call.State state) {
+            if (state == mState) return;
+            super.setState(state);
+            mState = state;
+        }
+
+        @Override
+        public Call.State getState() {
+            return mState;
+        }
+
+        @Override
+        public boolean isIncoming() {
+            return mIncoming;
+        }
+
+        @Override
+        public String getAddress() {
+            return getUriString(mPeer);
+        }
+
+        @Override
+        public SipCall getCall() {
+            return mOwner;
+        }
+
+        @Override
+        protected Phone getPhone() {
+            return mOwner.getPhone();
+        }
+
+        @Override
+        public void hangup() throws CallStateException {
+            Log.v(LOG_TAG, "hangup conn: " + mPeer.getUriString() + ": "
+                    + ": on phone " + getPhone());
+            try {
+                mSipAudioCall.endCall();
+                setState(Call.State.DISCONNECTING);
+                setDisconnectCause(DisconnectCause.LOCAL);
+            } catch (SipException e) {
+                throw new CallStateException("hangup(): " + e);
+            }
+        }
+
+        @Override
+        public void separate() throws CallStateException {
+            // TODO: what's this for SIP?
+            /*
+            if (!disconnected) {
+                owner.separate(this);
+            } else {
+                throw new CallStateException ("disconnected");
+            }
+            */
+        }
+
+        @Override
+        public UUSInfo getUUSInfo() {
+            return null;
+        }
+    }
+
+    private static Call.State getCallStateFrom(SipAudioCall sipAudioCall) {
+        if (sipAudioCall.isOnHold()) return Call.State.HOLDING;
+        SipSessionState sessionState = sipAudioCall.getState();
+        switch (sessionState) {
+            case READY_TO_CALL:            return Call.State.IDLE;
+            case INCOMING_CALL:
+            case INCOMING_CALL_ANSWERING:  return Call.State.INCOMING;
+            case OUTGOING_CALL:            return Call.State.DIALING;
+            case OUTGOING_CALL_RING_BACK:  return Call.State.ALERTING;
+            case OUTGOING_CALL_CANCELING:  return Call.State.DISCONNECTING;
+            case IN_CALL:                  return Call.State.ACTIVE;
+            default:
+                Log.w(LOG_TAG, "illegal connection state: " + sessionState);
+                return Call.State.DISCONNECTED;
+        }
+    }
+
+    private abstract class SipAudioCallAdapter extends SipAudioCall.Adapter {
+        protected abstract void onCallEnded(Connection.DisconnectCause cause);
+        protected abstract void onError(String errorMessage);
+
+        @Override
+        public void onCallEnded(SipAudioCall call) {
+            onCallEnded(Connection.DisconnectCause.NORMAL);
+        }
+
+        @Override
+        public void onCallBusy(SipAudioCall call) {
+            onCallEnded(Connection.DisconnectCause.BUSY);
+        }
+
+        @Override
+        public void onError(SipAudioCall call, String errorMessage) {
+            onError(errorMessage);
+        }
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
new file mode 100755
index 0000000..36d65db
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.sip;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.RegistrantList;
+import android.os.SystemProperties;
+import android.preference.PreferenceManager;
+import android.provider.Telephony;
+import android.telephony.CellLocation;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.text.TextUtils;
+import android.util.Log;
+
+import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE;
+import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
+import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE;
+import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
+import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION;
+
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.CallStateException;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.Connection;
+import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.IccFileHandler;
+import com.android.internal.telephony.IccPhoneBookInterfaceManager;
+import com.android.internal.telephony.IccSmsInterfaceManager;
+import com.android.internal.telephony.MmiCode;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneBase;
+import com.android.internal.telephony.PhoneNotifier;
+import com.android.internal.telephony.PhoneProxy;
+import com.android.internal.telephony.PhoneSubInfo;
+import com.android.internal.telephony.TelephonyProperties;
+//import com.android.internal.telephony.UUSInfo;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+abstract class SipPhoneBase extends PhoneBase {
+    // NOTE that LOG_TAG here is "Sip", which means that log messages
+    // from this file will go into the radio log rather than the main
+    // log.  (Use "adb logcat -b radio" to see them.)
+    static final String LOG_TAG = "SipPhone";
+    private static final boolean LOCAL_DEBUG = true;
+
+    //SipCallTracker mCT;
+    PhoneSubInfo mSubInfo;
+
+    Registrant mPostDialHandler;
+
+    final RegistrantList mRingbackRegistrants = new RegistrantList();
+
+    private State state = State.IDLE;
+
+    public SipPhoneBase(Context context, PhoneNotifier notifier) {
+        super(notifier, context, new SipCommandInterface(context), false);
+
+        // FIXME: what's this for SIP?
+        //Change the system property
+        //SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
+        //        new Integer(Phone.PHONE_TYPE_GSM).toString());
+    }
+
+    public abstract Call getForegroundCall();
+
+    public abstract Call getBackgroundCall();
+
+    public abstract Call getRingingCall();
+
+    /*
+    public Connection dial(String dialString, UUSInfo uusInfo)
+            throws CallStateException {
+        // ignore UUSInfo
+        return dial(dialString);
+    }
+    */
+
+    void migrateFrom(SipPhoneBase from) {
+        migrate(mRingbackRegistrants, from.mRingbackRegistrants);
+        migrate(mPreciseCallStateRegistrants, from.mPreciseCallStateRegistrants);
+        migrate(mNewRingingConnectionRegistrants, from.mNewRingingConnectionRegistrants);
+        migrate(mIncomingRingRegistrants, from.mIncomingRingRegistrants);
+        migrate(mDisconnectRegistrants, from.mDisconnectRegistrants);
+        migrate(mServiceStateRegistrants, from.mServiceStateRegistrants);
+        migrate(mMmiCompleteRegistrants, from.mMmiCompleteRegistrants);
+        migrate(mMmiRegistrants, from.mMmiRegistrants);
+        migrate(mUnknownConnectionRegistrants, from.mUnknownConnectionRegistrants);
+        migrate(mSuppServiceFailedRegistrants, from.mSuppServiceFailedRegistrants);
+    }
+
+    static void migrate(RegistrantList to, RegistrantList from) {
+        from.removeCleared();
+        for (int i = 0, n = from.size(); i < n; i++) {
+            to.add((Registrant) from.get(i));
+        }
+    }
+
+    @Override
+    public void registerForRingbackTone(Handler h, int what, Object obj) {
+        mRingbackRegistrants.addUnique(h, what, obj);
+    }
+
+    @Override
+    public void unregisterForRingbackTone(Handler h) {
+        mRingbackRegistrants.remove(h);
+    }
+
+    protected void startRingbackTone() {
+        AsyncResult result = new AsyncResult(null, new Boolean(true), null);
+        mRingbackRegistrants.notifyRegistrants(result);
+    }
+
+    protected void stopRingbackTone() {
+        AsyncResult result = new AsyncResult(null, new Boolean(false), null);
+        mRingbackRegistrants.notifyRegistrants(result);
+    }
+
+    public void dispose() {
+        mIsTheCurrentActivePhone = false;
+        mSubInfo.dispose();
+    }
+
+    public void removeReferences() {
+        mSubInfo = null;
+    }
+
+    public ServiceState getServiceState() {
+        // FIXME: we may need to provide this when data connectivity is lost
+        // or when server is down
+        ServiceState s = new ServiceState();
+        s.setState(ServiceState.STATE_IN_SERVICE);
+        return s;
+    }
+
+    public CellLocation getCellLocation() {
+        return null; //mSST.cellLoc;
+    }
+
+    public State getState() {
+        return state;
+    }
+
+    public String getPhoneName() {
+        return "SIP";
+    }
+
+    public int getPhoneType() {
+        // FIXME: add SIP phone type
+        return Phone.PHONE_TYPE_GSM;
+    }
+
+    public SignalStrength getSignalStrength() {
+        return new SignalStrength();
+    }
+
+    public boolean getMessageWaitingIndicator() {
+        return false;
+    }
+
+    public boolean getCallForwardingIndicator() {
+        return false;
+    }
+
+    public List<? extends MmiCode> getPendingMmiCodes() {
+        return new ArrayList<MmiCode>(0);
+    }
+
+    public DataState getDataConnectionState() {
+        return DataState.DISCONNECTED;
+    }
+
+    public DataState getDataConnectionState(String apnType) {
+        return DataState.DISCONNECTED;
+    }
+
+    public DataActivityState getDataActivityState() {
+        return DataActivityState.NONE;
+    }
+
+    /**
+     * Notify any interested party of a Phone state change {@link Phone.State}
+     */
+    void notifyPhoneStateChanged() {
+        mNotifier.notifyPhoneState(this);
+    }
+
+    /**
+     * 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.
+     */
+    void notifyPreciseCallStateChanged() {
+        /* we'd love it if this was package-scoped*/
+        super.notifyPreciseCallStateChangedP();
+    }
+
+    void notifyNewRingingConnection(Connection c) {
+        /* we'd love it if this was package-scoped*/
+        super.notifyNewRingingConnectionP(c);
+    }
+
+    void notifyDisconnect(Connection cn) {
+        mDisconnectRegistrants.notifyResult(cn);
+    }
+
+    void notifyUnknownConnection() {
+        mUnknownConnectionRegistrants.notifyResult(this);
+    }
+
+    void notifySuppServiceFailed(SuppService code) {
+        mSuppServiceFailedRegistrants.notifyResult(code);
+    }
+
+    void notifyServiceStateChanged(ServiceState ss) {
+        super.notifyServiceStateChangedP(ss);
+    }
+
+    public void notifyCallForwardingIndicator() {
+        mNotifier.notifyCallForwardingChanged(this);
+    }
+
+    public boolean canDial() {
+        int serviceState = getServiceState().getState();
+        Log.v(LOG_TAG, "canDial(): serviceState = " + serviceState);
+        if (serviceState == ServiceState.STATE_POWER_OFF) return false;
+
+        String disableCall = SystemProperties.get(
+                TelephonyProperties.PROPERTY_DISABLE_CALL, "false");
+        Log.v(LOG_TAG, "canDial(): disableCall = " + disableCall);
+        if (disableCall.equals("true")) return false;
+
+        Log.v(LOG_TAG, "canDial(): ringingCall: " + getRingingCall().getState());
+        Log.v(LOG_TAG, "canDial(): foregndCall: " + getForegroundCall().getState());
+        Log.v(LOG_TAG, "canDial(): backgndCall: " + getBackgroundCall().getState());
+        return !getRingingCall().isRinging()
+                && (!getForegroundCall().getState().isAlive()
+                    || !getBackgroundCall().getState().isAlive());
+    }
+
+    public boolean handleInCallMmiCommands(String dialString)
+            throws CallStateException {
+        return false;
+    }
+
+    boolean isInCall() {
+        Call.State foregroundCallState = getForegroundCall().getState();
+        Call.State backgroundCallState = getBackgroundCall().getState();
+        Call.State ringingCallState = getRingingCall().getState();
+
+       return (foregroundCallState.isAlive() || backgroundCallState.isAlive()
+            || ringingCallState.isAlive());
+    }
+
+    public boolean handlePinMmi(String dialString) {
+        return false;
+    }
+
+    public void sendUssdResponse(String ussdMessge) {
+    }
+
+    public void registerForSuppServiceNotification(
+            Handler h, int what, Object obj) {
+    }
+
+    public void unregisterForSuppServiceNotification(Handler h) {
+    }
+
+    public void setRadioPower(boolean power) {
+    }
+
+    public String getVoiceMailNumber() {
+        return null;
+    }
+
+    public String getVoiceMailAlphaTag() {
+        return null;
+    }
+
+    public String getDeviceId() {
+        return null;
+    }
+
+    public String getDeviceSvn() {
+        return null;
+    }
+
+    public String getEsn() {
+        Log.e(LOG_TAG, "[SipPhone] getEsn() is a CDMA method");
+        return "0";
+    }
+
+    public String getMeid() {
+        Log.e(LOG_TAG, "[SipPhone] getMeid() is a CDMA method");
+        return "0";
+    }
+
+    public String getSubscriberId() {
+        return null;
+    }
+
+    public String getIccSerialNumber() {
+        return null;
+    }
+
+    public String getLine1Number() {
+        return null;
+    }
+
+    public String getLine1AlphaTag() {
+        return null;
+    }
+
+    public void setLine1Number(String alphaTag, String number, Message onComplete) {
+        // FIXME: what to reply for SIP?
+        AsyncResult.forMessage(onComplete, null, null);
+        onComplete.sendToTarget();
+    }
+
+    public void setVoiceMailNumber(String alphaTag, String voiceMailNumber,
+            Message onComplete) {
+        // FIXME: what to reply for SIP?
+        AsyncResult.forMessage(onComplete, null, null);
+        onComplete.sendToTarget();
+    }
+
+    private boolean isValidCommandInterfaceCFReason(int commandInterfaceCFReason) {
+        switch (commandInterfaceCFReason) {
+        case CF_REASON_UNCONDITIONAL:
+        case CF_REASON_BUSY:
+        case CF_REASON_NO_REPLY:
+        case CF_REASON_NOT_REACHABLE:
+        case CF_REASON_ALL:
+        case CF_REASON_ALL_CONDITIONAL:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) {
+        switch (commandInterfaceCFAction) {
+        case CF_ACTION_DISABLE:
+        case CF_ACTION_ENABLE:
+        case CF_ACTION_REGISTRATION:
+        case CF_ACTION_ERASURE:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    protected  boolean isCfEnable(int action) {
+        return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION);
+    }
+
+    public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) {
+        if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) {
+            // FIXME: what to reply?
+            AsyncResult.forMessage(onComplete, null, null);
+            onComplete.sendToTarget();
+        }
+    }
+
+    public void setCallForwardingOption(int commandInterfaceCFAction,
+            int commandInterfaceCFReason, String dialingNumber,
+            int timerSeconds, Message onComplete) {
+        if (isValidCommandInterfaceCFAction(commandInterfaceCFAction)
+                && isValidCommandInterfaceCFReason(commandInterfaceCFReason)) {
+            // FIXME: what to reply?
+            AsyncResult.forMessage(onComplete, null, null);
+            onComplete.sendToTarget();
+        }
+    }
+
+    public void getOutgoingCallerIdDisplay(Message onComplete) {
+        // FIXME: what to reply?
+        AsyncResult.forMessage(onComplete, null, null);
+        onComplete.sendToTarget();
+    }
+
+    public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode,
+                                           Message onComplete) {
+        // FIXME: what's this for SIP?
+        AsyncResult.forMessage(onComplete, null, null);
+        onComplete.sendToTarget();
+    }
+
+    public void getCallWaiting(Message onComplete) {
+        // FIXME: what to reply?
+        AsyncResult.forMessage(onComplete, null, null);
+        onComplete.sendToTarget();
+    }
+
+    public void setCallWaiting(boolean enable, Message onComplete) {
+        // FIXME: what to reply?
+        Log.e(LOG_TAG, "call waiting not supported");
+    }
+
+    public boolean getIccRecordsLoaded() {
+        return false;
+    }
+
+    public IccCard getIccCard() {
+        return null;
+    }
+
+    public void getAvailableNetworks(Message response) {
+        // FIXME: what to reply?
+    }
+
+    public void setNetworkSelectionModeAutomatic(Message response) {
+        // FIXME: what to reply?
+    }
+
+    public void selectNetworkManually(
+            com.android.internal.telephony.gsm.NetworkInfo network,
+            Message response) {
+        // FIXME: what to reply?
+    }
+
+    public void getNeighboringCids(Message response) {
+        // FIXME: what to reply?
+    }
+
+    public void setOnPostDialCharacter(Handler h, int what, Object obj) {
+        mPostDialHandler = new Registrant(h, what, obj);
+    }
+
+    public void getDataCallList(Message response) {
+        // FIXME: what to reply?
+    }
+
+    public List<DataConnection> getCurrentDataConnectionList () {
+        return null;
+    }
+
+    public void updateServiceLocation() {
+    }
+
+    public void enableLocationUpdates() {
+    }
+
+    public void disableLocationUpdates() {
+    }
+
+    public boolean getDataRoamingEnabled() {
+        return false;
+    }
+
+    public void setDataRoamingEnabled(boolean enable) {
+    }
+
+    public boolean enableDataConnectivity() {
+        return false;
+    }
+
+    public boolean disableDataConnectivity() {
+        return false;
+    }
+
+    public boolean isDataConnectivityPossible() {
+        return false;
+    }
+
+    boolean updateCurrentCarrierInProvider() {
+        return false;
+    }
+
+    public void saveClirSetting(int commandInterfaceCLIRMode) {
+        // FIXME: what's this for SIP?
+    }
+
+    /**
+     * Retrieves the PhoneSubInfo of the SipPhone
+     */
+    public PhoneSubInfo getPhoneSubInfo(){
+        return mSubInfo;
+    }
+
+    /** {@inheritDoc} */
+    public IccSmsInterfaceManager getIccSmsInterfaceManager(){
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    public IccFileHandler getIccFileHandler(){
+        return null;
+    }
+
+    public void activateCellBroadcastSms(int activate, Message response) {
+        Log.e(LOG_TAG, "Error! This functionality is not implemented for SIP.");
+    }
+
+    public void getCellBroadcastSmsConfig(Message response) {
+        Log.e(LOG_TAG, "Error! This functionality is not implemented for SIP.");
+    }
+
+    public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){
+        Log.e(LOG_TAG, "Error! This functionality is not implemented for SIP.");
+    }
+
+    void updatePhoneState() {
+        State oldState = state;
+
+        if (getRingingCall().isRinging()) {
+            state = State.RINGING;
+        } else if (getForegroundCall().isIdle()
+                && getBackgroundCall().isIdle()) {
+            state = State.IDLE;
+        } else {
+            state = State.OFFHOOK;
+        }
+        Log.e(LOG_TAG, "    ^^^^^^   new phone state: " + state);
+
+        if (state != oldState) {
+            notifyPhoneStateChanged();
+        }
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneFactory.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneFactory.java
new file mode 100644
index 0000000..c9e9762
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneFactory.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.sip;
+
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneNotifier;
+
+import android.content.Context;
+import android.net.sip.SipProfile;
+import android.util.Log;
+
+import java.text.ParseException;
+
+/**
+ * @hide
+ */
+public class SipPhoneFactory {
+    private static PhoneNotifier sPhoneNotifier = makeDefaultPhoneNotifier();
+    private static Context sContext;
+
+    public static void makeDefaultPhones(Context context) {
+        makeDefaultPhone(context);
+    }
+
+    public static void makeDefaultPhone(Context context) {
+        sContext = context;
+        SipPhoneProxy.getInstance().setPhone(
+                makePhone("sip:anonymous@localhost"));
+    }
+
+    public static Phone getDefaultPhone() {
+       return SipPhoneProxy.getInstance();
+    }
+
+    public static SipPhone makePhone(String sipProfileUri) {
+        try {
+            SipProfile profile = new SipProfile.Builder(sipProfileUri).build();
+            return new SipPhone(sContext, sPhoneNotifier, profile);
+        } catch (ParseException e) {
+            Log.v("SipPhoneProxy", "setPhone", e);
+            return null;
+        }
+    }
+
+    private static PhoneNotifier makeDefaultPhoneNotifier() {
+        try {
+            return new com.android.internal.telephony.SipPhoneNotifier();
+        } catch (Error e) {
+            Log.e("SipPhoneProxy", "makeDefaultPhoneNotifier", e);
+            throw e;
+        }
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneProxy.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneProxy.java
new file mode 100644
index 0000000..7cc1a9b
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneProxy.java
@@ -0,0 +1,749 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.sip;
+
+import com.android.internal.telephony.*;
+import com.android.internal.telephony.gsm.NetworkInfo;
+import com.android.internal.telephony.test.SimulatedRadioControl;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.telephony.CellLocation;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * Temporary. Will be removed after integrating with CallManager.
+ * (TODO)
+ * @hide
+ */
+public class SipPhoneProxy implements Phone {
+    private static final String LOG_TAG = "PHONE";
+
+    private static SipPhoneProxy sPhoneProxy = new SipPhoneProxy();
+
+    public static SipPhoneProxy getInstance() {
+        return sPhoneProxy;
+    }
+
+    private SipPhone mActivePhone;
+    private CallProxy mRingingCall = new CallProxy();
+    private CallProxy mForegroundCall = new CallProxy();
+    private CallProxy mBackgroundCall = new CallProxy();
+
+    private SipPhoneProxy() {
+    }
+
+    public void onNewCall(Object call) {
+        if (mActivePhone.canTake(call)) {
+            Log.v("SipPhoneProxy", "onNewCall(): call taken: " + call);
+        } else {
+            Log.v("SipPhoneProxy", "onNewCall(): call dropped: " + call);
+        }
+    }
+
+    public synchronized void setPhone(SipPhone phone) {
+        if (phone == null) return;
+        if (mActivePhone != null) phone.migrateFrom(mActivePhone);
+        mActivePhone = phone;
+        mForegroundCall.setTarget(phone.getForegroundCall());
+        mBackgroundCall.setTarget(phone.getBackgroundCall());
+        mRingingCall.setTarget(phone.getRingingCall());
+    }
+
+    public synchronized Call getForegroundCall() {
+        return mForegroundCall;
+    }
+
+    public synchronized Call getBackgroundCall() {
+        return mBackgroundCall;
+    }
+
+    public synchronized Call getRingingCall() {
+        return mRingingCall;
+    }
+
+
+    public ServiceState getServiceState() {
+        return mActivePhone.getServiceState();
+    }
+
+    public CellLocation getCellLocation() {
+        return mActivePhone.getCellLocation();
+    }
+
+    public DataState getDataConnectionState() {
+        return mActivePhone.getDataConnectionState();
+    }
+
+    public DataActivityState getDataActivityState() {
+        return mActivePhone.getDataActivityState();
+    }
+
+    public Context getContext() {
+        return mActivePhone.getContext();
+    }
+
+    public void disableDnsCheck(boolean b) {
+        mActivePhone.disableDnsCheck(b);
+    }
+
+    public boolean isDnsCheckDisabled() {
+        return mActivePhone.isDnsCheckDisabled();
+    }
+
+    public State getState() {
+        return mActivePhone.getState();
+    }
+
+    public String getPhoneName() {
+        return mActivePhone.getPhoneName();
+    }
+
+    public int getPhoneType() {
+        return mActivePhone.getPhoneType();
+    }
+
+    public String[] getActiveApnTypes() {
+        return mActivePhone.getActiveApnTypes();
+    }
+
+    public String getActiveApn() {
+        return mActivePhone.getActiveApn();
+    }
+
+    public SignalStrength getSignalStrength() {
+        return mActivePhone.getSignalStrength();
+    }
+
+    public void registerForUnknownConnection(Handler h, int what, Object obj) {
+        mActivePhone.registerForUnknownConnection(h, what, obj);
+    }
+
+    public void unregisterForUnknownConnection(Handler h) {
+        mActivePhone.unregisterForUnknownConnection(h);
+    }
+
+    public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) {
+        mActivePhone.registerForPreciseCallStateChanged(h, what, obj);
+    }
+
+    public void unregisterForPreciseCallStateChanged(Handler h) {
+        mActivePhone.unregisterForPreciseCallStateChanged(h);
+    }
+
+    public void registerForNewRingingConnection(Handler h, int what, Object obj) {
+        mActivePhone.registerForNewRingingConnection(h, what, obj);
+    }
+
+    public void unregisterForNewRingingConnection(Handler h) {
+        mActivePhone.unregisterForNewRingingConnection(h);
+    }
+
+    public void registerForIncomingRing(Handler h, int what, Object obj) {
+        mActivePhone.registerForIncomingRing(h, what, obj);
+    }
+
+    public void unregisterForIncomingRing(Handler h) {
+        mActivePhone.unregisterForIncomingRing(h);
+    }
+
+    public void registerForDisconnect(Handler h, int what, Object obj) {
+        mActivePhone.registerForDisconnect(h, what, obj);
+    }
+
+    public void unregisterForDisconnect(Handler h) {
+        mActivePhone.unregisterForDisconnect(h);
+    }
+
+    public void registerForMmiInitiate(Handler h, int what, Object obj) {
+        mActivePhone.registerForMmiInitiate(h, what, obj);
+    }
+
+    public void unregisterForMmiInitiate(Handler h) {
+        mActivePhone.unregisterForMmiInitiate(h);
+    }
+
+    public void registerForMmiComplete(Handler h, int what, Object obj) {
+        mActivePhone.registerForMmiComplete(h, what, obj);
+    }
+
+    public void unregisterForMmiComplete(Handler h) {
+        mActivePhone.unregisterForMmiComplete(h);
+    }
+
+    public List<? extends MmiCode> getPendingMmiCodes() {
+        return mActivePhone.getPendingMmiCodes();
+    }
+
+    public void sendUssdResponse(String ussdMessge) {
+        mActivePhone.sendUssdResponse(ussdMessge);
+    }
+
+    public void registerForServiceStateChanged(Handler h, int what, Object obj) {
+        mActivePhone.registerForServiceStateChanged(h, what, obj);
+    }
+
+    public void unregisterForServiceStateChanged(Handler h) {
+        mActivePhone.unregisterForServiceStateChanged(h);
+    }
+
+    public void registerForSuppServiceNotification(Handler h, int what, Object obj) {
+        mActivePhone.registerForSuppServiceNotification(h, what, obj);
+    }
+
+    public void unregisterForSuppServiceNotification(Handler h) {
+        mActivePhone.unregisterForSuppServiceNotification(h);
+    }
+
+    public void registerForSuppServiceFailed(Handler h, int what, Object obj) {
+        mActivePhone.registerForSuppServiceFailed(h, what, obj);
+    }
+
+    public void unregisterForSuppServiceFailed(Handler h) {
+        mActivePhone.unregisterForSuppServiceFailed(h);
+    }
+
+    public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){
+        mActivePhone.registerForInCallVoicePrivacyOn(h,what,obj);
+    }
+
+    public void unregisterForInCallVoicePrivacyOn(Handler h){
+        mActivePhone.unregisterForInCallVoicePrivacyOn(h);
+    }
+
+    public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){
+        mActivePhone.registerForInCallVoicePrivacyOff(h,what,obj);
+    }
+
+    public void unregisterForInCallVoicePrivacyOff(Handler h){
+        mActivePhone.unregisterForInCallVoicePrivacyOff(h);
+    }
+
+    public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
+        mActivePhone.registerForCdmaOtaStatusChange(h,what,obj);
+    }
+
+    public void unregisterForCdmaOtaStatusChange(Handler h) {
+         mActivePhone.unregisterForCdmaOtaStatusChange(h);
+    }
+
+    public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
+        mActivePhone.registerForSubscriptionInfoReady(h, what, obj);
+    }
+
+    public void unregisterForSubscriptionInfoReady(Handler h) {
+        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 void registerForRingbackTone(Handler h, int what, Object obj) {
+        mActivePhone.registerForRingbackTone(h,what,obj);
+    }
+
+    public void unregisterForRingbackTone(Handler h) {
+        mActivePhone.unregisterForRingbackTone(h);
+    }
+
+    public void registerForResendIncallMute(Handler h, int what, Object obj) {
+        mActivePhone.registerForResendIncallMute(h,what,obj);
+    }
+
+    public void unregisterForResendIncallMute(Handler h) {
+        mActivePhone.unregisterForResendIncallMute(h);
+    }
+
+    public boolean getIccRecordsLoaded() {
+        return mActivePhone.getIccRecordsLoaded();
+    }
+
+    public IccCard getIccCard() {
+        return mActivePhone.getIccCard();
+    }
+
+    public void acceptCall() throws CallStateException {
+        mActivePhone.acceptCall();
+    }
+
+    public void rejectCall() throws CallStateException {
+        mActivePhone.rejectCall();
+    }
+
+    public void switchHoldingAndActive() throws CallStateException {
+        mActivePhone.switchHoldingAndActive();
+    }
+
+    public boolean canConference() {
+        return mActivePhone.canConference();
+    }
+
+    public void conference() throws CallStateException {
+        mActivePhone.conference();
+    }
+
+    public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
+        mActivePhone.enableEnhancedVoicePrivacy(enable, onComplete);
+    }
+
+    public void getEnhancedVoicePrivacy(Message onComplete) {
+        mActivePhone.getEnhancedVoicePrivacy(onComplete);
+    }
+
+    public boolean canTransfer() {
+        return mActivePhone.canTransfer();
+    }
+
+    public void explicitCallTransfer() throws CallStateException {
+        mActivePhone.explicitCallTransfer();
+    }
+
+    public void clearDisconnected() {
+        mActivePhone.clearDisconnected();
+    }
+
+    public Connection dial(String dialString) throws CallStateException {
+        return mActivePhone.dial(dialString);
+    }
+
+    public Connection dial(String dialString, UUSInfo uusInfo) throws CallStateException {
+        return mActivePhone.dial(dialString);
+    }
+
+    public boolean handlePinMmi(String dialString) {
+        return mActivePhone.handlePinMmi(dialString);
+    }
+
+    public boolean handleInCallMmiCommands(String command) throws CallStateException {
+        return mActivePhone.handleInCallMmiCommands(command);
+    }
+
+    public void sendDtmf(char c) {
+        mActivePhone.sendDtmf(c);
+    }
+
+    public void startDtmf(char c) {
+        mActivePhone.startDtmf(c);
+    }
+
+    public void stopDtmf() {
+        mActivePhone.stopDtmf();
+    }
+
+    public void setRadioPower(boolean power) {
+        mActivePhone.setRadioPower(power);
+    }
+
+    public boolean getMessageWaitingIndicator() {
+        return mActivePhone.getMessageWaitingIndicator();
+    }
+
+    public boolean getCallForwardingIndicator() {
+        return mActivePhone.getCallForwardingIndicator();
+    }
+
+    public String getLine1Number() {
+        return mActivePhone.getLine1Number();
+    }
+
+    public String getCdmaMin() {
+        return mActivePhone.getCdmaMin();
+    }
+
+    public boolean isMinInfoReady() {
+        return mActivePhone.isMinInfoReady();
+    }
+
+    public String getCdmaPrlVersion() {
+        return mActivePhone.getCdmaPrlVersion();
+    }
+
+    public String getLine1AlphaTag() {
+        return mActivePhone.getLine1AlphaTag();
+    }
+
+    public void setLine1Number(String alphaTag, String number, Message onComplete) {
+        mActivePhone.setLine1Number(alphaTag, number, onComplete);
+    }
+
+    public String getVoiceMailNumber() {
+        return mActivePhone.getVoiceMailNumber();
+    }
+
+     /** @hide */
+    public int getVoiceMessageCount(){
+        return mActivePhone.getVoiceMessageCount();
+    }
+
+    public String getVoiceMailAlphaTag() {
+        return mActivePhone.getVoiceMailAlphaTag();
+    }
+
+    public void setVoiceMailNumber(String alphaTag,String voiceMailNumber,
+            Message onComplete) {
+        mActivePhone.setVoiceMailNumber(alphaTag, voiceMailNumber, onComplete);
+    }
+
+    public void getCallForwardingOption(int commandInterfaceCFReason,
+            Message onComplete) {
+        mActivePhone.getCallForwardingOption(commandInterfaceCFReason,
+                onComplete);
+    }
+
+    public void setCallForwardingOption(int commandInterfaceCFReason,
+            int commandInterfaceCFAction, String dialingNumber,
+            int timerSeconds, Message onComplete) {
+        mActivePhone.setCallForwardingOption(commandInterfaceCFReason,
+            commandInterfaceCFAction, dialingNumber, timerSeconds, onComplete);
+    }
+
+    public void getOutgoingCallerIdDisplay(Message onComplete) {
+        mActivePhone.getOutgoingCallerIdDisplay(onComplete);
+    }
+
+    public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode,
+            Message onComplete) {
+        mActivePhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode,
+                onComplete);
+    }
+
+    public void getCallWaiting(Message onComplete) {
+        mActivePhone.getCallWaiting(onComplete);
+    }
+
+    public void setCallWaiting(boolean enable, Message onComplete) {
+        mActivePhone.setCallWaiting(enable, onComplete);
+    }
+
+    public void getAvailableNetworks(Message response) {
+        mActivePhone.getAvailableNetworks(response);
+    }
+
+    public void setNetworkSelectionModeAutomatic(Message response) {
+        mActivePhone.setNetworkSelectionModeAutomatic(response);
+    }
+
+    public void selectNetworkManually(NetworkInfo network, Message response) {
+        mActivePhone.selectNetworkManually(network, response);
+    }
+
+    public void setPreferredNetworkType(int networkType, Message response) {
+        mActivePhone.setPreferredNetworkType(networkType, response);
+    }
+
+    public void getPreferredNetworkType(Message response) {
+        mActivePhone.getPreferredNetworkType(response);
+    }
+
+    public void getNeighboringCids(Message response) {
+        mActivePhone.getNeighboringCids(response);
+    }
+
+    public void setOnPostDialCharacter(Handler h, int what, Object obj) {
+        mActivePhone.setOnPostDialCharacter(h, what, obj);
+    }
+
+    public void setMute(boolean muted) {
+        mActivePhone.setMute(muted);
+    }
+
+    public boolean getMute() {
+        return mActivePhone.getMute();
+    }
+
+    public void invokeOemRilRequestRaw(byte[] data, Message response) {
+        mActivePhone.invokeOemRilRequestRaw(data, response);
+    }
+
+    public void invokeOemRilRequestStrings(String[] strings, Message response) {
+        mActivePhone.invokeOemRilRequestStrings(strings, response);
+    }
+
+    public void getDataCallList(Message response) {
+        mActivePhone.getDataCallList(response);
+    }
+
+    public List<DataConnection> getCurrentDataConnectionList() {
+        return mActivePhone.getCurrentDataConnectionList();
+    }
+
+    public void updateServiceLocation() {
+        mActivePhone.updateServiceLocation();
+    }
+
+    public void enableLocationUpdates() {
+        mActivePhone.enableLocationUpdates();
+    }
+
+    public void disableLocationUpdates() {
+        mActivePhone.disableLocationUpdates();
+    }
+
+    public void setUnitTestMode(boolean f) {
+        mActivePhone.setUnitTestMode(f);
+    }
+
+    public boolean getUnitTestMode() {
+        return mActivePhone.getUnitTestMode();
+    }
+
+    public void setBandMode(int bandMode, Message response) {
+        mActivePhone.setBandMode(bandMode, response);
+    }
+
+    public void queryAvailableBandMode(Message response) {
+        mActivePhone.queryAvailableBandMode(response);
+    }
+
+    public boolean getDataRoamingEnabled() {
+        return mActivePhone.getDataRoamingEnabled();
+    }
+
+    public void setDataRoamingEnabled(boolean enable) {
+        mActivePhone.setDataRoamingEnabled(enable);
+    }
+
+    public void queryCdmaRoamingPreference(Message response) {
+        mActivePhone.queryCdmaRoamingPreference(response);
+    }
+
+    public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) {
+        mActivePhone.setCdmaRoamingPreference(cdmaRoamingType, response);
+    }
+
+    public void setCdmaSubscription(int cdmaSubscriptionType, Message response) {
+        mActivePhone.setCdmaSubscription(cdmaSubscriptionType, response);
+    }
+
+    public SimulatedRadioControl getSimulatedRadioControl() {
+        return mActivePhone.getSimulatedRadioControl();
+    }
+
+    public boolean enableDataConnectivity() {
+        return mActivePhone.enableDataConnectivity();
+    }
+
+    public boolean disableDataConnectivity() {
+        return mActivePhone.disableDataConnectivity();
+    }
+
+    public int enableApnType(String type) {
+        return mActivePhone.enableApnType(type);
+    }
+
+    public int disableApnType(String type) {
+        return mActivePhone.disableApnType(type);
+    }
+
+    public boolean isDataConnectivityEnabled() {
+        return mActivePhone.isDataConnectivityEnabled();
+    }
+
+    public boolean isDataConnectivityPossible() {
+        return mActivePhone.isDataConnectivityPossible();
+    }
+
+    public String getInterfaceName(String apnType) {
+        return mActivePhone.getInterfaceName(apnType);
+    }
+
+    public String getIpAddress(String apnType) {
+        return mActivePhone.getIpAddress(apnType);
+    }
+
+    public String getGateway(String apnType) {
+        return mActivePhone.getGateway(apnType);
+    }
+
+    public String[] getDnsServers(String apnType) {
+        return mActivePhone.getDnsServers(apnType);
+    }
+
+    public String getDeviceId() {
+        return mActivePhone.getDeviceId();
+    }
+
+    public String getDeviceSvn() {
+        return mActivePhone.getDeviceSvn();
+    }
+
+    public String getSubscriberId() {
+        return mActivePhone.getSubscriberId();
+    }
+
+    public String getIccSerialNumber() {
+        return mActivePhone.getIccSerialNumber();
+    }
+
+    public String getEsn() {
+        return mActivePhone.getEsn();
+    }
+
+    public String getMeid() {
+        return mActivePhone.getMeid();
+    }
+
+    public PhoneSubInfo getPhoneSubInfo(){
+        return mActivePhone.getPhoneSubInfo();
+    }
+
+    public IccSmsInterfaceManager getIccSmsInterfaceManager(){
+        return mActivePhone.getIccSmsInterfaceManager();
+    }
+
+    public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
+        return mActivePhone.getIccPhoneBookInterfaceManager();
+    }
+
+    public void setTTYMode(int ttyMode, Message onComplete) {
+        mActivePhone.setTTYMode(ttyMode, onComplete);
+    }
+
+    public void queryTTYMode(Message onComplete) {
+        mActivePhone.queryTTYMode(onComplete);
+    }
+
+    public void activateCellBroadcastSms(int activate, Message response) {
+        mActivePhone.activateCellBroadcastSms(activate, response);
+    }
+
+    public void getCellBroadcastSmsConfig(Message response) {
+        mActivePhone.getCellBroadcastSmsConfig(response);
+    }
+
+    public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
+        mActivePhone.setCellBroadcastSmsConfig(configValuesArray, response);
+    }
+
+    public void notifyDataActivity() {
+         mActivePhone.notifyDataActivity();
+    }
+
+    public void getSmscAddress(Message result) {
+        mActivePhone.getSmscAddress(result);
+    }
+
+    public void setSmscAddress(String address, Message result) {
+        mActivePhone.setSmscAddress(address, result);
+    }
+
+    public int getCdmaEriIconIndex() {
+         return mActivePhone.getCdmaEriIconIndex();
+    }
+
+     public String getCdmaEriText() {
+         return mActivePhone.getCdmaEriText();
+     }
+
+    public int getCdmaEriIconMode() {
+         return mActivePhone.getCdmaEriIconMode();
+    }
+
+    public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete){
+        mActivePhone.sendBurstDtmf(dtmfString, on, off, onComplete);
+    }
+
+    public void exitEmergencyCallbackMode(){
+        mActivePhone.exitEmergencyCallbackMode();
+    }
+
+    public boolean isOtaSpNumber(String dialStr){
+        return mActivePhone.isOtaSpNumber(dialStr);
+    }
+
+    public void registerForCallWaiting(Handler h, int what, Object obj){
+        mActivePhone.registerForCallWaiting(h,what,obj);
+    }
+
+    public void unregisterForCallWaiting(Handler h){
+        mActivePhone.unregisterForCallWaiting(h);
+    }
+
+    public void registerForSignalInfo(Handler h, int what, Object obj) {
+        mActivePhone.registerForSignalInfo(h,what,obj);
+    }
+
+    public void unregisterForSignalInfo(Handler h) {
+        mActivePhone.unregisterForSignalInfo(h);
+    }
+
+    public void registerForDisplayInfo(Handler h, int what, Object obj) {
+        mActivePhone.registerForDisplayInfo(h,what,obj);
+    }
+
+    public void unregisterForDisplayInfo(Handler h) {
+        mActivePhone.unregisterForDisplayInfo(h);
+    }
+
+    public void registerForNumberInfo(Handler h, int what, Object obj) {
+        mActivePhone.registerForNumberInfo(h, what, obj);
+    }
+
+    public void unregisterForNumberInfo(Handler h) {
+        mActivePhone.unregisterForNumberInfo(h);
+    }
+
+    public void registerForRedirectedNumberInfo(Handler h, int what, Object obj) {
+        mActivePhone.registerForRedirectedNumberInfo(h, what, obj);
+    }
+
+    public void unregisterForRedirectedNumberInfo(Handler h) {
+        mActivePhone.unregisterForRedirectedNumberInfo(h);
+    }
+
+    public void registerForLineControlInfo(Handler h, int what, Object obj) {
+        mActivePhone.registerForLineControlInfo( h, what, obj);
+    }
+
+    public void unregisterForLineControlInfo(Handler h) {
+        mActivePhone.unregisterForLineControlInfo(h);
+    }
+
+    public void registerFoT53ClirlInfo(Handler h, int what, Object obj) {
+        mActivePhone.registerFoT53ClirlInfo(h, what, obj);
+    }
+
+    public void unregisterForT53ClirInfo(Handler h) {
+        mActivePhone.unregisterForT53ClirInfo(h);
+    }
+
+    public void registerForT53AudioControlInfo(Handler h, int what, Object obj) {
+        mActivePhone.registerForT53AudioControlInfo( h, what, obj);
+    }
+
+    public void unregisterForT53AudioControlInfo(Handler h) {
+        mActivePhone.unregisterForT53AudioControlInfo(h);
+    }
+
+    public void setOnEcbModeExitResponse(Handler h, int what, Object obj){
+        mActivePhone.setOnEcbModeExitResponse(h,what,obj);
+    }
+
+    public void unsetOnEcbModeExitResponse(Handler h){
+        mActivePhone.unsetOnEcbModeExitResponse(h);
+    }
+}