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