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; 18 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.net.Uri; 24 import android.os.BadParcelableException; 25 import android.os.Build; 26 import android.telephony.NetworkRegistrationState; 27 import android.telephony.Rlog; 28 import android.telephony.ServiceState; 29 import android.telephony.ims.ImsCallProfile; 30 import android.telephony.ims.ImsConferenceState; 31 import android.telephony.ims.ImsExternalCallState; 32 import android.telephony.ims.ImsReasonInfo; 33 34 import com.android.ims.ImsCall; 35 import com.android.internal.telephony.gsm.SuppServiceNotification; 36 import com.android.internal.telephony.imsphone.ImsExternalCallTracker; 37 import com.android.internal.telephony.imsphone.ImsPhone; 38 import com.android.internal.telephony.imsphone.ImsPhoneCall; 39 import com.android.internal.telephony.test.TestConferenceEventPackageParser; 40 41 import java.io.File; 42 import java.io.FileInputStream; 43 import java.io.FileNotFoundException; 44 import java.util.ArrayList; 45 import java.util.List; 46 47 /** 48 * Telephony tester receives the following intents where {name} is the phone name 49 * 50 * adb shell am broadcast -a com.android.internal.telephony.{name}.action_detached 51 * adb shell am broadcast -a com.android.internal.telephony.{name}.action_attached 52 * adb shell am broadcast -a com.android.internal.telephony.TestConferenceEventPackage -e filename 53 * test_filename.xml 54 * adb shell am broadcast -a com.android.internal.telephony.TestServiceState --ei data_rat 10 --ei 55 * data_roaming_type 3 56 * adb shell am broadcast -a com.android.internal.telephony.TestServiceState --es action reset 57 * 58 */ 59 public class TelephonyTester { 60 private static final String LOG_TAG = "TelephonyTester"; 61 private static final boolean DBG = true; 62 63 /** 64 * Test-only intent used to send a test conference event package to the IMS framework. 65 */ 66 private static final String ACTION_TEST_CONFERENCE_EVENT_PACKAGE = 67 "com.android.internal.telephony.TestConferenceEventPackage"; 68 69 /** 70 * Test-only intent used to send a test dialog event package to the IMS framework. 71 */ 72 private static final String ACTION_TEST_DIALOG_EVENT_PACKAGE = 73 "com.android.internal.telephony.TestDialogEventPackage"; 74 75 private static final String EXTRA_FILENAME = "filename"; 76 private static final String EXTRA_STARTPACKAGE = "startPackage"; 77 private static final String EXTRA_SENDPACKAGE = "sendPackage"; 78 private static final String EXTRA_DIALOGID = "dialogId"; 79 private static final String EXTRA_NUMBER = "number"; 80 private static final String EXTRA_STATE = "state"; 81 private static final String EXTRA_CANPULL = "canPull"; 82 83 /** 84 * Test-only intent used to trigger supp service notification failure. 85 */ 86 private static final String ACTION_TEST_SUPP_SRVC_FAIL = 87 "com.android.internal.telephony.TestSuppSrvcFail"; 88 private static final String EXTRA_FAILURE_CODE = "failureCode"; 89 90 /** 91 * Test-only intent used to trigger the signalling which occurs when a handover to WIFI fails. 92 */ 93 private static final String ACTION_TEST_HANDOVER_FAIL = 94 "com.android.internal.telephony.TestHandoverFail"; 95 96 /** 97 * Test-only intent used to trigger signalling of a 98 * {@link com.android.internal.telephony.gsm.SuppServiceNotification} to the {@link ImsPhone}. 99 * Use {@link #EXTRA_CODE} to specify the 100 * {@link com.android.internal.telephony.gsm.SuppServiceNotification#code}. 101 */ 102 private static final String ACTION_TEST_SUPP_SRVC_NOTIFICATION = 103 "com.android.internal.telephony.TestSuppSrvcNotification"; 104 105 private static final String EXTRA_CODE = "code"; 106 private static final String EXTRA_TYPE = "type"; 107 108 private static final String ACTION_TEST_SERVICE_STATE = 109 "com.android.internal.telephony.TestServiceState"; 110 111 private static final String EXTRA_ACTION = "action"; 112 private static final String EXTRA_VOICE_RAT = "voice_rat"; 113 private static final String EXTRA_DATA_RAT = "data_rat"; 114 private static final String EXTRA_VOICE_REG_STATE = "voice_reg_state"; 115 private static final String EXTRA_DATA_REG_STATE = "data_reg_state"; 116 private static final String EXTRA_VOICE_ROAMING_TYPE = "voice_roaming_type"; 117 private static final String EXTRA_DATA_ROAMING_TYPE = "data_roaming_type"; 118 119 private static final String ACTION_RESET = "reset"; 120 121 private static List<ImsExternalCallState> mImsExternalCallStates = null; 122 123 private Intent mServiceStateTestIntent; 124 125 private Phone mPhone; 126 127 // The static intent receiver one for all instances and we assume this 128 // is running on the same thread as Dcc. 129 protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 130 @Override 131 public void onReceive(Context context, Intent intent) { 132 String action = intent.getAction(); 133 try { 134 if (DBG) log("sIntentReceiver.onReceive: action=" + action); 135 if (action.equals(mPhone.getActionDetached())) { 136 log("simulate detaching"); 137 mPhone.getServiceStateTracker().mDetachedRegistrants.notifyRegistrants(); 138 } else if (action.equals(mPhone.getActionAttached())) { 139 log("simulate attaching"); 140 mPhone.getServiceStateTracker().mAttachedRegistrants.notifyRegistrants(); 141 } else if (action.equals(ACTION_TEST_CONFERENCE_EVENT_PACKAGE)) { 142 log("inject simulated conference event package"); 143 handleTestConferenceEventPackage(context, 144 intent.getStringExtra(EXTRA_FILENAME)); 145 } else if (action.equals(ACTION_TEST_DIALOG_EVENT_PACKAGE)) { 146 log("handle test dialog event package intent"); 147 handleTestDialogEventPackageIntent(intent); 148 } else if (action.equals(ACTION_TEST_SUPP_SRVC_FAIL)) { 149 log("handle test supp svc failed intent"); 150 handleSuppServiceFailedIntent(intent); 151 } else if (action.equals(ACTION_TEST_HANDOVER_FAIL)) { 152 log("handle handover fail test intent"); 153 handleHandoverFailedIntent(); 154 } else if (action.equals(ACTION_TEST_SUPP_SRVC_NOTIFICATION)) { 155 log("handle supp service notification test intent"); 156 sendTestSuppServiceNotification(intent); 157 } else if (action.equals(ACTION_TEST_SERVICE_STATE)) { 158 log("handle test service state changed intent"); 159 // Trigger the service state update. The replacement will be done in 160 // overrideServiceState(). 161 mServiceStateTestIntent = intent; 162 mPhone.getServiceStateTracker().sendEmptyMessage( 163 ServiceStateTracker.EVENT_NETWORK_STATE_CHANGED); 164 } else { 165 if (DBG) log("onReceive: unknown action=" + action); 166 } 167 } catch (BadParcelableException e) { 168 Rlog.w(LOG_TAG, e); 169 } 170 } 171 }; 172 TelephonyTester(Phone phone)173 TelephonyTester(Phone phone) { 174 mPhone = phone; 175 176 if (Build.IS_DEBUGGABLE) { 177 IntentFilter filter = new IntentFilter(); 178 179 filter.addAction(mPhone.getActionDetached()); 180 log("register for intent action=" + mPhone.getActionDetached()); 181 182 filter.addAction(mPhone.getActionAttached()); 183 log("register for intent action=" + mPhone.getActionAttached()); 184 185 if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) { 186 log("register for intent action=" + ACTION_TEST_CONFERENCE_EVENT_PACKAGE); 187 filter.addAction(ACTION_TEST_CONFERENCE_EVENT_PACKAGE); 188 filter.addAction(ACTION_TEST_DIALOG_EVENT_PACKAGE); 189 filter.addAction(ACTION_TEST_SUPP_SRVC_FAIL); 190 filter.addAction(ACTION_TEST_HANDOVER_FAIL); 191 filter.addAction(ACTION_TEST_SUPP_SRVC_NOTIFICATION); 192 mImsExternalCallStates = new ArrayList<ImsExternalCallState>(); 193 } else { 194 filter.addAction(ACTION_TEST_SERVICE_STATE); 195 log("register for intent action=" + ACTION_TEST_SERVICE_STATE); 196 } 197 198 phone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone.getHandler()); 199 } 200 } 201 dispose()202 void dispose() { 203 if (Build.IS_DEBUGGABLE) { 204 mPhone.getContext().unregisterReceiver(mIntentReceiver); 205 } 206 } 207 log(String s)208 private static void log(String s) { 209 Rlog.d(LOG_TAG, s); 210 } 211 handleSuppServiceFailedIntent(Intent intent)212 private void handleSuppServiceFailedIntent(Intent intent) { 213 ImsPhone imsPhone = (ImsPhone) mPhone; 214 if (imsPhone == null) { 215 return; 216 } 217 int code = intent.getIntExtra(EXTRA_FAILURE_CODE, 0); 218 imsPhone.notifySuppServiceFailed(PhoneInternalInterface.SuppService.values()[code]); 219 } 220 handleHandoverFailedIntent()221 private void handleHandoverFailedIntent() { 222 // Attempt to get the active IMS call 223 ImsPhone imsPhone = (ImsPhone) mPhone; 224 if (imsPhone == null) { 225 return; 226 } 227 228 ImsPhoneCall imsPhoneCall = imsPhone.getForegroundCall(); 229 if (imsPhoneCall == null) { 230 return; 231 } 232 233 ImsCall imsCall = imsPhoneCall.getImsCall(); 234 if (imsCall == null) { 235 return; 236 } 237 238 imsCall.getImsCallSessionListenerProxy().callSessionHandoverFailed(imsCall.getCallSession(), 239 ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN, 240 new ImsReasonInfo()); 241 } 242 243 /** 244 * Handles request to send a test conference event package to the active Ims call. 245 * 246 * @see com.android.internal.telephony.test.TestConferenceEventPackageParser 247 * @param context The context. 248 * @param fileName The name of the test conference event package file to read. 249 */ handleTestConferenceEventPackage(Context context, String fileName)250 private void handleTestConferenceEventPackage(Context context, String fileName) { 251 // Attempt to get the active IMS call before parsing the test XML file. 252 ImsPhone imsPhone = (ImsPhone) mPhone; 253 if (imsPhone == null) { 254 return; 255 } 256 257 ImsPhoneCall imsPhoneCall = imsPhone.getForegroundCall(); 258 if (imsPhoneCall == null) { 259 return; 260 } 261 262 ImsCall imsCall = imsPhoneCall.getImsCall(); 263 if (imsCall == null) { 264 return; 265 } 266 267 File packageFile = new File(context.getFilesDir(), fileName); 268 final FileInputStream is; 269 try { 270 is = new FileInputStream(packageFile); 271 } catch (FileNotFoundException ex) { 272 log("Test conference event package file not found: " + packageFile.getAbsolutePath()); 273 return; 274 } 275 276 TestConferenceEventPackageParser parser = new TestConferenceEventPackageParser(is); 277 ImsConferenceState imsConferenceState = parser.parse(); 278 if (imsConferenceState == null) { 279 return; 280 } 281 282 imsCall.conferenceStateUpdated(imsConferenceState); 283 } 284 285 /** 286 * Handles intents containing test dialog event package data. 287 * 288 * @param intent 289 */ handleTestDialogEventPackageIntent(Intent intent)290 private void handleTestDialogEventPackageIntent(Intent intent) { 291 ImsPhone imsPhone = (ImsPhone) mPhone; 292 if (imsPhone == null) { 293 return; 294 } 295 ImsExternalCallTracker externalCallTracker = imsPhone.getExternalCallTracker(); 296 if (externalCallTracker == null) { 297 return; 298 } 299 300 if (intent.hasExtra(EXTRA_STARTPACKAGE)) { 301 mImsExternalCallStates.clear(); 302 } else if (intent.hasExtra(EXTRA_SENDPACKAGE)) { 303 externalCallTracker.refreshExternalCallState(mImsExternalCallStates); 304 mImsExternalCallStates.clear(); 305 } else if (intent.hasExtra(EXTRA_DIALOGID)) { 306 ImsExternalCallState state = new ImsExternalCallState( 307 intent.getIntExtra(EXTRA_DIALOGID, 0), 308 Uri.parse(intent.getStringExtra(EXTRA_NUMBER)), 309 intent.getBooleanExtra(EXTRA_CANPULL, true), 310 intent.getIntExtra(EXTRA_STATE, 311 ImsExternalCallState.CALL_STATE_CONFIRMED), 312 ImsCallProfile.CALL_TYPE_VOICE, 313 false /* isHeld */ 314 ); 315 mImsExternalCallStates.add(state); 316 } 317 } 318 sendTestSuppServiceNotification(Intent intent)319 private void sendTestSuppServiceNotification(Intent intent) { 320 if (intent.hasExtra(EXTRA_CODE) && intent.hasExtra(EXTRA_TYPE)) { 321 int code = intent.getIntExtra(EXTRA_CODE, -1); 322 int type = intent.getIntExtra(EXTRA_TYPE, -1); 323 ImsPhone imsPhone = (ImsPhone) mPhone; 324 if (imsPhone == null) { 325 return; 326 } 327 log("Test supp service notification:" + code); 328 SuppServiceNotification suppServiceNotification = new SuppServiceNotification(); 329 suppServiceNotification.code = code; 330 suppServiceNotification.notificationType = type; 331 imsPhone.notifySuppSvcNotification(suppServiceNotification); 332 } 333 } 334 overrideServiceState(ServiceState ss)335 void overrideServiceState(ServiceState ss) { 336 if (mServiceStateTestIntent == null || ss == null) return; 337 if (mServiceStateTestIntent.hasExtra(EXTRA_ACTION) 338 && ACTION_RESET.equals(mServiceStateTestIntent.getStringExtra(EXTRA_ACTION))) { 339 log("Service state override reset"); 340 return; 341 } 342 if (mServiceStateTestIntent.hasExtra(EXTRA_VOICE_REG_STATE)) { 343 ss.setVoiceRegState(mServiceStateTestIntent.getIntExtra(EXTRA_VOICE_REG_STATE, 344 NetworkRegistrationState.REG_STATE_UNKNOWN)); 345 log("Override voice reg state with " + ss.getVoiceRegState()); 346 } 347 if (mServiceStateTestIntent.hasExtra(EXTRA_DATA_REG_STATE)) { 348 ss.setDataRegState(mServiceStateTestIntent.getIntExtra(EXTRA_DATA_REG_STATE, 349 NetworkRegistrationState.REG_STATE_UNKNOWN)); 350 log("Override data reg state with " + ss.getDataRegState()); 351 } 352 if (mServiceStateTestIntent.hasExtra(EXTRA_VOICE_RAT)) { 353 ss.setRilVoiceRadioTechnology(mServiceStateTestIntent.getIntExtra(EXTRA_VOICE_RAT, 354 ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)); 355 log("Override voice rat with " + ss.getRilVoiceRadioTechnology()); 356 } 357 if (mServiceStateTestIntent.hasExtra(EXTRA_DATA_RAT)) { 358 ss.setRilDataRadioTechnology(mServiceStateTestIntent.getIntExtra(EXTRA_DATA_RAT, 359 ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)); 360 log("Override data rat with " + ss.getRilDataRadioTechnology()); 361 } 362 if (mServiceStateTestIntent.hasExtra(EXTRA_VOICE_ROAMING_TYPE)) { 363 ss.setVoiceRoamingType(mServiceStateTestIntent.getIntExtra(EXTRA_VOICE_ROAMING_TYPE, 364 ServiceState.ROAMING_TYPE_UNKNOWN)); 365 log("Override voice roaming type with " + ss.getVoiceRoamingType()); 366 } 367 if (mServiceStateTestIntent.hasExtra(EXTRA_DATA_ROAMING_TYPE)) { 368 ss.setDataRoamingType(mServiceStateTestIntent.getIntExtra(EXTRA_DATA_ROAMING_TYPE, 369 ServiceState.ROAMING_TYPE_UNKNOWN)); 370 log("Override data roaming type with " + ss.getDataRoamingType()); 371 } 372 } 373 }