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