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 import com.android.internal.telephony.CommandException; 25 26 import java.io.FileDescriptor; 27 import java.io.PrintWriter; 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 Connection mHandoverConnection; 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 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 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 88 isCommandExceptionRadioNotAvailable(Throwable e) { 89 return e != null && e instanceof CommandException 90 && ((CommandException)e).getCommandError() 91 == CommandException.Error.RADIO_NOT_AVAILABLE; 92 } 93 94 protected abstract void handlePollCalls(AsyncResult ar); 95 96 protected void notifySrvccState(Call.SrvccState state, Connection c) { 97 if (state == Call.SrvccState.STARTED) { 98 mHandoverConnection = c; 99 } else if (state != Call.SrvccState.COMPLETED) { 100 mHandoverConnection = null; 101 } 102 } 103 104 protected void handleRadioAvailable() { 105 pollCallsWhenSafe(); 106 } 107 108 /** 109 * Obtain a complete message that indicates that this operation 110 * does not require polling of getCurrentCalls(). However, if other 111 * operations that do need getCurrentCalls() are pending or are 112 * scheduled while this operation is pending, the invocation 113 * of getCurrentCalls() will be postponed until this 114 * operation is also complete. 115 */ 116 protected Message 117 obtainNoPollCompleteMessage(int what) { 118 mPendingOperations++; 119 mLastRelevantPoll = null; 120 return obtainMessage(what); 121 } 122 123 /** 124 * @return true if we're idle or there's a call to getCurrentCalls() pending 125 * but nothing else 126 */ 127 private boolean 128 checkNoOperationsPending() { 129 if (DBG_POLL) log("checkNoOperationsPending: pendingOperations=" + 130 mPendingOperations); 131 return mPendingOperations == 0; 132 } 133 134 /** 135 * Routine called from dial to check if the number is a test Emergency number 136 * and if so remap the number. This allows a short emergency number to be remapped 137 * to a regular number for testing how the frameworks handles emergency numbers 138 * without actually calling an emergency number. 139 * 140 * This is not a full test and is not a substitute for testing real emergency 141 * numbers but can be useful. 142 * 143 * To use this feature set a system property ril.test.emergencynumber to a pair of 144 * numbers separated by a colon. If the first number matches the number parameter 145 * this routine returns the second number. Example: 146 * 147 * ril.test.emergencynumber=112:1-123-123-45678 148 * 149 * To test Dial 112 take call then hang up on MO device to enter ECM 150 * see RIL#processSolicited RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND 151 * 152 * @param dialString to test if it should be remapped 153 * @return the same number or the remapped number. 154 */ 155 protected String checkForTestEmergencyNumber(String dialString) { 156 String testEn = SystemProperties.get("ril.test.emergencynumber"); 157 if (DBG_POLL) { 158 log("checkForTestEmergencyNumber: dialString=" + dialString + 159 " testEn=" + testEn); 160 } 161 if (!TextUtils.isEmpty(testEn)) { 162 String values[] = testEn.split(":"); 163 log("checkForTestEmergencyNumber: values.length=" + values.length); 164 if (values.length == 2) { 165 if (values[0].equals( 166 android.telephony.PhoneNumberUtils.stripSeparators(dialString))) { 167 mCi.testingEmergencyCall(); 168 log("checkForTestEmergencyNumber: remap " + 169 dialString + " to " + values[1]); 170 dialString = values[1]; 171 } 172 } 173 } 174 return dialString; 175 } 176 177 protected String convertNumberIfNecessary(PhoneBase phoneBase, String dialNumber) { 178 if (dialNumber == null) { 179 return dialNumber; 180 } 181 String[] convertMaps = phoneBase.getContext().getResources().getStringArray( 182 com.android.internal.R.array.dial_string_replace); 183 log("convertNumberIfNecessary Roaming" 184 + " convertMaps.length " + convertMaps.length 185 + " dialNumber.length() " + dialNumber.length()); 186 187 if (convertMaps.length < 1 || dialNumber.length() < VALID_COMPARE_LENGTH) { 188 return dialNumber; 189 } 190 191 String[] entry; 192 String[] tmpArray; 193 String outNumber = ""; 194 for(String convertMap : convertMaps) { 195 log("convertNumberIfNecessary: " + convertMap); 196 entry = convertMap.split(":"); 197 if (entry.length > 1) { 198 tmpArray = entry[1].split(","); 199 if (!TextUtils.isEmpty(entry[0]) && dialNumber.equals(entry[0])) { 200 if (tmpArray.length >= 2 && !TextUtils.isEmpty(tmpArray[1])) { 201 if (compareGid1(phoneBase, tmpArray[1])) { 202 mNumberConverted = true; 203 } 204 } else if (outNumber.isEmpty()) { 205 mNumberConverted = true; 206 } 207 if (mNumberConverted) { 208 if(!TextUtils.isEmpty(tmpArray[0]) && tmpArray[0].endsWith("MDN")) { 209 String prefix = tmpArray[0].substring(0, tmpArray[0].length() -3); 210 outNumber = prefix + phoneBase.getLine1Number(); 211 } else { 212 outNumber = tmpArray[0]; 213 } 214 } 215 } 216 } 217 } 218 219 if (mNumberConverted) { 220 log("convertNumberIfNecessary: convert service number"); 221 return outNumber; 222 } 223 224 return dialNumber; 225 226 } 227 228 private boolean compareGid1(PhoneBase phoneBase, String serviceGid1) { 229 String gid1 = phoneBase.getGroupIdLevel1(); 230 int gid_length = serviceGid1.length(); 231 boolean ret = true; 232 233 if (serviceGid1 == null || serviceGid1.equals("")) { 234 log("compareGid1 serviceGid is empty, return " + ret); 235 return ret; 236 } 237 // Check if gid1 match service GID1 238 if (!((gid1 != null) && (gid1.length() >= gid_length) && 239 gid1.substring(0, gid_length).equalsIgnoreCase(serviceGid1))) { 240 log(" gid1 " + gid1 + " serviceGid1 " + serviceGid1); 241 ret = false; 242 } 243 log("compareGid1 is " + (ret?"Same":"Different")); 244 return ret; 245 } 246 247 //***** Overridden from Handler 248 @Override 249 public abstract void handleMessage (Message msg); 250 public abstract void registerForVoiceCallStarted(Handler h, int what, Object obj); 251 public abstract void unregisterForVoiceCallStarted(Handler h); 252 public abstract void registerForVoiceCallEnded(Handler h, int what, Object obj); 253 public abstract void unregisterForVoiceCallEnded(Handler h); 254 255 protected abstract void log(String msg); 256 257 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 258 pw.println("CallTracker:"); 259 pw.println(" mPendingOperations=" + mPendingOperations); 260 pw.println(" mNeedsPoll=" + mNeedsPoll); 261 pw.println(" mLastRelevantPoll=" + mLastRelevantPoll); 262 } 263 } 264