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