1 /* 2 * Copyright (C) 2009 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.phone; 18 19 import com.android.internal.telephony.Phone; 20 import com.android.internal.telephony.PhoneConstants; 21 import com.android.internal.telephony.TelephonyCapabilities; 22 import com.android.internal.telephony.TelephonyProperties; 23 import com.android.phone.OtaUtils.CdmaOtaInCallScreenUiState.State; 24 25 import android.app.Activity; 26 import android.app.ActivityManager; 27 import android.app.AlertDialog; 28 import android.app.PendingIntent; 29 import android.app.PendingIntent.CanceledException; 30 import android.content.ActivityNotFoundException; 31 import android.content.Context; 32 import android.content.DialogInterface; 33 import android.content.Intent; 34 import android.net.Uri; 35 import android.os.AsyncResult; 36 import android.os.Handler; 37 import android.os.SystemClock; 38 import android.os.SystemProperties; 39 import android.os.UserHandle; 40 import android.telecom.PhoneAccount; 41 import android.telephony.TelephonyManager; 42 import android.util.Log; 43 import android.view.KeyEvent; 44 import android.view.View; 45 import android.view.ViewGroup; 46 import android.view.WindowManager; 47 import android.widget.Button; 48 import android.widget.ProgressBar; 49 import android.widget.TextView; 50 import android.widget.ToggleButton; 51 52 /** 53 * Handles all OTASP Call related logic and UI functionality. 54 * The InCallScreen interacts with this class to perform an OTASP Call. 55 * 56 * OTASP is a CDMA-specific feature: 57 * OTA or OTASP == Over The Air service provisioning 58 * SPC == Service Programming Code 59 * TODO: Include pointer to more detailed documentation. 60 * 61 * TODO: This is Over The Air Service Provisioning (OTASP) 62 * A better name would be OtaspUtils.java. 63 */ 64 public class OtaUtils { 65 private static final String LOG_TAG = "OtaUtils"; 66 private static final boolean DBG = false; 67 68 public static final int OTA_SHOW_ACTIVATION_SCREEN_OFF = 0; 69 public static final int OTA_SHOW_ACTIVATION_SCREEN_ON = 1; 70 public static final int OTA_SHOW_LISTENING_SCREEN_OFF =0; 71 public static final int OTA_SHOW_LISTENING_SCREEN_ON =1; 72 public static final int OTA_SHOW_ACTIVATE_FAIL_COUNT_OFF = 0; 73 public static final int OTA_SHOW_ACTIVATE_FAIL_COUNT_THREE = 3; 74 public static final int OTA_PLAY_SUCCESS_FAILURE_TONE_OFF = 0; 75 public static final int OTA_PLAY_SUCCESS_FAILURE_TONE_ON = 1; 76 77 // SPC Timeout is 60 seconds 78 public final int OTA_SPC_TIMEOUT = 60; 79 public final int OTA_FAILURE_DIALOG_TIMEOUT = 2; 80 81 // Constants for OTASP-related Intents and intent extras. 82 // Watch out: these must agree with the corresponding constants in 83 // apps/SetupWizard! 84 85 // Intent action to launch an OTASP call. 86 public static final String ACTION_PERFORM_CDMA_PROVISIONING = 87 "com.android.phone.PERFORM_CDMA_PROVISIONING"; 88 89 // Intent action to launch activation on a non-voice capable device 90 public static final String ACTION_PERFORM_VOICELESS_CDMA_PROVISIONING = 91 "com.android.phone.PERFORM_VOICELESS_CDMA_PROVISIONING"; 92 93 // Intent action to display the InCallScreen in the OTASP "activation" state. 94 public static final String ACTION_DISPLAY_ACTIVATION_SCREEN = 95 "com.android.phone.DISPLAY_ACTIVATION_SCREEN"; 96 97 // boolean voiceless provisioning extra that enables a "don't show this again" checkbox 98 // the user can check to never see the activity upon bootup again 99 public static final String EXTRA_VOICELESS_PROVISIONING_OFFER_DONTSHOW = 100 "com.android.phone.VOICELESS_PROVISIONING_OFFER_DONTSHOW"; 101 102 // Activity result codes for the ACTION_PERFORM_CDMA_PROVISIONING intent 103 // (see the InCallScreenShowActivation activity.) 104 // 105 // Note: currently, our caller won't ever actually receive the 106 // RESULT_INTERACTIVE_OTASP_STARTED result code; see comments in 107 // InCallScreenShowActivation.onCreate() for details. 108 109 public static final int RESULT_INTERACTIVE_OTASP_STARTED = Activity.RESULT_FIRST_USER; 110 public static final int RESULT_NONINTERACTIVE_OTASP_STARTED = Activity.RESULT_FIRST_USER + 1; 111 public static final int RESULT_NONINTERACTIVE_OTASP_FAILED = Activity.RESULT_FIRST_USER + 2; 112 113 // Testing: Extra for the ACTION_PERFORM_CDMA_PROVISIONING intent that 114 // allows the caller to manually enable/disable "interactive mode" for 115 // the OTASP call. Only available in userdebug or eng builds. 116 public static final String EXTRA_OVERRIDE_INTERACTIVE_MODE = 117 "ota_override_interactive_mode"; 118 119 // Extra for the ACTION_PERFORM_CDMA_PROVISIONING intent, holding a 120 // PendingIntent which the phone app can use to send a result code 121 // back to the caller. 122 public static final String EXTRA_OTASP_RESULT_CODE_PENDING_INTENT = 123 "otasp_result_code_pending_intent"; 124 125 // Extra attached to the above PendingIntent that indicates 126 // success or failure. 127 public static final String EXTRA_OTASP_RESULT_CODE = "otasp_result_code"; 128 129 // Extra attached to the above PendingIntent that contains an error code. 130 public static final String EXTRA_OTASP_ERROR_CODE = "otasp_error_code"; 131 132 public static final int OTASP_UNKNOWN = 0; 133 public static final int OTASP_USER_SKIPPED = 1; // Only meaningful with interactive OTASP 134 public static final int OTASP_SUCCESS = 2; 135 public static final int OTASP_FAILURE = 3; 136 // failed due to CDMA_OTA_PROVISION_STATUS_SPC_RETRIES_EXCEEDED 137 public static final int OTASP_FAILURE_SPC_RETRIES = 4; 138 // TODO: Distinguish between interactive and non-interactive success 139 // and failure. Then, have the PendingIntent be sent after 140 // interactive OTASP as well (so the caller can find out definitively 141 // when interactive OTASP completes.) 142 143 private static final String OTASP_NUMBER = "*228"; 144 private static final String OTASP_NUMBER_NON_INTERACTIVE = "*22899"; 145 146 private Context mContext; 147 private PhoneGlobals mApplication; 148 private OtaWidgetData mOtaWidgetData; 149 150 private static boolean sIsWizardMode = true; 151 152 // How many times do we retry maybeDoOtaCall() if the LTE state is not known yet, 153 // and how long do we wait between retries 154 private static final int OTA_CALL_LTE_RETRIES_MAX = 5; 155 private static final int OTA_CALL_LTE_RETRY_PERIOD = 3000; 156 private static int sOtaCallLteRetries = 0; 157 158 // In "interactive mode", the OtaUtils object is tied to an 159 // InCallScreen instance, where we display a bunch of UI specific to 160 // the OTASP call. But on devices that are not "voice capable", the 161 // OTASP call runs in a non-interactive mode, and we don't have 162 // an InCallScreen or CallCard or any OTASP UI elements at all. 163 private boolean mInteractive = true; 164 165 // used when setting speakerphone 166 private final BluetoothManager mBluetoothManager; 167 168 /** 169 * OtaWidgetData class represent all OTA UI elements 170 * 171 * TODO(OTASP): It's really ugly for the OtaUtils object to reach into the 172 * InCallScreen like this and directly manipulate its widgets. 173 * 174 * Instead, the model/view separation should be more clear: OtaUtils 175 * should only know about a higher-level abstraction of the 176 * OTASP-specific UI state (just like how the CallController uses the 177 * InCallUiState object), and the InCallScreen itself should translate 178 * that higher-level abstraction into actual onscreen views and widgets. 179 */ 180 private class OtaWidgetData { 181 public Button otaEndButton; 182 public Button otaActivateButton; 183 public Button otaSkipButton; 184 public Button otaNextButton; 185 public ToggleButton otaSpeakerButton; 186 public ViewGroup otaUpperWidgets; 187 public View callCardOtaButtonsFailSuccess; 188 public ProgressBar otaTextProgressBar; 189 public TextView otaTextSuccessFail; 190 public View callCardOtaButtonsActivate; 191 public View callCardOtaButtonsListenProgress; 192 public TextView otaTextActivate; 193 public TextView otaTextListenProgress; 194 public AlertDialog spcErrorDialog; 195 public AlertDialog otaFailureDialog; 196 public AlertDialog otaSkipConfirmationDialog; 197 public TextView otaTitle; 198 public Button otaTryAgainButton; 199 } 200 201 /** 202 * OtaUtils constructor. 203 * 204 * @param context the Context of the calling Activity or Application 205 * @param interactive if true, use the InCallScreen to display the progress 206 * and result of the OTASP call. In practice this is 207 * true IFF the current device is a voice-capable phone. 208 * 209 * Note if interactive is true, you must also call updateUiWidgets() as soon 210 * as the InCallScreen instance is ready. 211 */ 212 public OtaUtils(Context context, boolean interactive, BluetoothManager bluetoothManager) { 213 if (DBG) log("OtaUtils constructor..."); 214 mApplication = PhoneGlobals.getInstance(); 215 mContext = context; 216 mInteractive = interactive; 217 mBluetoothManager = bluetoothManager; 218 } 219 220 /** 221 * Starts the OTA provisioning call. If the MIN isn't available yet, it returns false and adds 222 * an event to return the request to the calling app when it becomes available. 223 * 224 * @param context 225 * @param handler 226 * @param request 227 * @return true if we were able to launch Ota activity or it's not required; false otherwise 228 */ 229 public static boolean maybeDoOtaCall(Context context, Handler handler, int request) { 230 PhoneGlobals app = PhoneGlobals.getInstance(); 231 Phone phone = PhoneGlobals.getPhone(); 232 233 if (ActivityManager.isRunningInTestHarness()) { 234 Log.i(LOG_TAG, "Don't run provisioning when in test harness"); 235 return true; 236 } 237 238 if (!TelephonyCapabilities.supportsOtasp(phone)) { 239 // Presumably not a CDMA phone. 240 if (DBG) log("maybeDoOtaCall: OTASP not supported on this device"); 241 return true; // Nothing to do here. 242 } 243 244 if (!phone.isMinInfoReady()) { 245 if (DBG) log("MIN is not ready. Registering to receive notification."); 246 phone.registerForSubscriptionInfoReady(handler, request, null); 247 return false; 248 } 249 phone.unregisterForSubscriptionInfoReady(handler); 250 251 if (getLteOnCdmaMode(context) == PhoneConstants.LTE_ON_CDMA_UNKNOWN) { 252 if (sOtaCallLteRetries < OTA_CALL_LTE_RETRIES_MAX) { 253 if (DBG) log("maybeDoOtaCall: LTE state still unknown: retrying"); 254 handler.sendEmptyMessageDelayed(request, OTA_CALL_LTE_RETRY_PERIOD); 255 sOtaCallLteRetries++; 256 return false; 257 } else { 258 Log.w(LOG_TAG, "maybeDoOtaCall: LTE state still unknown: giving up"); 259 return true; 260 } 261 } 262 263 boolean phoneNeedsActivation = phone.needsOtaServiceProvisioning(); 264 if (DBG) log("phoneNeedsActivation is set to " + phoneNeedsActivation); 265 266 int otaShowActivationScreen = context.getResources().getInteger( 267 R.integer.OtaShowActivationScreen); 268 if (DBG) log("otaShowActivationScreen: " + otaShowActivationScreen); 269 270 // Run the OTASP call in "interactive" mode only if 271 // this is a non-LTE "voice capable" device. 272 if (PhoneGlobals.sVoiceCapable && getLteOnCdmaMode(context) == PhoneConstants.LTE_ON_CDMA_FALSE) { 273 if (phoneNeedsActivation 274 && (otaShowActivationScreen == OTA_SHOW_ACTIVATION_SCREEN_ON)) { 275 app.cdmaOtaProvisionData.isOtaCallIntentProcessed = false; 276 sIsWizardMode = false; 277 278 if (DBG) Log.d(LOG_TAG, "==> Starting interactive CDMA provisioning..."); 279 OtaUtils.startInteractiveOtasp(context); 280 281 if (DBG) log("maybeDoOtaCall: voice capable; activation started."); 282 } else { 283 if (DBG) log("maybeDoOtaCall: voice capable; activation NOT started."); 284 } 285 } else { 286 if (phoneNeedsActivation) { 287 app.cdmaOtaProvisionData.isOtaCallIntentProcessed = false; 288 Intent newIntent = new Intent(ACTION_PERFORM_VOICELESS_CDMA_PROVISIONING); 289 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 290 newIntent.putExtra(EXTRA_VOICELESS_PROVISIONING_OFFER_DONTSHOW, true); 291 try { 292 context.startActivity(newIntent); 293 } catch (ActivityNotFoundException e) { 294 loge("No activity Handling PERFORM_VOICELESS_CDMA_PROVISIONING!"); 295 return false; 296 } 297 if (DBG) log("maybeDoOtaCall: non-interactive; activation intent sent."); 298 } else { 299 if (DBG) log("maybeDoOtaCall: non-interactive, no need for OTASP."); 300 } 301 } 302 return true; 303 } 304 305 /** 306 * Starts a normal "interactive" OTASP call (i.e. CDMA activation 307 * for regular voice-capable phone devices.) 308 * 309 * This method is called from the InCallScreenShowActivation activity when 310 * handling the ACTION_PERFORM_CDMA_PROVISIONING intent. 311 */ 312 public static void startInteractiveOtasp(Context context) { 313 if (DBG) log("startInteractiveOtasp()..."); 314 PhoneGlobals app = PhoneGlobals.getInstance(); 315 316 // There are two ways to start OTASP on voice-capable devices: 317 // 318 // (1) via the PERFORM_CDMA_PROVISIONING intent 319 // - this is triggered by the "Activate device" button in settings, 320 // or can be launched automatically upon boot if the device 321 // thinks it needs to be provisioned. 322 // - the intent is handled by InCallScreenShowActivation.onCreate(), 323 // which calls this method 324 // - we prepare for OTASP by initializing the OtaUtils object 325 // - we bring up the InCallScreen in the ready-to-activate state 326 // - when the user presses the "Activate" button we launch the 327 // call by calling CallController.placeCall() via the 328 // otaPerformActivation() method. 329 // 330 // (2) by manually making an outgoing call to a special OTASP number 331 // like "*228" or "*22899". 332 // - That sequence does NOT involve this method (OtaUtils.startInteractiveOtasp()). 333 // Instead, the outgoing call request goes straight to CallController.placeCall(). 334 // - CallController.placeCall() notices that it's an OTASP 335 // call, and initializes the OtaUtils object. 336 // - The InCallScreen is launched (as the last step of 337 // CallController.placeCall()). The InCallScreen notices that 338 // OTASP is active and shows the correct UI. 339 340 // Here, we start sequence (1): 341 // Do NOT immediately start the call. Instead, bring up the InCallScreen 342 // in the special "activate" state (see OtaUtils.otaShowActivateScreen()). 343 // We won't actually make the call until the user presses the "Activate" 344 // button. 345 346 Intent activationScreenIntent = new Intent().setClass(context, InCallScreen.class) 347 .setAction(ACTION_DISPLAY_ACTIVATION_SCREEN); 348 349 // Watch out: in the scenario where OTASP gets triggered from the 350 // BOOT_COMPLETED broadcast (see OtaStartupReceiver.java), we might be 351 // running in the PhoneApp's context right now. 352 // So the FLAG_ACTIVITY_NEW_TASK flag is required here. 353 activationScreenIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 354 355 // We're about to start the OTASP sequence, so create and initialize the 356 // OtaUtils instance. (This needs to happen before bringing up the 357 // InCallScreen.) 358 OtaUtils.setupOtaspCall(activationScreenIntent); 359 360 // And bring up the InCallScreen... 361 Log.i(LOG_TAG, "startInteractiveOtasp: launching InCallScreen in 'activate' state: " 362 + activationScreenIntent); 363 context.startActivity(activationScreenIntent); 364 } 365 366 /** 367 * Starts the OTASP call *without* involving the InCallScreen or 368 * displaying any UI. 369 * 370 * This is used on data-only devices, which don't support any kind of 371 * in-call phone UI. 372 * 373 * @return PhoneUtils.CALL_STATUS_DIALED if we successfully 374 * dialed the OTASP number, or one of the other 375 * CALL_STATUS_* constants if there was a failure. 376 */ 377 public static int startNonInteractiveOtasp(Context context) { 378 if (DBG) log("startNonInteractiveOtasp()..."); 379 PhoneGlobals app = PhoneGlobals.getInstance(); 380 381 if (app.otaUtils != null) { 382 // An OtaUtils instance already exists, presumably from a previous OTASP call. 383 Log.i(LOG_TAG, "startNonInteractiveOtasp: " 384 + "OtaUtils already exists; nuking the old one and starting again..."); 385 } 386 387 // Create the OtaUtils instance. 388 app.otaUtils = new OtaUtils(context, false /* non-interactive mode */, 389 app.getBluetoothManager()); 390 if (DBG) log("- created OtaUtils: " + app.otaUtils); 391 392 // ... and kick off the OTASP call. 393 // TODO(InCallScreen redesign): This should probably go through 394 // the CallController, rather than directly calling 395 // PhoneUtils.placeCall(). 396 Phone phone = PhoneGlobals.getPhone(); 397 String number = OTASP_NUMBER_NON_INTERACTIVE; 398 Log.i(LOG_TAG, "startNonInteractiveOtasp: placing call to '" + number + "'..."); 399 int callStatus = PhoneUtils.placeCall(context, 400 phone, 401 number, 402 null, // contactRef 403 false); //isEmergencyCall 404 405 if (callStatus == PhoneUtils.CALL_STATUS_DIALED) { 406 if (DBG) log(" ==> successful return from placeCall(): callStatus = " + callStatus); 407 } else { 408 Log.w(LOG_TAG, "Failure from placeCall() for OTA number '" 409 + number + "': code " + callStatus); 410 return callStatus; 411 } 412 413 // TODO: Any other special work to do here? 414 // Such as: 415 // 416 // - manually kick off progress updates, either using TelephonyRegistry 417 // or else by sending PendingIntents directly to our caller? 418 // 419 // - manually silence the in-call audio? (Probably unnecessary 420 // if Stingray truly has no audio path from phone baseband 421 // to the device's speakers.) 422 // 423 424 return callStatus; 425 } 426 427 /** 428 * @return true if the specified Intent is a CALL action that's an attempt 429 * to initate an OTASP call. 430 * 431 * OTASP is a CDMA-specific concept, so this method will always return false 432 * on GSM phones. 433 * 434 * This code was originally part of the InCallScreen.checkIsOtaCall() method. 435 */ 436 public static boolean isOtaspCallIntent(Intent intent) { 437 if (DBG) log("isOtaspCallIntent(" + intent + ")..."); 438 PhoneGlobals app = PhoneGlobals.getInstance(); 439 Phone phone = app.mCM.getDefaultPhone(); 440 441 if (intent == null) { 442 return false; 443 } 444 if (!TelephonyCapabilities.supportsOtasp(phone)) { 445 return false; 446 } 447 448 String action = intent.getAction(); 449 if (action == null) { 450 return false; 451 } 452 if (!action.equals(Intent.ACTION_CALL)) { 453 if (DBG) log("isOtaspCallIntent: not a CALL action: '" + action + "' ==> not OTASP"); 454 return false; 455 } 456 457 if ((app.cdmaOtaScreenState == null) || (app.cdmaOtaProvisionData == null)) { 458 // Uh oh -- something wrong with our internal OTASP state. 459 // (Since this is an OTASP-capable device, these objects 460 // *should* have already been created by PhoneApp.onCreate().) 461 throw new IllegalStateException("isOtaspCallIntent: " 462 + "app.cdmaOta* objects(s) not initialized"); 463 } 464 465 // This is an OTASP call iff the number we're trying to dial is one of 466 // the magic OTASP numbers. 467 String number; 468 try { 469 number = PhoneUtils.getInitialNumber(intent); 470 } catch (PhoneUtils.VoiceMailNumberMissingException ex) { 471 // This was presumably a "voicemail:" intent, so it's 472 // obviously not an OTASP number. 473 if (DBG) log("isOtaspCallIntent: VoiceMailNumberMissingException => not OTASP"); 474 return false; 475 } 476 if (phone.isOtaSpNumber(number)) { 477 if (DBG) log("isOtaSpNumber: ACTION_CALL to '" + number + "' ==> OTASP call!"); 478 return true; 479 } 480 return false; 481 } 482 483 /** 484 * Set up for an OTASP call. 485 * 486 * This method is called as part of the CallController placeCall() sequence 487 * before initiating an outgoing OTASP call. 488 * 489 * The purpose of this method is mainly to create and initialize the 490 * OtaUtils instance, along with some other misc pre-OTASP cleanup. 491 */ 492 public static void setupOtaspCall(Intent intent) { 493 if (DBG) log("setupOtaspCall(): preparing for OTASP call to " + intent); 494 PhoneGlobals app = PhoneGlobals.getInstance(); 495 496 if (app.otaUtils != null) { 497 // An OtaUtils instance already exists, presumably from a prior OTASP call. 498 // Nuke the old one and start this call with a fresh instance. 499 Log.i(LOG_TAG, "setupOtaspCall: " 500 + "OtaUtils already exists; replacing with new instance..."); 501 } 502 503 // Create the OtaUtils instance. 504 app.otaUtils = new OtaUtils(app.getApplicationContext(), true /* interactive */, 505 app.getBluetoothManager()); 506 if (DBG) log("- created OtaUtils: " + app.otaUtils); 507 508 // NOTE we still need to call OtaUtils.updateUiWidgets() once the 509 // InCallScreen instance is ready; see InCallScreen.checkOtaspStateOnResume() 510 511 // Make sure the InCallScreen knows that it needs to switch into OTASP mode. 512 // 513 // NOTE in gingerbread and earlier, we used to do 514 // setInCallScreenMode(InCallScreenMode.OTA_NORMAL); 515 // directly in the InCallScreen, back when this check happened inside the InCallScreen. 516 // 517 // But now, set the global CdmaOtaInCallScreenUiState object into 518 // NORMAL mode, which will then cause the InCallScreen (when it 519 // comes up) to realize that an OTA call is active. 520 521 app.otaUtils.setCdmaOtaInCallScreenUiState( 522 OtaUtils.CdmaOtaInCallScreenUiState.State.NORMAL); 523 524 // TODO(OTASP): note app.inCallUiState.inCallScreenMode and 525 // app.cdmaOtaInCallScreenUiState.state are mostly redundant. Combine them. 526 // app.inCallUiState.inCallScreenMode = InCallUiState.InCallScreenMode.OTA_NORMAL; 527 528 // TODO(OTASP / bug 5092031): we ideally should call 529 // otaShowListeningScreen() here to make sure that the DTMF dialpad 530 // becomes visible at the start of the "*228" call: 531 // 532 // // ...and get the OTASP-specific UI into the right state. 533 // app.otaUtils.otaShowListeningScreen(); 534 // if (app.otaUtils.mInCallScreen != null) { 535 // app.otaUtils.mInCallScreen.requestUpdateScreen(); 536 // } 537 // 538 // But this doesn't actually work; the call to otaShowListeningScreen() 539 // *doesn't* actually bring up the listening screen, since the 540 // cdmaOtaConfigData.otaShowListeningScreen config parameter hasn't been 541 // initialized (we haven't run readXmlSettings() yet at this point!) 542 543 // Also, since the OTA call is now just starting, clear out 544 // the "committed" flag in app.cdmaOtaProvisionData. 545 if (app.cdmaOtaProvisionData != null) { 546 app.cdmaOtaProvisionData.isOtaCallCommitted = false; 547 } 548 } 549 550 private void setSpeaker(boolean state) { 551 if (DBG) log("setSpeaker : " + state ); 552 553 if (!mInteractive) { 554 if (DBG) log("non-interactive mode, ignoring setSpeaker."); 555 return; 556 } 557 558 if (state == PhoneUtils.isSpeakerOn(mContext)) { 559 if (DBG) log("no change. returning"); 560 return; 561 } 562 563 if (state && mBluetoothManager.isBluetoothAvailable() 564 && mBluetoothManager.isBluetoothAudioConnected()) { 565 mBluetoothManager.disconnectBluetoothAudio(); 566 } 567 PhoneUtils.turnOnSpeaker(mContext, state, true); 568 } 569 570 /** 571 * Handles OTA Provision events from the telephony layer. 572 * These events come in to this method whether or not 573 * the InCallScreen is visible. 574 * 575 * Possible events are: 576 * OTA Commit Event - OTA provisioning was successful 577 * SPC retries exceeded - SPC failure retries has exceeded, and Phone needs to 578 * power down. 579 */ 580 public void onOtaProvisionStatusChanged(AsyncResult r) { 581 int OtaStatus[] = (int[]) r.result; 582 if (DBG) log("Provision status event!"); 583 if (DBG) log("onOtaProvisionStatusChanged(): status = " 584 + OtaStatus[0] + " ==> " + otaProvisionStatusToString(OtaStatus[0])); 585 586 // In practice, in a normal successful OTASP call, events come in as follows: 587 // - SPL_UNLOCKED within a couple of seconds after the call starts 588 // - then a delay of around 45 seconds 589 // - then PRL_DOWNLOADED and MDN_DOWNLOADED and COMMITTED within a span of 2 seconds 590 591 switch(OtaStatus[0]) { 592 case Phone.CDMA_OTA_PROVISION_STATUS_SPC_RETRIES_EXCEEDED: 593 if (DBG) log("onOtaProvisionStatusChanged(): RETRIES EXCEEDED"); 594 updateOtaspProgress(); 595 mApplication.cdmaOtaProvisionData.otaSpcUptime = SystemClock.elapsedRealtime(); 596 if (mInteractive) { 597 otaShowSpcErrorNotice(OTA_SPC_TIMEOUT); 598 } else { 599 sendOtaspResult(OTASP_FAILURE_SPC_RETRIES); 600 } 601 // Power.shutdown(); 602 break; 603 604 case Phone.CDMA_OTA_PROVISION_STATUS_COMMITTED: 605 if (DBG) { 606 log("onOtaProvisionStatusChanged(): DONE, isOtaCallCommitted set to true"); 607 } 608 mApplication.cdmaOtaProvisionData.isOtaCallCommitted = true; 609 if (mApplication.cdmaOtaScreenState.otaScreenState != 610 CdmaOtaScreenState.OtaScreenState.OTA_STATUS_UNDEFINED) { 611 updateOtaspProgress(); 612 } 613 614 break; 615 616 case Phone.CDMA_OTA_PROVISION_STATUS_SPL_UNLOCKED: 617 case Phone.CDMA_OTA_PROVISION_STATUS_A_KEY_EXCHANGED: 618 case Phone.CDMA_OTA_PROVISION_STATUS_SSD_UPDATED: 619 case Phone.CDMA_OTA_PROVISION_STATUS_NAM_DOWNLOADED: 620 case Phone.CDMA_OTA_PROVISION_STATUS_MDN_DOWNLOADED: 621 case Phone.CDMA_OTA_PROVISION_STATUS_IMSI_DOWNLOADED: 622 case Phone.CDMA_OTA_PROVISION_STATUS_PRL_DOWNLOADED: 623 case Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STARTED: 624 case Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED: 625 case Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_ABORTED: 626 // Only update progress when OTA call is in normal state 627 if (getCdmaOtaInCallScreenUiState() == CdmaOtaInCallScreenUiState.State.NORMAL) { 628 if (DBG) log("onOtaProvisionStatusChanged(): change to ProgressScreen"); 629 updateOtaspProgress(); 630 } 631 break; 632 633 default: 634 if (DBG) log("onOtaProvisionStatusChanged(): Ignoring OtaStatus " + OtaStatus[0]); 635 break; 636 } 637 } 638 639 /** 640 * Handle a disconnect event from the OTASP call. 641 */ 642 public void onOtaspDisconnect() { 643 if (DBG) log("onOtaspDisconnect()..."); 644 // We only handle this event explicitly in non-interactive mode. 645 // (In interactive mode, the InCallScreen does any post-disconnect 646 // cleanup.) 647 if (!mInteractive) { 648 // Send a success or failure indication back to our caller. 649 updateNonInteractiveOtaSuccessFailure(); 650 } 651 } 652 653 private void otaShowHome() { 654 if (DBG) log("otaShowHome()..."); 655 mApplication.cdmaOtaScreenState.otaScreenState = 656 CdmaOtaScreenState.OtaScreenState.OTA_STATUS_UNDEFINED; 657 // mInCallScreen.endInCallScreenSession(); 658 Intent intent = new Intent(Intent.ACTION_MAIN); 659 intent.addCategory (Intent.CATEGORY_HOME); 660 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 661 mContext.startActivityAsUser(intent, UserHandle.CURRENT); 662 return; 663 } 664 665 private void otaSkipActivation() { 666 if (DBG) log("otaSkipActivation()..."); 667 668 sendOtaspResult(OTASP_USER_SKIPPED); 669 670 // if (mInteractive) mInCallScreen.finish(); 671 return; 672 } 673 674 /** 675 * Actually initiate the OTASP call. This method is triggered by the 676 * onscreen "Activate" button, and is only used in interactive mode. 677 */ 678 private void otaPerformActivation() { 679 if (DBG) log("otaPerformActivation()..."); 680 if (!mInteractive) { 681 // We shouldn't ever get here in non-interactive mode! 682 Log.w(LOG_TAG, "otaPerformActivation: not interactive!"); 683 return; 684 } 685 686 if (!mApplication.cdmaOtaProvisionData.inOtaSpcState) { 687 // Place an outgoing call to the special OTASP number: 688 Intent newIntent = new Intent(Intent.ACTION_CALL); 689 newIntent.setData(Uri.fromParts(PhoneAccount.SCHEME_TEL, OTASP_NUMBER, null)); 690 691 // Initiate the outgoing call: 692 mApplication.callController.placeCall(newIntent); 693 694 // ...and get the OTASP-specific UI into the right state. 695 otaShowListeningScreen(); 696 // mInCallScreen.requestUpdateScreen(); 697 } 698 return; 699 } 700 701 /** 702 * Show Activation Screen when phone powers up and OTA provision is 703 * required. Also shown when activation fails and user needs 704 * to re-attempt it. Contains ACTIVATE and SKIP buttons 705 * which allow user to start OTA activation or skip the activation process. 706 */ 707 public void otaShowActivateScreen() { 708 if (DBG) log("otaShowActivateScreen()..."); 709 if (mApplication.cdmaOtaConfigData.otaShowActivationScreen 710 == OTA_SHOW_ACTIVATION_SCREEN_ON) { 711 if (DBG) log("otaShowActivateScreen(): show activation screen"); 712 if (!isDialerOpened()) { 713 otaScreenInitialize(); 714 mOtaWidgetData.otaSkipButton.setVisibility(sIsWizardMode ? 715 View.VISIBLE : View.INVISIBLE); 716 mOtaWidgetData.otaTextActivate.setVisibility(View.VISIBLE); 717 mOtaWidgetData.callCardOtaButtonsActivate.setVisibility(View.VISIBLE); 718 } 719 mApplication.cdmaOtaScreenState.otaScreenState = 720 CdmaOtaScreenState.OtaScreenState.OTA_STATUS_ACTIVATION; 721 } else { 722 if (DBG) log("otaShowActivateScreen(): show home screen"); 723 otaShowHome(); 724 } 725 } 726 727 /** 728 * Show "Listen for Instruction" screen during OTA call. Shown when OTA Call 729 * is initiated and user needs to listen for network instructions and press 730 * appropriate DTMF digits to proceed to the "Programming in Progress" phase. 731 */ 732 private void otaShowListeningScreen() { 733 if (DBG) log("otaShowListeningScreen()..."); 734 if (!mInteractive) { 735 // We shouldn't ever get here in non-interactive mode! 736 Log.w(LOG_TAG, "otaShowListeningScreen: not interactive!"); 737 return; 738 } 739 740 if (mApplication.cdmaOtaConfigData.otaShowListeningScreen 741 == OTA_SHOW_LISTENING_SCREEN_ON) { 742 if (DBG) log("otaShowListeningScreen(): show listening screen"); 743 if (!isDialerOpened()) { 744 otaScreenInitialize(); 745 mOtaWidgetData.otaTextListenProgress.setVisibility(View.VISIBLE); 746 mOtaWidgetData.otaTextListenProgress.setText(R.string.ota_listen); 747 // mOtaWidgetData.otaDtmfDialerView.setVisibility(View.VISIBLE); 748 mOtaWidgetData.callCardOtaButtonsListenProgress.setVisibility(View.VISIBLE); 749 mOtaWidgetData.otaSpeakerButton.setVisibility(View.VISIBLE); 750 boolean speakerOn = PhoneUtils.isSpeakerOn(mContext); 751 mOtaWidgetData.otaSpeakerButton.setChecked(speakerOn); 752 } 753 mApplication.cdmaOtaScreenState.otaScreenState = 754 CdmaOtaScreenState.OtaScreenState.OTA_STATUS_LISTENING; 755 } else { 756 if (DBG) log("otaShowListeningScreen(): show progress screen"); 757 otaShowInProgressScreen(); 758 } 759 } 760 761 /** 762 * Do any necessary updates (of onscreen UI, for example) 763 * based on the latest status of the OTASP call. 764 */ 765 private void updateOtaspProgress() { 766 if (DBG) log("updateOtaspProgress()... mInteractive = " + mInteractive); 767 if (mInteractive) { 768 // On regular phones we just call through to 769 // otaShowInProgressScreen(), which updates the 770 // InCallScreen's onscreen UI. 771 otaShowInProgressScreen(); 772 } else { 773 // We're not using the InCallScreen to show OTA progress. 774 775 // For now, at least, there's nothing to do here. 776 // The overall "success" or "failure" indication we send back 777 // (to our caller) is triggered by the DISCONNECT event; 778 // see updateNonInteractiveOtaSuccessFailure(). 779 780 // But if we ever need to send *intermediate* progress updates back 781 // to our caller, we'd do that here, possbily using the same 782 // PendingIntent that we already use to indicate success or failure. 783 } 784 } 785 786 /** 787 * When a non-interactive OTASP call completes, send a success or 788 * failure indication back to our caller. 789 * 790 * This is basically the non-interactive equivalent of 791 * otaShowSuccessFailure(). 792 */ 793 private void updateNonInteractiveOtaSuccessFailure() { 794 // This is basically the same logic as otaShowSuccessFailure(): we 795 // check the isOtaCallCommitted bit, and if that's true it means 796 // that activation was successful. 797 798 if (DBG) log("updateNonInteractiveOtaSuccessFailure(): isOtaCallCommitted = " 799 + mApplication.cdmaOtaProvisionData.isOtaCallCommitted); 800 int resultCode = 801 mApplication.cdmaOtaProvisionData.isOtaCallCommitted 802 ? OTASP_SUCCESS : OTASP_FAILURE; 803 sendOtaspResult(resultCode); 804 } 805 806 /** 807 * Sends the specified OTASP result code back to our caller (presumably 808 * SetupWizard) via the PendingIntent that they originally sent along with 809 * the ACTION_PERFORM_CDMA_PROVISIONING intent. 810 */ 811 private void sendOtaspResult(int resultCode) { 812 if (DBG) log("sendOtaspResult: resultCode = " + resultCode); 813 814 // Pass the success or failure indication back to our caller by 815 // adding an additional extra to the PendingIntent we already 816 // have. 817 // (NB: there's a PendingIntent send() method that takes a resultCode 818 // directly, but we can't use that here since that call is only 819 // meaningful for pending intents that are actually used as activity 820 // results.) 821 822 Intent extraStuff = new Intent(); 823 extraStuff.putExtra(EXTRA_OTASP_RESULT_CODE, resultCode); 824 // When we call PendingIntent.send() below, the extras from this 825 // intent will get merged with any extras already present in 826 // cdmaOtaScreenState.otaspResultCodePendingIntent. 827 828 if (mApplication.cdmaOtaScreenState == null) { 829 Log.e(LOG_TAG, "updateNonInteractiveOtaSuccessFailure: no cdmaOtaScreenState object!"); 830 return; 831 } 832 if (mApplication.cdmaOtaScreenState.otaspResultCodePendingIntent == null) { 833 Log.w(LOG_TAG, "updateNonInteractiveOtaSuccessFailure: " 834 + "null otaspResultCodePendingIntent!"); 835 return; 836 } 837 838 try { 839 if (DBG) log("- sendOtaspResult: SENDING PENDING INTENT: " + 840 mApplication.cdmaOtaScreenState.otaspResultCodePendingIntent); 841 mApplication.cdmaOtaScreenState.otaspResultCodePendingIntent.send( 842 mContext, 843 0, /* resultCode (unused) */ 844 extraStuff); 845 } catch (CanceledException e) { 846 // should never happen because no code cancels the pending intent right now, 847 Log.e(LOG_TAG, "PendingIntent send() failed: " + e); 848 } 849 } 850 851 /** 852 * Show "Programming In Progress" screen during OTA call. Shown when OTA 853 * provisioning is in progress after user has selected an option. 854 */ 855 private void otaShowInProgressScreen() { 856 if (DBG) log("otaShowInProgressScreen()..."); 857 if (!mInteractive) { 858 // We shouldn't ever get here in non-interactive mode! 859 Log.w(LOG_TAG, "otaShowInProgressScreen: not interactive!"); 860 return; 861 } 862 863 mApplication.cdmaOtaScreenState.otaScreenState = 864 CdmaOtaScreenState.OtaScreenState.OTA_STATUS_PROGRESS; 865 866 if ((mOtaWidgetData == null) /* || (mInCallScreen == null) */) { 867 Log.w(LOG_TAG, "otaShowInProgressScreen: UI widgets not set up yet!"); 868 869 // TODO(OTASP): our CdmaOtaScreenState is now correct; we just set 870 // it to OTA_STATUS_PROGRESS. But we still need to make sure that 871 // when the InCallScreen eventually comes to the foreground, it 872 // notices that state and does all the same UI updating we do below. 873 return; 874 } 875 876 if (!isDialerOpened()) { 877 otaScreenInitialize(); 878 mOtaWidgetData.otaTextListenProgress.setVisibility(View.VISIBLE); 879 mOtaWidgetData.otaTextListenProgress.setText(R.string.ota_progress); 880 mOtaWidgetData.otaTextProgressBar.setVisibility(View.VISIBLE); 881 mOtaWidgetData.callCardOtaButtonsListenProgress.setVisibility(View.VISIBLE); 882 mOtaWidgetData.otaSpeakerButton.setVisibility(View.VISIBLE); 883 boolean speakerOn = PhoneUtils.isSpeakerOn(mContext); 884 mOtaWidgetData.otaSpeakerButton.setChecked(speakerOn); 885 } 886 } 887 888 /** 889 * Show programming failure dialog when OTA provisioning fails. 890 * If OTA provisioning attempts fail more than 3 times, then unsuccessful 891 * dialog is shown. Otherwise a two-second notice is shown with unsuccessful 892 * information. When notice expires, phone returns to activation screen. 893 */ 894 private void otaShowProgramFailure(int length) { 895 if (DBG) log("otaShowProgramFailure()..."); 896 mApplication.cdmaOtaProvisionData.activationCount++; 897 if ((mApplication.cdmaOtaProvisionData.activationCount < 898 mApplication.cdmaOtaConfigData.otaShowActivateFailTimes) 899 && (mApplication.cdmaOtaConfigData.otaShowActivationScreen == 900 OTA_SHOW_ACTIVATION_SCREEN_ON)) { 901 if (DBG) log("otaShowProgramFailure(): activationCount" 902 + mApplication.cdmaOtaProvisionData.activationCount); 903 if (DBG) log("otaShowProgramFailure(): show failure notice"); 904 otaShowProgramFailureNotice(length); 905 } else { 906 if (DBG) log("otaShowProgramFailure(): show failure dialog"); 907 otaShowProgramFailureDialog(); 908 } 909 } 910 911 /** 912 * Show either programming success dialog when OTA provisioning succeeds, or 913 * programming failure dialog when it fails. See {@link #otaShowProgramFailure} 914 * for more details. 915 */ 916 public void otaShowSuccessFailure() { 917 if (DBG) log("otaShowSuccessFailure()..."); 918 if (!mInteractive) { 919 // We shouldn't ever get here in non-interactive mode! 920 Log.w(LOG_TAG, "otaShowSuccessFailure: not interactive!"); 921 return; 922 } 923 924 otaScreenInitialize(); 925 if (DBG) log("otaShowSuccessFailure(): isOtaCallCommitted" 926 + mApplication.cdmaOtaProvisionData.isOtaCallCommitted); 927 if (mApplication.cdmaOtaProvisionData.isOtaCallCommitted) { 928 if (DBG) log("otaShowSuccessFailure(), show success dialog"); 929 otaShowProgramSuccessDialog(); 930 } else { 931 if (DBG) log("otaShowSuccessFailure(), show failure dialog"); 932 otaShowProgramFailure(OTA_FAILURE_DIALOG_TIMEOUT); 933 } 934 return; 935 } 936 937 /** 938 * Show programming failure dialog when OTA provisioning fails more than 3 939 * times. 940 */ 941 private void otaShowProgramFailureDialog() { 942 if (DBG) log("otaShowProgramFailureDialog()..."); 943 mApplication.cdmaOtaScreenState.otaScreenState = 944 CdmaOtaScreenState.OtaScreenState.OTA_STATUS_SUCCESS_FAILURE_DLG; 945 mOtaWidgetData.otaTitle.setText(R.string.ota_title_problem_with_activation); 946 mOtaWidgetData.otaTextSuccessFail.setVisibility(View.VISIBLE); 947 mOtaWidgetData.otaTextSuccessFail.setText(R.string.ota_unsuccessful); 948 mOtaWidgetData.callCardOtaButtonsFailSuccess.setVisibility(View.VISIBLE); 949 mOtaWidgetData.otaTryAgainButton.setVisibility(View.VISIBLE); 950 //close the dialer if open 951 // if (isDialerOpened()) { 952 // mOtaCallCardDtmfDialer.closeDialer(false); 953 // } 954 } 955 956 /** 957 * Show programming success dialog when OTA provisioning succeeds. 958 */ 959 private void otaShowProgramSuccessDialog() { 960 if (DBG) log("otaShowProgramSuccessDialog()..."); 961 mApplication.cdmaOtaScreenState.otaScreenState = 962 CdmaOtaScreenState.OtaScreenState.OTA_STATUS_SUCCESS_FAILURE_DLG; 963 mOtaWidgetData.otaTitle.setText(R.string.ota_title_activate_success); 964 mOtaWidgetData.otaTextSuccessFail.setVisibility(View.VISIBLE); 965 mOtaWidgetData.otaTextSuccessFail.setText(R.string.ota_successful); 966 mOtaWidgetData.callCardOtaButtonsFailSuccess.setVisibility(View.VISIBLE); 967 mOtaWidgetData.otaNextButton.setVisibility(View.VISIBLE); 968 //close the dialer if open 969 // if (isDialerOpened()) { 970 // mOtaCallCardDtmfDialer.closeDialer(false); 971 // } 972 } 973 974 /** 975 * Show SPC failure notice when SPC attempts exceed 15 times. 976 * During OTA provisioning, if SPC code is incorrect OTA provisioning will 977 * fail. When SPC attempts are over 15, it shows SPC failure notice for one minute and 978 * then phone will power down. 979 */ 980 private void otaShowSpcErrorNotice(int length) { 981 if (DBG) log("otaShowSpcErrorNotice()..."); 982 if (mOtaWidgetData.spcErrorDialog == null) { 983 mApplication.cdmaOtaProvisionData.inOtaSpcState = true; 984 DialogInterface.OnKeyListener keyListener; 985 keyListener = new DialogInterface.OnKeyListener() { 986 public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { 987 log("Ignoring key events..."); 988 return true; 989 }}; 990 mOtaWidgetData.spcErrorDialog = new AlertDialog.Builder(null /* mInCallScreen */) 991 .setMessage(R.string.ota_spc_failure) 992 .setOnKeyListener(keyListener) 993 .create(); 994 mOtaWidgetData.spcErrorDialog.getWindow().addFlags( 995 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 996 | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 997 mOtaWidgetData.spcErrorDialog.show(); 998 //close the dialer if open 999 // if (isDialerOpened()) { 1000 // mOtaCallCardDtmfDialer.closeDialer(false); 1001 // } 1002 long noticeTime = length*1000; 1003 if (DBG) log("otaShowSpcErrorNotice(), remaining SPC noticeTime" + noticeTime); 1004 // mInCallScreen.requestCloseSpcErrorNotice(noticeTime); 1005 } 1006 } 1007 1008 /** 1009 * When SPC notice times out, force phone to power down. 1010 */ 1011 public void onOtaCloseSpcNotice() { 1012 if (DBG) log("onOtaCloseSpcNotice(), send shutdown intent"); 1013 Intent shutdown = new Intent(Intent.ACTION_REQUEST_SHUTDOWN); 1014 shutdown.putExtra(Intent.EXTRA_KEY_CONFIRM, false); 1015 shutdown.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1016 mContext.startActivity(shutdown); 1017 } 1018 1019 /** 1020 * Show two-second notice when OTA provisioning fails and number of failed attempts 1021 * is less then 3. 1022 */ 1023 private void otaShowProgramFailureNotice(int length) { 1024 if (DBG) log("otaShowProgramFailureNotice()..."); 1025 if (mOtaWidgetData.otaFailureDialog == null) { 1026 mOtaWidgetData.otaFailureDialog = new AlertDialog.Builder(null /* mInCallScreen */) 1027 .setMessage(R.string.ota_failure) 1028 .create(); 1029 mOtaWidgetData.otaFailureDialog.getWindow().addFlags( 1030 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 1031 | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 1032 mOtaWidgetData.otaFailureDialog.show(); 1033 1034 long noticeTime = length*1000; 1035 // mInCallScreen.requestCloseOtaFailureNotice(noticeTime); 1036 } 1037 } 1038 1039 /** 1040 * Handle OTA unsuccessful notice expiry. Dismisses the 1041 * two-second notice and shows the activation screen. 1042 */ 1043 public void onOtaCloseFailureNotice() { 1044 if (DBG) log("onOtaCloseFailureNotice()..."); 1045 if (mOtaWidgetData.otaFailureDialog != null) { 1046 mOtaWidgetData.otaFailureDialog.dismiss(); 1047 mOtaWidgetData.otaFailureDialog = null; 1048 } 1049 otaShowActivateScreen(); 1050 } 1051 1052 /** 1053 * Initialize all OTA UI elements to be gone. Also set inCallPanel, 1054 * callCard and the dialpad handle to be gone. This is called before any OTA screen 1055 * gets drawn. 1056 */ 1057 private void otaScreenInitialize() { 1058 if (DBG) log("otaScreenInitialize()..."); 1059 1060 if (!mInteractive) { 1061 // We should never be doing anything with UI elements in 1062 // non-interactive mode. 1063 Log.w(LOG_TAG, "otaScreenInitialize: not interactive!"); 1064 return; 1065 } 1066 1067 // if (mInCallTouchUi != null) mInCallTouchUi.setVisibility(View.GONE); 1068 // if (mCallCard != null) { 1069 // mCallCard.setVisibility(View.GONE); 1070 // // TODO: try removing this. 1071 // mCallCard.hideCallCardElements(); 1072 // } 1073 1074 mOtaWidgetData.otaTitle.setText(R.string.ota_title_activate); 1075 mOtaWidgetData.otaTextActivate.setVisibility(View.GONE); 1076 mOtaWidgetData.otaTextListenProgress.setVisibility(View.GONE); 1077 mOtaWidgetData.otaTextProgressBar.setVisibility(View.GONE); 1078 mOtaWidgetData.otaTextSuccessFail.setVisibility(View.GONE); 1079 mOtaWidgetData.callCardOtaButtonsActivate.setVisibility(View.GONE); 1080 mOtaWidgetData.callCardOtaButtonsListenProgress.setVisibility(View.GONE); 1081 mOtaWidgetData.callCardOtaButtonsFailSuccess.setVisibility(View.GONE); 1082 // mOtaWidgetData.otaDtmfDialerView.setVisibility(View.GONE); 1083 mOtaWidgetData.otaSpeakerButton.setVisibility(View.GONE); 1084 mOtaWidgetData.otaTryAgainButton.setVisibility(View.GONE); 1085 mOtaWidgetData.otaNextButton.setVisibility(View.GONE); 1086 mOtaWidgetData.otaUpperWidgets.setVisibility(View.VISIBLE); 1087 mOtaWidgetData.otaSkipButton.setVisibility(View.VISIBLE); 1088 } 1089 1090 public void hideOtaScreen() { 1091 if (DBG) log("hideOtaScreen()..."); 1092 1093 mOtaWidgetData.callCardOtaButtonsActivate.setVisibility(View.GONE); 1094 mOtaWidgetData.callCardOtaButtonsListenProgress.setVisibility(View.GONE); 1095 mOtaWidgetData.callCardOtaButtonsFailSuccess.setVisibility(View.GONE); 1096 mOtaWidgetData.otaUpperWidgets.setVisibility(View.GONE); 1097 } 1098 1099 public boolean isDialerOpened() { 1100 // boolean retval = (mOtaCallCardDtmfDialer != null && mOtaCallCardDtmfDialer.isOpened()); 1101 boolean retval = false; 1102 if (DBG) log("- isDialerOpened() ==> " + retval); 1103 return retval; 1104 } 1105 1106 /** 1107 * Show the appropriate OTA screen based on the current state of OTA call. 1108 * 1109 * This is called from the InCallScreen when the screen needs to be 1110 * refreshed (and thus is only ever used in interactive mode.) 1111 * 1112 * Since this is called as part of the InCallScreen.updateScreen() sequence, 1113 * this method does *not* post an mInCallScreen.requestUpdateScreen() 1114 * request. 1115 */ 1116 public void otaShowProperScreen() { 1117 if (DBG) log("otaShowProperScreen()..."); 1118 if (!mInteractive) { 1119 // We shouldn't ever get here in non-interactive mode! 1120 Log.w(LOG_TAG, "otaShowProperScreen: not interactive!"); 1121 return; 1122 } 1123 1124 // if ((mInCallScreen != null) && mInCallScreen.isForegroundActivity()) { 1125 // if (DBG) log("otaShowProperScreen(): InCallScreen in foreground, currentstate = " 1126 // + mApplication.cdmaOtaScreenState.otaScreenState); 1127 // if (mInCallTouchUi != null) { 1128 // mInCallTouchUi.setVisibility(View.GONE); 1129 // } 1130 // if (mCallCard != null) { 1131 // mCallCard.setVisibility(View.GONE); 1132 // } 1133 // if (mApplication.cdmaOtaScreenState.otaScreenState 1134 // == CdmaOtaScreenState.OtaScreenState.OTA_STATUS_ACTIVATION) { 1135 // otaShowActivateScreen(); 1136 // } else if (mApplication.cdmaOtaScreenState.otaScreenState 1137 // == CdmaOtaScreenState.OtaScreenState.OTA_STATUS_LISTENING) { 1138 // otaShowListeningScreen(); 1139 // } else if (mApplication.cdmaOtaScreenState.otaScreenState 1140 // == CdmaOtaScreenState.OtaScreenState.OTA_STATUS_PROGRESS) { 1141 // otaShowInProgressScreen(); 1142 // } 1143 1144 // if (mApplication.cdmaOtaProvisionData.inOtaSpcState) { 1145 // otaShowSpcErrorNotice(getOtaSpcDisplayTime()); 1146 // } 1147 // } 1148 } 1149 1150 /** 1151 * Read configuration values for each OTA screen from config.xml. 1152 * These configuration values control visibility of each screen. 1153 */ 1154 private void readXmlSettings() { 1155 if (DBG) log("readXmlSettings()..."); 1156 if (mApplication.cdmaOtaConfigData.configComplete) { 1157 return; 1158 } 1159 1160 mApplication.cdmaOtaConfigData.configComplete = true; 1161 int tmpOtaShowActivationScreen = 1162 mContext.getResources().getInteger(R.integer.OtaShowActivationScreen); 1163 mApplication.cdmaOtaConfigData.otaShowActivationScreen = tmpOtaShowActivationScreen; 1164 if (DBG) log("readXmlSettings(), otaShowActivationScreen = " 1165 + mApplication.cdmaOtaConfigData.otaShowActivationScreen); 1166 1167 int tmpOtaShowListeningScreen = 1168 mContext.getResources().getInteger(R.integer.OtaShowListeningScreen); 1169 mApplication.cdmaOtaConfigData.otaShowListeningScreen = tmpOtaShowListeningScreen; 1170 if (DBG) log("readXmlSettings(), otaShowListeningScreen = " 1171 + mApplication.cdmaOtaConfigData.otaShowListeningScreen); 1172 1173 int tmpOtaShowActivateFailTimes = 1174 mContext.getResources().getInteger(R.integer.OtaShowActivateFailTimes); 1175 mApplication.cdmaOtaConfigData.otaShowActivateFailTimes = tmpOtaShowActivateFailTimes; 1176 if (DBG) log("readXmlSettings(), otaShowActivateFailTimes = " 1177 + mApplication.cdmaOtaConfigData.otaShowActivateFailTimes); 1178 1179 int tmpOtaPlaySuccessFailureTone = 1180 mContext.getResources().getInteger(R.integer.OtaPlaySuccessFailureTone); 1181 mApplication.cdmaOtaConfigData.otaPlaySuccessFailureTone = tmpOtaPlaySuccessFailureTone; 1182 if (DBG) log("readXmlSettings(), otaPlaySuccessFailureTone = " 1183 + mApplication.cdmaOtaConfigData.otaPlaySuccessFailureTone); 1184 } 1185 1186 /** 1187 * Handle the click events for OTA buttons. 1188 */ 1189 public void onClickHandler(int id) { 1190 switch (id) { 1191 case R.id.otaEndButton: 1192 onClickOtaEndButton(); 1193 break; 1194 1195 case R.id.otaSpeakerButton: 1196 onClickOtaSpeakerButton(); 1197 break; 1198 1199 case R.id.otaActivateButton: 1200 onClickOtaActivateButton(); 1201 break; 1202 1203 case R.id.otaSkipButton: 1204 onClickOtaActivateSkipButton(); 1205 break; 1206 1207 case R.id.otaNextButton: 1208 onClickOtaActivateNextButton(); 1209 break; 1210 1211 case R.id.otaTryAgainButton: 1212 onClickOtaTryAgainButton(); 1213 break; 1214 1215 default: 1216 if (DBG) log ("onClickHandler: received a click event for unrecognized id"); 1217 break; 1218 } 1219 } 1220 1221 private void onClickOtaTryAgainButton() { 1222 if (DBG) log("Activation Try Again Clicked!"); 1223 if (!mApplication.cdmaOtaProvisionData.inOtaSpcState) { 1224 otaShowActivateScreen(); 1225 } 1226 } 1227 1228 private void onClickOtaEndButton() { 1229 if (DBG) log("Activation End Call Button Clicked!"); 1230 if (!mApplication.cdmaOtaProvisionData.inOtaSpcState) { 1231 if (PhoneUtils.hangup(mApplication.mCM) == false) { 1232 // If something went wrong when placing the OTA call, 1233 // the screen is not updated by the call disconnect 1234 // handler and we have to do it here 1235 setSpeaker(false); 1236 // mInCallScreen.handleOtaCallEnd(); 1237 } 1238 } 1239 } 1240 1241 private void onClickOtaSpeakerButton() { 1242 if (DBG) log("OTA Speaker button Clicked!"); 1243 if (!mApplication.cdmaOtaProvisionData.inOtaSpcState) { 1244 boolean isChecked = !PhoneUtils.isSpeakerOn(mContext); 1245 setSpeaker(isChecked); 1246 } 1247 } 1248 1249 private void onClickOtaActivateButton() { 1250 if (DBG) log("Call Activation Clicked!"); 1251 otaPerformActivation(); 1252 } 1253 1254 private void onClickOtaActivateSkipButton() { 1255 if (DBG) log("Activation Skip Clicked!"); 1256 DialogInterface.OnKeyListener keyListener; 1257 keyListener = new DialogInterface.OnKeyListener() { 1258 public boolean onKey(DialogInterface dialog, int keyCode, 1259 KeyEvent event) { 1260 if (DBG) log("Ignoring key events..."); 1261 return true; 1262 } 1263 }; 1264 mOtaWidgetData.otaSkipConfirmationDialog = new AlertDialog.Builder(null /* mInCallScreen */) 1265 .setTitle(R.string.ota_skip_activation_dialog_title) 1266 .setMessage(R.string.ota_skip_activation_dialog_message) 1267 .setPositiveButton( 1268 android.R.string.ok, 1269 // "OK" means "skip activation". 1270 new AlertDialog.OnClickListener() { 1271 public void onClick(DialogInterface dialog, int which) { 1272 otaSkipActivation(); 1273 } 1274 }) 1275 .setNegativeButton( 1276 android.R.string.cancel, 1277 // "Cancel" means just dismiss the dialog. 1278 // Don't actually start an activation call. 1279 null) 1280 .setOnKeyListener(keyListener) 1281 .create(); 1282 mOtaWidgetData.otaSkipConfirmationDialog.show(); 1283 } 1284 1285 private void onClickOtaActivateNextButton() { 1286 if (DBG) log("Dialog Next Clicked!"); 1287 if (!mApplication.cdmaOtaProvisionData.inOtaSpcState) { 1288 mApplication.cdmaOtaScreenState.otaScreenState = 1289 CdmaOtaScreenState.OtaScreenState.OTA_STATUS_UNDEFINED; 1290 otaShowHome(); 1291 } 1292 } 1293 1294 public void dismissAllOtaDialogs() { 1295 if (mOtaWidgetData != null) { 1296 if (mOtaWidgetData.spcErrorDialog != null) { 1297 if (DBG) log("- DISMISSING mSpcErrorDialog."); 1298 mOtaWidgetData.spcErrorDialog.dismiss(); 1299 mOtaWidgetData.spcErrorDialog = null; 1300 } 1301 if (mOtaWidgetData.otaFailureDialog != null) { 1302 if (DBG) log("- DISMISSING mOtaFailureDialog."); 1303 mOtaWidgetData.otaFailureDialog.dismiss(); 1304 mOtaWidgetData.otaFailureDialog = null; 1305 } 1306 } 1307 } 1308 1309 private int getOtaSpcDisplayTime() { 1310 if (DBG) log("getOtaSpcDisplayTime()..."); 1311 int tmpSpcTime = 1; 1312 if (mApplication.cdmaOtaProvisionData.inOtaSpcState) { 1313 long tmpOtaSpcRunningTime = 0; 1314 long tmpOtaSpcLeftTime = 0; 1315 tmpOtaSpcRunningTime = SystemClock.elapsedRealtime(); 1316 tmpOtaSpcLeftTime = 1317 tmpOtaSpcRunningTime - mApplication.cdmaOtaProvisionData.otaSpcUptime; 1318 if (tmpOtaSpcLeftTime >= OTA_SPC_TIMEOUT*1000) { 1319 tmpSpcTime = 1; 1320 } else { 1321 tmpSpcTime = OTA_SPC_TIMEOUT - (int)tmpOtaSpcLeftTime/1000; 1322 } 1323 } 1324 if (DBG) log("getOtaSpcDisplayTime(), time for SPC error notice: " + tmpSpcTime); 1325 return tmpSpcTime; 1326 } 1327 1328 /** 1329 * Initialize the OTA widgets for all OTA screens. 1330 */ 1331 private void initOtaInCallScreen() { 1332 if (DBG) log("initOtaInCallScreen()..."); 1333 // mOtaWidgetData.otaTitle = (TextView) mInCallScreen.findViewById(R.id.otaTitle); 1334 // mOtaWidgetData.otaTextActivate = (TextView) mInCallScreen.findViewById(R.id.otaActivate); 1335 mOtaWidgetData.otaTextActivate.setVisibility(View.GONE); 1336 // mOtaWidgetData.otaTextListenProgress = 1337 // (TextView) mInCallScreen.findViewById(R.id.otaListenProgress); 1338 // mOtaWidgetData.otaTextProgressBar = 1339 // (ProgressBar) mInCallScreen.findViewById(R.id.progress_large); 1340 mOtaWidgetData.otaTextProgressBar.setIndeterminate(true); 1341 // mOtaWidgetData.otaTextSuccessFail = 1342 // (TextView) mInCallScreen.findViewById(R.id.otaSuccessFailStatus); 1343 1344 // mOtaWidgetData.otaUpperWidgets = 1345 // (ViewGroup) mInCallScreen.findViewById(R.id.otaUpperWidgets); 1346 // mOtaWidgetData.callCardOtaButtonsListenProgress = 1347 // (View) mInCallScreen.findViewById(R.id.callCardOtaListenProgress); 1348 // mOtaWidgetData.callCardOtaButtonsActivate = 1349 // (View) mInCallScreen.findViewById(R.id.callCardOtaActivate); 1350 // mOtaWidgetData.callCardOtaButtonsFailSuccess = 1351 // (View) mInCallScreen.findViewById(R.id.callCardOtaFailOrSuccessful); 1352 1353 // mOtaWidgetData.otaEndButton = (Button) mInCallScreen.findViewById(R.id.otaEndButton); 1354 // mOtaWidgetData.otaEndButton.setOnClickListener(mInCallScreen); 1355 // mOtaWidgetData.otaSpeakerButton = 1356 // (ToggleButton) mInCallScreen.findViewById(R.id.otaSpeakerButton); 1357 // mOtaWidgetData.otaSpeakerButton.setOnClickListener(mInCallScreen); 1358 // mOtaWidgetData.otaActivateButton = 1359 // (Button) mInCallScreen.findViewById(R.id.otaActivateButton); 1360 // mOtaWidgetData.otaActivateButton.setOnClickListener(mInCallScreen); 1361 // mOtaWidgetData.otaSkipButton = (Button) mInCallScreen.findViewById(R.id.otaSkipButton); 1362 // mOtaWidgetData.otaSkipButton.setOnClickListener(mInCallScreen); 1363 // mOtaWidgetData.otaNextButton = (Button) mInCallScreen.findViewById(R.id.otaNextButton); 1364 // mOtaWidgetData.otaNextButton.setOnClickListener(mInCallScreen); 1365 // mOtaWidgetData.otaTryAgainButton = 1366 // (Button) mInCallScreen.findViewById(R.id.otaTryAgainButton); 1367 // mOtaWidgetData.otaTryAgainButton.setOnClickListener(mInCallScreen); 1368 1369 // mOtaWidgetData.otaDtmfDialerView = 1370 // (DTMFTwelveKeyDialerView) mInCallScreen.findViewById(R.id.otaDtmfDialerView); 1371 // Sanity-check: the otaDtmfDialerView widget should *always* be present. 1372 // if (mOtaWidgetData.otaDtmfDialerView == null) { 1373 // throw new IllegalStateException("initOtaInCallScreen: couldn't find otaDtmfDialerView"); 1374 // } 1375 1376 // Create a new DTMFTwelveKeyDialer instance purely for use by the 1377 // DTMFTwelveKeyDialerView ("otaDtmfDialerView") that comes from 1378 // otacall_card.xml. 1379 // mOtaCallCardDtmfDialer = new DTMFTwelveKeyDialer(mInCallScreen, 1380 // mOtaWidgetData.otaDtmfDialerView); 1381 1382 // Initialize the new DTMFTwelveKeyDialer instance. This is 1383 // needed to play local DTMF tones. 1384 // mOtaCallCardDtmfDialer.startDialerSession(); 1385 1386 // mOtaWidgetData.otaDtmfDialerView.setDialer(mOtaCallCardDtmfDialer); 1387 } 1388 1389 /** 1390 * Clear out all OTA UI widget elements. Needs to get called 1391 * when OTA call ends or InCallScreen is destroyed. 1392 * @param disableSpeaker parameter control whether Speaker should be turned off. 1393 */ 1394 public void cleanOtaScreen(boolean disableSpeaker) { 1395 if (DBG) log("OTA ends, cleanOtaScreen!"); 1396 1397 mApplication.cdmaOtaScreenState.otaScreenState = 1398 CdmaOtaScreenState.OtaScreenState.OTA_STATUS_UNDEFINED; 1399 mApplication.cdmaOtaProvisionData.isOtaCallCommitted = false; 1400 mApplication.cdmaOtaProvisionData.isOtaCallIntentProcessed = false; 1401 mApplication.cdmaOtaProvisionData.inOtaSpcState = false; 1402 mApplication.cdmaOtaProvisionData.activationCount = 0; 1403 mApplication.cdmaOtaProvisionData.otaSpcUptime = 0; 1404 mApplication.cdmaOtaInCallScreenUiState.state = State.UNDEFINED; 1405 1406 if (mInteractive && (mOtaWidgetData != null)) { 1407 // if (mInCallTouchUi != null) mInCallTouchUi.setVisibility(View.VISIBLE); 1408 // if (mCallCard != null) { 1409 // mCallCard.setVisibility(View.VISIBLE); 1410 // mCallCard.hideCallCardElements(); 1411 // } 1412 1413 // Free resources from the DTMFTwelveKeyDialer instance we created 1414 // in initOtaInCallScreen(). 1415 // if (mOtaCallCardDtmfDialer != null) { 1416 // mOtaCallCardDtmfDialer.stopDialerSession(); 1417 // } 1418 1419 mOtaWidgetData.otaTextActivate.setVisibility(View.GONE); 1420 mOtaWidgetData.otaTextListenProgress.setVisibility(View.GONE); 1421 mOtaWidgetData.otaTextProgressBar.setVisibility(View.GONE); 1422 mOtaWidgetData.otaTextSuccessFail.setVisibility(View.GONE); 1423 mOtaWidgetData.callCardOtaButtonsActivate.setVisibility(View.GONE); 1424 mOtaWidgetData.callCardOtaButtonsListenProgress.setVisibility(View.GONE); 1425 mOtaWidgetData.callCardOtaButtonsFailSuccess.setVisibility(View.GONE); 1426 mOtaWidgetData.otaUpperWidgets.setVisibility(View.GONE); 1427 // mOtaWidgetData.otaDtmfDialerView.setVisibility(View.GONE); 1428 mOtaWidgetData.otaNextButton.setVisibility(View.GONE); 1429 mOtaWidgetData.otaTryAgainButton.setVisibility(View.GONE); 1430 } 1431 1432 // turn off the speaker in case it was turned on 1433 // but the OTA call could not be completed 1434 if (disableSpeaker) { 1435 setSpeaker(false); 1436 } 1437 } 1438 1439 /** 1440 * Defines OTA information that needs to be maintained during 1441 * an OTA call when display orientation changes. 1442 */ 1443 public static class CdmaOtaProvisionData { 1444 public boolean isOtaCallCommitted; 1445 public boolean isOtaCallIntentProcessed; 1446 public boolean inOtaSpcState; 1447 public int activationCount; 1448 public long otaSpcUptime; 1449 } 1450 1451 /** 1452 * Defines OTA screen configuration items read from config.xml 1453 * and used to control OTA display. 1454 */ 1455 public static class CdmaOtaConfigData { 1456 public int otaShowActivationScreen; 1457 public int otaShowListeningScreen; 1458 public int otaShowActivateFailTimes; 1459 public int otaPlaySuccessFailureTone; 1460 public boolean configComplete; 1461 public CdmaOtaConfigData() { 1462 if (DBG) log("CdmaOtaConfigData constructor!"); 1463 otaShowActivationScreen = OTA_SHOW_ACTIVATION_SCREEN_OFF; 1464 otaShowListeningScreen = OTA_SHOW_LISTENING_SCREEN_OFF; 1465 otaShowActivateFailTimes = OTA_SHOW_ACTIVATE_FAIL_COUNT_OFF; 1466 otaPlaySuccessFailureTone = OTA_PLAY_SUCCESS_FAILURE_TONE_OFF; 1467 } 1468 } 1469 1470 /** 1471 * The state of the OTA InCallScreen UI. 1472 */ 1473 public static class CdmaOtaInCallScreenUiState { 1474 public enum State { 1475 UNDEFINED, 1476 NORMAL, 1477 ENDED 1478 } 1479 1480 public State state; 1481 1482 public CdmaOtaInCallScreenUiState() { 1483 if (DBG) log("CdmaOtaInCallScreenState: constructor init to UNDEFINED"); 1484 state = CdmaOtaInCallScreenUiState.State.UNDEFINED; 1485 } 1486 } 1487 1488 /** 1489 * Save the Ota InCallScreen UI state 1490 */ 1491 public void setCdmaOtaInCallScreenUiState(CdmaOtaInCallScreenUiState.State state) { 1492 if (DBG) log("setCdmaOtaInCallScreenState: " + state); 1493 mApplication.cdmaOtaInCallScreenUiState.state = state; 1494 } 1495 1496 /** 1497 * Get the Ota InCallScreen UI state 1498 */ 1499 public CdmaOtaInCallScreenUiState.State getCdmaOtaInCallScreenUiState() { 1500 if (DBG) log("getCdmaOtaInCallScreenState: " 1501 + mApplication.cdmaOtaInCallScreenUiState.state); 1502 return mApplication.cdmaOtaInCallScreenUiState.state; 1503 } 1504 1505 /** 1506 * The OTA screen state machine. 1507 */ 1508 public static class CdmaOtaScreenState { 1509 public enum OtaScreenState { 1510 OTA_STATUS_UNDEFINED, 1511 OTA_STATUS_ACTIVATION, 1512 OTA_STATUS_LISTENING, 1513 OTA_STATUS_PROGRESS, 1514 OTA_STATUS_SUCCESS_FAILURE_DLG 1515 } 1516 1517 public OtaScreenState otaScreenState; 1518 1519 public CdmaOtaScreenState() { 1520 otaScreenState = OtaScreenState.OTA_STATUS_UNDEFINED; 1521 } 1522 1523 /** 1524 * {@link PendingIntent} used to report an OTASP result status code 1525 * back to our caller. Can be null. 1526 * 1527 * Our caller (presumably SetupWizard) may create this PendingIntent, 1528 * pointing back at itself, and passes it along as an extra with the 1529 * ACTION_PERFORM_CDMA_PROVISIONING intent. Then, when there's an 1530 * OTASP result to report, we send that PendingIntent back, adding an 1531 * extra called EXTRA_OTASP_RESULT_CODE to indicate the result. 1532 * 1533 * Possible result values are the OTASP_RESULT_* constants. 1534 */ 1535 public PendingIntent otaspResultCodePendingIntent; 1536 } 1537 1538 /** @see com.android.internal.telephony.Phone */ 1539 private static String otaProvisionStatusToString(int status) { 1540 switch (status) { 1541 case Phone.CDMA_OTA_PROVISION_STATUS_SPL_UNLOCKED: 1542 return "SPL_UNLOCKED"; 1543 case Phone.CDMA_OTA_PROVISION_STATUS_SPC_RETRIES_EXCEEDED: 1544 return "SPC_RETRIES_EXCEEDED"; 1545 case Phone.CDMA_OTA_PROVISION_STATUS_A_KEY_EXCHANGED: 1546 return "A_KEY_EXCHANGED"; 1547 case Phone.CDMA_OTA_PROVISION_STATUS_SSD_UPDATED: 1548 return "SSD_UPDATED"; 1549 case Phone.CDMA_OTA_PROVISION_STATUS_NAM_DOWNLOADED: 1550 return "NAM_DOWNLOADED"; 1551 case Phone.CDMA_OTA_PROVISION_STATUS_MDN_DOWNLOADED: 1552 return "MDN_DOWNLOADED"; 1553 case Phone.CDMA_OTA_PROVISION_STATUS_IMSI_DOWNLOADED: 1554 return "IMSI_DOWNLOADED"; 1555 case Phone.CDMA_OTA_PROVISION_STATUS_PRL_DOWNLOADED: 1556 return "PRL_DOWNLOADED"; 1557 case Phone.CDMA_OTA_PROVISION_STATUS_COMMITTED: 1558 return "COMMITTED"; 1559 case Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STARTED: 1560 return "OTAPA_STARTED"; 1561 case Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED: 1562 return "OTAPA_STOPPED"; 1563 case Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_ABORTED: 1564 return "OTAPA_ABORTED"; 1565 default: 1566 return "<unknown status" + status + ">"; 1567 } 1568 } 1569 1570 private static int getLteOnCdmaMode(Context context) { 1571 final TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService( 1572 Context.TELEPHONY_SERVICE); 1573 // If the telephony manager is not available yet, or if it doesn't know the answer yet, 1574 // try falling back on the system property that may or may not be there 1575 if (telephonyManager == null 1576 || telephonyManager.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_UNKNOWN) { 1577 return SystemProperties.getInt(TelephonyProperties.PROPERTY_LTE_ON_CDMA_DEVICE, 1578 PhoneConstants.LTE_ON_CDMA_UNKNOWN); 1579 } 1580 return telephonyManager.getLteOnCdmaMode(); 1581 } 1582 1583 private static void log(String msg) { 1584 Log.d(LOG_TAG, msg); 1585 } 1586 1587 private static void loge(String msg) { 1588 Log.e(LOG_TAG, msg); 1589 } 1590 } 1591