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