Files
i2p.i2p-bote.android/src/i2p/bote/android/config/SettingsActivity.java
2014-05-22 12:54:03 +00:00

466 lines
15 KiB
Java

package i2p.bote.android.config;
import i2p.bote.Configuration;
import i2p.bote.I2PBote;
import i2p.bote.android.R;
import i2p.bote.email.EmailIdentity;
import i2p.bote.fileencryption.PasswordException;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.TextView;
public class SettingsActivity extends PreferenceActivity {
// Actions for legacy settings
private static final String ACTION_PREFS_GENERAL = "i2p.bote.PREFS_GENERAL";
static final int ALTER_IDENTITY_LIST = 1;
// Preference Header vars
private Header[] mIdentityListHeaders;
private List<Header> mGeneratedHeaders;
private String mRequestedIdentityKey;
private String mDeletingIdentityKey;
// Async tasks
private LoadIdentityListTask mLoadIdentityListTask;
//
// Android lifecycle
//
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String action = getIntent().getAction();
if (action != null) {
loadLegacySettings(action);
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
// Load the legacy preferences headers
buildLegacyHeaders();
}
}
@Override
public void onResume() {
super.onResume();
updateIdentities();
}
@Override
protected void onPause() {
Configuration config = I2PBote.getInstance().getConfiguration();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
Map<String, ?> all = prefs.getAll();
Iterator<String> iterator = all.keySet().iterator();
while (iterator.hasNext()) {
String x = iterator.next();
if (x.startsWith("i2pbote.")) // Skip over Android-specific settings
continue;
else if ("autoMailCheckEnabled".equals(x))
config.setAutoMailCheckEnabled(prefs.getBoolean(x, true));
else if ("mailCheckInterval".equals(x))
config.setMailCheckInterval(prefs.getInt(x, 30));
else if ("deliveryCheckEnabled".equals(x))
config.setDeliveryCheckEnabled(prefs.getBoolean(x, true));
else if ("hideLocale".equals(x))
config.setHideLocale(prefs.getBoolean(x, true));
else if ("includeSentTime".equals(x))
config.setIncludeSentTime(prefs.getBoolean(x, true));
else if ("numSendHops".equals(x))
config.setNumStoreHops(Integer.parseInt(prefs.getString(x, "0")));
else if ("relayMinDelay".equals(x))
config.setRelayMinDelay(prefs.getInt(x, 5));
else if ("relayMaxDelay".equals(x))
config.setRelayMaxDelay(prefs.getInt(x, 40));
}
config.save();
// Store the settings in Android
super.onPause();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu
getMenuInflater().inflate(R.menu.settings, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_new_identity:
Intent ni = new Intent(this, EditIdentityActivity.class);
startActivityForResult(ni, ALTER_IDENTITY_LIST);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ALTER_IDENTITY_LIST) {
if (resultCode == Activity.RESULT_OK) {
updateIdentities();
}
}
}
@Override
protected boolean isValidFragment(String fragmentName) {
return SettingsFragment.class.getName().equals(fragmentName);
}
//
// Building Headers
//
@SuppressWarnings("deprecation")
private void buildLegacyHeaders() {
// Always add general preferences as first header
addPreferencesFromResource(R.xml.settings_headers_legacy);
// Then add zero or more identity headers as necessary
// TODO: implement
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public void onBuildHeaders(List<Header> target) {
// The resource com.android.internal.R.bool.preferences_prefer_dual_pane
// has different definitions based upon screen size. At present, it will
// be true for -sw720dp devices, false otherwise. For your curiosity, in
// Nexus 7 it is false.
// Always add general preferences as first header
target.clear();
loadHeadersFromResource(R.xml.settings_headers, target);
// Then add zero or more identity headers as necessary
if (mIdentityListHeaders != null) {
final int headerCount = mIdentityListHeaders.length;
for (int index = 0; index < headerCount; index++) {
Header header = mIdentityListHeaders[index];
if (header != null && header.id != HEADER_ID_UNDEFINED) {
String key = header.extras.getString(
ViewIdentityFragment.IDENTITY_KEY);
if (key != mDeletingIdentityKey) {
target.add(header);
if (key == mRequestedIdentityKey) {
mRequestedIdentityKey = null;
}
}
}
}
}
// Save for later use (see setListAdapter)
mGeneratedHeaders = target;
}
//
// Settings pages
//
@SuppressWarnings("deprecation")
private void loadLegacySettings(String action) {
if (ACTION_PREFS_GENERAL.equals(action)) {
addPreferencesFromResource(R.xml.settings_general);
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class SettingsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String settings = getArguments().getString("settings");
if ("general".equals(settings)) {
addPreferencesFromResource(R.xml.settings_general);
}
}
}
//
// Update list of identities in headers
//
/**
* Starts the async reload of the identities list
* (if the headers are being displayed)
*/
private void updateIdentities() {
if (shouldUpdateIdentities()) {
mLoadIdentityListTask = (LoadIdentityListTask)
new LoadIdentityListTask().execute();
}
}
private boolean shouldUpdateIdentities() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
return getIntent().getAction() == null;
else
return showingHeaders();
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private boolean showingHeaders() {
return hasHeaders();
}
//
// Load list of identities and convert
// into appropriate type of header
//
private class LoadIdentityListTask extends AsyncTask<String, Void, Object[]> {
protected Object[] doInBackground(String... params) {
try {
Collection<EmailIdentity> identities = I2PBote.getInstance().getIdentities().getAll();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
// Return legacy headers
return loadLegacyHeaders(identities);
} else {
// Return list of Headers
return loadHeaders(identities);
}
} catch (PasswordException e) {
cancel(false);
return new Object[] {e};
} catch (IOException e) {
cancel(false);
return new Object[] {e};
} catch (GeneralSecurityException e) {
cancel(false);
return new Object[] {e};
}
}
private Object[] loadLegacyHeaders(Collection<EmailIdentity> identities) {
// TODO: implement
return new Object[] {null};
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private Object[] loadHeaders(Collection<EmailIdentity> identities) {
Header[] result = new Header[identities.size()];
int index = 0;
for (EmailIdentity identity : identities) {
final long id = identity.getHash().hashCode();
final String name = identity.getPublicName();
final String desc = identity.getDescription();
final String key = identity.getKey();
final Intent intent = new Intent(
getApplicationContext(), ViewIdentityActivity.class);
final Bundle args = new Bundle();
args.putString(ViewIdentityFragment.IDENTITY_KEY, key);
intent.putExtras(args);
final Header newHeader = new Header();
newHeader.id = id;
newHeader.title = name;
newHeader.summary = desc;
newHeader.intent = intent;
newHeader.extras = args;
result[index++] = newHeader;
}
return new Object[] {result};
}
@Override
protected void onPostExecute(Object[] result) {
if (isCancelled()) return;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
showLegacyHeaders(result);
} else {
showHeaders(result);
}
}
private void showLegacyHeaders(Object[] result) {
// TODO: implement
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void showHeaders(Object[] result) {
final Header[] headers = (Header[]) result[0];
mIdentityListHeaders = headers;
invalidateHeaders();
}
@Override
protected void onCancelled(Object[] result) {
}
}
//
// Styling for headers
//
@Override
public void setListAdapter(ListAdapter adapter) {
if (adapter == null) {
super.setListAdapter(null);
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
super.setListAdapter(adapter); // TODO: implement legacy headers styling
} else {
// TODO: Fix NPE when rotating screen
super.setListAdapter(new HeaderAdapter(this, mGeneratedHeaders));
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private static class HeaderAdapter extends ArrayAdapter<Header> {
static final int HEADER_TYPE_CATEGORY = 0;
static final int HEADER_TYPE_NORMAL = 1;
private static final int HEADER_TYPE_COUNT = HEADER_TYPE_NORMAL + 1;
private static class HeaderViewHolder {
TextView title;
TextView summary;
}
private LayoutInflater mInflater;
static int getHeaderType(Header header) {
if (header.fragment == null && header.intent == null) {
return HEADER_TYPE_CATEGORY;
} else {
return HEADER_TYPE_NORMAL;
}
}
@Override
public int getItemViewType(int position) {
Header header = getItem(position);
return getHeaderType(header);
}
@Override
public boolean areAllItemsEnabled() {
return false; // because of categories
}
@Override
public boolean isEnabled(int position) {
try {
return getItemViewType(position) != HEADER_TYPE_CATEGORY;
} catch (IndexOutOfBoundsException e) {
// Happens when deleting an identity
return false;
}
}
@Override
public int getViewTypeCount() {
return HEADER_TYPE_COUNT;
}
@Override
public boolean hasStableIds() {
return true;
}
public HeaderAdapter(Context context, List<Header> objects) {
super(context, 0, objects);
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
HeaderViewHolder holder;
Header header = getItem(position);
int headerType = getHeaderType(header);
View view = null;
if (convertView == null) {
holder = new HeaderViewHolder();
switch (headerType) {
case HEADER_TYPE_CATEGORY:
view = new TextView(getContext(), null,
android.R.attr.listSeparatorTextViewStyle);
holder.title = (TextView) view;
break;
case HEADER_TYPE_NORMAL:
view = mInflater.inflate(
R.layout.preference_header_item, parent,
false);
holder.title = (TextView)
view.findViewById(android.R.id.title);
holder.summary = (TextView)
view.findViewById(android.R.id.summary);
break;
}
view.setTag(holder);
} else {
view = convertView;
holder = (HeaderViewHolder) view.getTag();
}
// All view fields must be updated every time, because the view may be recycled
switch (headerType) {
case HEADER_TYPE_CATEGORY:
holder.title.setText(header.getTitle(getContext().getResources()));
break;
case HEADER_TYPE_NORMAL:
updateCommonHeaderView(header, holder);
break;
}
return view;
}
private void updateCommonHeaderView(Header header, HeaderViewHolder holder) {
holder.title.setText(header.getTitle(getContext().getResources()));
CharSequence summary = header.getSummary(getContext().getResources());
if (summary != null && !summary.toString().isEmpty()) {
holder.summary.setVisibility(View.VISIBLE);
holder.summary.setText(summary);
} else {
holder.summary.setVisibility(View.GONE);
}
}
}
}