org.openremote.android.console.AppSettingsActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.openremote.android.console.AppSettingsActivity.java

Source

/* OpenRemote, the Home of the Digital Home.
* Copyright 2008-2010, OpenRemote Inc.
*
* See the contributors.txt file in the distribution for a
* full listing of individual contributors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.openremote.android.console;

import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.openremote.android.console.model.AppSettingsModel;
import org.openremote.android.console.model.ControllerException;
import org.openremote.android.console.model.ViewHelper;
import org.openremote.android.console.net.IPAutoDiscoveryServer;
import org.openremote.android.console.net.ORConnection;
import org.openremote.android.console.net.ORConnectionDelegate;
import org.openremote.android.console.net.ORHttpMethod;
import org.openremote.android.console.ssl.ORPKCS10CertificationRequest;
import org.openremote.android.console.ssl.ORKeyPair;
import org.openremote.android.console.ssl.ORKeyStore;
import org.openremote.android.console.util.AsyncGroupLoader;
import org.openremote.android.console.util.FileUtil;
import org.openremote.android.console.util.StringUtil;
import org.openremote.android.console.view.PanelSelectSpinnerView;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import android.widget.CompoundButton.OnCheckedChangeListener;

/**
 * Application global settings view.
 * It is for configuring controller server, panel identity and security.
 * It also can delete image caches.
 * 
 * @author Tomsky Wang
 * @author Dan Cong
 *
 */

public class AppSettingsActivity extends GenericActivity implements ORConnectionDelegate {

    /** The app settings view contains auto discovery, auto servers, custom servers,
     * select panel identity, clear image cache and security configuration. 
    */
    private LinearLayout appSettingsView;

    /** The custom list view contains custom server list. */
    private ListView customListView;
    private int currentCustomServerIndex = -1;

    /** The auto mode is to indicate if auto discovery servers. */
    private boolean autoMode;
    public static String currentServer = "";

    /** The view for selecting panel identity. */
    private PanelSelectSpinnerView panelSelectSpinnerView;

    /** The progress layout display auto discovery progress. */
    private LinearLayout progressLayout;

    private ProgressDialog loadingPanelProgress;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setTitle(R.string.settings);

        this.autoMode = AppSettingsModel.isAutoMode(AppSettingsActivity.this);

        // The main layout contains all application configuration items.
        LinearLayout mainLayout = new LinearLayout(this);
        mainLayout
                .setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        mainLayout.setOrientation(LinearLayout.VERTICAL);
        mainLayout.setBackgroundColor(0);
        mainLayout.setTag(R.string.settings);

        loadingPanelProgress = new ProgressDialog(this);

        // The scroll view contains appSettingsView, and make the appSettingsView can be scrolled.
        ScrollView scroll = new ScrollView(this);
        scroll.setVerticalScrollBarEnabled(true);
        scroll.setLayoutParams(
                new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT, 1));
        appSettingsView = new LinearLayout(this);
        appSettingsView
                .setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        appSettingsView.setOrientation(LinearLayout.VERTICAL);

        appSettingsView.addView(createAutoLayout());
        appSettingsView.addView(createChooseControllerLabel());

        currentServer = "";
        if (autoMode) {
            appSettingsView.addView(constructAutoServersView());
        } else {
            appSettingsView.addView(constructCustomServersView());
        }
        appSettingsView.addView(createChoosePanelLabel());
        panelSelectSpinnerView = new PanelSelectSpinnerView(this);
        appSettingsView.addView(panelSelectSpinnerView);

        appSettingsView.addView(createCacheText());
        appSettingsView.addView(createClearImageCacheButton());
        appSettingsView.addView(createSSLLayout());
        scroll.addView(appSettingsView);

        mainLayout.addView(scroll);
        mainLayout.addView(createDoneAndCancelLayout());

        setContentView(mainLayout);
        initSSLState();
        addOnclickListenerOnDoneButton();
        addOnclickListenerOnCancelButton();
        progressLayout = (LinearLayout) findViewById(R.id.choose_controller_progress);

    }

    @Override
    protected void onResume() {
        super.onResume();

        if (getIntent().getBooleanExtra("SSL_CLIENT", false)) {
            Toast.makeText(this, "You don't have access yet", Toast.LENGTH_LONG).show();
            if (AppSettingsModel.isSSLEnabled(getApplicationContext())) {
                ViewHelper.showAlertViewWithTitle(this, "No Access",
                        "The administrator didn't approve you yet so you don't have access.");
            } else {
                ViewHelper.showAlertViewWithTitle(this, "No Access",
                        "You don't have access to this controller at the moment. Is ssl enabled?");
            }
        } else if (getIntent().getBooleanExtra("SSL_CLIENT_PROTOCOL", false)) {
            Toast.makeText(this, "You don't have access yet", Toast.LENGTH_LONG).show();
            if (AppSettingsModel.isSSLEnabled(getApplicationContext())) {
                ViewHelper.showAlertViewWithTitle(this, "No Access",
                        "There went something wrong setting up the SSL connection. Please try again.");
            }
        }
    }

    /**
     * Creates the image cache text view.
     * 
     * @return the text view
     */
    private TextView createCacheText() {
        TextView cacheText = new TextView(this);
        cacheText.setPadding(10, 5, 0, 5);
        cacheText.setText("Image Cache:");
        cacheText.setBackgroundColor(Color.DKGRAY);
        return cacheText;
    }

    /**
     * Creates the choose panel identity text.
     * 
     * @return the text view
     */
    private TextView createChoosePanelLabel() {
        TextView choosePanelInfo = new TextView(this);
        choosePanelInfo.setPadding(10, 5, 0, 5);
        choosePanelInfo.setText("Choose Panel Identity:");
        choosePanelInfo.setBackgroundColor(Color.DKGRAY);
        return choosePanelInfo;
    }

    /**
     * Creates the choose controller bar, which contains "Choose controller:" text and 
     * a progress bar(used in auto discovery servers).
     * 
     * @return the linear layout
     */
    private LinearLayout createChooseControllerLabel() {
        LayoutInflater inflater = (AppSettingsActivity.this).getLayoutInflater();
        LinearLayout chooseController = (LinearLayout) inflater.inflate(R.layout.choose_controller_bar, null);
        return chooseController;
    }

    /**
     * Creates the done and cancel layout that is inflated from xml.
     * 
     * @return the linear layout
     */
    private LinearLayout createDoneAndCancelLayout() {
        LayoutInflater inflater = (AppSettingsActivity.this).getLayoutInflater();
        LinearLayout saveAndCancelLayout = (LinearLayout) inflater.inflate(R.layout.bottom_button_bar, null);
        return saveAndCancelLayout;
    }

    /**
     * Creates the ssl layout.
     * It contains ssl switch and ssl port.
     * 
     * @return the linear layout
     */
    private LinearLayout createSSLLayout() {
        LayoutInflater inflater = (AppSettingsActivity.this).getLayoutInflater();
        LinearLayout sslLayout = (LinearLayout) inflater.inflate(R.layout.ssl_field_view, null);

        return sslLayout;
    }

    /**
     * Initializes the SSL related UI widget properties and event handlers to deal with user
     * interactions.
     */
    private void initSSLState() {
        // Get UI Widget references...

        final ToggleButton sslToggleButton = (ToggleButton) findViewById(R.id.ssl_toggle);
        final EditText sslPortEditField = (EditText) findViewById(R.id.ssl_port);

        final TextView pin = (TextView) findViewById(R.id.ssl_clientcert_pin);

        // Configure UI to current settings state...

        boolean sslEnabled = AppSettingsModel.isSSLEnabled(this);

        sslToggleButton.setChecked(sslEnabled);
        sslPortEditField.setText("" + AppSettingsModel.getSSLPort(this));

        // If SSL is off, disable the port edit field by default...

        if (!sslEnabled) {
            sslPortEditField.setEnabled(false);
            sslPortEditField.setFocusable(false);
            sslPortEditField.setFocusableInTouchMode(false);
        }

        // Manage state changes to SSL toggle...

        sslToggleButton.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView, boolean isEnabled) {

                // If SSL is being disabled, and the user had soft keyboard open, close it...

                if (!isEnabled) {
                    InputMethodManager input = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                    input.hideSoftInputFromWindow(sslPortEditField.getWindowToken(), 0);
                }

                // Set SSL state in config model accordingly...

                AppSettingsModel.enableSSL(AppSettingsActivity.this, isEnabled);

                // Enable/Disable SSL Port text field according to SSL toggle on/off state...

                sslPortEditField.setEnabled(isEnabled);
                sslPortEditField.setFocusable(isEnabled);
                sslPortEditField.setFocusableInTouchMode(isEnabled);
            }
        });

        pin.setText("...");

        final Handler pinHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                pin.setText(msg.getData().getString("pin"));
            }
        };

        new Thread() {
            public void run() {
                String pin = ORKeyPair.getInstance().getPIN(getApplicationContext());

                Bundle bundle = new Bundle();
                bundle.putString("pin", pin);

                Message msg = pinHandler.obtainMessage();
                msg.setData(bundle);

                msg.sendToTarget();
            }
        }.start();

        sslPortEditField.setOnKeyListener(new OnKeyListener() {
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                //TODO not very user friendly
                if (keyCode == KeyEvent.KEYCODE_ENTER) {
                    String sslPortStr = ((EditText) v).getText().toString();

                    try {
                        int sslPort = Integer.parseInt(sslPortStr.trim());
                        AppSettingsModel.setSSLPort(AppSettingsActivity.this, sslPort);
                    }

                    catch (NumberFormatException ex) {
                        Toast toast = Toast.makeText(getApplicationContext(), "SSL port format is not correct.", 1);
                        toast.show();

                        return false;
                    }

                    catch (IllegalArgumentException e) {
                        Toast toast = Toast.makeText(getApplicationContext(), e.getMessage(), 2);
                        toast.show();

                        sslPortEditField.setText("" + AppSettingsModel.getSSLPort(AppSettingsActivity.this));

                        return false;
                    }
                }

                return false;
            }

        });

    }

    /**
     * Adds the onclick listener on done button.
     * 
     * If success, start Main activity and reload the application.
     */
    private void addOnclickListenerOnDoneButton() {
        Button doneButton = (Button) findViewById(R.id.setting_done);
        doneButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                if ("".equals(currentServer)) {
                    ViewHelper.showAlertViewWithTitle(AppSettingsActivity.this, "Warning",
                            "No controller. Please configure Controller URL manually.");
                    return;
                }
                String selectedPanel = (String) panelSelectSpinnerView.getSelectedItem();
                if (!TextUtils.isEmpty(selectedPanel)
                        && !selectedPanel.equals(PanelSelectSpinnerView.CHOOSE_PANEL)) {
                    AppSettingsModel.setCurrentPanelIdentity(AppSettingsActivity.this, selectedPanel);
                } else {
                    ViewHelper.showAlertViewWithTitle(AppSettingsActivity.this, "Warning",
                            "No Panel. Please configure Panel Identity manually.");
                    return;
                }
                if (AppSettingsModel.isSSLEnabled(getApplicationContext())
                        && AppSettingsModel.getSSLPort(getApplicationContext()) == 8443) {
                    retrieveCertificate();
                    return;
                }

                startMain();

            }
        });
    }

    /**
     * Finish the settings activity.
     */
    private void addOnclickListenerOnCancelButton() {
        Button cancelButton = (Button) findViewById(R.id.setting_cancel);
        cancelButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                finish();
            }
        });
    }

    /**
     * Creates the clear image cache button, add listener for clear image cache.
     * @return the relative layout
     */
    private RelativeLayout createClearImageCacheButton() {
        RelativeLayout clearImageView = new RelativeLayout(this);
        clearImageView.setLayoutParams(
                new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));

        Button clearImgCacheBtn = new Button(this);
        clearImgCacheBtn.setText("Clear Image Cache");
        RelativeLayout.LayoutParams clearButtonLayout = new RelativeLayout.LayoutParams(150,
                LayoutParams.WRAP_CONTENT);
        clearButtonLayout.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        clearImgCacheBtn.setLayoutParams(clearButtonLayout);
        clearImgCacheBtn.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                ViewHelper.showAlertViewWithTitleYesOrNo(AppSettingsActivity.this, "",
                        "Are you sure you want to clear image cache?", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                FileUtil.clearImagesInCache(AppSettingsActivity.this);
                            }
                        });
            }
        });

        clearImageView.addView(clearImgCacheBtn);
        return clearImageView;
    }

    /**
     * Creates the auto layout.
     * It contains toggle button to switch auto state, two text view to indicate auto messages.
     * 
     * @return the relative layout
     */
    private RelativeLayout createAutoLayout() {
        RelativeLayout autoLayout = new RelativeLayout(this);
        autoLayout.setPadding(10, 5, 10, 10);
        autoLayout.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, 80));
        TextView autoText = new TextView(this);
        RelativeLayout.LayoutParams autoTextLayout = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT);
        autoTextLayout.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
        autoTextLayout.addRule(RelativeLayout.CENTER_VERTICAL);
        autoText.setLayoutParams(autoTextLayout);
        autoText.setText("Auto Discovery");

        ToggleButton autoButton = new ToggleButton(this);
        autoButton.setWidth(150);
        RelativeLayout.LayoutParams autoButtonLayout = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT);
        autoButtonLayout.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        autoButtonLayout.addRule(RelativeLayout.CENTER_VERTICAL);
        autoButton.setLayoutParams(autoButtonLayout);
        autoButton.setChecked(autoMode);
        autoButton.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                appSettingsView.removeViewAt(2);
                currentServer = "";
                if (isChecked) {
                    IPAutoDiscoveryServer.isInterrupted = false;
                    appSettingsView.addView(constructAutoServersView(), 2);
                } else {
                    IPAutoDiscoveryServer.isInterrupted = true;
                    appSettingsView.addView(constructCustomServersView(), 2);
                }
                AppSettingsModel.setAutoMode(AppSettingsActivity.this, isChecked);
            }
        });

        TextView infoText = new TextView(this);
        RelativeLayout.LayoutParams infoTextLayout = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT);
        infoTextLayout.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        infoTextLayout.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
        infoText.setLayoutParams(infoTextLayout);
        infoText.setTextSize(10);
        infoText.setText("Turn off auto-discovery to input controller url manually.");

        autoLayout.addView(autoText);
        autoLayout.addView(autoButton);
        autoLayout.addView(infoText);
        return autoLayout;
    }

    /**
     * Inits the custom servers from customServers.xml.
     * 
     * @param customServers the custom servers
     */
    private void initCustomServersFromFile(ArrayList<String> customServers) {
        String storedUrls = AppSettingsModel.getCustomServers(this);
        if (!TextUtils.isEmpty(storedUrls)) {
            String[] data = storedUrls.split(",");
            int dataNum = data.length;
            for (int i = 0; i < dataNum; i++) {
                if (!data[i].startsWith("+")) {
                    customServers.add(data[i]);
                } else {
                    currentCustomServerIndex = i;
                    customServers.add(data[i].substring(1));
                    AppSettingsModel.setCurrentServer(AppSettingsActivity.this, data[i].substring(1));
                }
            }
        }
    }

    /**
     * It contains a list view to display custom servers, 
     * "Add" button to add custom server, "Delete" button to delete custom server.
     * The custom servers would be saved in customServers.xml. If click a list item, it would be saved as current server.
     * 
     * @return the linear layout
     */
    private LinearLayout constructCustomServersView() {
        LinearLayout custumeView = new LinearLayout(this);
        custumeView.setOrientation(LinearLayout.VERTICAL);
        custumeView.setPadding(20, 5, 5, 0);
        custumeView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));

        ArrayList<String> customServers = new ArrayList<String>();
        initCustomServersFromFile(customServers);

        RelativeLayout buttonsView = new RelativeLayout(this);
        buttonsView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, 80));
        Button addServer = new Button(this);
        addServer.setWidth(80);
        RelativeLayout.LayoutParams addServerLayout = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT);
        addServerLayout.addRule(RelativeLayout.CENTER_HORIZONTAL);
        addServer.setLayoutParams(addServerLayout);
        addServer.setText("Add");
        addServer.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setClass(AppSettingsActivity.this, AddServerActivity.class);
                startActivityForResult(intent, Constants.REQUEST_CODE);
            }

        });
        Button deleteServer = new Button(this);
        deleteServer.setWidth(80);
        RelativeLayout.LayoutParams deleteServerLayout = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT);
        deleteServerLayout.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        deleteServer.setLayoutParams(deleteServerLayout);
        deleteServer.setText("Delete");
        deleteServer.setOnClickListener(new OnClickListener() {
            @SuppressWarnings("unchecked")
            public void onClick(View v) {
                int checkedPosition = customListView.getCheckedItemPosition();
                if (!(checkedPosition == ListView.INVALID_POSITION)) {
                    customListView.setItemChecked(checkedPosition, false);
                    ((ArrayAdapter<String>) customListView.getAdapter())
                            .remove(customListView.getItemAtPosition(checkedPosition).toString());
                    currentServer = "";
                    AppSettingsModel.setCurrentServer(AppSettingsActivity.this, currentServer);
                    writeCustomServerToFile();
                }
            }
        });

        buttonsView.addView(addServer);
        buttonsView.addView(deleteServer);

        customListView = new ListView(this);
        customListView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, 200));
        customListView.setCacheColorHint(0);
        final ArrayAdapter<String> serverListAdapter = new ArrayAdapter<String>(appSettingsView.getContext(),
                R.layout.server_list_item, customServers);
        customListView.setAdapter(serverListAdapter);
        customListView.setItemsCanFocus(true);
        customListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        if (currentCustomServerIndex != -1) {
            customListView.setItemChecked(currentCustomServerIndex, true);
            currentServer = (String) customListView.getItemAtPosition(currentCustomServerIndex);
        }
        customListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                currentServer = (String) parent.getItemAtPosition(position);
                AppSettingsModel.setCurrentServer(AppSettingsActivity.this, currentServer);
                writeCustomServerToFile();
                requestPanelList();
                checkAuthentication();
                requestAccess();
            }

        });

        custumeView.addView(customListView);
        custumeView.addView(buttonsView);
        requestPanelList();
        checkAuthentication();
        requestAccess();
        return custumeView;
    }

    /**
     * Received custom server from AddServerActivity, add prefix "http://" before it.
     * Add the result in custom server list and set it as current server.
     * 
     * @see android.app.Activity#onActivityResult(int, int, android.content.Intent)
     */
    @SuppressWarnings("unchecked")
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (data != null) {
            String result = data.getDataString();
            if (Constants.REQUEST_CODE == requestCode && !TextUtils.isEmpty(result)) {
                if (Constants.RESULT_CONTROLLER_URL == resultCode) {
                    currentServer = "http://" + result;
                    ArrayAdapter<String> customeListAdapter = (ArrayAdapter<String>) customListView.getAdapter();
                    customeListAdapter.add(currentServer);
                    customListView.setItemChecked(customeListAdapter.getCount() - 1, true);
                    AppSettingsModel.setCurrentServer(AppSettingsActivity.this, currentServer);
                    writeCustomServerToFile();
                    requestPanelList();
                    checkAuthentication();
                    requestAccess();
                }
            }
        }
    }

    /**
     * Auto discovery servers and add them in a list view.
     * Click a list item and make it as current server.
     * 
     * @return the list view
     */
    private ListView constructAutoServersView() {
        final ListView lv = new ListView(this);
        lv.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, 200));
        lv.setPadding(20, 5, 5, 10);
        lv.setBackgroundColor(0);
        lv.setCacheColorHint(0);
        lv.setItemsCanFocus(true);
        lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        final ArrayAdapter<String> serverListAdapter = new ArrayAdapter<String>(appSettingsView.getContext(),
                R.layout.server_list_item, new ArrayList<String>());
        lv.setAdapter(serverListAdapter);

        new IPAutoDiscoveryServer() {
            @Override
            protected void onProgressUpdate(Void... values) {
                if (progressLayout != null) {
                    progressLayout.setVisibility(View.VISIBLE);
                }
            }

            @Override
            protected void onPostExecute(List<String> result) {
                int length = result.size();
                for (int i = 0; i < length; i++) {
                    serverListAdapter.add(result.get(i));
                }
                if (length > 0) {
                    lv.setItemChecked(0, true);
                    currentServer = serverListAdapter.getItem(0);
                    AppSettingsModel.setCurrentServer(AppSettingsActivity.this, currentServer);
                }
                if (progressLayout != null) {
                    progressLayout.setVisibility(View.INVISIBLE);
                }
                requestPanelList();
                checkAuthentication();
                requestAccess();
            }
        }.execute((Void) null);

        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                currentServer = (String) parent.getItemAtPosition(position);
                AppSettingsModel.setCurrentServer(AppSettingsActivity.this, currentServer);
                requestPanelList();
                checkAuthentication();
                requestAccess();
            }
        });

        return lv;
    }

    /**
     *  Construct custom servers to a string which split by "," and write it to customServers.xml.
     */
    private void writeCustomServerToFile() {
        int customServerCount = customListView.getCount();
        if (customServerCount > 0) {
            int checkedPosition = customListView.getCheckedItemPosition();
            String customServerUrls = "";
            for (int i = 0; i < customServerCount; i++) {
                if (i != checkedPosition) {
                    customServerUrls = customServerUrls + customListView.getItemAtPosition(i).toString();
                } else {
                    customServerUrls = customServerUrls + StringUtil
                            .markControllerServerURLSelected(customListView.getItemAtPosition(i).toString());
                }
                if (i != customServerCount - 1) {
                    customServerUrls = customServerUrls + ",";
                }
            }
            if (!TextUtils.isEmpty(customServerUrls)) {
                AppSettingsModel.setCustomServers(customListView.getContext(), customServerUrls);
            }
        }
    }

    /**
     * Submits a Certification Request to the controller
     */
    private void requestAccess() {
        final String hostname = AppSettingsActivity.currentServer;

        if (!TextUtils.isEmpty(hostname)) {
            final ProgressDialog progress = new ProgressDialog(this);
            final Handler handler = new Handler() {
                public void handleMessage(Message msg) {
                    if (progress.isShowing()) {
                        progress.dismiss();
                    }
                }
            };

            if (isActivityResumed()) {
                progress.show();
            }

            new Thread() {
                public void run() {
                    handler.sendEmptyMessage(ORPKCS10CertificationRequest.getInstance(getApplicationContext())
                            .submitCertificationRequest(hostname));
                }
            }.start();
        }
    }

    /**
     * Check if Client Authentication is enabled on the server if so 
     * enable to SSL button in the GUI
     */
    private void checkAuthentication() {
        final Handler checkHandler = new Handler() {
            public void handleMessage(Message msg) {
                final ToggleButton sslToggleButton = (ToggleButton) findViewById(R.id.ssl_toggle);
                if (msg.what == 1) {
                    AppSettingsModel.enableSSL(AppSettingsActivity.this, true);
                    sslToggleButton.setChecked(true);
                    // show pin
                    findViewById(R.id.ssl_pin_row).setVisibility(View.VISIBLE);
                } else {
                    AppSettingsModel.enableSSL(AppSettingsActivity.this, false);
                    sslToggleButton.setChecked(false);
                    // hide pin
                    findViewById(R.id.ssl_pin_row).setVisibility(View.GONE);
                }
            }
        };
        new Thread() {
            public void run() {
                if (this.checkAuthentication()) {
                    checkHandler.sendEmptyMessage(1);
                } else {
                    checkHandler.sendEmptyMessage(0);
                }
            }

            private boolean checkAuthentication() {
                boolean returnValue = false;

                if (!TextUtils.isEmpty(currentServer)) {
                    try {
                        HttpRequestBase request = null;
                        HttpResponse response = null;
                        HttpParams params = new BasicHttpParams();

                        // set time-out at 3 seconds
                        HttpConnectionParams.setConnectionTimeout(params, 3 * 1000);
                        HttpConnectionParams.setSoTimeout(params, 3 * 1000);

                        HttpClient client = new DefaultHttpClient(params);
                        request = new HttpGet(new URL(currentServer + "/rest/authentication/check").toURI());

                        response = client.execute(request);

                        returnValue = (response.getStatusLine().getStatusCode() == 200) ? true : false;
                    } catch (IOException e) {
                        returnValue = false;
                        Log.e(Constants.LOG_CATEGORY + "AUTH_CHECK", "Can't check authentication: ", e);
                    } catch (IllegalArgumentException e) {
                        returnValue = false;
                        Log.e(Constants.LOG_CATEGORY + "AUTH_CHECK", "Can't check authentication: ", e);
                    } catch (URISyntaxException e) {
                        returnValue = false;
                        Log.e(Constants.LOG_CATEGORY + "AUTH_CHECK", "Invalid URI: ", e);
                    }
                }
                return returnValue;
            }
        }.start();
    }

    private void retrieveCertificate() {
        final Button doneButton = (Button) findViewById(R.id.setting_done);
        doneButton.setEnabled(false);
        final ProgressDialog dialog = ProgressDialog.show(this, "Fetching certificate",
                "Busy fetching certificate");

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                doneButton.setEnabled(true);
                dialog.cancel();
                switch (msg.what) {
                case -1:
                    ViewHelper.showAlertViewWithTitle(AppSettingsActivity.this, "Connection error",
                            "Can't connect to the server.");
                    break;
                case 0:
                    startMain();
                    break;
                case 1:
                    ViewHelper.showAlertViewWithTitle(AppSettingsActivity.this, "No access",
                            "You don't have access.\nPlease ask the administrator for permission.");
                    break;
                case 2:
                    ViewHelper.showAlertViewWithTitle(AppSettingsActivity.this, "No access",
                            "You don't have access.\nYour certificate is invalid.");
                    break;
                case 3:
                    ViewHelper.showAlertViewWithTitle(AppSettingsActivity.this, "No access",
                            "You don't have access.\nYour certificate expired.");
                    break;
                }
            }
        };

        ORKeyStore.getInstance(getApplicationContext())
                .checkCertificateChain(AppSettingsModel.getCurrentServer(getApplicationContext()), handler);
    }

    /**
     * Start {@link Main} activity
     */
    private void startMain() {
        Intent intent = new Intent();
        intent.setClass(AppSettingsActivity.this, Main.class);
        startActivity(intent);
        finish();
    }

    /**
     * Request panel identity list from controller.
     */
    private void requestPanelList() {
        setEmptySpinnerContent();
        if (!TextUtils.isEmpty(AppSettingsActivity.currentServer) && isActivityResumed()) {
            loadingPanelProgress.show();
            new ORConnection(this.getApplicationContext(), ORHttpMethod.GET, true,
                    AppSettingsActivity.currentServer + "/rest/panels", this);
        }
    }

    @Override
    public void urlConnectionDidFailWithException(Exception e) {
        loadingPanelProgress.dismiss();
    }

    @Override
    public void urlConnectionDidReceiveData(InputStream data) {
        loadingPanelProgress.dismiss();
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document dom = builder.parse(data);
            Element root = dom.getDocumentElement();

            NodeList nodeList = root.getElementsByTagName("panel");
            int nodeNums = nodeList.getLength();
            if (nodeNums == 1) {
                panelSelectSpinnerView
                        .setOnlyPanel(nodeList.item(0).getAttributes().getNamedItem("name").getNodeValue());
            }
        } catch (IOException e) {
            Log.e(Constants.LOG_CATEGORY + "PANEL LIST", "The data is from ORConnection is bad", e);
            return;
        } catch (ParserConfigurationException e) {
            Log.e(Constants.LOG_CATEGORY + "PANEL LIST", "Cant build new Document builder", e);
            return;
        } catch (SAXException e) {
            Log.e(Constants.LOG_CATEGORY + "PANEL LIST", "Parse data error", e);
            return;
        }

    }

    @Override
    public void urlConnectionDidReceiveResponse(HttpResponse httpResponse) {
        int statusCode = httpResponse.getStatusLine().getStatusCode();
        if (statusCode != Constants.HTTP_SUCCESS) {
            loadingPanelProgress.dismiss();
            if (statusCode == ControllerException.UNAUTHORIZED) {
                LoginDialog loginDialog = new LoginDialog(this);
                loginDialog.setOnClickListener(loginDialog.new OnloginClickListener() {
                    @Override
                    public void onClick(View v) {
                        super.onClick(v);
                        requestPanelList();
                        checkAuthentication();
                        requestAccess();
                    }

                });
            } else {
                // The following code customizes the dialog, because the finish method should do after dialog show and click ok.
                AlertDialog alertDialog = new AlertDialog.Builder(this).create();
                alertDialog.setTitle("Panel List Not Found");
                alertDialog.setMessage(ControllerException.exceptionMessageOfCode(statusCode));
                alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        return;
                    }
                });
                alertDialog.show();
            }
        }

    }

    private void setEmptySpinnerContent() {
        if (panelSelectSpinnerView != null) {
            panelSelectSpinnerView.setOnlyPanel(PanelSelectSpinnerView.CHOOSE_PANEL);
        }
    }
}