org.opendatakit.services.preferences.fragments.ServerSettingsFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.opendatakit.services.preferences.fragments.ServerSettingsFragment.java

Source

/*
 * Copyright (C) 2016 University of Washington
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package org.opendatakit.services.preferences.fragments;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.AlertDialog;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Environment;
import android.preference.*;
import android.preference.Preference.OnPreferenceChangeListener;
import android.text.InputFilter;
import android.text.Spanned;
import android.widget.Toast;

import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.io.FileUtils;
import org.opendatakit.consts.IntentConsts;
import org.opendatakit.services.preferences.activities.IOdkAppPropertiesActivity;
import org.opendatakit.properties.CommonToolProperties;
import org.opendatakit.properties.PropertiesSingleton;
import org.opendatakit.services.preferences.PasswordPreferenceScreen;
import org.opendatakit.services.R;
import org.opendatakit.services.utilities.SettingsUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class ServerSettingsFragment extends PreferenceFragment implements OnPreferenceChangeListener {

    private static final String t = "ServerSettingsFragment";

    private EditTextPreference mServerUrlPreference;
    private ListPreference mSignOnCredentialPreference;
    private EditTextPreference mUsernamePreference;
    private ListPreference mSelectedGoogleAccountPreference;
    private EditTextPreference mOfficeId;
    private SettingsUtils settingsUtils;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        PropertiesSingleton props = ((IOdkAppPropertiesActivity) this.getActivity()).getProps();

        addPreferencesFromResource(R.xml.server_preferences);

        // not super safe, but we're just putting in this mode to help
        // administrate
        // would require code to access it
        boolean adminMode;
        adminMode = (this.getArguments() == null) ? false
                : (this.getArguments().containsKey(IntentConsts.INTENT_KEY_SETTINGS_IN_ADMIN_MODE)
                        ? this.getArguments().getBoolean(IntentConsts.INTENT_KEY_SETTINGS_IN_ADMIN_MODE)
                        : false);

        String adminPwd = props.getProperty(CommonToolProperties.KEY_ADMIN_PW);
        boolean adminConfigured = (adminPwd != null && adminPwd.length() != 0);

        boolean serverAvailable = !adminConfigured
                || props.getBooleanProperty(CommonToolProperties.KEY_CHANGE_SYNC_SERVER);

        PreferenceCategory serverCategory = (PreferenceCategory) findPreference(
                CommonToolProperties.GROUPING_SERVER_CATEGORY);

        // Initialize the Server URL Text Preference
        mServerUrlPreference = (EditTextPreference) findPreference(CommonToolProperties.KEY_SYNC_SERVER_URL);
        if (props.containsKey(CommonToolProperties.KEY_SYNC_SERVER_URL)) {
            String url = props.getProperty(CommonToolProperties.KEY_SYNC_SERVER_URL);
            mServerUrlPreference.setSummary(url);
            mServerUrlPreference.setText(url);
        }

        mServerUrlPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
            @Override
            public boolean onPreferenceChange(Preference preference, Object newValue) {
                String url = newValue.toString();

                // disallow any whitespace
                if (url.contains(" ") || !url.equals(url.trim())) {
                    Toast.makeText(getActivity().getApplicationContext(), R.string.url_error_whitespace,
                            Toast.LENGTH_SHORT).show();
                    return false;
                }

                // remove all trailing "/"s
                while (url.endsWith("/")) {
                    url = url.substring(0, url.length() - 1);
                }

                boolean isValid = false;
                try {
                    new URL(url);
                    isValid = true;
                } catch (MalformedURLException e) {
                    // ignore
                }

                if (isValid) {
                    preference.setSummary(newValue.toString());

                    PropertiesSingleton props = ((IOdkAppPropertiesActivity) ServerSettingsFragment.this
                            .getActivity()).getProps();
                    props.setProperty(CommonToolProperties.KEY_SYNC_SERVER_URL, newValue.toString());
                    props.setProperty(CommonToolProperties.KEY_ROLES_LIST, "");
                    props.setProperty(CommonToolProperties.KEY_USERS_LIST, "");
                    return true;
                } else {
                    Toast.makeText(getActivity().getApplicationContext(), R.string.url_error, Toast.LENGTH_SHORT)
                            .show();
                    return false;
                }
            }
        });
        mServerUrlPreference.setSummary(mServerUrlPreference.getText());
        mServerUrlPreference.getEditText().setFilters(new InputFilter[] { getReturnFilter() });

        mServerUrlPreference.setEnabled(serverAvailable || adminMode);

        boolean credentialAvailable = !adminConfigured
                || props.getBooleanProperty(CommonToolProperties.KEY_CHANGE_AUTHENTICATION_TYPE);
        mSignOnCredentialPreference = (ListPreference) findPreference(CommonToolProperties.KEY_AUTHENTICATION_TYPE);
        if (props.containsKey(CommonToolProperties.KEY_AUTHENTICATION_TYPE)) {
            String chosenFontSize = props.getProperty(CommonToolProperties.KEY_AUTHENTICATION_TYPE);
            CharSequence entryValues[] = mSignOnCredentialPreference.getEntryValues();
            for (int i = 0; i < entryValues.length; i++) {
                String entry = entryValues[i].toString();
                if (entry.equals(chosenFontSize)) {
                    mSignOnCredentialPreference.setValue(entry);
                    mSignOnCredentialPreference.setSummary(mSignOnCredentialPreference.getEntries()[i]);
                }
            }
        }

        mSignOnCredentialPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {

            @Override
            public boolean onPreferenceChange(Preference preference, Object newValue) {
                int index = ((ListPreference) preference).findIndexOfValue(newValue.toString());
                String entry = (String) ((ListPreference) preference).getEntries()[index];
                ((ListPreference) preference).setSummary(entry);

                PropertiesSingleton props = ((IOdkAppPropertiesActivity) ServerSettingsFragment.this.getActivity())
                        .getProps();
                props.setProperty(CommonToolProperties.KEY_AUTHENTICATION_TYPE, newValue.toString());
                props.setProperty(CommonToolProperties.KEY_ROLES_LIST, "");
                props.setProperty(CommonToolProperties.KEY_USERS_LIST, "");
                return true;
            }
        });

        mSignOnCredentialPreference.setEnabled(credentialAvailable || adminMode);

        //////////////////
        mUsernamePreference = (EditTextPreference) findPreference(CommonToolProperties.KEY_USERNAME);
        if (props.containsKey(CommonToolProperties.KEY_USERNAME)) {
            String user = props.getProperty(CommonToolProperties.KEY_USERNAME);
            mUsernamePreference.setSummary(user);
            mUsernamePreference.setText(user);
        }

        mUsernamePreference.setOnPreferenceChangeListener(this);

        mUsernamePreference.getEditText().setFilters(new InputFilter[] { getReturnFilter() });

        boolean usernamePasswordAvailable = !adminConfigured
                || props.getBooleanProperty(CommonToolProperties.KEY_CHANGE_USERNAME_PASSWORD);

        mUsernamePreference.setEnabled(usernamePasswordAvailable || adminMode);

        PasswordPreferenceScreen passwordScreen = (PasswordPreferenceScreen) this
                .findPreference(CommonToolProperties.GROUPING_PASSWORD_SCREEN);
        passwordScreen.setCallback(new PasswordPreferenceScreen.PasswordActionCallback() {
            @Override
            public void showPasswordDialog() {
                // DialogFragment.show() will take care of adding the fragment
                // in a transaction.  We also want to remove any currently showing
                // dialog, so make our own transaction and take care of that here.
                FragmentTransaction ft = getFragmentManager().beginTransaction();
                Fragment prev = getFragmentManager()
                        .findFragmentByTag(CommonToolProperties.GROUPING_PASSWORD_SCREEN);
                if (prev != null) {
                    ft.remove(prev);
                }

                // Create and show the dialog.
                PasswordDialogFragment newFragment = PasswordDialogFragment
                        .newPasswordDialog(CommonToolProperties.KEY_PASSWORD);
                newFragment.show(ft, CommonToolProperties.GROUPING_PASSWORD_SCREEN);
            }
        });

        passwordScreen.setEnabled((usernamePasswordAvailable || adminMode));

        mSelectedGoogleAccountPreference = (ListPreference) findPreference(CommonToolProperties.KEY_ACCOUNT);

        // get list of google accounts
        final Account[] accounts = AccountManager.get(getActivity().getApplicationContext())
                .getAccountsByType("com.google");
        ArrayList<String> accountEntries = new ArrayList<String>();
        ArrayList<String> accountValues = new ArrayList<String>();

        for (int i = 0; i < accounts.length; i++) {
            accountEntries.add(accounts[i].name);
            accountValues.add(accounts[i].name);
        }
        accountEntries.add(getString(R.string.no_account));
        accountValues.add("");

        mSelectedGoogleAccountPreference.setEntries(accountEntries.toArray(new String[accountEntries.size()]));
        mSelectedGoogleAccountPreference.setEntryValues(accountValues.toArray(new String[accountValues.size()]));
        mSelectedGoogleAccountPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {

            @Override
            public boolean onPreferenceChange(Preference preference, Object newValue) {
                int index = ((ListPreference) preference).findIndexOfValue(newValue.toString());
                String value = (String) ((ListPreference) preference).getEntryValues()[index];
                preference.setSummary(value);
                PropertiesSingleton props = ((IOdkAppPropertiesActivity) ServerSettingsFragment.this.getActivity())
                        .getProps();
                props.setProperty(CommonToolProperties.KEY_ACCOUNT, value);
                props.setProperty(CommonToolProperties.KEY_AUTH, "");
                props.setProperty(CommonToolProperties.KEY_ROLES_LIST, "");
                props.setProperty(CommonToolProperties.KEY_USERS_LIST, "");
                return true;
            }
        });

        String googleAccount = props.getProperty(CommonToolProperties.KEY_ACCOUNT);
        if (googleAccount == null) {
            googleAccount = "";
        }
        boolean found = false;
        for (int i = 0; i < accountValues.size(); ++i) {
            if (googleAccount.equals(accountValues.get(i))) {
                mSelectedGoogleAccountPreference.setValue(googleAccount);
                mSelectedGoogleAccountPreference.setSummary(accountEntries.get(i));
                found = true;
            }
        }
        if (!found) {
            // clear the property (prevents clarice@ from being identified)
            props.setProperty(CommonToolProperties.KEY_ACCOUNT, "");
            // set to "none"
            mSelectedGoogleAccountPreference.setValue(accountValues.get(accountValues.size() - 1));
            mSelectedGoogleAccountPreference.setSummary(accountEntries.get(accountEntries.size() - 1));
        }

        Boolean googleAccountAvailable = props.getBooleanProperty(CommonToolProperties.KEY_CHANGE_GOOGLE_ACCOUNT);
        mSelectedGoogleAccountPreference.setEnabled(googleAccountAvailable || adminMode);

        if (!adminMode && (!serverAvailable || !credentialAvailable || !usernamePasswordAvailable
                || !googleAccountAvailable)) {
            serverCategory.setTitle(R.string.server_restrictions_apply);
        }

        mOfficeId = (EditTextPreference) findPreference("common.officeID");
        this.settingsUtils = new SettingsUtils(getActivity().getApplicationContext());
        String officeId = settingsUtils.getOfficeIdFromFile();
        if (officeId != null && !officeId.equals("null")) {
            mOfficeId.setSummary(officeId);
            mOfficeId.setText(officeId);
        }

        mOfficeId.setOnPreferenceChangeListener(this);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        PropertiesSingleton props = ((IOdkAppPropertiesActivity) this.getActivity()).getProps();
        props.writeProperties();
    }

    @Override
    public void onPause() {
        PropertiesSingleton props = ((IOdkAppPropertiesActivity) this.getActivity()).getProps();
        props.writeProperties();
        super.onPause();
    }

    /**
     * Disallows whitespace from user entry
     *
     * @return
     */
    private InputFilter getWhitespaceFilter() {
        InputFilter whitespaceFilter = new InputFilter() {
            public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart,
                    int dend) {
                for (int i = start; i < end; i++) {
                    if (Character.isWhitespace(source.charAt(i))) {
                        return "";
                    }
                }
                return null;
            }
        };
        return whitespaceFilter;
    }

    /**
     * Disallows carriage returns from user entry
     *
     * @return
     */
    private InputFilter getReturnFilter() {
        InputFilter returnFilter = new InputFilter() {
            public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart,
                    int dend) {
                for (int i = start; i < end; i++) {
                    if (Character.getType((source.charAt(i))) == Character.CONTROL) {
                        return "";
                    }
                }
                return null;
            }
        };
        return returnFilter;
    }

    public void createOfficeIdConfirmChangeDialog(final Preference preference, final Object newValue) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setMessage(R.string.confirm_change_office_id);
        builder.setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                settingsUtils.deleteAllForms();
                settingsUtils.saveOfficeIdToFile(newValue.toString());
                preference.setSummary((CharSequence) newValue);
                mOfficeId.setText(newValue.toString());
                dialog.dismiss();
            }
        });
        builder.setCancelable(true);
        builder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });
        builder.create().show();
    }

    /**
     * Generic listener that sets the summary to the newly selected/entered value
     */
    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        PropertiesSingleton props = ((IOdkAppPropertiesActivity) this.getActivity()).getProps();
        if (props.containsKey(preference.getKey())) {
            preference.setSummary((CharSequence) newValue);
            props.setProperty(preference.getKey(), newValue.toString());
            props.setProperty(CommonToolProperties.KEY_ROLES_LIST, "");
            props.setProperty(CommonToolProperties.KEY_USERS_LIST, "");
        } else if (preference.getKey().equals("common.officeID")) {
            createOfficeIdConfirmChangeDialog(preference, newValue);
            return false;
        } else {
            throw new IllegalStateException("Unexpected case");
        }
        return true;
    }
}