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