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