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