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