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