• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 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;
18 
19 import android.compat.annotation.UnsupportedAppUsage;
20 import android.content.Context;
21 import android.os.AsyncResult;
22 import android.os.Build;
23 import android.os.Handler;
24 import android.os.Message;
25 import android.os.PersistableBundle;
26 import android.telephony.CarrierConfigManager;
27 import android.text.TextUtils;
28 
29 import java.io.FileDescriptor;
30 import java.io.PrintWriter;
31 import java.util.ArrayList;
32 
33 
34 /**
35  * {@hide}
36  */
37 public abstract class CallTracker extends Handler {
38 
39     private static final boolean DBG_POLL = false;
40 
41     //***** Constants
42 
43     static final int POLL_DELAY_MSEC = 250;
44 
45     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
46     protected int mPendingOperations;
47     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
48     protected boolean mNeedsPoll;
49     protected Message mLastRelevantPoll;
50     protected ArrayList<Connection> mHandoverConnections = new ArrayList<Connection>();
51 
52     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
53     public CommandsInterface mCi;
54 
55     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
56     protected boolean mNumberConverted = false;
57     private final int VALID_COMPARE_LENGTH   = 3;
58 
59     //***** Events
60 
61     protected static final int EVENT_POLL_CALLS_RESULT             = 1;
62     protected static final int EVENT_CALL_STATE_CHANGE             = 2;
63     protected static final int EVENT_REPOLL_AFTER_DELAY            = 3;
64     protected static final int EVENT_OPERATION_COMPLETE            = 4;
65     protected static final int EVENT_GET_LAST_CALL_FAIL_CAUSE      = 5;
66 
67     protected static final int EVENT_SWITCH_RESULT                 = 8;
68     protected static final int EVENT_RADIO_AVAILABLE               = 9;
69     protected static final int EVENT_RADIO_NOT_AVAILABLE           = 10;
70     protected static final int EVENT_CONFERENCE_RESULT             = 11;
71     protected static final int EVENT_SEPARATE_RESULT               = 12;
72     protected static final int EVENT_ECT_RESULT                    = 13;
73     protected static final int EVENT_EXIT_ECM_RESPONSE_CDMA        = 14;
74     protected static final int EVENT_CALL_WAITING_INFO_CDMA        = 15;
75     protected static final int EVENT_THREE_WAY_DIAL_L2_RESULT_CDMA = 16;
76     protected static final int EVENT_THREE_WAY_DIAL_BLANK_FLASH    = 20;
77 
78     @UnsupportedAppUsage
CallTracker()79     public CallTracker() {
80     }
81 
pollCallsWhenSafe()82     protected void pollCallsWhenSafe() {
83         mNeedsPoll = true;
84 
85         if (checkNoOperationsPending()) {
86             mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
87             mCi.getCurrentCalls(mLastRelevantPoll);
88         }
89     }
90 
91     protected void
pollCallsAfterDelay()92     pollCallsAfterDelay() {
93         Message msg = obtainMessage();
94 
95         msg.what = EVENT_REPOLL_AFTER_DELAY;
96         sendMessageDelayed(msg, POLL_DELAY_MSEC);
97     }
98 
99     protected boolean
isCommandExceptionRadioNotAvailable(Throwable e)100     isCommandExceptionRadioNotAvailable(Throwable e) {
101         return e != null && e instanceof CommandException
102                 && ((CommandException)e).getCommandError()
103                         == CommandException.Error.RADIO_NOT_AVAILABLE;
104     }
105 
handlePollCalls(AsyncResult ar)106     protected abstract void handlePollCalls(AsyncResult ar);
107 
getPhone()108     protected abstract Phone getPhone();
109 
getHoConnection(DriverCall dc)110     protected Connection getHoConnection(DriverCall dc) {
111         for (Connection hoConn : mHandoverConnections) {
112             log("getHoConnection - compare number: hoConn= " + hoConn.toString());
113             if (hoConn.getAddress() != null && hoConn.getAddress().contains(dc.number)) {
114                 log("getHoConnection: Handover connection match found = " + hoConn.toString());
115                 return hoConn;
116             }
117         }
118         for (Connection hoConn : mHandoverConnections) {
119             log("getHoConnection: compare state hoConn= " + hoConn.toString());
120             if (hoConn.getStateBeforeHandover() == Call.stateFromDCState(dc.state)) {
121                 log("getHoConnection: Handover connection match found = " + hoConn.toString());
122                 return hoConn;
123             }
124         }
125         return null;
126     }
127 
notifySrvccState(Call.SrvccState state, ArrayList<Connection> c)128     protected void notifySrvccState(Call.SrvccState state, ArrayList<Connection> c) {
129         if (state == Call.SrvccState.STARTED && c != null) {
130             // SRVCC started. Prepare handover connections list
131             mHandoverConnections.addAll(c);
132         } else if (state != Call.SrvccState.COMPLETED) {
133             // SRVCC FAILED/CANCELED. Clear the handover connections list
134             // Individual connections will be removed from the list in handlePollCalls()
135             mHandoverConnections.clear();
136         }
137         log("notifySrvccState: state=" + state.name() + ", mHandoverConnections= "
138                 + mHandoverConnections.toString());
139     }
140 
handleRadioAvailable()141     protected void handleRadioAvailable() {
142         pollCallsWhenSafe();
143     }
144 
145     /**
146      * Obtain a complete message that indicates that this operation
147      * does not require polling of getCurrentCalls(). However, if other
148      * operations that do need getCurrentCalls() are pending or are
149      * scheduled while this operation is pending, the invocation
150      * of getCurrentCalls() will be postponed until this
151      * operation is also complete.
152      */
153     protected Message
obtainNoPollCompleteMessage(int what)154     obtainNoPollCompleteMessage(int what) {
155         mPendingOperations++;
156         mLastRelevantPoll = null;
157         return obtainMessage(what);
158     }
159 
160     /**
161      * @return true if we're idle or there's a call to getCurrentCalls() pending
162      * but nothing else
163      */
164     private boolean
checkNoOperationsPending()165     checkNoOperationsPending() {
166         if (DBG_POLL) log("checkNoOperationsPending: pendingOperations=" +
167                 mPendingOperations);
168         return mPendingOperations == 0;
169     }
170 
convertNumberIfNecessary(Phone phone, String dialNumber)171     protected String convertNumberIfNecessary(Phone phone, String dialNumber) {
172         if (dialNumber == null) {
173             return dialNumber;
174         }
175         String[] convertMaps = null;
176         CarrierConfigManager configManager = (CarrierConfigManager)
177                 phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
178         PersistableBundle bundle = configManager.getConfigForSubId(phone.getSubId());
179         if (bundle != null) {
180             convertMaps =
181                     bundle.getStringArray(CarrierConfigManager.KEY_DIAL_STRING_REPLACE_STRING_ARRAY);
182         }
183         if (convertMaps == null) {
184             // By default no replacement is necessary
185             log("convertNumberIfNecessary convertMaps is null");
186             return dialNumber;
187         }
188 
189         log("convertNumberIfNecessary Roaming"
190             + " convertMaps.length " + convertMaps.length
191             + " dialNumber.length() " + dialNumber.length());
192 
193         if (convertMaps.length < 1 || dialNumber.length() < VALID_COMPARE_LENGTH) {
194             return dialNumber;
195         }
196 
197         String[] entry;
198         String outNumber = "";
199         for(String convertMap : convertMaps) {
200             log("convertNumberIfNecessary: " + convertMap);
201             // entry format is  "dialStringToReplace:dialStringReplacement"
202             entry = convertMap.split(":");
203             if (entry != null && entry.length > 1) {
204                 String dsToReplace = entry[0];
205                 String dsReplacement = entry[1];
206                 if (!TextUtils.isEmpty(dsToReplace) && dialNumber.equals(dsToReplace)) {
207                     // Needs to be converted
208                     if (!TextUtils.isEmpty(dsReplacement) && dsReplacement.endsWith("MDN")) {
209                         String mdn = phone.getLine1Number();
210                         if (!TextUtils.isEmpty(mdn)) {
211                             if (mdn.startsWith("+")) {
212                                 outNumber = mdn;
213                             } else {
214                                 outNumber = dsReplacement.substring(0, dsReplacement.length() -3)
215                                         + mdn;
216                             }
217                         }
218                     } else {
219                         outNumber = dsReplacement;
220                     }
221                     break;
222                 }
223             }
224         }
225 
226         if (!TextUtils.isEmpty(outNumber)) {
227             log("convertNumberIfNecessary: convert service number");
228             mNumberConverted = true;
229             return outNumber;
230         }
231 
232         return dialNumber;
233 
234     }
235 
compareGid1(Phone phone, String serviceGid1)236     private boolean compareGid1(Phone phone, String serviceGid1) {
237         String gid1 = phone.getGroupIdLevel1();
238         int gid_length = serviceGid1.length();
239         boolean ret = true;
240 
241         if (serviceGid1 == null || serviceGid1.equals("")) {
242             log("compareGid1 serviceGid is empty, return " + ret);
243             return ret;
244         }
245         // Check if gid1 match service GID1
246         if (!((gid1 != null) && (gid1.length() >= gid_length) &&
247                 gid1.substring(0, gid_length).equalsIgnoreCase(serviceGid1))) {
248             log(" gid1 " + gid1 + " serviceGid1 " + serviceGid1);
249             ret = false;
250         }
251         log("compareGid1 is " + (ret?"Same":"Different"));
252         return ret;
253     }
254 
255     /**
256      * Get the ringing connections which during SRVCC handover.
257      */
getRingingHandoverConnection()258     public Connection getRingingHandoverConnection() {
259         for (Connection hoConn : mHandoverConnections) {
260             if (hoConn.getCall().isRinging()) {
261                 return hoConn;
262             }
263         }
264         return null;
265     }
266 
267     //***** Overridden from Handler
268     @Override
handleMessage(Message msg)269     public abstract void handleMessage (Message msg);
registerForVoiceCallStarted(Handler h, int what, Object obj)270     public abstract void registerForVoiceCallStarted(Handler h, int what, Object obj);
unregisterForVoiceCallStarted(Handler h)271     public abstract void unregisterForVoiceCallStarted(Handler h);
272     @UnsupportedAppUsage
registerForVoiceCallEnded(Handler h, int what, Object obj)273     public abstract void registerForVoiceCallEnded(Handler h, int what, Object obj);
unregisterForVoiceCallEnded(Handler h)274     public abstract void unregisterForVoiceCallEnded(Handler h);
275     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getState()276     public abstract PhoneConstants.State getState();
277     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
log(String msg)278     protected abstract void log(String msg);
279 
280     /**
281      * Called when the call tracker should attempt to reconcile its calls against its underlying
282      * phone implementation and cleanup any stale calls.
283      */
cleanupCalls()284     public void cleanupCalls() {
285         // no base implementation
286     }
287 
dump(FileDescriptor fd, PrintWriter pw, String[] args)288     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
289         pw.println("CallTracker:");
290         pw.println(" mPendingOperations=" + mPendingOperations);
291         pw.println(" mNeedsPoll=" + mNeedsPoll);
292         pw.println(" mLastRelevantPoll=" + mLastRelevantPoll);
293     }
294 }
295