/*
* Copyright (C) 2011 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.odk.collect.android.preferences;
import org.odk.collect.android.R;
import org.odk.collect.android.activities.AccountList;
import org.odk.collect.android.application.Collect;
import org.odk.collect.android.utilities.UrlUtils;
import org.odk.collect.android.utilities.WebUtils;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.provider.MediaStore.Images;
import android.text.InputFilter;
import android.text.Spanned;
import android.widget.Toast;
/**
* @author yanokwa
*/
public class PreferencesActivity extends PreferenceActivity implements
OnSharedPreferenceChangeListener {
protected static final int IMAGE_CHOOSER = 0;
public static String KEY_LAST_VERSION = "lastVersion";
public static String KEY_FIRST_RUN = "firstRun";
public static String KEY_SHOW_SPLASH = "showSplash";
public static String KEY_SPLASH_PATH = "splashPath";
public static String KEY_FONT_SIZE = "font_size";
public static String KEY_SELECTED_GOOGLE_ACCOUNT = "selected_google_account";
public static String KEY_GOOGLE_SUBMISSION = "google_submission_id";
public static String KEY_SERVER_URL = "server_url";
public static String KEY_USERNAME = "username";
public static String KEY_PASSWORD = "password";
public static String KEY_PROTOCOL = "protocol";
public static String KEY_FORMLIST_URL = "formlist_url";
public static String KEY_SUBMISSION_URL = "submission_url";
public static String KEY_COMPLETED_DEFAULT = "default_completed";
public static String KEY_SHOW_START_SCREEN = "odk_show_entry_screen";
public static String KEY_HELP_MODE_TRAY = "help_mode_tray";
public static String KEY_PROGRESS_BAR = "progress_bar";
public static String KEY_NAVIGATION_BAR = "pref_nav_bar";
public static String KEY_AUTH = "auth";
public static String KEY_ACCOUNT = "account";
public static String KEY_SERVER_PREFS = "serverprefs";
public static String googleServerBaseUrl = "https://gather.apis.google.com/odk/n/";
private PreferenceScreen mSplashPathPreference;
private EditTextPreference mSubmissionUrlPreference;
private EditTextPreference mFormListUrlPreference;
private EditTextPreference mServerUrlPreference;
private EditTextPreference mUsernamePreference;
private EditTextPreference mPasswordPreference;
private PreferenceScreen mSelectedGoogleAccountPreference;
private EditTextPreference mGoogleCollectionEffortPreference;
private Context mContext;
/*
* (non-Javadoc)
* @see android.preference.PreferenceActivity#onCreate(android.os.Bundle)
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
mContext = this;
setTitle(getString(R.string.app_name) + " > " + getString(R.string.general_preferences));
if(Collect.getInstance() != null) {
setupSplashPathPreference();
setupSelectedGoogleAccountPreference();
updateServerUrl();
updateUsername();
updatePassword();
updateFormListUrl();
updateSubmissionUrl();
updateSplashPath();
updateProtocol();
updateSelectedGoogleAccount();
updateGoogleCollectionEffort();
} else {
//If there's no collect instance we're running in a library, so we should
//hide everything that's irrelevant
this.getPreferenceScreen().removePreference(this.findPreference(KEY_SERVER_PREFS));
}
updateFontSize();
updateShowStart();
}
private void setupSplashPathPreference() {
mSplashPathPreference = (PreferenceScreen) findPreference(KEY_SPLASH_PATH);
if (mSplashPathPreference != null) {
mSplashPathPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
private void launchImageChooser() {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.setType("image/*");
startActivityForResult(i, PreferencesActivity.IMAGE_CHOOSER);
}
/*
* (non-Javadoc)
* @see android.preference.Preference.OnPreferenceClickListener#onPreferenceClick(android.preference.Preference)
*/
@Override
public boolean onPreferenceClick(Preference preference) {
// if you have a value, you can clear it or select new.
CharSequence cs = mSplashPathPreference.getSummary();
if (cs != null && cs.toString().contains("/")) {
final CharSequence[] items =
{
getString(R.string.select_another_image),
getString(R.string.use_odk_default)
};
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setTitle(getString(R.string.change_splash_path));
builder.setNeutralButton(getString(R.string.cancel),
new DialogInterface.OnClickListener() {
/*
* (non-Javadoc)
* @see android.content.DialogInterface.OnClickListener#onClick(android.content.DialogInterface, int)
*/
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
builder.setItems(items, new DialogInterface.OnClickListener() {
/*
* (non-Javadoc)
* @see android.content.DialogInterface.OnClickListener#onClick(android.content.DialogInterface, int)
*/
@Override
public void onClick(DialogInterface dialog, int item) {
if (items[item].equals(getString(R.string.select_another_image))) {
launchImageChooser();
} else {
setSplashPath(getString(R.string.default_splash_path));
}
}
});
AlertDialog alert = builder.create();
alert.show();
} else {
launchImageChooser();
}
return true;
}
});
}
}
private void setSplashPath(String path) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
Editor editor = sharedPreferences.edit();
editor.putString(KEY_SPLASH_PATH, path);
editor.commit();
}
/*
* (non-Javadoc)
* @see android.app.Activity#onPause()
*/
@Override
protected void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(
this);
}
/*
* (non-Javadoc)
* @see android.app.Activity#onResume()
*/
@Override
protected void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
if(Collect.getInstance() != null) {
updateServerUrl();
updateUsername();
updatePassword();
updateFormListUrl();
updateSubmissionUrl();
updateSplashPath();
updateProtocol();
updateSelectedGoogleAccount();
updateGoogleCollectionEffort();
}
updateFontSize();
updateShowStart();
}
/*
* (non-Javadoc)
* @see android.preference.PreferenceActivity#onActivityResult(int, int, android.content.Intent)
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (resultCode == RESULT_CANCELED) {
// request was canceled, so do nothing
return;
}
switch (requestCode) {
case IMAGE_CHOOSER:
String sourceImagePath = null;
// get gp of chosen file
Uri uri = intent.getData();
if (uri.toString().startsWith("file")) {
sourceImagePath = uri.toString().substring(6);
} else {
String[] projection = {
Images.Media.DATA
};
Cursor c = managedQuery(uri, projection, null, null, null);
startManagingCursor(c);
int i = c.getColumnIndexOrThrow(Images.Media.DATA);
c.moveToFirst();
sourceImagePath = c.getString(i);
}
// setting image path
setSplashPath(sourceImagePath);
updateSplashPath();
break;
}
}
/*
* (non-Javadoc)
* @see android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged(android.content.SharedPreferences, java.lang.String)
*/
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(KEY_PROTOCOL)) {
updateProtocol();
updateSelectedGoogleAccount();
updateGoogleCollectionEffort();
updateServerUrl();
updateUsername();
updatePassword();
updateFormListUrl();
updateSubmissionUrl();
} else if (key.equals(KEY_SELECTED_GOOGLE_ACCOUNT)) {
updateSelectedGoogleAccount();
updateGoogleCollectionEffort();
updateServerUrl();
} else if (key.equals(KEY_GOOGLE_SUBMISSION)) {
updateSelectedGoogleAccount();
updateGoogleCollectionEffort();
updateServerUrl();
} else if (key.equals(KEY_SERVER_URL)) {
updateServerUrl();
} else if (key.equals(KEY_FORMLIST_URL)) {
updateFormListUrl();
} else if (key.equals(KEY_SUBMISSION_URL)) {
updateSubmissionUrl();
} else if (key.equals(KEY_USERNAME)) {
updateUsername();
} else if (key.equals(KEY_PASSWORD)) {
updatePassword();
} else if (key.equals(KEY_SPLASH_PATH)) {
updateSplashPath();
} else if (key.equals(KEY_FONT_SIZE)) {
updateFontSize();
} else if(key.equals(KEY_SHOW_START_SCREEN)) {
updateShowStart();
}
}
private void validateUrl(EditTextPreference preference) {
if (preference != null) {
String url = preference.getText();
if (UrlUtils.isValidUrl(url)) {
preference.setText(url);
preference.setSummary(url);
} else {
// preference.setText((String) preference.getSummary());
Toast.makeText(getApplicationContext(), getString(R.string.url_error),
Toast.LENGTH_SHORT).show();
}
}
}
private void updateServerUrl() {
mServerUrlPreference = (EditTextPreference) findPreference(KEY_SERVER_URL);
// remove all trailing "/"s
while (mServerUrlPreference.getText().endsWith("/")) {
mServerUrlPreference.setText(mServerUrlPreference.getText().substring(0,
mServerUrlPreference.getText().length() - 1));
}
validateUrl(mServerUrlPreference);
mServerUrlPreference.setSummary(mServerUrlPreference.getText());
mServerUrlPreference.getEditText().setFilters(new InputFilter[] {
getReturnFilter()
});
}
private void updateSplashPath() {
mSplashPathPreference = (PreferenceScreen) findPreference(KEY_SPLASH_PATH);
mSplashPathPreference.setSummary(mSplashPathPreference.getSharedPreferences().getString(
KEY_SPLASH_PATH, getString(R.string.default_splash_path)));
}
private void updateUsername() {
mUsernamePreference = (EditTextPreference) findPreference(KEY_USERNAME);
mUsernamePreference.setSummary(mUsernamePreference.getText());
mUsernamePreference.getEditText().setFilters(new InputFilter[] {
getWhitespaceFilter()
});
WebUtils.clearAllCredentials();
}
private void updatePassword() {
mPasswordPreference = (EditTextPreference) findPreference(KEY_PASSWORD);
if (mPasswordPreference.getText() != null && mPasswordPreference.getText().length() > 0) {
mPasswordPreference.setSummary("********");
} else {
mPasswordPreference.setSummary("");
}
mPasswordPreference.getEditText().setFilters(new InputFilter[] {
getWhitespaceFilter()
});
WebUtils.clearAllCredentials();
}
private void updateFormListUrl() {
mFormListUrlPreference = (EditTextPreference) findPreference(KEY_FORMLIST_URL);
mFormListUrlPreference.setSummary(mFormListUrlPreference.getText());
mFormListUrlPreference.getEditText().setFilters(new InputFilter[] {
getReturnFilter()
});
}
private void updateSubmissionUrl() {
mSubmissionUrlPreference = (EditTextPreference) findPreference(KEY_SUBMISSION_URL);
mSubmissionUrlPreference.setSummary(mSubmissionUrlPreference.getText());
mSubmissionUrlPreference.getEditText().setFilters(new InputFilter[] {
getReturnFilter()
});
}
private void updateFontSize() {
ListPreference lp = (ListPreference) findPreference(KEY_FONT_SIZE);
lp.setSummary(lp.getEntry());
}
private void updateShowStart() {
// ListPreference lp = (ListPreference) findPreference(KEY_SHOW_START_SCREEN);
// lp.setSummary(lp.getEntry());
}
private void updateSelectedGoogleAccount() {
mSelectedGoogleAccountPreference =
(PreferenceScreen) findPreference(KEY_SELECTED_GOOGLE_ACCOUNT);
mSelectedGoogleAccountPreference.setSummary(mSelectedGoogleAccountPreference
.getSharedPreferences().getString(KEY_ACCOUNT, ""));
}
private void updateGoogleCollectionEffort() {
mGoogleCollectionEffortPreference =
(EditTextPreference) findPreference(KEY_GOOGLE_SUBMISSION);
mGoogleCollectionEffortPreference.setSummary(mGoogleCollectionEffortPreference
.getSharedPreferences().getString(KEY_GOOGLE_SUBMISSION, ""));
// We have a fixed URL for using Google's service.
if (((ListPreference) findPreference(KEY_PROTOCOL)).getValue().equals("google")) {
String submissionId =
((EditTextPreference) findPreference(KEY_GOOGLE_SUBMISSION)).getText();
mServerUrlPreference.setText(googleServerBaseUrl + submissionId);
updateServerUrl();
}
}
private void setupSelectedGoogleAccountPreference() {
mSelectedGoogleAccountPreference =
(PreferenceScreen) findPreference(KEY_SELECTED_GOOGLE_ACCOUNT);
if (mSelectedGoogleAccountPreference == null) {
return;
}
updateSelectedGoogleAccount();
mSelectedGoogleAccountPreference
.setOnPreferenceClickListener(new OnPreferenceClickListener() {
/*
* (non-Javadoc)
* @see android.preference.Preference.OnPreferenceClickListener#onPreferenceClick(android.preference.Preference)
*/
@Override
public boolean onPreferenceClick(Preference preference) {
Intent i = new Intent(getApplicationContext(), AccountList.class);
startActivity(i);
return true;
}
});
}
private void updateProtocol() {
ListPreference lp = (ListPreference) findPreference(KEY_PROTOCOL);
lp.setSummary(lp.getEntry());
String protocol = lp.getValue();
if (protocol.equals("odk_default")) {
if (mGoogleCollectionEffortPreference != null) {
mGoogleCollectionEffortPreference.setEnabled(false);
}
if (mSelectedGoogleAccountPreference != null) {
mSelectedGoogleAccountPreference.setEnabled(false);
}
if (mServerUrlPreference != null) {
mServerUrlPreference.setEnabled(true);
}
if (mUsernamePreference != null) {
mUsernamePreference.setEnabled(true);
}
if (mPasswordPreference != null) {
mPasswordPreference.setEnabled(true);
}
if (mFormListUrlPreference != null) {
mFormListUrlPreference.setText(getText(R.string.default_odk_formlist).toString());
mFormListUrlPreference.setEnabled(false);
}
if (mSubmissionUrlPreference != null) {
mSubmissionUrlPreference.setText(getText(R.string.default_odk_submission)
.toString());
mSubmissionUrlPreference.setEnabled(false);
}
} else if (protocol.equals("google")) {
if (mGoogleCollectionEffortPreference != null) {
mGoogleCollectionEffortPreference.setEnabled(true);
}
if (mSelectedGoogleAccountPreference != null) {
mSelectedGoogleAccountPreference.setEnabled(true);
}
if (mServerUrlPreference != null) {
mServerUrlPreference.setEnabled(false);
}
if (mUsernamePreference != null) {
mUsernamePreference.setEnabled(false);
}
if (mPasswordPreference != null) {
mPasswordPreference.setEnabled(false);
}
if (mFormListUrlPreference != null) {
mFormListUrlPreference.setEnabled(false);
}
if (mSubmissionUrlPreference != null) {
mSubmissionUrlPreference.setEnabled(false);
}
updateSelectedGoogleAccount();
updateGoogleCollectionEffort();
} else {
if (mGoogleCollectionEffortPreference != null) {
mGoogleCollectionEffortPreference.setEnabled(false);
}
if (mSelectedGoogleAccountPreference != null) {
mSelectedGoogleAccountPreference.setEnabled(false);
}
if (mServerUrlPreference != null) {
mServerUrlPreference.setEnabled(true);
}
if (mUsernamePreference != null) {
mUsernamePreference.setEnabled(true);
}
if (mPasswordPreference != null) {
mPasswordPreference.setEnabled(true);
}
if (mFormListUrlPreference != null) {
mFormListUrlPreference.setEnabled(true);
}
if (mSubmissionUrlPreference != null) {
mSubmissionUrlPreference.setEnabled(true);
}
}
}
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;
}
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 enum ProgressBarMode {
None (false, false),
ProgressOnly (true, false),
NavBar (true, true),
//NOTE: We can't actually handle this yet
NavBarNoProgress (false, true);
boolean progress = false;
boolean nav = false;
private ProgressBarMode(boolean progress, boolean nav) { this.progress = progress; this.nav = nav; }
public boolean useNavigationBar() { return nav;}
public boolean useProgressBar() { return progress; }
}
public static ProgressBarMode getProgressBarMode(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean navBar = prefs.getBoolean(KEY_NAVIGATION_BAR, false);
boolean progressBar = prefs.getBoolean(KEY_PROGRESS_BAR, true);
if(!navBar && !progressBar) { return ProgressBarMode.None;}
else if(!navBar && progressBar) { return ProgressBarMode.ProgressOnly;}
else if(navBar && !progressBar) { return ProgressBarMode.NavBarNoProgress;}
else { return ProgressBarMode.NavBar;}
}
public static boolean showFirstScreen(Context context) {
return !PreferencesActivity.getProgressBarMode(context).useNavigationBar() &&
PreferenceManager.getDefaultSharedPreferences(context).getBoolean(PreferencesActivity.KEY_SHOW_START_SCREEN, true);
}
}