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