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