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 0000000000000..4c4e718928529 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SipPhoneNotifier.java @@ -0,0 +1,258 @@ +/* + * 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.net.LinkCapabilities; +import android.net.LinkProperties; +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, String apnType) { + doNotifyDataConnection(sender, reason, apnType, sender.getDataConnectionState(apnType)); + } + + public void notifyDataConnection(Phone sender, String reason, String apnType, + Phone.DataState state) { + doNotifyDataConnection(sender, reason, apnType, state); + } + + private void doNotifyDataConnection(Phone sender, String reason, String apnType, + Phone.DataState state) { + // TODO + // use apnType as the key to which connection we're talking about. + // pass apnType back up to fetch particular for this one. + TelephonyManager telephony = TelephonyManager.getDefault(); + LinkProperties linkProperties = null; + LinkCapabilities linkCapabilities = null; + if (state == Phone.DataState.CONNECTED) { + linkProperties = sender.getLinkProperties(apnType); + linkCapabilities = sender.getLinkCapabilities(apnType); + } + try { + mRegistry.notifyDataConnection( + convertDataState(state), + sender.isDataConnectivityPossible(), reason, + sender.getActiveApn(), + apnType, + linkProperties, + linkCapabilities, + ((telephony!=null) ? telephony.getNetworkType() : + TelephonyManager.NETWORK_TYPE_UNKNOWN)); + } catch (RemoteException ex) { + // system process is dead + } + } + + public void notifyDataConnectionFailed(Phone sender, String reason, String apnType) { + try { + mRegistry.notifyDataConnectionFailed(reason, apnType); + } 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 0000000000000..58fb408b6161c --- /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 0000000000000..fad9663cf2c31 --- /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 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 index 9050a4382a59b..7e407b2122c4f 100644 --- a/telephony/java/com/android/internal/telephony/sip/SipCallBase.java +++ b/telephony/java/com/android/internal/telephony/sip/SipCallBase.java @@ -19,6 +19,7 @@ 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; @@ -27,10 +28,15 @@ import java.util.Iterator; import java.util.List; abstract class SipCallBase extends Call { + private static final int MAX_CONNECTIONS_PER_CALL = 5; + protected List connections = new ArrayList(); protected abstract void setState(State newState); + public void dispose() { + } + public List getConnections() { // FIXME should return Collections.unmodifiableList(); return connections; @@ -41,7 +47,48 @@ abstract class SipCallBase extends Call { } public String toString() { - return state.toString() + ":" + super.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() { diff --git a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java index ed578c89938ac..33c89f862e511 100644 --- a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java +++ b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java @@ -330,6 +330,7 @@ class SipCommandInterface extends BaseCommands implements CommandsInterface { public void setGsmBroadcastActivation(boolean activate, Message response) { } + // ***** Methods for CDMA support public void getDeviceIdentity(Message response) { } diff --git a/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java b/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java index 5f7efd41da89c..f5d84eb62d976 100644 --- a/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java +++ b/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java @@ -16,16 +16,29 @@ package com.android.internal.telephony.sip; -import com.android.internal.telephony.Call; -import com.android.internal.telephony.Connection; -import com.android.internal.telephony.Phone; - +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; @@ -34,6 +47,10 @@ abstract class SipConnectionBase extends Connection { 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(), @@ -150,6 +167,55 @@ abstract class SipConnectionBase extends Connection { 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 diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java index 55e3002769217..38700cd7f2cb9 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java @@ -16,7 +16,10 @@ 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.rtp.AudioStream; import android.net.sip.SipAudioCall; @@ -26,20 +29,42 @@ import android.net.sip.SipManager; import android.net.sip.SipProfile; import android.net.sip.SipSession; 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 java.io.IOException; import java.text.ParseException; +import java.util.ArrayList; import java.util.List; /** @@ -47,7 +72,7 @@ import java.util.List; */ public class SipPhone extends SipPhoneBase { private static final String LOG_TAG = "SipPhone"; - private static final boolean DEBUG = true; + private static final boolean LOCAL_DEBUG = true; private static final int TIMEOUT_MAKE_CALL = 15; // in seconds private static final int TIMEOUT_ANSWER_CALL = 8; // in seconds private static final int TIMEOUT_HOLD_CALL = 15; // in seconds @@ -63,12 +88,17 @@ public class SipPhone extends SipPhoneBase { SipPhone (Context context, PhoneNotifier notifier, SipProfile profile) { super(context, notifier); - if (DEBUG) Log.d(LOG_TAG, "new SipPhone: " + profile.getUriString()); + Log.v(LOG_TAG, " +++++++++++++++++++++ new SipPhone: " + profile.getUriString()); ringingCall = new SipCall(); foregroundCall = new SipCall(); backgroundCall = new SipCall(); mProfile = profile; mSipManager = SipManager.newInstance(context); + + // FIXME: what's this for SIP? + //Change the system property + //SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE, + // new Integer(Phone.PHONE_TYPE_GSM).toString()); } @Override @@ -105,7 +135,7 @@ public class SipPhone extends SipPhoneBase { try { SipAudioCall sipAudioCall = (SipAudioCall) incomingCall; - if (DEBUG) Log.d(LOG_TAG, "+++ taking call from: " + Log.d(LOG_TAG, "+++ taking call from: " + sipAudioCall.getPeerProfile().getUriString()); String localUri = sipAudioCall.getLocalProfile().getUriString(); if (localUri.equals(mProfile.getUriString())) { @@ -114,7 +144,7 @@ public class SipPhone extends SipPhoneBase { if (sipAudioCall.getState() != SipSession.State.INCOMING_CALL) { // Peer cancelled the call! - if (DEBUG) Log.d(LOG_TAG, " call cancelled !!"); + Log.d(LOG_TAG, " call cancelled !!"); ringingCall.reset(); } return true; @@ -131,9 +161,13 @@ public class SipPhone extends SipPhoneBase { 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) || (ringingCall.getState() == Call.State.WAITING)) { - if (DEBUG) Log.d(LOG_TAG, "acceptCall"); + Log.v(LOG_TAG, "acceptCall"); // Always unmute when answering a new call setMute(false); ringingCall.acceptCall(); @@ -146,7 +180,7 @@ public class SipPhone extends SipPhoneBase { public void rejectCall() throws CallStateException { synchronized (SipPhone.class) { if (ringingCall.getState().isRinging()) { - if (DEBUG) Log.d(LOG_TAG, "rejectCall"); + Log.v(LOG_TAG, "rejectCall"); ringingCall.rejectCall(); } else { throw new CallStateException("phone not ringing"); @@ -162,6 +196,10 @@ public class SipPhone extends SipPhoneBase { 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()) { @@ -176,6 +214,7 @@ public class SipPhone extends SipPhoneBase { } setMute(false); + //cm.dial(pendingMO.address, clirMode, obtainCompleteMessage()); try { Connection c = foregroundCall.dial(dialString); return c; @@ -186,7 +225,7 @@ public class SipPhone extends SipPhoneBase { } public void switchHoldingAndActive() throws CallStateException { - if (DEBUG) Log.d(LOG_TAG, " ~~~~~~ switch fg and bg"); + Log.v(LOG_TAG, " ~~~~~~ switch fg and bg"); synchronized (SipPhone.class) { foregroundCall.switchWith(backgroundCall); if (backgroundCall.getState().isAlive()) backgroundCall.hold(); @@ -300,9 +339,8 @@ public class SipPhone extends SipPhoneBase { audioGroup.setMode(enabled ? AudioGroup.MODE_ECHO_SUPPRESSION : AudioGroup.MODE_NORMAL); - if (DEBUG) Log.d(LOG_TAG, String.format( - "audioGroup mode change: %d --> %d", mode, - audioGroup.getMode())); + Log.d(LOG_TAG, String.format("audioGroup mode change: %d --> %d", + mode, audioGroup.getMode())); } } @@ -392,11 +430,9 @@ public class SipPhone extends SipPhoneBase { CallerInfo info = new CallerInfo(); info.name = name; info.phoneNumber = number; - if (DEBUG) { - Log.d(LOG_TAG, "create caller info from scratch:"); - Log.d(LOG_TAG, " name: " + info.name); - Log.d(LOG_TAG, " numb: " + info.phoneNumber); - } + Log.v(LOG_TAG, "create caller info from scratch:"); + Log.v(LOG_TAG, " name: " + info.name); + Log.v(LOG_TAG, " numb: " + info.phoneNumber); return info; } @@ -404,12 +440,10 @@ public class SipPhone extends SipPhoneBase { private CallerInfo findCallerInfo(String number) { CallerInfo info = CallerInfo.getCallerInfo(mContext, number); if ((info == null) || (info.name == null)) return null; - if (DEBUG) { - Log.d(LOG_TAG, "got caller info from contact:"); - Log.d(LOG_TAG, " name: " + info.name); - Log.d(LOG_TAG, " numb: " + info.phoneNumber); - Log.d(LOG_TAG, " pres: " + info.numberPresentation); - } + Log.v(LOG_TAG, "got caller 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; } @@ -443,8 +477,8 @@ public class SipPhone extends SipPhoneBase { public void hangup() throws CallStateException { synchronized (SipPhone.class) { if (state.isAlive()) { - if (DEBUG) Log.d(LOG_TAG, "hang up call: " + getState() - + ": " + this + " on phone " + getPhone()); + Log.d(LOG_TAG, "hang up call: " + getState() + ": " + this + + " on phone " + getPhone()); setState(State.DISCONNECTING); CallStateException excp = null; for (Connection c : connections) { @@ -456,8 +490,8 @@ public class SipPhone extends SipPhoneBase { } if (excp != null) throw excp; } else { - if (DEBUG) Log.d(LOG_TAG, "hang up dead call: " + getState() - + ": " + this + " on phone " + getPhone()); + Log.d(LOG_TAG, "hang up dead call: " + getState() + ": " + + this + " on phone " + getPhone()); } } } @@ -569,7 +603,7 @@ public class SipPhone extends SipPhoneBase { @Override protected void setState(State newState) { if (state != newState) { - if (DEBUG) Log.v(LOG_TAG, "+***+ call state changed: " + state + Log.v(LOG_TAG, "++******++ call state changed: " + state + " --> " + newState + ": " + this + ": on phone " + getPhone() + " " + connections.size()); @@ -596,11 +630,10 @@ public class SipPhone extends SipPhoneBase { // set state to DISCONNECTED only when all conns are disconnected if (state != State.DISCONNECTED) { boolean allConnectionsDisconnected = true; - if (DEBUG) Log.d(LOG_TAG, "---check connections: " + Log.v(LOG_TAG, "---check if all connections are disconnected: " + connections.size()); for (Connection c : connections) { - if (DEBUG) Log.d(LOG_TAG, " state=" + c.getState() + ": " - + c); + Log.v(LOG_TAG, " state=" + c.getState() + ": " + c); if (c.getState() != State.DISCONNECTED) { allConnectionsDisconnected = false; break; @@ -637,7 +670,7 @@ public class SipPhone extends SipPhoneBase { String sessionState = (sipAudioCall == null) ? "" : (sipAudioCall.getState() + ", "); - if (DEBUG) Log.d(LOG_TAG, "--- connection ended: " + Log.v(LOG_TAG, "--- connection ended: " + mPeer.getUriString() + ": " + sessionState + "cause: " + getDisconnectCause() + ", on phone " + getPhone()); @@ -684,7 +717,7 @@ public class SipPhone extends SipPhoneBase { setState(newState); } mOwner.onConnectionStateChanged(SipConnection.this); - if (DEBUG) Log.v(LOG_TAG, "+***+ connection state changed: " + Log.v(LOG_TAG, "++******++ connection state changed: " + mPeer.getUriString() + ": " + mState + " on phone " + getPhone()); } @@ -692,7 +725,7 @@ public class SipPhone extends SipPhoneBase { @Override protected void onError(DisconnectCause cause) { - if (DEBUG) Log.d(LOG_TAG, "SIP error: " + cause); + Log.w(LOG_TAG, "SIP error: " + cause); if (mSipAudioCall.isInCall() && (cause != DisconnectCause.LOST_SIGNAL)) { // Don't end the call when in a call. @@ -797,9 +830,8 @@ public class SipPhone extends SipPhoneBase { @Override public void hangup() throws CallStateException { synchronized (SipPhone.class) { - if (DEBUG) Log.d(LOG_TAG, "hangup conn: " + mPeer.getUriString() - + ": " + mState + ": on phone " - + getPhone().getPhoneName()); + Log.v(LOG_TAG, "hangup conn: " + mPeer.getUriString() + ": " + + mState + ": on phone " + getPhone().getPhoneName()); if (!mState.isAlive()) return; try { SipAudioCall sipAudioCall = mSipAudioCall; @@ -824,9 +856,8 @@ public class SipPhone extends SipPhoneBase { "cannot put conn back to a call in non-idle state: " + call.getState()); } - if (DEBUG) Log.d(LOG_TAG, "separate conn: " - + mPeer.getUriString() + " from " + mOwner + " back to " - + call); + Log.v(LOG_TAG, "separate conn: " + mPeer.getUriString() + + " from " + mOwner + " back to " + call); AudioGroup audioGroup = call.getAudioGroup(); // may be null call.add(this); diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java index afd4d0c45a3d2..5f26af4eeb402 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java @@ -16,21 +16,43 @@ package com.android.internal.telephony.sip; +import android.content.ContentValues; import android.content.Context; +import android.content.SharedPreferences; import android.net.LinkProperties; +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; @@ -41,21 +63,38 @@ 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 { - private static final String LOG_TAG = "SipPhone"; + // 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 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(); @@ -110,6 +149,15 @@ abstract class SipPhoneBase extends PhoneBase { 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 @@ -119,7 +167,7 @@ abstract class SipPhoneBase extends PhoneBase { } public CellLocation getCellLocation() { - return null; + return null; //mSST.cellLoc; } public State getState() { @@ -175,6 +223,7 @@ abstract class SipPhoneBase extends PhoneBase { } void notifyNewRingingConnection(Connection c) { + /* we'd love it if this was package-scoped*/ super.notifyNewRingingConnectionP(c); } @@ -302,12 +351,53 @@ abstract class SipPhoneBase extends PhoneBase { 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) { @@ -324,11 +414,13 @@ abstract class SipPhoneBase extends PhoneBase { } 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"); } @@ -341,23 +433,29 @@ abstract class SipPhoneBase extends PhoneBase { } 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 getCurrentDataConnectionList () { @@ -397,20 +495,27 @@ abstract class SipPhoneBase extends PhoneBase { } public void saveClirSetting(int commandInterfaceCLIRMode) { + // FIXME: what's this for SIP? } + /** + * Retrieves the PhoneSubInfo of the SipPhone + */ public PhoneSubInfo getPhoneSubInfo(){ - return null; + return mSubInfo; } + /** {@inheritDoc} */ public IccSmsInterfaceManager getIccSmsInterfaceManager(){ return null; } + /** {@inheritDoc} */ public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){ return null; } + /** {@inheritDoc} */ public IccFileHandler getIccFileHandler(){ return null; } @@ -450,9 +555,9 @@ abstract class SipPhoneBase extends PhoneBase { } else { state = State.OFFHOOK; } + Log.e(LOG_TAG, " ^^^^^^ new phone state: " + state); if (state != oldState) { - Log.d(LOG_TAG, " ^^^ new phone state: " + state); notifyPhoneStateChanged(); } }