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