AccountCheckSettingsFragment.java revision 31e25767918193217c884db72aaa98e50a4957d3
155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler/* 255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * Copyright (C) 2010 The Android Open Source Project 355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * 455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * Licensed under the Apache License, Version 2.0 (the "License"); 555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * you may not use this file except in compliance with the License. 655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * You may obtain a copy of the License at 755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * 855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * http://www.apache.org/licenses/LICENSE-2.0 955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * 1055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * Unless required by applicable law or agreed to in writing, software 1155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * distributed under the License is distributed on an "AS IS" BASIS, 1255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * See the License for the specific language governing permissions and 1455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * limitations under the License. 1555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 1655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 1755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerpackage com.android.email.activity.setup; 1855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 1955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport com.android.email.Email; 2055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport com.android.email.R; 2155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport com.android.email.Utility; 226d51b7eb630d3b2632b44699e14730eb7b995f78Marc Blankimport com.android.email.SecurityPolicy.PolicySet; 2355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport com.android.email.mail.MessagingException; 2455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport com.android.email.mail.Sender; 2555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport com.android.email.mail.Store; 2655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport com.android.email.provider.EmailContent.Account; 272731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadlerimport com.android.email.provider.EmailContent.HostAuth; 2855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport com.android.email.service.EmailServiceProxy; 2955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 30fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadlerimport android.app.Activity; 3155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport android.app.AlertDialog; 3255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport android.app.Dialog; 3355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport android.app.DialogFragment; 3455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport android.app.Fragment; 3555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport android.app.FragmentManager; 3655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport android.app.ProgressDialog; 3755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport android.content.Context; 3855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport android.content.DialogInterface; 3955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport android.os.AsyncTask; 4055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport android.os.Bundle; 4155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerimport android.util.Log; 4255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 4355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler/** 4455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * Check incoming or outgoing settings, or perform autodiscovery. 4555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * 4655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * There are three components that work together. 1. This fragment is retained and non-displayed, 4755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * and controls the overall process. 2. An AsyncTask that works with the stores/services to 4855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * check the accounts settings. 3. A stateless progress dialog (which will be recreated on 4955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * orientation changes). 5055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * 5155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * There are also two lightweight error dialogs which are used for notification of terminal 5255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * conditions. 5355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 5455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadlerpublic class AccountCheckSettingsFragment extends Fragment { 5555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 5655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public final static String TAG = "AccountCheckSettingsFragment"; 5755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 5855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // Debugging flags - for debugging the UI 592731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // If true, use a "fake" account check cycle 602731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler private static final boolean DEBUG_FAKE_CHECK_CYCLE = false; // DO NOT CHECK IN TRUE 612731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // If true, use fake check cycle, return failure 622731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler private static final boolean DEBUG_FAKE_CHECK_ERR = false; // DO NOT CHECK IN TRUE 632731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // If true, use fake check cycle, return "security required" 642731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler private static final boolean DEBUG_FORCE_SECURITY_REQUIRED = false; // DO NOT CHECK IN TRUE 6555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 6655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // State 6755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private final static int STATE_START = 0; 6855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private final static int STATE_CHECK_AUTODISCOVER = 1; 6955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private final static int STATE_CHECK_INCOMING = 2; 7055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private final static int STATE_CHECK_OUTGOING = 3; 712731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler private final static int STATE_CHECK_OK = 4; // terminal 722731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler private final static int STATE_CHECK_SHOW_SECURITY = 5; // terminal 732731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler private final static int STATE_CHECK_ERROR = 6; // terminal 742731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler private final static int STATE_AUTODISCOVER_AUTH_DIALOG = 7; // terminal 752731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler private final static int STATE_AUTODISCOVER_RESULT = 8; // terminal 7655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private int mState = STATE_START; 7755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 7855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // Support for UI 7955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private boolean mAttached; 8055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private CheckingDialog mCheckingDialog; 8155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private int mErrorStringId; 8255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private String mErrorMessage; 832731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler private HostAuth mAutoDiscoverResult; 84fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler 8555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // Support for AsyncTask and account checking 8655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler AccountCheckTask mAccountCheckTask; 872731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler 882731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // Result codes returned by onCheckSettingsComplete. 892731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler /** Check settings returned successfully */ 902731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler public final static int CHECK_SETTINGS_OK = 0; 912731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler /** Check settings failed due to connection, authentication, or other server error */ 922731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler public final static int CHECK_SETTINGS_SERVER_ERROR = 1; 932731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler /** Check settings failed due to user refusing to accept security requirements */ 942731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler public final static int CHECK_SETTINGS_SECURITY_USER_DENY = 2; 952731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler 962731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // Result codes returned by onAutoDiscoverComplete. 972731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler /** AutoDiscover completed successfully with server setup data */ 982731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler public final static int AUTODISCOVER_OK = 0; 992731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler /** AutoDiscover completed with no data (no server or AD not supported) */ 1002731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler public final static int AUTODISCOVER_NO_DATA = 1; 1012731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler /** AutoDiscover reported authentication error */ 1022731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler public final static int AUTODISCOVER_AUTHENTICATION = 2; 1032731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler 10455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 105fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler * Callback interface for any target or activity doing account check settings 106fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler */ 107fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler public interface Callbacks { 108fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler /** 1092731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * Called when CheckSettings completed 1102731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * @param result check settings result code - success is CHECK_SETTINGS_OK 111fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler */ 1122731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler public void onCheckSettingsComplete(int result); 1132731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler 1142731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler /** 1152731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * Called when autodiscovery completes. 1162731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * @param result autodiscovery result code - success is AUTODISCOVER_OK 1172731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * @param hostAuth configuration data returned by AD server, or null if no data available 1182731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler */ 1192731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler public void onAutoDiscoverComplete(int result, HostAuth hostAuth); 120fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler } 1212731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler 122fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler /** 12355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * Create a retained, invisible fragment that checks accounts 12455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * 12555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * @param mode incoming or outgoing 12655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 12755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public static AccountCheckSettingsFragment newInstance(int mode, Fragment parentFragment) { 12855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler AccountCheckSettingsFragment f = new AccountCheckSettingsFragment(); 12955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler f.setTargetFragment(parentFragment, mode); 13055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler return f; 13155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 13255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 13355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 13455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * Fragment initialization. Because we never implement onCreateView, and call 13555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * setRetainInstance here, this creates an invisible, persistent, "worker" fragment. 13655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 13755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler @Override 13855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public void onCreate(Bundle savedInstanceState) { 13955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler super.onCreate(savedInstanceState); 14055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler setRetainInstance(true); 14155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 14255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 14355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 14455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * This is called when the Fragment's Activity is ready to go, after 14555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * its content view has been installed; it is called both after 14655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * the initial fragment creation and after the fragment is re-attached 14755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * to a new activity. 14855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 14955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler @Override 15055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public void onActivityCreated(Bundle savedInstanceState) { 15155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler super.onActivityCreated(savedInstanceState); 15255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler mAttached = true; 15355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 15455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // If this is the first time, start the AsyncTask 15555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (mAccountCheckTask == null) { 15655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler int checkMode = getTargetRequestCode(); 15755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler Account checkAccount = SetupData.getAccount(); 15855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler mAccountCheckTask = (AccountCheckTask) 1592731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler new AccountCheckTask(checkMode, checkAccount) 16055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler .execute(); 16155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 162f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler } 163f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler 164f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler /** 165f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler * When resuming, restart the progress/error UI if necessary by re-reporting previous values 166f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler */ 167f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler @Override 168f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler public void onResume() { 169f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler super.onResume(); 17055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 17155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (mState != STATE_START) { 1722731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler reportProgress(mState, mErrorStringId, mErrorMessage, mAutoDiscoverResult); 17355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 17455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 17555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 17655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 17755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * This is called when the fragment is going away. It is NOT called 17855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * when the fragment is being propagated between activity instances. 17955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 18055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler @Override 18155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public void onDestroy() { 18255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler super.onDestroy(); 18355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler Utility.cancelTaskInterrupt(mAccountCheckTask); 18455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler mAccountCheckTask = null; 18555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 18655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 18755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 18855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * This is called right before the fragment is detached from its current activity instance. 18955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * All reporting and callbacks are halted until we reattach. 19055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 19155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler @Override 19255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public void onDetach() { 19355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler super.onDetach(); 19455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler mAttached = false; 19555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 19655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 19755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 19855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * The worker (AsyncTask) will call this (in the UI thread) to report progress. If we are 19955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * attached to an activity, update the progress immediately; If not, simply hold the 20055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * progress for later. 20155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * @param newState The new progress state being reported 20255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * @param errorStringId Resource Id of an error string to display 20355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * @param errorMessage Additional string to insert if the resource string takes a parameter. 2042731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * @param autoDiscoverResult If doing autodiscovery, the setup info returned from AD server 20555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 2062731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler public void reportProgress(int newState, int errorStringId, String errorMessage, 2072731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler HostAuth autoDiscoverResult) { 20855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler mState = newState; 20955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler mErrorStringId = errorStringId; 21055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler mErrorMessage = errorMessage; 2112731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler mAutoDiscoverResult = autoDiscoverResult; 21255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 21355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // If we are attached, create, recover, and/or update the dialog 21455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (mAttached) { 21555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler FragmentManager fm = getFragmentManager(); 21655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 2172731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler switch (newState) { 2182731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler case STATE_CHECK_OK: 2192731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // immediately terminate, clean up, and report back 2202731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // 1. get rid of progress dialog (if any) 2212731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler recoverAndDismissCheckingDialog(); 2222731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // 2. exit self 2232731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler fm.popBackStack(); 2242731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // 3. report OK back to target fragment or activity 2252731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler getCallbackTarget().onCheckSettingsComplete(CHECK_SETTINGS_OK); 2262731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler break; 2272731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler case STATE_CHECK_SHOW_SECURITY: 2282731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // 1. get rid of progress dialog (if any) 2292731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler recoverAndDismissCheckingDialog(); 230f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler // 2. launch the error dialog, if needed 231f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler if (fm.findFragmentByTag(SecurityRequiredDialog.TAG) == null) { 232f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler SecurityRequiredDialog securityRequiredDialog = 233f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler SecurityRequiredDialog.newInstance(this, mErrorMessage); 23431e25767918193217c884db72aaa98e50a4957d3Dianne Hackborn fm.beginTransaction() 235f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler .add(securityRequiredDialog, SecurityRequiredDialog.TAG) 236f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler .commit(); 237f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler } 2382731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler break; 2392731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler case STATE_CHECK_ERROR: 2402731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler case STATE_AUTODISCOVER_AUTH_DIALOG: 2412731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // 1. get rid of progress dialog (if any) 2422731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler recoverAndDismissCheckingDialog(); 243f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler // 2. launch the error dialog, if needed 244f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler if (fm.findFragmentByTag(ErrorDialog.TAG) == null) { 245f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler ErrorDialog errorDialog = 246f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler ErrorDialog.newInstance(this, mErrorStringId, mErrorMessage); 24731e25767918193217c884db72aaa98e50a4957d3Dianne Hackborn fm.beginTransaction() 248f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler .add(errorDialog, ErrorDialog.TAG) 249f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler .commit(); 250f946ff001914abce9ea06b1ceecd29cdb7e10ef3Andy Stadler } 2512731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler break; 2522731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler case STATE_AUTODISCOVER_RESULT: 2532731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // 1. get rid of progress dialog (if any) 2542731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler recoverAndDismissCheckingDialog(); 2552731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // 2. exit self 2562731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler fm.popBackStack(); 2572731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // 3. report back to target fragment or activity 2582731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler getCallbackTarget().onAutoDiscoverComplete( 2592731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler (mAutoDiscoverResult != null) ? AUTODISCOVER_OK : AUTODISCOVER_NO_DATA, 2602731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler mAutoDiscoverResult); 2612731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler break; 2622731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler default: 2632731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // Display a normal progress message 2642731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler mCheckingDialog = (CheckingDialog) fm.findFragmentByTag(CheckingDialog.TAG); 2652731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler 2662731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler if (mCheckingDialog == null) { 2672731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler mCheckingDialog = CheckingDialog.newInstance(this, mState); 26831e25767918193217c884db72aaa98e50a4957d3Dianne Hackborn fm.beginTransaction() 2692731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler .add(mCheckingDialog, CheckingDialog.TAG) 2702731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler .commit(); 2712731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } else { 2722731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler mCheckingDialog.updateProgress(mState); 2732731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } 2742731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler break; 27555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 27655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 27755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 27855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 27955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 280fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler * Find the callback target, either a target fragment or the activity 281fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler */ 282fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler private Callbacks getCallbackTarget() { 283fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler Fragment target = getTargetFragment(); 284fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler if (target instanceof Callbacks) { 285fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler return (Callbacks) target; 286fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler } 287fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler Activity activity = getActivity(); 288fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler if (activity instanceof Callbacks) { 289fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler return (Callbacks) activity; 290fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler } 291fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler throw new IllegalStateException(); 2922731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } 293fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler 294fd14496c494a0d38c35c3788c9cc55f1984592e4Andrew Stadler /** 29555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * Recover and dismiss the progress dialog fragment 29655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 29755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private void recoverAndDismissCheckingDialog() { 29855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (mCheckingDialog == null) { 29955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler mCheckingDialog = (CheckingDialog) 30055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler getFragmentManager().findFragmentByTag(CheckingDialog.TAG); 30155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 30255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (mCheckingDialog != null) { 30355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler mCheckingDialog.dismiss(); 30455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler mCheckingDialog = null; 30555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 30655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 30755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 30855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 30955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * This is called when the user clicks "cancel" on the progress dialog. Shuts everything 31055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * down and dismisses everything. 31155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * This should cause us to remain in the current screen (not accepting the settings) 31255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 31355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private void onCheckingDialogCancel() { 31455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // 1. kill the checker 31555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler Utility.cancelTaskInterrupt(mAccountCheckTask); 31655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler mAccountCheckTask = null; 31755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // 2. kill self with no report - this is "cancel" 31855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler getFragmentManager().popBackStack(); 31955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 32055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 32155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 32255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * This is called when the user clicks "edit" from the error dialog. The error dialog 32355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * should have already dismissed itself. 3242731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * Depending on the context, the target will remain in the current activity (e.g. editing 3252731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * settings) or return to its own parent (e.g. enter new credentials). 32655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 32755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private void onErrorDialogEditButton() { 3282731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler Callbacks callbackTarget = getCallbackTarget(); 3292731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler if (mState == STATE_AUTODISCOVER_AUTH_DIALOG) { 3302731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // report auth error to target fragment or activity 3312731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler callbackTarget.onAutoDiscoverComplete(AUTODISCOVER_AUTHENTICATION, null); 3322731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } else { 3332731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // report check settings failure to target fragment or activity 3342731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler callbackTarget.onCheckSettingsComplete(CHECK_SETTINGS_SERVER_ERROR); 3352731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } 33655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler getFragmentManager().popBackStack(); 33755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 33855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 33955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 34055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * This is called when the user clicks "ok" or "cancel" on the "security required" dialog. 34155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * Shuts everything down and dismisses everything, and reports the result appropriately. 34255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 3432731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler private void onSecurityRequiredDialogResultOk(boolean okPressed) { 3442731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // 1. handle OK/cancel - notify that security is OK and we can proceed 3452731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler Callbacks callbackTarget = getCallbackTarget(); 3462731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler callbackTarget.onCheckSettingsComplete( 3472731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler okPressed ? CHECK_SETTINGS_OK : CHECK_SETTINGS_SECURITY_USER_DENY); 3482731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler 349d8f1d8f2ff75502b86c8ce7b8a738eddc731a607Andy Stadler // 2. kill self if not already killed by callback 350d8f1d8f2ff75502b86c8ce7b8a738eddc731a607Andy Stadler FragmentManager fm = getFragmentManager(); 351d8f1d8f2ff75502b86c8ce7b8a738eddc731a607Andy Stadler if (fm != null) { 352d8f1d8f2ff75502b86c8ce7b8a738eddc731a607Andy Stadler fm.popBackStack(); 353d8f1d8f2ff75502b86c8ce7b8a738eddc731a607Andy Stadler } 35455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 35555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 35655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 3572731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * This exception class is used to report autodiscover results via the reporting mechanism. 3582731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler */ 3592731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler public static class AutoDiscoverResults extends MessagingException { 3602731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler public final HostAuth mHostAuth; 3612731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler 3622731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler /** 3632731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * @param authenticationError true if auth failure, false for result (or no response) 3642731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * @param hostAuth null for "no autodiscover", non-null for server info to return 3652731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler */ 3662731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler public AutoDiscoverResults(boolean authenticationError, HostAuth hostAuth) { 3672731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler super(null); 3682731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler if (authenticationError) { 3692731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler mExceptionType = AUTODISCOVER_AUTHENTICATION_FAILED; 3702731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } else { 3712731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler mExceptionType = AUTODISCOVER_AUTHENTICATION_RESULT; 3722731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } 3732731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler mHostAuth = hostAuth; 3742731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } 3752731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } 3762731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler 3772731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler /** 37855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * This AsyncTask does the actual account checking 37955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * 38055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * TODO: It would be better to remove the UI complete from here (the exception->string 38155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * conversions). 38255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 38355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private class AccountCheckTask extends AsyncTask<Void, Integer, MessagingException> { 38455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 38555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler final Context mContext; 38655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler final int mMode; 38755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler final String mStoreUri; 38855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler final String mStoreHost; 38955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler final String mSenderUri; 3902731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler final String mCheckEmail; 3912731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler final String mCheckPassword; 39255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 39355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 39455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * Create task and parameterize it 39555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * @param mode bits request operations 3962731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * @param checkAccount account holding values to be checked 39755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 3982731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler public AccountCheckTask(int mode, Account checkAccount) { 39955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler mContext = getActivity().getApplicationContext(); 40055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler mMode = mode; 4012731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler mStoreUri = checkAccount.getStoreUri(mContext); 4022731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler mStoreHost = checkAccount.mHostAuthRecv.mAddress; 4032731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler mSenderUri = checkAccount.getSenderUri(mContext); 4042731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler mCheckEmail = checkAccount.mEmailAddress; 4052731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler mCheckPassword = checkAccount.mHostAuthRecv.mPassword; 40655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 40755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 40855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler @Override 40955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler protected MessagingException doInBackground(Void... params) { 41055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (DEBUG_FAKE_CHECK_CYCLE) { 41155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler return fakeChecker(); 41255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 41355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 41455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler try { 41555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if ((mMode & SetupData.CHECK_AUTODISCOVER) != 0) { 41655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (isCancelled()) return null; 41755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler publishProgress(STATE_CHECK_AUTODISCOVER); 4182731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler Log.d(Email.LOG_TAG, "Begin auto-discover for " + mCheckEmail); 4192731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler Store store = Store.getInstance(mStoreUri, mContext, null); 4202731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler Bundle result = store.autoDiscover(mContext, mCheckEmail, mCheckPassword); 4212731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // Result will be one of: 4222731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // null: remote exception - proceed to manual setup 4232731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // MessagingException.AUTHENTICATION_FAILED: username/password rejected 4242731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // Other error: proceed to manual setup 4252731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // No error: return autodiscover results 4262731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler if (result == null) { 4272731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler return new AutoDiscoverResults(false, null); 4282731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } 4292731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler int errorCode = 4302731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler result.getInt(EmailServiceProxy.AUTO_DISCOVER_BUNDLE_ERROR_CODE); 4312731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler if (errorCode == MessagingException.AUTHENTICATION_FAILED) { 4322731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler return new AutoDiscoverResults(true, null); 4332731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } else if (errorCode != MessagingException.NO_ERROR) { 4342731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler return new AutoDiscoverResults(false, null); 4352731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } else { 4362731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler HostAuth serverInfo = (HostAuth) 4372731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler result.getParcelable(EmailServiceProxy.AUTO_DISCOVER_BUNDLE_HOST_AUTH); 4382731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler return new AutoDiscoverResults(false, serverInfo); 4392731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } 44055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 44155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 44255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // Check Incoming Settings 44355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if ((mMode & SetupData.CHECK_INCOMING) != 0) { 44455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (isCancelled()) return null; 44555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler Log.d(Email.LOG_TAG, "Begin check of incoming email settings"); 44655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler publishProgress(STATE_CHECK_INCOMING); 44755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler Store store = Store.getInstance(mStoreUri, mContext, null); 44855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler Bundle bundle = store.checkSettings(); 44955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler int resultCode = MessagingException.UNSPECIFIED_EXCEPTION; 45055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (bundle != null) { 45155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler resultCode = bundle.getInt( 45255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler EmailServiceProxy.VALIDATE_BUNDLE_RESULT_CODE); 45355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 45455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (resultCode == MessagingException.SECURITY_POLICIES_REQUIRED) { 45555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler SetupData.setPolicySet((PolicySet)bundle.getParcelable( 45655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler EmailServiceProxy.VALIDATE_BUNDLE_POLICY_SET)); 45755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler return new MessagingException( 45855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler MessagingException.SECURITY_POLICIES_REQUIRED, mStoreHost); 45955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 46055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (resultCode != MessagingException.NO_ERROR) { 46155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler String errorMessage = 46255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler bundle.getString(EmailServiceProxy.VALIDATE_BUNDLE_ERROR_MESSAGE); 46355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler return new MessagingException(resultCode, errorMessage); 46455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 46555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 46655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 46755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // Check Outgoing Settings 46855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if ((mMode & SetupData.CHECK_OUTGOING) != 0) { 46955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (isCancelled()) return null; 47055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler Log.d(Email.LOG_TAG, "Begin check of outgoing email settings"); 47155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler publishProgress(STATE_CHECK_OUTGOING); 47255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler Sender sender = Sender.getInstance(mContext, mSenderUri); 47355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler sender.close(); 47455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler sender.open(); 47555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler sender.close(); 47655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 47755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 47855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // If we reached the end, we completed the check(s) successfully 47955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler return null; 48055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } catch (final MessagingException me) { 48155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // Some of the legacy account checkers return errors by throwing MessagingException, 48255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // which we catch and return here. 48355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler return me; 48455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 48555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 48655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 48755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 4882731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * Dummy background worker, for testing UI only. 48955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 49055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private MessagingException fakeChecker() { 49155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // Dummy: Publish a series of progress setups, 2 sec delays between them; 49255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // then return "ok" (null) 49355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler final int DELAY = 2*1000; 49455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (isCancelled()) return null; 49555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if ((mMode & SetupData.CHECK_AUTODISCOVER) != 0) { 49655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler publishProgress(STATE_CHECK_AUTODISCOVER); 49755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler try { 49855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler Thread.sleep(DELAY); 49955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } catch (InterruptedException e) { } 5002731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler if (DEBUG_FAKE_CHECK_ERR) { 5012731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler return new MessagingException(MessagingException.AUTHENTICATION_FAILED); 5022731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } 5032731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // Return "real" AD results 5042731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler HostAuth serverInfo = new HostAuth(); 5052731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler serverInfo.setStoreUri("eas://user:password@testserver.com"); 5062731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler return new AutoDiscoverResults(false, serverInfo); 50755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 50855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (isCancelled()) return null; 50955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if ((mMode & SetupData.CHECK_INCOMING) != 0) { 51055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler publishProgress(STATE_CHECK_INCOMING); 51155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler try { 51255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler Thread.sleep(DELAY); 51355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } catch (InterruptedException e) { } 5142731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler if (DEBUG_FAKE_CHECK_ERR) { 5152731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler return new MessagingException(MessagingException.IOERROR); 5162731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } else if (DEBUG_FORCE_SECURITY_REQUIRED) { 5172731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler return new MessagingException( 5182731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler MessagingException.SECURITY_POLICIES_REQUIRED); 5192731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } 52055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 52155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (isCancelled()) return null; 52255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if ((mMode & SetupData.CHECK_OUTGOING) != 0) { 52355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler publishProgress(STATE_CHECK_OUTGOING); 52455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler try { 52555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler Thread.sleep(DELAY); 52655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } catch (InterruptedException e) { } 5272731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler if (DEBUG_FAKE_CHECK_ERR) { 5282731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler return new MessagingException(MessagingException.TLS_REQUIRED); 5292731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler } 53055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 53155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler return null; 53255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 53355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 53455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 53555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * Progress reports (runs in UI thread). This should be used for real progress only 53655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * (not for errors). 53755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 53855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler @Override 53955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler protected void onProgressUpdate(Integer... progress) { 54055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (isCancelled()) return; 5412731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler reportProgress(progress[0], 0, null, null); 54255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 54355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 54455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 5452731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * Result handler (runs in UI thread). 5462731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * 5472731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * AutoDiscover authentication errors are handled a bit differently than the 5482731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * other errors; If encountered, we display the error dialog, but we return with 5492731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * a different callback used only for AutoDiscover. 5502731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * 55155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * @param result null for a successful check; exception for various errors 55255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 55355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler @Override 55455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler protected void onPostExecute(MessagingException result) { 55555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (isCancelled()) return; 55655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (result == null) { 5572731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler reportProgress(STATE_CHECK_OK, 0, null, null); 55855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } else { 5592731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler int progressState = STATE_CHECK_ERROR; 56055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler int exceptionType = result.getExceptionType(); 56155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler String message = result.getMessage(); 5622731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler HostAuth hostAuth = null; 5632731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler int id = 0; 5642731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler 56555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler switch (exceptionType) { 5662731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // NOTE: AutoDiscover reports have their own reporting state, handle differently 5672731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // from the other exception types 5682731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler case MessagingException.AUTODISCOVER_AUTHENTICATION_FAILED: 5692731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler id = (message == null) 5702731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler ? R.string.account_setup_failed_dlg_auth_message 5712731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler : R.string.account_setup_failed_dlg_auth_message_fmt; 5722731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler progressState = STATE_AUTODISCOVER_AUTH_DIALOG; 5732731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler break; 5742731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler case MessagingException.AUTODISCOVER_AUTHENTICATION_RESULT: 5752731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler hostAuth = ((AutoDiscoverResults)result).mHostAuth; 5762731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler progressState = STATE_AUTODISCOVER_RESULT; 5772731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler break; 5782731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler 57955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // NOTE: Security policies required has its own report state, handle it a bit 58055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // differently from the other exception types. 58155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler case MessagingException.SECURITY_POLICIES_REQUIRED: 5822731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler progressState = STATE_CHECK_SHOW_SECURITY; 5832731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler break; 5842731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler 5852731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // The remaining exception types are handled by setting the state to 5862731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler // STATE_CHECK_ERROR (above, default) and conversion to specific error strings. 58755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler case MessagingException.CERTIFICATE_VALIDATION_ERROR: 58855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler id = (message == null) 58955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler ? R.string.account_setup_failed_dlg_certificate_message 59055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler : R.string.account_setup_failed_dlg_certificate_message_fmt; 59155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler break; 59255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler case MessagingException.AUTHENTICATION_FAILED: 59355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler id = (message == null) 59455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler ? R.string.account_setup_failed_dlg_auth_message 59555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler : R.string.account_setup_failed_dlg_auth_message_fmt; 59655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler break; 59714a5d8d947972f8a05bed80549bde2b99cfb2a8bMarc Blank case MessagingException.AUTHENTICATION_FAILED_OR_SERVER_ERROR: 59814a5d8d947972f8a05bed80549bde2b99cfb2a8bMarc Blank id = R.string.account_setup_failed_check_credentials_message; 59914a5d8d947972f8a05bed80549bde2b99cfb2a8bMarc Blank break; 60055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler case MessagingException.IOERROR: 60155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler id = R.string.account_setup_failed_ioerror; 60255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler break; 60355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler case MessagingException.TLS_REQUIRED: 60455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler id = R.string.account_setup_failed_tls_required; 60555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler break; 60655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler case MessagingException.AUTH_REQUIRED: 60755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler id = R.string.account_setup_failed_auth_required; 60855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler break; 60955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler case MessagingException.SECURITY_POLICIES_UNSUPPORTED: 61055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler id = R.string.account_setup_failed_security_policies_unsupported; 61155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler break; 6126d51b7eb630d3b2632b44699e14730eb7b995f78Marc Blank case MessagingException.PROTOCOL_VERSION_UNSUPPORTED: 6136d51b7eb630d3b2632b44699e14730eb7b995f78Marc Blank id = R.string.account_setup_failed_protocol_unsupported; 6146d51b7eb630d3b2632b44699e14730eb7b995f78Marc Blank break; 61555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler case MessagingException.GENERAL_SECURITY: 61655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler id = R.string.account_setup_failed_security; 61755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler break; 61855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler default: 61955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler id = (message == null) 62055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler ? R.string.account_setup_failed_dlg_server_message 62155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler : R.string.account_setup_failed_dlg_server_message_fmt; 62255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler break; 62355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 6242731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler reportProgress(progressState, id, message, hostAuth); 62555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 62655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 62755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 62855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 62955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 63055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * Simple dialog that shows progress as we work through the settings checks. 63155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * This is stateless except for its UI (e.g. current strings) and can be torn down or 63255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * recreated at any time without affecting the account checking progress. 63355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 63455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public static class CheckingDialog extends DialogFragment { 63555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public final static String TAG = "CheckProgressDialog"; 63655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 63755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // Extras for saved instance state 63855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private final String EXTRA_PROGRESS_STRING = "CheckProgressDialog.Progress"; 63955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 64055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // UI 64155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private String mProgressString; 64255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 64355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 64455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * Create a dialog that reports progress 64555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * @param progress initial progress indication 64655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 64755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public static CheckingDialog newInstance(AccountCheckSettingsFragment parentFragment, 64855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler int progress) { 64955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler CheckingDialog f = new CheckingDialog(); 65055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler f.setTargetFragment(parentFragment, progress); 65155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler return f; 65255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 65355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 65455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 65555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * Update the progress of an existing dialog 65655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * @param progress latest progress to be displayed 65755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 65855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public void updateProgress(int progress) { 65955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler mProgressString = getProgressString(progress); 66055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler AlertDialog dialog = (AlertDialog) getDialog(); 66155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler dialog.setMessage(mProgressString); 66255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 66355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 66455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler @Override 66555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public Dialog onCreateDialog(Bundle savedInstanceState) { 66655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler Context context = getActivity(); 66755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (savedInstanceState != null) { 66855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler mProgressString = savedInstanceState.getString(EXTRA_PROGRESS_STRING); 66955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 67055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler if (mProgressString == null) { 67155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler mProgressString = getProgressString(getTargetRequestCode()); 67255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 67355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler final AccountCheckSettingsFragment target = 67455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler (AccountCheckSettingsFragment) getTargetFragment(); 67555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 67655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler ProgressDialog dialog = new ProgressDialog(context); 67755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler dialog.setIndeterminate(true); 67855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler dialog.setMessage(mProgressString); 67955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler dialog.setButton(DialogInterface.BUTTON_NEGATIVE, 68055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler context.getString(R.string.cancel_action), 68155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler new DialogInterface.OnClickListener() { 68255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public void onClick(DialogInterface dialog, int which) { 68355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler dismiss(); 68455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler target.onCheckingDialogCancel(); 68555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 68655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler }); 68755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler return dialog; 68855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 68955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 690992b7e7ed34334a622d8ccb1d2f692a83a15360eAndy Stadler /** 691992b7e7ed34334a622d8ccb1d2f692a83a15360eAndy Stadler * Listen for cancellation, which can happen from places other than the 692992b7e7ed34334a622d8ccb1d2f692a83a15360eAndy Stadler * negative button (e.g. touching outside the dialog), and stop the checker 693992b7e7ed34334a622d8ccb1d2f692a83a15360eAndy Stadler */ 694992b7e7ed34334a622d8ccb1d2f692a83a15360eAndy Stadler @Override 695992b7e7ed34334a622d8ccb1d2f692a83a15360eAndy Stadler public void onCancel(DialogInterface dialog) { 696992b7e7ed34334a622d8ccb1d2f692a83a15360eAndy Stadler AccountCheckSettingsFragment target = 697992b7e7ed34334a622d8ccb1d2f692a83a15360eAndy Stadler (AccountCheckSettingsFragment) getTargetFragment(); 698992b7e7ed34334a622d8ccb1d2f692a83a15360eAndy Stadler target.onCheckingDialogCancel(); 699992b7e7ed34334a622d8ccb1d2f692a83a15360eAndy Stadler super.onCancel(dialog); 700992b7e7ed34334a622d8ccb1d2f692a83a15360eAndy Stadler } 701992b7e7ed34334a622d8ccb1d2f692a83a15360eAndy Stadler 70255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler @Override 70355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public void onSaveInstanceState(Bundle outState) { 70455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler super.onSaveInstanceState(outState); 70555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler outState.putString(EXTRA_PROGRESS_STRING, mProgressString); 70655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 70755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 70855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 70955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * Convert progress to message 71055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 71155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private String getProgressString(int progress) { 71255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler int stringId = 0; 71355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler switch (progress) { 71455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler case STATE_CHECK_AUTODISCOVER: 71555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler stringId = R.string.account_setup_check_settings_retr_info_msg; 71655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler break; 71755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler case STATE_CHECK_INCOMING: 71855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler stringId = R.string.account_setup_check_settings_check_incoming_msg; 71955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler break; 72055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler case STATE_CHECK_OUTGOING: 72155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler stringId = R.string.account_setup_check_settings_check_outgoing_msg; 72255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler break; 72355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 72455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler return getActivity().getString(stringId); 72555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 72655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 72755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 72855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 72955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler * The standard error dialog. Calls back to onErrorDialogButton(). 73055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 73155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public static class ErrorDialog extends DialogFragment { 73255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public final static String TAG = "ErrorDialog"; 73355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 73455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // Bundle keys for arguments 73555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private final static String ARGS_MESSAGE_ID = "ErrorDialog.Message.Id"; 73655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private final static String ARGS_MESSAGE_ARGS = "ErrorDialog.Message.Args"; 73755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 73855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public static ErrorDialog newInstance(AccountCheckSettingsFragment target, 73955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler int messageId, String... messageArguments) { 74055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler ErrorDialog fragment = new ErrorDialog(); 74155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler Bundle arguments = new Bundle(); 74255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler arguments.putInt(ARGS_MESSAGE_ID, messageId); 74355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler arguments.putStringArray(ARGS_MESSAGE_ARGS, messageArguments); 74455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler fragment.setArguments(arguments); 74555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler fragment.setTargetFragment(target, 0); 74655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler return fragment; 74755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 74855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 74955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler @Override 75055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public Dialog onCreateDialog(Bundle savedInstanceState) { 75155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler final Context context = getActivity(); 75255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler final Bundle arguments = getArguments(); 75355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler final int messageId = arguments.getInt(ARGS_MESSAGE_ID); 75455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler final Object[] messageArguments = arguments.getStringArray(ARGS_MESSAGE_ARGS); 75555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler final AccountCheckSettingsFragment target = 75655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler (AccountCheckSettingsFragment) getTargetFragment(); 75755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 75855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler return new AlertDialog.Builder(context) 75955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler .setIcon(android.R.drawable.ic_dialog_alert) 76055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler .setTitle(context.getString(R.string.account_setup_failed_dlg_title)) 76155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler .setMessage(context.getString(messageId, messageArguments)) 76255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler .setCancelable(true) 76355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler .setPositiveButton( 76455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler context.getString(R.string.account_setup_failed_dlg_edit_details_action), 76555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler new DialogInterface.OnClickListener() { 76655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public void onClick(DialogInterface dialog, int which) { 76755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler dismiss(); 76855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler target.onErrorDialogEditButton(); 76955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 77055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler }) 77155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler .create(); 77255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 77355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 77455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 77555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 77655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler /** 7772731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * The "security required" error dialog. This is presented whenever an exchange account 7782731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * reports that it will require security policy control, and provide the user with the 7792731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * opportunity to accept or deny this. 7802731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * 7812731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * If the user clicks OK, calls onSecurityRequiredDialogResultOk(true) which reports back 7822731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * to the target as if the settings check was "ok". If the user clicks "cancel", calls 7832731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * onSecurityRequiredDialogResultOk(false) which simply closes the checker (this is the 7842731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler * same as any other failed check.) 78555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler */ 78655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public static class SecurityRequiredDialog extends DialogFragment { 78755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public final static String TAG = "SecurityRequiredDialog"; 78855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 78955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler // Bundle keys for arguments 79055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler private final static String ARGS_HOST_NAME = "SecurityRequiredDialog.HostName"; 79155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 79255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public static SecurityRequiredDialog newInstance(AccountCheckSettingsFragment target, 79355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler String hostName) { 79455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler SecurityRequiredDialog fragment = new SecurityRequiredDialog(); 79555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler Bundle arguments = new Bundle(); 79655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler arguments.putString(ARGS_HOST_NAME, hostName); 79755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler fragment.setArguments(arguments); 79855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler fragment.setTargetFragment(target, 0); 79955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler return fragment; 80055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 80155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 80255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler @Override 80355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public Dialog onCreateDialog(Bundle savedInstanceState) { 80455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler final Context context = getActivity(); 80555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler final Bundle arguments = getArguments(); 80655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler final String hostName = arguments.getString(ARGS_HOST_NAME); 80755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler final AccountCheckSettingsFragment target = 80855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler (AccountCheckSettingsFragment) getTargetFragment(); 80955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 81055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler return new AlertDialog.Builder(context) 81155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler .setIcon(android.R.drawable.ic_dialog_alert) 81255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler .setTitle(context.getString(R.string.account_setup_security_required_title)) 81355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler .setMessage(context.getString( 81455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler R.string.account_setup_security_policies_required_fmt, hostName)) 81555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler .setCancelable(true) 81655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler .setPositiveButton( 81755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler context.getString(R.string.okay_action), 81855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler new DialogInterface.OnClickListener() { 81955110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public void onClick(DialogInterface dialog, int which) { 82055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler dismiss(); 8212731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler target.onSecurityRequiredDialogResultOk(true); 82255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 82355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler }) 82455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler .setNegativeButton( 82555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler context.getString(R.string.cancel_action), 82655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler new DialogInterface.OnClickListener() { 82755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler public void onClick(DialogInterface dialog, int which) { 82855110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler dismiss(); 8292731aef45c6f2f9792ae698ebf7d65ca6338a02cAndrew Stadler target.onSecurityRequiredDialogResultOk(false); 83055110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 83155110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler }) 83255110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler .create(); 83355110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 83455110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 83555110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler } 83655110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler 83755110ca1ad8ce48a5429f9f351d013691c10b806Andrew Stadler} 838