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.os.AsyncResult; 20 import android.os.Handler; 21 import android.os.Message; 22 import android.os.SystemProperties; 23 import android.text.TextUtils; 24 25 import java.io.FileDescriptor; 26 import java.io.PrintWriter; 27 import java.util.ArrayList; 28 29 30 /** 31 * {@hide} 32 */ 33 public abstract class CallTracker extends Handler { 34 35 private static final boolean DBG_POLL = false; 36 37 //***** Constants 38 39 static final int POLL_DELAY_MSEC = 250; 40 41 protected int mPendingOperations; 42 protected boolean mNeedsPoll; 43 protected Message mLastRelevantPoll; 44 protected ArrayList<Connection> mHandoverConnections = new ArrayList<Connection>(); 45 46 public CommandsInterface mCi; 47 48 protected boolean mNumberConverted = false; 49 private final int VALID_COMPARE_LENGTH = 3; 50 51 //***** Events 52 53 protected static final int EVENT_POLL_CALLS_RESULT = 1; 54 protected static final int EVENT_CALL_STATE_CHANGE = 2; 55 protected static final int EVENT_REPOLL_AFTER_DELAY = 3; 56 protected static final int EVENT_OPERATION_COMPLETE = 4; 57 protected static final int EVENT_GET_LAST_CALL_FAIL_CAUSE = 5; 58 59 protected static final int EVENT_SWITCH_RESULT = 8; 60 protected static final int EVENT_RADIO_AVAILABLE = 9; 61 protected static final int EVENT_RADIO_NOT_AVAILABLE = 10; 62 protected static final int EVENT_CONFERENCE_RESULT = 11; 63 protected static final int EVENT_SEPARATE_RESULT = 12; 64 protected static final int EVENT_ECT_RESULT = 13; 65 protected static final int EVENT_EXIT_ECM_RESPONSE_CDMA = 14; 66 protected static final int EVENT_CALL_WAITING_INFO_CDMA = 15; 67 protected static final int EVENT_THREE_WAY_DIAL_L2_RESULT_CDMA = 16; 68 protected static final int EVENT_THREE_WAY_DIAL_BLANK_FLASH = 20; 69 pollCallsWhenSafe()70 protected void pollCallsWhenSafe() { 71 mNeedsPoll = true; 72 73 if (checkNoOperationsPending()) { 74 mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); 75 mCi.getCurrentCalls(mLastRelevantPoll); 76 } 77 } 78 79 protected void pollCallsAfterDelay()80 pollCallsAfterDelay() { 81 Message msg = obtainMessage(); 82 83 msg.what = EVENT_REPOLL_AFTER_DELAY; 84 sendMessageDelayed(msg, POLL_DELAY_MSEC); 85 } 86 87 protected boolean isCommandExceptionRadioNotAvailable(Throwable e)88 isCommandExceptionRadioNotAvailable(Throwable e) { 89 return e != null && e instanceof CommandException 90 && ((CommandException)e).getCommandError() 91 == CommandException.Error.RADIO_NOT_AVAILABLE; 92 } 93 handlePollCalls(AsyncResult ar)94 protected abstract void handlePollCalls(AsyncResult ar); 95 getHoConnection(DriverCall dc)96 protected Connection getHoConnection(DriverCall dc) { 97 for (Connection hoConn : mHandoverConnections) { 98 log("getHoConnection - compare number: hoConn= " + hoConn.toString()); 99 if (hoConn.getAddress() != null && hoConn.getAddress().contains(dc.number)) { 100 log("getHoConnection: Handover connection match found = " + hoConn.toString()); 101 return hoConn; 102 } 103 } 104 for (Connection hoConn : mHandoverConnections) { 105 log("getHoConnection: compare state hoConn= " + hoConn.toString()); 106 if (hoConn.getStateBeforeHandover() == Call.stateFromDCState(dc.state)) { 107 log("getHoConnection: Handover connection match found = " + hoConn.toString()); 108 return hoConn; 109 } 110 } 111 return null; 112 } 113 notifySrvccState(Call.SrvccState state, ArrayList<Connection> c)114 protected void notifySrvccState(Call.SrvccState state, ArrayList<Connection> c) { 115 if (state == Call.SrvccState.STARTED && c != null) { 116 // SRVCC started. Prepare handover connections list 117 mHandoverConnections.addAll(c); 118 } else if (state != Call.SrvccState.COMPLETED) { 119 // SRVCC FAILED/CANCELED. Clear the handover connections list 120 // Individual connections will be removed from the list in handlePollCalls() 121 mHandoverConnections.clear(); 122 } 123 log("notifySrvccState: mHandoverConnections= " + mHandoverConnections.toString()); 124 } 125 handleRadioAvailable()126 protected void handleRadioAvailable() { 127 pollCallsWhenSafe(); 128 } 129 130 /** 131 * Obtain a complete message that indicates that this operation 132 * does not require polling of getCurrentCalls(). However, if other 133 * operations that do need getCurrentCalls() are pending or are 134 * scheduled while this operation is pending, the invocation 135 * of getCurrentCalls() will be postponed until this 136 * operation is also complete. 137 */ 138 protected Message obtainNoPollCompleteMessage(int what)139 obtainNoPollCompleteMessage(int what) { 140 mPendingOperations++; 141 mLastRelevantPoll = null; 142 return obtainMessage(what); 143 } 144 145 /** 146 * @return true if we're idle or there's a call to getCurrentCalls() pending 147 * but nothing else 148 */ 149 private boolean checkNoOperationsPending()150 checkNoOperationsPending() { 151 if (DBG_POLL) log("checkNoOperationsPending: pendingOperations=" + 152 mPendingOperations); 153 return mPendingOperations == 0; 154 } 155 156 /** 157 * Routine called from dial to check if the number is a test Emergency number 158 * and if so remap the number. This allows a short emergency number to be remapped 159 * to a regular number for testing how the frameworks handles emergency numbers 160 * without actually calling an emergency number. 161 * 162 * This is not a full test and is not a substitute for testing real emergency 163 * numbers but can be useful. 164 * 165 * To use this feature set a system property ril.test.emergencynumber to a pair of 166 * numbers separated by a colon. If the first number matches the number parameter 167 * this routine returns the second number. Example: 168 * 169 * ril.test.emergencynumber=112:1-123-123-45678 170 * 171 * To test Dial 112 take call then hang up on MO device to enter ECM 172 * see RIL#processSolicited RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND 173 * 174 * @param dialString to test if it should be remapped 175 * @return the same number or the remapped number. 176 */ checkForTestEmergencyNumber(String dialString)177 protected String checkForTestEmergencyNumber(String dialString) { 178 String testEn = SystemProperties.get("ril.test.emergencynumber"); 179 if (DBG_POLL) { 180 log("checkForTestEmergencyNumber: dialString=" + dialString + 181 " testEn=" + testEn); 182 } 183 if (!TextUtils.isEmpty(testEn)) { 184 String values[] = testEn.split(":"); 185 log("checkForTestEmergencyNumber: values.length=" + values.length); 186 if (values.length == 2) { 187 if (values[0].equals( 188 android.telephony.PhoneNumberUtils.stripSeparators(dialString))) { 189 // mCi will be null for ImsPhoneCallTracker. 190 if (mCi != null) { 191 mCi.testingEmergencyCall(); 192 } 193 log("checkForTestEmergencyNumber: remap " + 194 dialString + " to " + values[1]); 195 dialString = values[1]; 196 } 197 } 198 } 199 return dialString; 200 } 201 convertNumberIfNecessary(Phone phone, String dialNumber)202 protected String convertNumberIfNecessary(Phone phone, String dialNumber) { 203 if (dialNumber == null) { 204 return dialNumber; 205 } 206 String[] convertMaps = phone.getContext().getResources().getStringArray( 207 com.android.internal.R.array.dial_string_replace); 208 log("convertNumberIfNecessary Roaming" 209 + " convertMaps.length " + convertMaps.length 210 + " dialNumber.length() " + dialNumber.length()); 211 212 if (convertMaps.length < 1 || dialNumber.length() < VALID_COMPARE_LENGTH) { 213 return dialNumber; 214 } 215 216 String[] entry; 217 String[] tmpArray; 218 String outNumber = ""; 219 boolean needConvert = false; 220 for(String convertMap : convertMaps) { 221 log("convertNumberIfNecessary: " + convertMap); 222 entry = convertMap.split(":"); 223 if (entry.length > 1) { 224 tmpArray = entry[1].split(","); 225 if (!TextUtils.isEmpty(entry[0]) && dialNumber.equals(entry[0])) { 226 if (tmpArray.length >= 2 && !TextUtils.isEmpty(tmpArray[1])) { 227 if (compareGid1(phone, tmpArray[1])) { 228 needConvert = true; 229 } 230 } else if (outNumber.isEmpty()) { 231 needConvert = true; 232 } 233 234 if (needConvert) { 235 if(!TextUtils.isEmpty(tmpArray[0]) && tmpArray[0].endsWith("MDN")) { 236 String mdn = phone.getLine1Number(); 237 if (!TextUtils.isEmpty(mdn) ) { 238 if (mdn.startsWith("+")) { 239 outNumber = mdn; 240 } else { 241 outNumber = tmpArray[0].substring(0, tmpArray[0].length() -3) 242 + mdn; 243 } 244 } 245 } else { 246 outNumber = tmpArray[0]; 247 } 248 needConvert = false; 249 } 250 } 251 } 252 } 253 254 if (!TextUtils.isEmpty(outNumber)) { 255 log("convertNumberIfNecessary: convert service number"); 256 mNumberConverted = true; 257 return outNumber; 258 } 259 260 return dialNumber; 261 262 } 263 compareGid1(Phone phone, String serviceGid1)264 private boolean compareGid1(Phone phone, String serviceGid1) { 265 String gid1 = phone.getGroupIdLevel1(); 266 int gid_length = serviceGid1.length(); 267 boolean ret = true; 268 269 if (serviceGid1 == null || serviceGid1.equals("")) { 270 log("compareGid1 serviceGid is empty, return " + ret); 271 return ret; 272 } 273 // Check if gid1 match service GID1 274 if (!((gid1 != null) && (gid1.length() >= gid_length) && 275 gid1.substring(0, gid_length).equalsIgnoreCase(serviceGid1))) { 276 log(" gid1 " + gid1 + " serviceGid1 " + serviceGid1); 277 ret = false; 278 } 279 log("compareGid1 is " + (ret?"Same":"Different")); 280 return ret; 281 } 282 283 //***** Overridden from Handler 284 @Override handleMessage(Message msg)285 public abstract void handleMessage (Message msg); registerForVoiceCallStarted(Handler h, int what, Object obj)286 public abstract void registerForVoiceCallStarted(Handler h, int what, Object obj); unregisterForVoiceCallStarted(Handler h)287 public abstract void unregisterForVoiceCallStarted(Handler h); registerForVoiceCallEnded(Handler h, int what, Object obj)288 public abstract void registerForVoiceCallEnded(Handler h, int what, Object obj); unregisterForVoiceCallEnded(Handler h)289 public abstract void unregisterForVoiceCallEnded(Handler h); getState()290 public abstract PhoneConstants.State getState(); log(String msg)291 protected abstract void log(String msg); 292 dump(FileDescriptor fd, PrintWriter pw, String[] args)293 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 294 pw.println("CallTracker:"); 295 pw.println(" mPendingOperations=" + mPendingOperations); 296 pw.println(" mNeedsPoll=" + mNeedsPoll); 297 pw.println(" mLastRelevantPoll=" + mLastRelevantPoll); 298 } 299 } 300