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