blob: 495df273a91c6ce475382fcd8306245a3de1fbb2 [file] [log] [blame]
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001/*
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
17package com.android.phone;
18
19import com.android.internal.telephony.Phone;
20import com.android.internal.telephony.PhoneConstants;
21import com.android.internal.telephony.TelephonyCapabilities;
22import com.android.internal.telephony.TelephonyProperties;
23import com.android.phone.OtaUtils.CdmaOtaInCallScreenUiState.State;
24
25import android.app.Activity;
26import android.app.ActivityManager;
27import android.app.AlertDialog;
28import android.app.PendingIntent;
29import android.app.PendingIntent.CanceledException;
30import android.content.ActivityNotFoundException;
31import android.content.Context;
32import android.content.DialogInterface;
33import android.content.Intent;
34import android.net.Uri;
35import android.os.AsyncResult;
36import android.os.Handler;
37import android.os.SystemClock;
38import android.os.SystemProperties;
39import android.os.UserHandle;
40import android.telephony.TelephonyManager;
41import android.util.Log;
42import android.view.KeyEvent;
43import android.view.View;
44import android.view.ViewGroup;
45import android.view.ViewStub;
46import android.view.WindowManager;
47import android.widget.Button;
48import android.widget.ProgressBar;
49import android.widget.ScrollView;
50import android.widget.TextView;
51import 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 */
65public 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}