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