/* * 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.LinkProperties; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; import android.os.SystemProperties; import android.telephony.CellInfo; import android.telephony.CellLocation; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.util.Log; import com.android.internal.telephony.Call; import com.android.internal.telephony.CallStateException; 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.OperatorInfo; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneBase; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneNotifier; import com.android.internal.telephony.PhoneSubInfo; import com.android.internal.telephony.TelephonyProperties; import com.android.internal.telephony.UUSInfo; import java.util.ArrayList; import java.util.List; abstract class SipPhoneBase extends PhoneBase { private static final String LOG_TAG = "SipPhone"; private RegistrantList mRingbackRegistrants = new RegistrantList(); private PhoneConstants.State state = PhoneConstants.State.IDLE; public SipPhoneBase(Context context, PhoneNotifier notifier) { super(notifier, context, new SipCommandInterface(context), false); } 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, Boolean.TRUE, null); mRingbackRegistrants.notifyRegistrants(result); } protected void stopRingbackTone() { AsyncResult result = new AsyncResult(null, Boolean.FALSE, null); mRingbackRegistrants.notifyRegistrants(result); } 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; } /** * @return all available cell information or null if none. */ @Override public List getAllCellInfo() { return getServiceStateTracker().getAllCellInfo(); } public CellLocation getCellLocation() { return null; } public PhoneConstants.State getState() { return state; } public int getPhoneType() { return PhoneConstants.PHONE_TYPE_SIP; } public SignalStrength getSignalStrength() { return new SignalStrength(); } public boolean getMessageWaitingIndicator() { return false; } public boolean getCallForwardingIndicator() { return false; } public List getPendingMmiCodes() { return new ArrayList(0); } public PhoneConstants.DataState getDataConnectionState() { return PhoneConstants.DataState.DISCONNECTED; } public PhoneConstants.DataState getDataConnectionState(String apnType) { return PhoneConstants.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) { 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 getImei() { 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(); } public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) { } public void setCallForwardingOption(int commandInterfaceCFAction, int commandInterfaceCFReason, String dialingNumber, int timerSeconds, Message onComplete) { } 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) { AsyncResult.forMessage(onComplete, null, null); onComplete.sendToTarget(); } public void setCallWaiting(boolean enable, Message onComplete) { Log.e(LOG_TAG, "call waiting not supported"); } public boolean getIccRecordsLoaded() { return false; } public IccCard getIccCard() { return null; } public void getAvailableNetworks(Message response) { } public void setNetworkSelectionModeAutomatic(Message response) { } public void selectNetworkManually( OperatorInfo network, Message response) { } public void getNeighboringCids(Message response) { } public void setOnPostDialCharacter(Handler h, int what, Object obj) { } public void getDataCallList(Message response) { } public List 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) { } public PhoneSubInfo getPhoneSubInfo(){ return null; } public IccSmsInterfaceManager getIccSmsInterfaceManager(){ return null; } public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){ return null; } 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."); } //@Override public boolean needsOtaServiceProvisioning() { // FIXME: what's this for SIP? return false; } //@Override public LinkProperties getLinkProperties(String apnType) { // FIXME: what's this for SIP? return null; } void updatePhoneState() { PhoneConstants.State oldState = state; if (getRingingCall().isRinging()) { state = PhoneConstants.State.RINGING; } else if (getForegroundCall().isIdle() && getBackgroundCall().isIdle()) { state = PhoneConstants.State.IDLE; } else { state = PhoneConstants.State.OFFHOOK; } if (state != oldState) { Log.d(LOG_TAG, " ^^^ new phone state: " + state); notifyPhoneStateChanged(); } } @Override protected void onUpdateIccAvailability() { } }