1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony.sip; 18 19 import android.content.Context; 20 import android.os.AsyncResult; 21 import android.os.Handler; 22 import android.os.Message; 23 import android.os.Registrant; 24 import android.os.RegistrantList; 25 import android.os.SystemProperties; 26 import android.telephony.CellLocation; 27 import android.telephony.ServiceState; 28 import android.telephony.SignalStrength; 29 import android.util.Log; 30 31 import com.android.internal.telephony.Call; 32 import com.android.internal.telephony.CallStateException; 33 import com.android.internal.telephony.Connection; 34 import com.android.internal.telephony.DataConnection; 35 import com.android.internal.telephony.IccCard; 36 import com.android.internal.telephony.IccFileHandler; 37 import com.android.internal.telephony.IccPhoneBookInterfaceManager; 38 import com.android.internal.telephony.IccSmsInterfaceManager; 39 import com.android.internal.telephony.MmiCode; 40 import com.android.internal.telephony.Phone; 41 import com.android.internal.telephony.PhoneBase; 42 import com.android.internal.telephony.PhoneNotifier; 43 import com.android.internal.telephony.PhoneSubInfo; 44 import com.android.internal.telephony.TelephonyProperties; 45 46 import java.util.ArrayList; 47 import java.util.List; 48 49 abstract class SipPhoneBase extends PhoneBase { 50 private static final String LOG_TAG = "SipPhone"; 51 52 private RegistrantList mRingbackRegistrants = new RegistrantList(); 53 private State state = State.IDLE; 54 55 public SipPhoneBase(Context context, PhoneNotifier notifier) { 56 super(notifier, context, new SipCommandInterface(context), false); 57 } 58 59 public abstract Call getForegroundCall(); 60 61 public abstract Call getBackgroundCall(); 62 63 public abstract Call getRingingCall(); 64 65 void migrateFrom(SipPhoneBase from) { 66 migrate(mRingbackRegistrants, from.mRingbackRegistrants); 67 migrate(mPreciseCallStateRegistrants, from.mPreciseCallStateRegistrants); 68 migrate(mNewRingingConnectionRegistrants, from.mNewRingingConnectionRegistrants); 69 migrate(mIncomingRingRegistrants, from.mIncomingRingRegistrants); 70 migrate(mDisconnectRegistrants, from.mDisconnectRegistrants); 71 migrate(mServiceStateRegistrants, from.mServiceStateRegistrants); 72 migrate(mMmiCompleteRegistrants, from.mMmiCompleteRegistrants); 73 migrate(mMmiRegistrants, from.mMmiRegistrants); 74 migrate(mUnknownConnectionRegistrants, from.mUnknownConnectionRegistrants); 75 migrate(mSuppServiceFailedRegistrants, from.mSuppServiceFailedRegistrants); 76 } 77 78 static void migrate(RegistrantList to, RegistrantList from) { 79 from.removeCleared(); 80 for (int i = 0, n = from.size(); i < n; i++) { 81 to.add((Registrant) from.get(i)); 82 } 83 } 84 85 @Override 86 public void registerForRingbackTone(Handler h, int what, Object obj) { 87 mRingbackRegistrants.addUnique(h, what, obj); 88 } 89 90 @Override 91 public void unregisterForRingbackTone(Handler h) { 92 mRingbackRegistrants.remove(h); 93 } 94 95 protected void startRingbackTone() { 96 AsyncResult result = new AsyncResult(null, new Boolean(true), null); 97 mRingbackRegistrants.notifyRegistrants(result); 98 } 99 100 protected void stopRingbackTone() { 101 AsyncResult result = new AsyncResult(null, new Boolean(false), null); 102 mRingbackRegistrants.notifyRegistrants(result); 103 } 104 105 public ServiceState getServiceState() { 106 // FIXME: we may need to provide this when data connectivity is lost 107 // or when server is down 108 ServiceState s = new ServiceState(); 109 s.setState(ServiceState.STATE_IN_SERVICE); 110 return s; 111 } 112 113 public CellLocation getCellLocation() { 114 return null; 115 } 116 117 public State getState() { 118 return state; 119 } 120 121 public int getPhoneType() { 122 return Phone.PHONE_TYPE_SIP; 123 } 124 125 public SignalStrength getSignalStrength() { 126 return new SignalStrength(); 127 } 128 129 public boolean getMessageWaitingIndicator() { 130 return false; 131 } 132 133 public boolean getCallForwardingIndicator() { 134 return false; 135 } 136 137 public List<? extends MmiCode> getPendingMmiCodes() { 138 return new ArrayList<MmiCode>(0); 139 } 140 141 public DataState getDataConnectionState() { 142 return DataState.DISCONNECTED; 143 } 144 145 public DataState getDataConnectionState(String apnType) { 146 return DataState.DISCONNECTED; 147 } 148 149 public DataActivityState getDataActivityState() { 150 return DataActivityState.NONE; 151 } 152 153 /** 154 * Notify any interested party of a Phone state change {@link Phone.State} 155 */ 156 void notifyPhoneStateChanged() { 157 mNotifier.notifyPhoneState(this); 158 } 159 160 /** 161 * Notify registrants of a change in the call state. This notifies changes in {@link Call.State} 162 * Use this when changes in the precise call state are needed, else use notifyPhoneStateChanged. 163 */ 164 void notifyPreciseCallStateChanged() { 165 /* we'd love it if this was package-scoped*/ 166 super.notifyPreciseCallStateChangedP(); 167 } 168 169 void notifyNewRingingConnection(Connection c) { 170 super.notifyNewRingingConnectionP(c); 171 } 172 173 void notifyDisconnect(Connection cn) { 174 mDisconnectRegistrants.notifyResult(cn); 175 } 176 177 void notifyUnknownConnection() { 178 mUnknownConnectionRegistrants.notifyResult(this); 179 } 180 181 void notifySuppServiceFailed(SuppService code) { 182 mSuppServiceFailedRegistrants.notifyResult(code); 183 } 184 185 void notifyServiceStateChanged(ServiceState ss) { 186 super.notifyServiceStateChangedP(ss); 187 } 188 189 public void notifyCallForwardingIndicator() { 190 mNotifier.notifyCallForwardingChanged(this); 191 } 192 193 public boolean canDial() { 194 int serviceState = getServiceState().getState(); 195 Log.v(LOG_TAG, "canDial(): serviceState = " + serviceState); 196 if (serviceState == ServiceState.STATE_POWER_OFF) return false; 197 198 String disableCall = SystemProperties.get( 199 TelephonyProperties.PROPERTY_DISABLE_CALL, "false"); 200 Log.v(LOG_TAG, "canDial(): disableCall = " + disableCall); 201 if (disableCall.equals("true")) return false; 202 203 Log.v(LOG_TAG, "canDial(): ringingCall: " + getRingingCall().getState()); 204 Log.v(LOG_TAG, "canDial(): foregndCall: " + getForegroundCall().getState()); 205 Log.v(LOG_TAG, "canDial(): backgndCall: " + getBackgroundCall().getState()); 206 return !getRingingCall().isRinging() 207 && (!getForegroundCall().getState().isAlive() 208 || !getBackgroundCall().getState().isAlive()); 209 } 210 211 public boolean handleInCallMmiCommands(String dialString) 212 throws CallStateException { 213 return false; 214 } 215 216 boolean isInCall() { 217 Call.State foregroundCallState = getForegroundCall().getState(); 218 Call.State backgroundCallState = getBackgroundCall().getState(); 219 Call.State ringingCallState = getRingingCall().getState(); 220 221 return (foregroundCallState.isAlive() || backgroundCallState.isAlive() 222 || ringingCallState.isAlive()); 223 } 224 225 public boolean handlePinMmi(String dialString) { 226 return false; 227 } 228 229 public void sendUssdResponse(String ussdMessge) { 230 } 231 232 public void registerForSuppServiceNotification( 233 Handler h, int what, Object obj) { 234 } 235 236 public void unregisterForSuppServiceNotification(Handler h) { 237 } 238 239 public void setRadioPower(boolean power) { 240 } 241 242 public String getVoiceMailNumber() { 243 return null; 244 } 245 246 public String getVoiceMailAlphaTag() { 247 return null; 248 } 249 250 public String getDeviceId() { 251 return null; 252 } 253 254 public String getDeviceSvn() { 255 return null; 256 } 257 258 public String getEsn() { 259 Log.e(LOG_TAG, "[SipPhone] getEsn() is a CDMA method"); 260 return "0"; 261 } 262 263 public String getMeid() { 264 Log.e(LOG_TAG, "[SipPhone] getMeid() is a CDMA method"); 265 return "0"; 266 } 267 268 public String getSubscriberId() { 269 return null; 270 } 271 272 public String getIccSerialNumber() { 273 return null; 274 } 275 276 public String getLine1Number() { 277 return null; 278 } 279 280 public String getLine1AlphaTag() { 281 return null; 282 } 283 284 public void setLine1Number(String alphaTag, String number, Message onComplete) { 285 // FIXME: what to reply for SIP? 286 AsyncResult.forMessage(onComplete, null, null); 287 onComplete.sendToTarget(); 288 } 289 290 public void setVoiceMailNumber(String alphaTag, String voiceMailNumber, 291 Message onComplete) { 292 // FIXME: what to reply for SIP? 293 AsyncResult.forMessage(onComplete, null, null); 294 onComplete.sendToTarget(); 295 } 296 297 public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) { 298 } 299 300 public void setCallForwardingOption(int commandInterfaceCFAction, 301 int commandInterfaceCFReason, String dialingNumber, 302 int timerSeconds, Message onComplete) { 303 } 304 305 public void getOutgoingCallerIdDisplay(Message onComplete) { 306 // FIXME: what to reply? 307 AsyncResult.forMessage(onComplete, null, null); 308 onComplete.sendToTarget(); 309 } 310 311 public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, 312 Message onComplete) { 313 // FIXME: what's this for SIP? 314 AsyncResult.forMessage(onComplete, null, null); 315 onComplete.sendToTarget(); 316 } 317 318 public void getCallWaiting(Message onComplete) { 319 AsyncResult.forMessage(onComplete, null, null); 320 onComplete.sendToTarget(); 321 } 322 323 public void setCallWaiting(boolean enable, Message onComplete) { 324 Log.e(LOG_TAG, "call waiting not supported"); 325 } 326 327 public boolean getIccRecordsLoaded() { 328 return false; 329 } 330 331 public IccCard getIccCard() { 332 return null; 333 } 334 335 public void getAvailableNetworks(Message response) { 336 } 337 338 public void setNetworkSelectionModeAutomatic(Message response) { 339 } 340 341 public void selectNetworkManually( 342 com.android.internal.telephony.gsm.NetworkInfo network, 343 Message response) { 344 } 345 346 public void getNeighboringCids(Message response) { 347 } 348 349 public void setOnPostDialCharacter(Handler h, int what, Object obj) { 350 } 351 352 public void getDataCallList(Message response) { 353 } 354 355 public List<DataConnection> getCurrentDataConnectionList () { 356 return null; 357 } 358 359 public void updateServiceLocation() { 360 } 361 362 public void enableLocationUpdates() { 363 } 364 365 public void disableLocationUpdates() { 366 } 367 368 public boolean getDataRoamingEnabled() { 369 return false; 370 } 371 372 public void setDataRoamingEnabled(boolean enable) { 373 } 374 375 public boolean enableDataConnectivity() { 376 return false; 377 } 378 379 public boolean disableDataConnectivity() { 380 return false; 381 } 382 383 public boolean isDataConnectivityPossible() { 384 return false; 385 } 386 387 boolean updateCurrentCarrierInProvider() { 388 return false; 389 } 390 391 public void saveClirSetting(int commandInterfaceCLIRMode) { 392 } 393 394 public PhoneSubInfo getPhoneSubInfo(){ 395 return null; 396 } 397 398 public IccSmsInterfaceManager getIccSmsInterfaceManager(){ 399 return null; 400 } 401 402 public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){ 403 return null; 404 } 405 406 public IccFileHandler getIccFileHandler(){ 407 return null; 408 } 409 410 public void activateCellBroadcastSms(int activate, Message response) { 411 Log.e(LOG_TAG, "Error! This functionality is not implemented for SIP."); 412 } 413 414 public void getCellBroadcastSmsConfig(Message response) { 415 Log.e(LOG_TAG, "Error! This functionality is not implemented for SIP."); 416 } 417 418 public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){ 419 Log.e(LOG_TAG, "Error! This functionality is not implemented for SIP."); 420 } 421 422 void updatePhoneState() { 423 State oldState = state; 424 425 if (getRingingCall().isRinging()) { 426 state = State.RINGING; 427 } else if (getForegroundCall().isIdle() 428 && getBackgroundCall().isIdle()) { 429 state = State.IDLE; 430 } else { 431 state = State.OFFHOOK; 432 } 433 434 if (state != oldState) { 435 Log.d(LOG_TAG, " ^^^ new phone state: " + state); 436 notifyPhoneStateChanged(); 437 } 438 } 439 } 440