| /* |
| * Copyright (C) 2009 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.phone; |
| |
| import com.android.internal.telephony.Phone; |
| import com.android.phone.OtaUtils.CdmaOtaInCallScreenUiState.State; |
| |
| import android.app.AlertDialog; |
| import android.app.PendingIntent; |
| import android.app.PendingIntent.CanceledException; |
| import android.content.ActivityNotFoundException; |
| import android.content.Context; |
| import android.content.DialogInterface; |
| import android.content.Intent; |
| import android.content.pm.ResolveInfo; |
| import android.os.AsyncResult; |
| import android.os.Handler; |
| import android.os.Message; |
| import android.os.SystemClock; |
| import android.os.SystemProperties; |
| import android.provider.Settings; |
| |
| import android.util.Log; |
| import android.view.KeyEvent; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.view.ViewStub; |
| import android.view.WindowManager; |
| |
| import android.widget.Button; |
| import android.widget.ScrollView; |
| import android.widget.ToggleButton; |
| import android.widget.ProgressBar; |
| import android.widget.TextView; |
| |
| /** |
| * Handles all OTA Call related logic and UI functionality. |
| * The InCallScreen interacts with this class to perform an OTA Call. |
| * |
| * OTA is a CDMA-specific feature: |
| * OTA or OTASP == Over The Air service provisioning |
| * SPC == Service Programming Code |
| * TODO: Include pointer to more detailed documentation. |
| */ |
| public class OtaUtils { |
| private static final String LOG_TAG = "OtaUtils"; |
| private static final String UNACTIVATED_MIN2_VALUE = "000000"; |
| private static final String UNACTIVATED_MIN_VALUE = "1111110111"; |
| private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 1); |
| |
| public static final int OTA_SHOW_ACTIVATION_SCREEN_OFF = 0; |
| public static final int OTA_SHOW_ACTIVATION_SCREEN_ON = 1; |
| public static final int OTA_SHOW_LISTENING_SCREEN_OFF =0; |
| public static final int OTA_SHOW_LISTENING_SCREEN_ON =1; |
| public static final int OTA_SHOW_ACTIVATE_FAIL_COUNT_OFF = 0; |
| public static final int OTA_SHOW_ACTIVATE_FAIL_COUNT_THREE = 3; |
| public static final int OTA_PLAY_SUCCESS_FAILURE_TONE_OFF = 0; |
| public static final int OTA_PLAY_SUCCESS_FAILURE_TONE_ON = 1; |
| |
| // SPC Timeout is 60 seconds |
| public final int OTA_SPC_TIMEOUT = 60; |
| public final int OTA_FAILURE_DIALOG_TIMEOUT = 2; |
| |
| private InCallScreen mInCallScreen; |
| private Context mContext; |
| private PhoneApp mApplication; |
| private OtaWidgetData mOtaWidgetData; |
| private ViewGroup mInCallPanel; |
| private CallCard mCallCard; |
| |
| // The DTMFTwelveKeyDialer instance owned by the InCallScreen, which |
| // the InCallScreen passes in to our constructor. |
| private DTMFTwelveKeyDialer mDialer; |
| // |
| // The DTMFTwelveKeyDialer instance that we create ourselves in |
| // initOtaInCallScreen(), and attach to the DTMFTwelveKeyDialerView |
| // ("otaDtmfDialerView") that comes from otacall_card.xml. |
| private DTMFTwelveKeyDialer mOtaCallCardDtmfDialer; |
| // TODO: we ought to share a single DTMFTwelveKeyDialer instance for |
| // both these uses, but see bug 2432289 for related issues. |
| |
| private static boolean mIsWizardMode = true; |
| |
| /** |
| * OtaWidgetData class represent all OTA UI elements |
| */ |
| private class OtaWidgetData { |
| public Button otaEndButton; |
| public Button otaActivateButton; |
| public Button otaSkipButton; |
| public Button otaNextButton; |
| public ToggleButton otaSpeakerButton; |
| public View otaCallCardBase; |
| public View callCardOtaButtonsFailSuccess; |
| public ProgressBar otaTextProgressBar; |
| public TextView otaTextSuccessFail; |
| public View callCardOtaButtonsActivate; |
| public View callCardOtaButtonsListenProgress; |
| public TextView otaTextActivate; |
| public TextView otaTextListenProgress; |
| public ScrollView otaTextListenProgressContainer; |
| public AlertDialog spcErrorDialog; |
| public AlertDialog otaFailureDialog; |
| public AlertDialog otaSkipConfirmationDialog; |
| public TextView otaTitle; |
| public DTMFTwelveKeyDialerView otaDtmfDialerView; |
| public Button otaTryAgainButton; |
| } |
| |
| public OtaUtils(Context context, |
| InCallScreen inCallScreen, |
| ViewGroup inCallPanel, |
| CallCard callCard, |
| DTMFTwelveKeyDialer dialer) { |
| |
| if (DBG) log("Enter OtaUtil constructor"); |
| |
| mInCallScreen = inCallScreen; |
| mContext = context; |
| mInCallPanel = inCallPanel; |
| mCallCard = callCard; |
| mDialer = dialer; |
| mApplication = PhoneApp.getInstance(); |
| mOtaWidgetData = new OtaWidgetData(); |
| |
| // inflate OTA Call card and footers |
| ViewStub otaCallCardStub = (ViewStub) mInCallScreen.findViewById(R.id.otaCallCardStub); |
| otaCallCardStub.inflate(); |
| readXmlSettings(); |
| initOtaInCallScreen(); |
| } |
| |
| /** |
| * Returns true if the phone needs activation. |
| * |
| * @param minString the phone's MIN configuration string |
| * @return true if phone needs activation |
| * @throws OtaConfigurationException if the string is invalid |
| */ |
| public static boolean needsActivation(String minString) throws IllegalArgumentException { |
| if (minString == null || (minString.length() < 6)) { |
| throw new IllegalArgumentException(); |
| } |
| return (minString.equals(UNACTIVATED_MIN_VALUE) |
| || minString.substring(0,6).equals(UNACTIVATED_MIN2_VALUE)) |
| || SystemProperties.getBoolean("test_cdma_setup", false); |
| } |
| |
| /** |
| * Starts the OTA provisioning call. If the MIN isn't available yet, it returns false and adds |
| * an event to return the request to the calling app when it becomes available. |
| * |
| * @param context |
| * @param handler |
| * @param request |
| * @return true if we were able to launch Ota activity or it's not required; false otherwise |
| */ |
| public static boolean maybeDoOtaCall(Context context, Handler handler, int request) { |
| |
| PhoneApp app = PhoneApp.getInstance(); |
| Phone phone = app.phone; |
| |
| if (!isCdmaPhone()) { |
| if (DBG) Log.v("OtaUtils", "Can't run provisioning on a non-CDMA phone"); |
| return true; // sanity check - a non-cdma phone doesn't need to run this |
| } |
| |
| if (!phone.isMinInfoReady()) { |
| if (DBG) log("MIN is not ready. Registering to receive notification."); |
| phone.registerForSubscriptionInfoReady(handler, request, null); |
| return false; |
| } |
| |
| phone.unregisterForSubscriptionInfoReady(handler); |
| String min = phone.getCdmaMin(); |
| |
| if (DBG) log("min_string: " + min); |
| |
| boolean phoneNeedsActivation = false; |
| try { |
| phoneNeedsActivation = needsActivation(min); |
| } catch (IllegalArgumentException e) { |
| if (DBG) log("invalid MIN string, exit"); |
| return true; // If the MIN string is wrong, there's nothing else we can do. |
| } |
| |
| if (DBG) log("phoneNeedsActivation is set to " + phoneNeedsActivation); |
| |
| int otaShowActivationScreen = context.getResources().getInteger( |
| R.integer.OtaShowActivationScreen); |
| |
| if (DBG) log("otaShowActivationScreen: " + otaShowActivationScreen); |
| |
| if (phoneNeedsActivation && (otaShowActivationScreen == OTA_SHOW_ACTIVATION_SCREEN_ON)) { |
| app.cdmaOtaProvisionData.isOtaCallIntentProcessed = false; |
| Intent newIntent = new Intent(InCallScreen.ACTION_SHOW_ACTIVATION); |
| newIntent.setClass(context, InCallScreen.class); |
| newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| mIsWizardMode = false; |
| context.startActivity(newIntent); |
| if (DBG) log("activation intent sent."); |
| } else { |
| if (DBG) log("activation intent NOT sent."); |
| } |
| return true; |
| } |
| |
| private void setSpeaker(boolean state) { |
| if (DBG) log("setSpeaker : " + state ); |
| if (state == PhoneUtils.isSpeakerOn(mContext)) { |
| if (DBG) log("no change. returning"); |
| return; |
| } |
| |
| if (state && mInCallScreen.isBluetoothAvailable() |
| && mInCallScreen.isBluetoothAudioConnected()) { |
| mInCallScreen.disconnectBluetoothAudio(); |
| } |
| PhoneUtils.turnOnSpeaker(mContext, state, true); |
| } |
| |
| /** |
| * Handle OTA Provision events from Framework. Possible events are: |
| * OTA Commit Event - OTA provisioning was successful |
| * SPC retries exceeded - SPC failure retries has exceeded, and Phone needs to |
| * power down. |
| */ |
| public void onOtaProvisionStatusChanged(AsyncResult r) { |
| int OtaStatus[] = (int[]) r.result; |
| if (DBG) log("onOtaProvisionStatusChanged(): OtaStatus[0]" + OtaStatus[0]); |
| |
| switch(OtaStatus[0]) { |
| case Phone.CDMA_OTA_PROVISION_STATUS_SPC_RETRIES_EXCEEDED: |
| otaShowInProgressScreen(); |
| mApplication.cdmaOtaProvisionData.otaSpcUptime = SystemClock.elapsedRealtime(); |
| otaShowSpcErrorNotice(OTA_SPC_TIMEOUT); |
| if (DBG) log("onOtaProvisionStatusChanged(): RETRIES EXCEEDED"); |
| // Power.shutdown(); |
| break; |
| |
| case Phone.CDMA_OTA_PROVISION_STATUS_COMMITTED: |
| otaShowInProgressScreen(); |
| mApplication.cdmaOtaProvisionData.isOtaCallCommitted = true; |
| if (DBG) log("onOtaProvisionStatusChanged(): DONE, isOtaCallCommitted set to true"); |
| break; |
| |
| case Phone.CDMA_OTA_PROVISION_STATUS_SPL_UNLOCKED: |
| case Phone.CDMA_OTA_PROVISION_STATUS_A_KEY_EXCHANGED: |
| case Phone.CDMA_OTA_PROVISION_STATUS_SSD_UPDATED: |
| case Phone.CDMA_OTA_PROVISION_STATUS_NAM_DOWNLOADED: |
| case Phone.CDMA_OTA_PROVISION_STATUS_MDN_DOWNLOADED: |
| case Phone.CDMA_OTA_PROVISION_STATUS_IMSI_DOWNLOADED: |
| case Phone.CDMA_OTA_PROVISION_STATUS_PRL_DOWNLOADED: |
| case Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STARTED: |
| case Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED: |
| case Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_ABORTED: |
| if (DBG) log("onOtaProvisionStatusChanged(): change to ProgressScreen"); |
| otaShowInProgressScreen(); |
| break; |
| |
| default: |
| if (DBG) log("onOtaProvisionStatusChanged(): Ignoring OtaStatus " + OtaStatus[0]); |
| break; |
| } |
| } |
| |
| private void otaShowHome() { |
| if (DBG) log("OtaShowHome()..."); |
| mApplication.cdmaOtaScreenState.otaScreenState = |
| CdmaOtaScreenState.OtaScreenState.OTA_STATUS_UNDEFINED; |
| mInCallScreen.endInCallScreenSession(); |
| Intent intent = new Intent(Intent.ACTION_MAIN); |
| intent.addCategory (Intent.CATEGORY_HOME); |
| intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| mContext.startActivity(intent); |
| return; |
| } |
| |
| private void otaSkipActivation() { |
| if (DBG) log("otaSkipActivation()..."); |
| |
| PhoneApp app = PhoneApp.getInstance(); |
| if (app != null && app.cdmaOtaInCallScreenUiState.reportSkipPendingIntent != null) { |
| try { |
| app.cdmaOtaInCallScreenUiState.reportSkipPendingIntent.send(); |
| } catch (CanceledException e) { |
| // should never happen because no code cancels the pending intent right now, |
| // but if it does, the user will simply be returned to the initial setup screen |
| } |
| } |
| |
| mInCallScreen.finish(); |
| return; |
| } |
| |
| private void otaPerformActivation() { |
| if (DBG) log("otaPerformActivation()..."); |
| if (!mApplication.cdmaOtaProvisionData.inOtaSpcState) { |
| Intent newIntent = new Intent(Intent.ACTION_CALL); |
| newIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, InCallScreen.OTA_NUMBER); |
| mInCallScreen.internalResolveIntent(newIntent); |
| otaShowListeningScreen(); |
| } |
| return; |
| } |
| |
| /** |
| * Show Activation Screen when phone powers up and OTA provision is |
| * required. Also shown when activation fails and user needs |
| * to re-attempt it. Contains ACTIVATE and SKIP buttons |
| * which allow user to start OTA activation or skip the activation process. |
| */ |
| public void otaShowActivateScreen() { |
| if (DBG) log("OtaShowActivationScreen()..."); |
| if (mApplication.cdmaOtaConfigData.otaShowActivationScreen |
| == OTA_SHOW_ACTIVATION_SCREEN_ON) { |
| if (DBG) log("OtaShowActivationScreen(): show activation screen"); |
| if (!isDialerOpened()) { |
| otaScreenInitialize(); |
| mOtaWidgetData.otaSkipButton.setVisibility(mIsWizardMode ? |
| View.VISIBLE : View.INVISIBLE); |
| mOtaWidgetData.otaTextActivate.setVisibility(View.VISIBLE); |
| mOtaWidgetData.callCardOtaButtonsActivate.setVisibility(View.VISIBLE); |
| } else { |
| mDialer.setHandleVisible(true); |
| } |
| mApplication.cdmaOtaScreenState.otaScreenState = |
| CdmaOtaScreenState.OtaScreenState.OTA_STATUS_ACTIVATION; |
| } else { |
| if (DBG) log("OtaShowActivationScreen(): show home screen"); |
| otaShowHome(); |
| } |
| } |
| |
| /** |
| * Show "Listen for Instruction" screen during OTA call. Shown when OTA Call |
| * is initiated and user needs to listen for network instructions and press |
| * appropriate DTMF digits to proceed to the "Programming in Progress" phase. |
| */ |
| private void otaShowListeningScreen() { |
| if (DBG) log("OtaShowListeningScreen()..."); |
| if (mApplication.cdmaOtaConfigData.otaShowListeningScreen |
| == OTA_SHOW_LISTENING_SCREEN_ON) { |
| if (DBG) log("OtaShowListeningScreen(): show listening screen"); |
| if (!isDialerOpened()) { |
| otaScreenInitialize(); |
| mOtaWidgetData.otaTextListenProgressContainer.setVisibility(View.VISIBLE); |
| mOtaWidgetData.otaTextListenProgress.setText(R.string.ota_listen); |
| mOtaWidgetData.otaDtmfDialerView.setVisibility(View.VISIBLE); |
| mOtaWidgetData.callCardOtaButtonsListenProgress.setVisibility(View.VISIBLE); |
| mOtaWidgetData.otaSpeakerButton.setVisibility(View.VISIBLE); |
| boolean speakerOn = PhoneUtils.isSpeakerOn(mContext); |
| mOtaWidgetData.otaSpeakerButton.setChecked(speakerOn); |
| } else { |
| mDialer.setHandleVisible(true); |
| } |
| mApplication.cdmaOtaScreenState.otaScreenState = |
| CdmaOtaScreenState.OtaScreenState.OTA_STATUS_LISTENING; |
| |
| // Update the state of the in-call menu items. |
| mInCallScreen.updateMenuItems(); |
| } else { |
| if (DBG) log("OtaShowListeningScreen(): show progress screen"); |
| otaShowInProgressScreen(); |
| } |
| } |
| |
| /** |
| * Show "Programming In Progress" screen during OTA call. Shown when OTA |
| * provisioning is in progress after user has selected an option. |
| */ |
| private void otaShowInProgressScreen() { |
| if (DBG) log("OtaShowInProgressScreen()..."); |
| if (!isDialerOpened()) { |
| otaScreenInitialize(); |
| mOtaWidgetData.otaTextListenProgressContainer.setVisibility(View.VISIBLE); |
| mOtaWidgetData.otaTextListenProgress.setText(R.string.ota_progress); |
| mOtaWidgetData.otaTextProgressBar.setVisibility(View.VISIBLE); |
| mOtaWidgetData.callCardOtaButtonsListenProgress.setVisibility(View.VISIBLE); |
| mOtaWidgetData.otaSpeakerButton.setVisibility(View.VISIBLE); |
| boolean speakerOn = PhoneUtils.isSpeakerOn(mContext); |
| mOtaWidgetData.otaSpeakerButton.setChecked(speakerOn); |
| } else { |
| mDialer.setHandleVisible(true); |
| } |
| mApplication.cdmaOtaScreenState.otaScreenState = |
| CdmaOtaScreenState.OtaScreenState.OTA_STATUS_PROGRESS; |
| |
| // Update the state of the in-call menu items. |
| mInCallScreen.updateMenuItems(); |
| } |
| |
| /** |
| * Show programming failure dialog when OTA provisioning fails. |
| * If OTA provisioning attempts fail more than 3 times, then unsuccessful |
| * dialog is shown. Otherwise a two-second notice is shown with unsuccessful |
| * information. When notice expires, phone returns to activation screen. |
| */ |
| private void otaShowProgramFailure(int length) { |
| if (DBG) log("OtaShowProgramFailure()..."); |
| mApplication.cdmaOtaProvisionData.activationCount++; |
| if ((mApplication.cdmaOtaProvisionData.activationCount < |
| mApplication.cdmaOtaConfigData.otaShowActivateFailTimes) |
| && (mApplication.cdmaOtaConfigData.otaShowActivationScreen == |
| OTA_SHOW_ACTIVATION_SCREEN_ON)) { |
| if (DBG) log("OtaShowProgramFailure(): activationCount" |
| + mApplication.cdmaOtaProvisionData.activationCount); |
| if (DBG) log("OtaShowProgramFailure(): show failure notice"); |
| otaShowProgramFailureNotice(length); |
| } else { |
| if (DBG) log("OtaShowProgramFailure(): show failure dialog"); |
| otaShowProgramFailureDialog(); |
| } |
| } |
| |
| /** |
| * Show either programming success dialog when OTA provisioning succeeds, or |
| * programming failure dialog when it fails. See {@link otaShowProgramFailure} |
| * for more details. |
| */ |
| public void otaShowSuccessFailure() { |
| if (DBG) log("OtaShowSuccessFailure()..."); |
| otaScreenInitialize(); |
| if (DBG) log("OtaShowSuccessFailure(): isOtaCallCommitted" |
| + mApplication.cdmaOtaProvisionData.isOtaCallCommitted); |
| if (mApplication.cdmaOtaProvisionData.isOtaCallCommitted) { |
| if (DBG) log("OtaShowSuccessFailure(), show success dialog"); |
| otaShowProgramSuccessDialog(); |
| } else { |
| if (DBG) log("OtaShowSuccessFailure(), show failure dialog"); |
| otaShowProgramFailure(OTA_FAILURE_DIALOG_TIMEOUT); |
| } |
| return; |
| } |
| |
| /** |
| * Show programming failure dialog when OTA provisioning fails more than 3 |
| * times. |
| */ |
| private void otaShowProgramFailureDialog() { |
| if (DBG) log("OtaShowProgramFailureDialog()..."); |
| mApplication.cdmaOtaScreenState.otaScreenState = |
| CdmaOtaScreenState.OtaScreenState.OTA_STATUS_SUCCESS_FAILURE_DLG; |
| mOtaWidgetData.otaTitle.setText(R.string.ota_title_problem_with_activation); |
| mOtaWidgetData.otaTextSuccessFail.setVisibility(View.VISIBLE); |
| mOtaWidgetData.otaTextSuccessFail.setText(R.string.ota_unsuccessful); |
| mOtaWidgetData.callCardOtaButtonsFailSuccess.setVisibility(View.VISIBLE); |
| mOtaWidgetData.otaTryAgainButton.setVisibility(View.VISIBLE); |
| //close the dialer if open |
| if (isDialerOpened()) { |
| mDialer.closeDialer(false); |
| } |
| } |
| |
| /** |
| * Show programming success dialog when OTA provisioning succeeds. |
| */ |
| private void otaShowProgramSuccessDialog() { |
| if (DBG) log("OtaShowProgramSuccessDialog()..."); |
| mApplication.cdmaOtaScreenState.otaScreenState = |
| CdmaOtaScreenState.OtaScreenState.OTA_STATUS_SUCCESS_FAILURE_DLG; |
| mOtaWidgetData.otaTitle.setText(R.string.ota_title_activate_success); |
| mOtaWidgetData.otaTextSuccessFail.setVisibility(View.VISIBLE); |
| mOtaWidgetData.otaTextSuccessFail.setText(R.string.ota_successful); |
| mOtaWidgetData.callCardOtaButtonsFailSuccess.setVisibility(View.VISIBLE); |
| mOtaWidgetData.otaNextButton.setVisibility(View.VISIBLE); |
| //close the dialer if open |
| if (isDialerOpened()) { |
| mDialer.closeDialer(false); |
| } |
| } |
| |
| /** |
| * Show SPC failure notice when SPC attempts exceed 15 times. |
| * During OTA provisioning, if SPC code is incorrect OTA provisioning will |
| * fail. When SPC attempts are over 15, it shows SPC failure notice for one minute and |
| * then phone will power down. |
| */ |
| private void otaShowSpcErrorNotice(int length) { |
| if (DBG) log("OtaShowSpcErrorNotice()..."); |
| if (mOtaWidgetData.spcErrorDialog == null) { |
| mApplication.cdmaOtaProvisionData.inOtaSpcState = true; |
| DialogInterface.OnKeyListener keyListener; |
| keyListener = new DialogInterface.OnKeyListener() { |
| public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { |
| log("Ignoring key events..."); |
| return true; |
| }}; |
| mOtaWidgetData.spcErrorDialog = new AlertDialog.Builder(mInCallScreen) |
| .setMessage(R.string.ota_spc_failure) |
| .setOnKeyListener(keyListener) |
| .create(); |
| mOtaWidgetData.spcErrorDialog.getWindow().addFlags( |
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
| | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); |
| mOtaWidgetData.spcErrorDialog.show(); |
| //close the dialer if open |
| if (isDialerOpened()) { |
| mDialer.closeDialer(false); |
| } |
| long noticeTime = length*1000; |
| if (DBG) log("OtaShowSpcErrorNotice(), remaining SPC noticeTime" + noticeTime); |
| mInCallScreen.requestCloseSpcErrorNotice(noticeTime); |
| } |
| } |
| |
| /** |
| * When SPC notice times out, force phone to power down. |
| */ |
| public void onOtaCloseSpcNotice() { |
| if (DBG) log("onOtaCloseSpcNotice(), send shutdown intent"); |
| Intent shutdown = new Intent(Intent.ACTION_REQUEST_SHUTDOWN); |
| shutdown.putExtra(Intent.EXTRA_KEY_CONFIRM, false); |
| shutdown.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| mContext.startActivity(shutdown); |
| } |
| |
| /** |
| * Show two-second notice when OTA provisioning fails and number of failed attempts |
| * is less then 3. |
| */ |
| private void otaShowProgramFailureNotice(int length) { |
| if (DBG) log("OtaShowProgramFailureNotice()..."); |
| if (mOtaWidgetData.otaFailureDialog == null) { |
| mOtaWidgetData.otaFailureDialog = new AlertDialog.Builder(mInCallScreen) |
| .setMessage(R.string.ota_failure) |
| .create(); |
| mOtaWidgetData.otaFailureDialog.getWindow().addFlags( |
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
| | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); |
| mOtaWidgetData.otaFailureDialog.show(); |
| |
| long noticeTime = length*1000; |
| mInCallScreen.requestCloseOtaFailureNotice(noticeTime); |
| } |
| } |
| |
| /** |
| * Handle OTA unsuccessful notice expiry. Dismisses the |
| * two-second notice and shows the activation screen. |
| */ |
| public void onOtaCloseFailureNotice() { |
| if (DBG) log("onOtaCloseFailureNotice()..."); |
| if (mOtaWidgetData.otaFailureDialog != null) { |
| mOtaWidgetData.otaFailureDialog.dismiss(); |
| mOtaWidgetData.otaFailureDialog = null; |
| } |
| otaShowActivateScreen(); |
| } |
| |
| /** |
| * Initialize all OTA UI elements to be gone. Also set inCallPanel, |
| * callCard and the dialpad handle to be gone. This is called before any OTA screen |
| * gets drawn. |
| */ |
| private void otaScreenInitialize() { |
| if (DBG) log("OtaScreenInitialize()..."); |
| |
| if (mInCallPanel != null) mInCallPanel.setVisibility(View.GONE); |
| if (mCallCard != null) mCallCard.hideCallCardElements(); |
| mDialer.setHandleVisible(false); |
| |
| mOtaWidgetData.otaTitle.setText(R.string.ota_title_activate); |
| mOtaWidgetData.otaTextActivate.setVisibility(View.GONE); |
| mOtaWidgetData.otaTextListenProgressContainer.setVisibility(View.GONE); |
| mOtaWidgetData.otaTextProgressBar.setVisibility(View.GONE); |
| mOtaWidgetData.otaTextSuccessFail.setVisibility(View.GONE); |
| mOtaWidgetData.callCardOtaButtonsActivate.setVisibility(View.GONE); |
| mOtaWidgetData.callCardOtaButtonsListenProgress.setVisibility(View.GONE); |
| mOtaWidgetData.callCardOtaButtonsFailSuccess.setVisibility(View.GONE); |
| mOtaWidgetData.otaDtmfDialerView.setVisibility(View.GONE); |
| mOtaWidgetData.otaSpeakerButton.setVisibility(View.GONE); |
| mOtaWidgetData.otaTryAgainButton.setVisibility(View.GONE); |
| mOtaWidgetData.otaNextButton.setVisibility(View.GONE); |
| mOtaWidgetData.otaCallCardBase.setVisibility(View.VISIBLE); |
| mOtaWidgetData.otaSkipButton.setVisibility(View.VISIBLE); |
| } |
| |
| public void hideOtaScreen() { |
| if (DBG) log("hideOtaScreen()..."); |
| |
| mOtaWidgetData.callCardOtaButtonsActivate.setVisibility(View.GONE); |
| mOtaWidgetData.callCardOtaButtonsListenProgress.setVisibility(View.GONE); |
| mOtaWidgetData.callCardOtaButtonsFailSuccess.setVisibility(View.GONE); |
| mOtaWidgetData.otaCallCardBase.setVisibility(View.GONE); |
| } |
| |
| public boolean isDialerOpened() { |
| return (mDialer != null && mDialer.isOpened()); |
| } |
| |
| /** |
| * Show the appropriate OTA screen based on the current state of OTA call. |
| * Shown whenever calling screen is resumed. |
| */ |
| public void otaShowProperScreen() { |
| if (DBG) log("otaShowProperScreen()..."); |
| if (mInCallScreen.isForegroundActivity()) { |
| if (DBG) log("otaShowProperScreen(), OTA is foreground activity, currentstate =" |
| + mApplication.cdmaOtaScreenState.otaScreenState); |
| if (mInCallPanel != null) { |
| mInCallPanel.setVisibility(View.GONE); |
| } |
| if (mApplication.cdmaOtaScreenState.otaScreenState |
| == CdmaOtaScreenState.OtaScreenState.OTA_STATUS_ACTIVATION) { |
| otaShowActivateScreen(); |
| } else if (mApplication.cdmaOtaScreenState.otaScreenState |
| == CdmaOtaScreenState.OtaScreenState.OTA_STATUS_LISTENING) { |
| otaShowListeningScreen(); |
| } else if (mApplication.cdmaOtaScreenState.otaScreenState |
| == CdmaOtaScreenState.OtaScreenState.OTA_STATUS_PROGRESS) { |
| otaShowInProgressScreen(); |
| } |
| |
| if (mApplication.cdmaOtaProvisionData.inOtaSpcState) { |
| otaShowSpcErrorNotice(getOtaSpcDisplayTime()); |
| } |
| } |
| } |
| |
| /** |
| * Read configuration values for each OTA screen from config.xml. |
| * These configuration values control visibility of each screen. |
| */ |
| private void readXmlSettings() { |
| if (DBG) log("readXmlSettings()..."); |
| if (mApplication.cdmaOtaConfigData.configComplete) { |
| return; |
| } |
| |
| mApplication.cdmaOtaConfigData.configComplete = true; |
| int tmpOtaShowActivationScreen = |
| mContext.getResources().getInteger(R.integer.OtaShowActivationScreen); |
| mApplication.cdmaOtaConfigData.otaShowActivationScreen = tmpOtaShowActivationScreen; |
| if (DBG) log("readXmlSettings(), otaShowActivationScreen" |
| + mApplication.cdmaOtaConfigData.otaShowActivationScreen); |
| |
| int tmpOtaShowListeningScreen = |
| mContext.getResources().getInteger(R.integer.OtaShowListeningScreen); |
| mApplication.cdmaOtaConfigData.otaShowListeningScreen = tmpOtaShowListeningScreen; |
| if (DBG) log("readXmlSettings(), otaShowListeningScreen" |
| + mApplication.cdmaOtaConfigData.otaShowListeningScreen); |
| |
| int tmpOtaShowActivateFailTimes = |
| mContext.getResources().getInteger(R.integer.OtaShowActivateFailTimes); |
| mApplication.cdmaOtaConfigData.otaShowActivateFailTimes = tmpOtaShowActivateFailTimes; |
| if (DBG) log("readXmlSettings(), otaShowActivateFailTimes" |
| + mApplication.cdmaOtaConfigData.otaShowActivateFailTimes); |
| |
| int tmpOtaPlaySuccessFailureTone = |
| mContext.getResources().getInteger(R.integer.OtaPlaySuccessFailureTone); |
| mApplication.cdmaOtaConfigData.otaPlaySuccessFailureTone = tmpOtaPlaySuccessFailureTone; |
| if (DBG) log("readXmlSettings(), otaPlaySuccessFailureTone" |
| + mApplication.cdmaOtaConfigData.otaPlaySuccessFailureTone); |
| } |
| |
| /** |
| * Handle the click events for OTA buttons. |
| */ |
| public void onClickHandler(int id) { |
| switch (id) { |
| case R.id.otaEndButton: |
| onClickOtaEndButton(); |
| break; |
| |
| case R.id.otaSpeakerButton: |
| onClickOtaSpeakerButton(); |
| break; |
| |
| case R.id.otaActivateButton: |
| onClickOtaActivateButton(); |
| break; |
| |
| case R.id.otaSkipButton: |
| onClickOtaActivateSkipButton(); |
| break; |
| |
| case R.id.otaNextButton: |
| onClickOtaActivateNextButton(); |
| break; |
| |
| case R.id.otaTryAgainButton: |
| onClickOtaTryAgainButton(); |
| break; |
| |
| default: |
| if (DBG) log ("onClickHandler: received a click event for unrecognized id"); |
| break; |
| } |
| } |
| |
| private void onClickOtaTryAgainButton() { |
| if (DBG) log("Activation Try Again Clicked!"); |
| if (!mApplication.cdmaOtaProvisionData.inOtaSpcState) { |
| otaShowActivateScreen(); |
| } |
| } |
| |
| private void onClickOtaEndButton() { |
| if (DBG) log("Activation End Call Button Clicked!"); |
| if (!mApplication.cdmaOtaProvisionData.inOtaSpcState) { |
| if (PhoneUtils.hangup(mApplication.mCM) == false) { |
| // If something went wrong when placing the OTA call, |
| // the screen is not updated by the call disconnect |
| // handler and we have to do it here |
| setSpeaker(false); |
| mInCallScreen.handleOtaCallEnd(); |
| } |
| } |
| } |
| |
| private void onClickOtaSpeakerButton() { |
| if (DBG) log("OTA Speaker button Clicked!"); |
| if (!mApplication.cdmaOtaProvisionData.inOtaSpcState) { |
| boolean isChecked = !PhoneUtils.isSpeakerOn(mContext); |
| setSpeaker(isChecked); |
| } |
| } |
| |
| private void onClickOtaActivateButton() { |
| if (DBG) log("Call Activation Clicked!"); |
| otaPerformActivation(); |
| } |
| |
| private void onClickOtaActivateSkipButton() { |
| if (DBG) log("Activation Skip Clicked!"); |
| DialogInterface.OnKeyListener keyListener; |
| keyListener = new DialogInterface.OnKeyListener() { |
| public boolean onKey(DialogInterface dialog, int keyCode, |
| KeyEvent event) { |
| if (DBG) log("Ignoring key events..."); |
| return true; |
| } |
| }; |
| mOtaWidgetData.otaSkipConfirmationDialog = new AlertDialog.Builder(mInCallScreen) |
| .setTitle(R.string.ota_skip_activation_dialog_title) |
| .setMessage(R.string.ota_skip_activation_dialog_message) |
| .setPositiveButton( |
| R.string.ota_skip_activation_dialog_skip_label, |
| new AlertDialog.OnClickListener() { |
| public void onClick(DialogInterface dialog, int which) { |
| otaSkipActivation(); |
| } |
| }) |
| .setNegativeButton( |
| R.string.ota_skip_activation_dialog_continue_label, |
| new AlertDialog.OnClickListener() { |
| public void onClick(DialogInterface dialog, int which) { |
| otaPerformActivation(); |
| } |
| }) |
| .setOnKeyListener(keyListener) |
| .create(); |
| mOtaWidgetData.otaSkipConfirmationDialog.show(); |
| } |
| |
| private void onClickOtaActivateNextButton() { |
| if (DBG) log("Dialog Next Clicked!"); |
| if (!mApplication.cdmaOtaProvisionData.inOtaSpcState) { |
| mApplication.cdmaOtaScreenState.otaScreenState = |
| CdmaOtaScreenState.OtaScreenState.OTA_STATUS_UNDEFINED; |
| otaShowHome(); |
| } |
| } |
| |
| public void dismissAllOtaDialogs() { |
| if (mOtaWidgetData.spcErrorDialog != null) { |
| if (DBG) log("- DISMISSING mSpcErrorDialog."); |
| mOtaWidgetData.spcErrorDialog.dismiss(); |
| mOtaWidgetData.spcErrorDialog = null; |
| } |
| if (mOtaWidgetData.otaFailureDialog != null) { |
| if (DBG) log("- DISMISSING mOtaFailureDialog."); |
| mOtaWidgetData.otaFailureDialog.dismiss(); |
| mOtaWidgetData.otaFailureDialog = null; |
| } |
| } |
| |
| private int getOtaSpcDisplayTime() { |
| if (DBG) log("getOtaSpcDisplayTime()..."); |
| int tmpSpcTime = 1; |
| if (mApplication.cdmaOtaProvisionData.inOtaSpcState) { |
| long tmpOtaSpcRunningTime = 0; |
| long tmpOtaSpcLeftTime = 0; |
| tmpOtaSpcRunningTime = SystemClock.elapsedRealtime(); |
| tmpOtaSpcLeftTime = |
| tmpOtaSpcRunningTime - mApplication.cdmaOtaProvisionData.otaSpcUptime; |
| if (tmpOtaSpcLeftTime >= OTA_SPC_TIMEOUT*1000) { |
| tmpSpcTime = 1; |
| } else { |
| tmpSpcTime = OTA_SPC_TIMEOUT - (int)tmpOtaSpcLeftTime/1000; |
| } |
| } |
| if (DBG) log("getOtaSpcDisplayTime(), time for SPC error notice: " + tmpSpcTime); |
| return tmpSpcTime; |
| } |
| |
| /** |
| * Initialize the OTA widgets for all OTA screens. |
| */ |
| private void initOtaInCallScreen() { |
| if (DBG) log("initOtaInCallScreen()..."); |
| mOtaWidgetData.otaTitle = (TextView) mInCallScreen.findViewById(R.id.otaTitle); |
| mOtaWidgetData.otaTextActivate = (TextView) mInCallScreen.findViewById(R.id.otaActivate); |
| mOtaWidgetData.otaTextActivate.setVisibility(View.GONE); |
| mOtaWidgetData.otaTextListenProgressContainer = |
| (ScrollView) mInCallScreen.findViewById(R.id.otaListenProgressContainer); |
| mOtaWidgetData.otaTextListenProgress = |
| (TextView) mInCallScreen.findViewById(R.id.otaListenProgress); |
| mOtaWidgetData.otaTextProgressBar = |
| (ProgressBar) mInCallScreen.findViewById(R.id.progress_large); |
| mOtaWidgetData.otaTextProgressBar.setIndeterminate(true); |
| mOtaWidgetData.otaTextSuccessFail = |
| (TextView) mInCallScreen.findViewById(R.id.otaSuccessFailStatus); |
| |
| mOtaWidgetData.otaCallCardBase = (View) mInCallScreen.findViewById(R.id.otaBase); |
| mOtaWidgetData.callCardOtaButtonsListenProgress = |
| (View) mInCallScreen.findViewById(R.id.callCardOtaListenProgress); |
| mOtaWidgetData.callCardOtaButtonsActivate = |
| (View) mInCallScreen.findViewById(R.id.callCardOtaActivate); |
| mOtaWidgetData.callCardOtaButtonsFailSuccess = |
| (View) mInCallScreen.findViewById(R.id.callCardOtaFailOrSuccessful); |
| |
| mOtaWidgetData.otaEndButton = (Button) mInCallScreen.findViewById(R.id.otaEndButton); |
| mOtaWidgetData.otaEndButton.setOnClickListener(mInCallScreen); |
| mOtaWidgetData.otaSpeakerButton = |
| (ToggleButton) mInCallScreen.findViewById(R.id.otaSpeakerButton); |
| mOtaWidgetData.otaSpeakerButton.setOnClickListener(mInCallScreen); |
| mOtaWidgetData.otaActivateButton = |
| (Button) mInCallScreen.findViewById(R.id.otaActivateButton); |
| mOtaWidgetData.otaActivateButton.setOnClickListener(mInCallScreen); |
| mOtaWidgetData.otaSkipButton = (Button) mInCallScreen.findViewById(R.id.otaSkipButton); |
| mOtaWidgetData.otaSkipButton.setOnClickListener(mInCallScreen); |
| mOtaWidgetData.otaNextButton = (Button) mInCallScreen.findViewById(R.id.otaNextButton); |
| mOtaWidgetData.otaNextButton.setOnClickListener(mInCallScreen); |
| mOtaWidgetData.otaTryAgainButton = |
| (Button) mInCallScreen.findViewById(R.id.otaTryAgainButton); |
| mOtaWidgetData.otaTryAgainButton.setOnClickListener(mInCallScreen); |
| |
| mOtaWidgetData.otaDtmfDialerView = |
| (DTMFTwelveKeyDialerView) mInCallScreen.findViewById(R.id.otaDtmfDialer); |
| // Sanity-check: the otaDtmfDialer widget should *always* be present. |
| if (mOtaWidgetData.otaDtmfDialerView == null) { |
| Log.e(LOG_TAG, "onCreate: couldn't find otaDtmfDialer", new IllegalStateException()); |
| } |
| |
| |
| // Create a new DTMFTwelveKeyDialer instance purely for use by the |
| // DTMFTwelveKeyDialerView ("otaDtmfDialerView") that comes from |
| // otacall_card.xml. |
| // (But note that mDialer is a separate DTMFTwelveKeyDialer |
| // instance, that belongs to the InCallScreen. This is confusing; |
| // see the TODO comment above.) |
| mOtaCallCardDtmfDialer = new DTMFTwelveKeyDialer(mInCallScreen, |
| mOtaWidgetData.otaDtmfDialerView, |
| null /* no SlidingDrawer used here */); |
| |
| // Initialize the new DTMFTwelveKeyDialer instance. This is |
| // needed to play local DTMF tones. |
| mOtaCallCardDtmfDialer.startDialerSession(); |
| |
| mOtaWidgetData.otaDtmfDialerView.setDialer(mOtaCallCardDtmfDialer); |
| } |
| |
| /** |
| * Clear out all OTA UI widget elements. Needs to get called |
| * when OTA call ends or InCallScreen is destroyed. |
| * @param disableSpeaker parameter control whether Speaker should be turned off. |
| */ |
| public void cleanOtaScreen(boolean disableSpeaker) { |
| if (DBG) log("OTA ends, cleanOtaScreen!"); |
| |
| mApplication.cdmaOtaScreenState.otaScreenState = |
| CdmaOtaScreenState.OtaScreenState.OTA_STATUS_UNDEFINED; |
| mApplication.cdmaOtaProvisionData.isOtaCallCommitted = false; |
| mApplication.cdmaOtaProvisionData.isOtaCallIntentProcessed = false; |
| mApplication.cdmaOtaProvisionData.inOtaSpcState = false; |
| mApplication.cdmaOtaProvisionData.activationCount = 0; |
| mApplication.cdmaOtaProvisionData.otaSpcUptime = 0; |
| mApplication.cdmaOtaInCallScreenUiState.state = State.UNDEFINED; |
| |
| if (mInCallPanel != null) mInCallPanel.setVisibility(View.VISIBLE); |
| if (mCallCard != null) mCallCard.hideCallCardElements(); |
| mDialer.setHandleVisible(true); |
| |
| // Free resources from the DTMFTwelveKeyDialer instance we created |
| // in initOtaInCallScreen(). |
| if (mOtaCallCardDtmfDialer != null) { |
| mOtaCallCardDtmfDialer.stopDialerSession(); |
| } |
| |
| mOtaWidgetData.otaTextActivate.setVisibility(View.GONE); |
| mOtaWidgetData.otaTextListenProgressContainer.setVisibility(View.GONE); |
| mOtaWidgetData.otaTextProgressBar.setVisibility(View.GONE); |
| mOtaWidgetData.otaTextSuccessFail.setVisibility(View.GONE); |
| mOtaWidgetData.callCardOtaButtonsActivate.setVisibility(View.GONE); |
| mOtaWidgetData.callCardOtaButtonsListenProgress.setVisibility(View.GONE); |
| mOtaWidgetData.callCardOtaButtonsFailSuccess.setVisibility(View.GONE); |
| mOtaWidgetData.otaCallCardBase.setVisibility(View.GONE); |
| mOtaWidgetData.otaDtmfDialerView.setVisibility(View.GONE); |
| mOtaWidgetData.otaNextButton.setVisibility(View.GONE); |
| mOtaWidgetData.otaTryAgainButton.setVisibility(View.GONE); |
| |
| // turn off the speaker in case it was turned on |
| // but the OTA call could not be completed |
| if (disableSpeaker) { |
| setSpeaker(false); |
| } |
| } |
| |
| /** |
| * Defines OTA information that needs to be maintained during |
| * an OTA call when display orientation changes. |
| */ |
| public static class CdmaOtaProvisionData { |
| public boolean isOtaCallCommitted; |
| public boolean isOtaCallIntentProcessed; |
| public boolean inOtaSpcState; |
| public int activationCount; |
| public long otaSpcUptime; |
| } |
| |
| /** |
| * Defines OTA screen configuration items read from config.xml |
| * and used to control OTA display. |
| */ |
| public static class CdmaOtaConfigData { |
| public int otaShowActivationScreen; |
| public int otaShowListeningScreen; |
| public int otaShowActivateFailTimes; |
| public int otaPlaySuccessFailureTone; |
| public boolean configComplete; |
| public CdmaOtaConfigData() { |
| if (DBG) log("CdmaOtaConfigData constructor!"); |
| otaShowActivationScreen = OTA_SHOW_ACTIVATION_SCREEN_OFF; |
| otaShowListeningScreen = OTA_SHOW_LISTENING_SCREEN_OFF; |
| otaShowActivateFailTimes = OTA_SHOW_ACTIVATE_FAIL_COUNT_OFF; |
| otaPlaySuccessFailureTone = OTA_PLAY_SUCCESS_FAILURE_TONE_OFF; |
| } |
| } |
| |
| /** |
| * The state of the OTA InCallScreen UI. |
| */ |
| public static class CdmaOtaInCallScreenUiState { |
| public enum State { |
| UNDEFINED, |
| NORMAL, |
| ENDED |
| } |
| |
| public State state; |
| |
| public CdmaOtaInCallScreenUiState() { |
| if (DBG) log("CdmaOtaInCallScreenState: constructor init to UNDEFINED"); |
| state = CdmaOtaInCallScreenUiState.State.UNDEFINED; |
| } |
| |
| // the pending intent used to report when the user skips ota provisioning |
| public PendingIntent reportSkipPendingIntent; |
| } |
| |
| /** |
| * Save the Ota InCallScreen UI state |
| */ |
| public void setCdmaOtaInCallScreenUiState(CdmaOtaInCallScreenUiState.State state) { |
| if (DBG) log("setCdmaOtaInCallScreenState: " + state); |
| mApplication.cdmaOtaInCallScreenUiState.state = state; |
| } |
| |
| /** |
| * Get the Ota InCallScreen UI state |
| */ |
| public CdmaOtaInCallScreenUiState.State getCdmaOtaInCallScreenUiState() { |
| if (DBG) log("getCdmaOtaInCallScreenState: " + mApplication.cdmaOtaInCallScreenUiState.state); |
| return mApplication.cdmaOtaInCallScreenUiState.state; |
| } |
| |
| /** |
| * The OTA screen state machine. |
| */ |
| public static class CdmaOtaScreenState { |
| public enum OtaScreenState { |
| OTA_STATUS_UNDEFINED, |
| OTA_STATUS_ACTIVATION, |
| OTA_STATUS_LISTENING, |
| OTA_STATUS_PROGRESS, |
| OTA_STATUS_SUCCESS_FAILURE_DLG |
| } |
| |
| public OtaScreenState otaScreenState; |
| |
| public CdmaOtaScreenState() { |
| otaScreenState = OtaScreenState.OTA_STATUS_UNDEFINED; |
| } |
| } |
| |
| private static void log(String msg) { |
| Log.d(LOG_TAG, msg); |
| } |
| |
| public static boolean isCdmaPhone() { |
| return (PhoneApp.getInstance().phone.getPhoneType() == Phone.PHONE_TYPE_CDMA); |
| } |
| } |