/*
* Copyright (C) 2010-2017 Stichting Akvo (Akvo Foundation)
*
* This file is part of Akvo Flow.
*
* Akvo Flow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Akvo Flow 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Akvo Flow. If not, see <http://www.gnu.org/licenses/>.
*/
package org.akvo.flow.activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.TextView;
import org.akvo.flow.R;
import org.akvo.flow.app.FlowApp;
import org.akvo.flow.data.preference.Prefs;
import org.akvo.flow.service.SurveyDownloadService;
import org.akvo.flow.util.ServerManager;
import org.akvo.flow.util.StringUtil;
import org.akvo.flow.util.ViewUtil;
import java.lang.ref.WeakReference;
/**
* Displays user editable preferences and takes care of persisting them to the
* database. Some options require the user to enter an administrator passcode
* via a dialog box before the operation can be performed.
*
* @author Christopher Fagiani
*/
public class PreferencesActivity extends BackActivity implements OnClickListener,
OnCheckedChangeListener {
private CheckBox screenOnCheckbox;
private CheckBox mobileDataCheckbox;
private TextView serverTextView;
private TextView identTextView;
private TextView maxImgSizeTextView;
private TextView localeTextView;
private Prefs prefs;
private ServerManager serverManager;
private String[] maxImgSizes;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_preferences);
setupToolBar();
screenOnCheckbox = (CheckBox) findViewById(R.id.screenoptcheckbox);
mobileDataCheckbox = (CheckBox) findViewById(R.id.uploadoptioncheckbox);
serverTextView = (TextView) findViewById(R.id.servervalue);
identTextView = (TextView) findViewById(R.id.identvalue);
maxImgSizeTextView = (TextView) findViewById(R.id.max_img_size_txt);
localeTextView = (TextView) findViewById(R.id.locale_name);
prefs = new Prefs(getApplicationContext());
serverManager = new ServerManager(getApplicationContext());
Resources res = getResources();
maxImgSizes = res.getStringArray(R.array.max_image_size_pref);
// Setup event listeners
screenOnCheckbox.setOnCheckedChangeListener(this);
mobileDataCheckbox.setOnCheckedChangeListener(this);
findViewById(R.id.pref_locale).setOnClickListener(this);
findViewById(R.id.pref_server).setOnClickListener(this);
findViewById(R.id.pref_deviceid).setOnClickListener(this);
findViewById(R.id.pref_resize).setOnClickListener(this);
}
/**
* loads the preferences from the DB and sets their current value in the UI
*/
private void populateFields() {
populateFromSharedPreferences();
populateLanguagePreferences();
}
private void populateLanguagePreferences() {
localeTextView.setText(FlowApp.getApp().getAppDisplayLanguage());
}
private void populateFromSharedPreferences() {
screenOnCheckbox
.setChecked(prefs.getBoolean(Prefs.KEY_SCREEN_ON, Prefs.DEFAULT_VALUE_SCREEN_ON));
mobileDataCheckbox.setChecked(prefs.getBoolean(Prefs.KEY_CELL_UPLOAD,
Prefs.DEFAULT_VALUE_CELL_UPLOAD));
serverTextView.setText(serverManager.getServerBase());
int maxImgSize = prefs.getInt(Prefs.KEY_MAX_IMG_SIZE, Prefs.DEFAULT_VALUE_IMAGE_SIZE);
maxImgSizeTextView.setText(maxImgSizes[maxImgSize]);
identTextView.setText(prefs.getString(Prefs.KEY_DEVICE_IDENTIFIER,
Prefs.DEFAULT_VALUE_DEVICE_IDENTIFIER));
}
/**
* opens db connection and sets up listeners (after we hydrate values so we
* don't trigger the onCheckChanged listener when we set initial values)
*/
public void onResume() {
super.onResume();
populateFields();
}
/**
* displays a pop-up dialog containing the upload or language options
* depending on what was clicked
*/
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.pref_locale:
showLanguageDialog();
break;
case R.id.pref_server:
StringPrefInputDialogListener dialogListener = new StringPrefInputDialogListener(
this) {
@Override
public void usePreference(String userInput) {
PreferencesActivity preferencesActivity = activityWeakReference.get();
if (preferencesActivity != null) {
preferencesActivity.saveBackendUrl(userInput);
}
}
};
//TODO: check duplicated title and subtitle --> remove subtitle
ViewUtil.showAdminAuthDialog(this,
new StringPreferencesAuthDialogListener(this, dialogListener,
R.string.serverlabel,
R.string.serverlabel,
serverManager.getServerBase())
);
break;
case R.id.pref_deviceid:
StringPrefInputDialogListener dialogListenerId = new StringPrefInputDialogListener(
this) {
@Override
public void usePreference(String userInput) {
PreferencesActivity preferencesActivity = activityWeakReference.get();
if (preferencesActivity != null) {
preferencesActivity.saveNewDeviceId(userInput);
}
}
};
ViewUtil.showAdminAuthDialog(this,
new StringPreferencesAuthDialogListener(this, dialogListenerId,
R.string.identlabel,
R.string.setidentlabel,
prefs.getString(Prefs.KEY_DEVICE_IDENTIFIER,
Prefs.DEFAULT_VALUE_DEVICE_IDENTIFIER))
);
break;
case R.id.pref_resize:
showPreferenceDialog(R.string.resize_large_images,
Prefs.KEY_MAX_IMG_SIZE,
maxImgSizes, maxImgSizeTextView);
break;
}
}
private void saveBackendUrl(String userInput) {
prefs.setString(Prefs.KEY_BACKEND_SERVER, userInput);
serverTextView.setText(userInput);
}
/**
* displays a dialog that allows the user to choose a setting from a string
* array
*
* @param titleId - resource id of dialog title
* @param settingKey - key of setting to edit
* @param values - string array containing values (text mapping of the key)
* @param currentValView - view to update with value selected
*/
private void showPreferenceDialog(int titleId, final String settingKey, final String[] values,
final TextView currentValView) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(titleId).setItems(values,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
prefs.setInt(settingKey, which);
currentValView.setText(values[which]);
if (dialog != null) {
dialog.dismiss();
}
}
}
);
builder.show();
}
/**
* saves the value of the checkbox to the database
*/
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView == screenOnCheckbox) {
prefs.setBoolean(Prefs.KEY_SCREEN_ON, isChecked);
} else if (buttonView == mobileDataCheckbox) {
prefs.setBoolean(Prefs.KEY_CELL_UPLOAD, isChecked);
}
}
private void showLanguageDialog() {
final String[] languageCodes = getResources().getStringArray(R.array.app_language_codes);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.app_language).setItems(R.array.app_languages,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
FlowApp.getApp().setAppLanguage(languageCodes[which], true);
}
}
);
builder.show();
}
private void saveNewDeviceId(String deviceId) {
identTextView.setText(deviceId);
prefs.setString(Prefs.KEY_DEVICE_IDENTIFIER, deviceId);
// Trigger the SurveyDownload Service, in order to force
// a backend connection with the new Device ID
startService(new Intent(this,
SurveyDownloadService.class));
}
static class StringPreferencesAuthDialogListener implements ViewUtil.AdminAuthDialogListener {
private final WeakReference<PreferencesActivity> activityWeakReference;
private final StringPrefInputDialogListener dialogListener;
private final int title;
private final int subtitle;
private final String originalValue;
StringPreferencesAuthDialogListener(PreferencesActivity activity,
StringPrefInputDialogListener dialogListener, int title,
int subtitle, String originalValue) {
this.activityWeakReference = new WeakReference<>(activity);
this.dialogListener = dialogListener;
this.title = title;
this.subtitle = subtitle;
this.originalValue = originalValue;
}
@Override
public void onAuthenticated() {
final PreferencesActivity preferencesActivity = activityWeakReference.get();
if (preferencesActivity != null) {
final EditText inputView = new EditText(preferencesActivity);
// one line only
inputView.setSingleLine();
inputView.setText(originalValue);
ViewUtil.ShowTextInputDialog(preferencesActivity, title,
subtitle, inputView, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
/**
* Drop any control chars, especially tabs
*/
String newDeviceId = StringUtil.controlToSpace(inputView
.getText().toString());
dialogListener.usePreference(newDeviceId);
}
});
}
}
}
public abstract class StringPrefInputDialogListener {
final WeakReference<PreferencesActivity> activityWeakReference;
protected StringPrefInputDialogListener(PreferencesActivity activity) {
this.activityWeakReference = new WeakReference<>(activity);
}
public abstract void usePreference(String userInput);
}
}