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