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