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