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