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