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