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