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