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