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