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