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