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