diff --git a/res/layout/activity_set_password.xml b/res/layout/activity_set_password.xml
index a0421d1..127e30b 100644
--- a/res/layout/activity_set_password.xml
+++ b/res/layout/activity_set_password.xml
@@ -1,62 +1,26 @@
-
+ android:layout_height="match_parent" >
-
-
-
+ android:orientation="vertical" >
-
-
+
+
-
+
+
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/res/layout/dialog_status.xml b/res/layout/dialog_status.xml
new file mode 100644
index 0000000..e2fec0f
--- /dev/null
+++ b/res/layout/dialog_status.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
diff --git a/res/layout/fragment_set_password.xml b/res/layout/fragment_set_password.xml
new file mode 100644
index 0000000..fdaaf63
--- /dev/null
+++ b/res/layout/fragment_set_password.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1cf4f9b..81e211a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -51,4 +51,5 @@
Old password:
New password:
Confirm new password:
+ Password changed successfully
diff --git a/src/i2p/bote/SetPasswordActivity.java b/src/i2p/bote/SetPasswordActivity.java
index b38a846..40ab717 100644
--- a/src/i2p/bote/SetPasswordActivity.java
+++ b/src/i2p/bote/SetPasswordActivity.java
@@ -1,88 +1,15 @@
package i2p.bote;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
-import android.view.View;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.TextView;
public class SetPasswordActivity extends ActionBarActivity {
- TextView error;
-
@Override
- protected void onCreate(Bundle savedInstanceState) {
+ public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_set_password);
// Enable ActionBar app icon to behave as action to go back
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
- final EditText oldField = (EditText) findViewById(R.id.password_old);
- final EditText newField = (EditText) findViewById(R.id.password_new);
- final EditText confirmField = (EditText) findViewById(R.id.password_confirm);
- final Button b = (Button) findViewById(R.id.submit_password);
- error = (TextView) findViewById(R.id.error);
-
- b.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- String oldPassword = oldField.getText().toString();
- String newPassword = newField.getText().toString();
- String confirmNewPassword = confirmField.getText().toString();
-
- InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.hideSoftInputFromWindow(newField.getWindowToken(), 0);
-
- new PasswordWaiter().execute(oldPassword, newPassword, confirmNewPassword);
- }
- });
- }
-
- private class PasswordWaiter extends AsyncTask {
- private final ProgressDialog dialog = new ProgressDialog(SetPasswordActivity.this);
-
- protected void onPreExecute() {
- dialog.setCancelable(false);
- dialog.show();
- }
-
- protected String doInBackground(String... params) {
- StatusListener lsnr = new StatusListener() {
- public void updateStatus(String status) {
- publishProgress(status);
- }
- };
- try {
- I2PBote.getInstance().changePassword(
- params[0].getBytes(),
- params[1].getBytes(),
- params[2].getBytes(),
- lsnr);
- return null;
- } catch (Throwable e) {
- cancel(false);
- return e.getMessage();
- }
- }
-
- protected void onProgressUpdate(String... values) {
- dialog.setMessage(values[0]);
- }
-
- protected void onCancelled(String result) {
- error.setText(result);
- dialog.dismiss();
- }
-
- protected void onPostExecute(String result) {
- dialog.dismiss();
- // Password changed successfully
- finish();
- }
}
}
diff --git a/src/i2p/bote/SetPasswordFragment.java b/src/i2p/bote/SetPasswordFragment.java
new file mode 100644
index 0000000..e25b0e7
--- /dev/null
+++ b/src/i2p/bote/SetPasswordFragment.java
@@ -0,0 +1,171 @@
+package i2p.bote;
+
+import i2p.bote.util.RobustAsyncTask;
+import i2p.bote.util.TaskFragment;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class SetPasswordFragment extends Fragment {
+ // Code to identify the fragment that is calling onActivityResult().
+ static final int PASSWORD_WAITER = 0;
+ // Tag so we can find the task fragment again, in another
+ // instance of this fragment after rotation.
+ static final String PASSWORD_WAITER_TAG = "passwordWaiterTask";
+
+ private FragmentManager mFM;
+ Button mSubmit;
+ TextView mError;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mFM = getFragmentManager();
+ PasswordWaiterFrag f = (PasswordWaiterFrag) mFM.findFragmentByTag(PASSWORD_WAITER_TAG);
+ if (f != null)
+ f.setTargetFragment(this, PASSWORD_WAITER);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_set_password, container);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ final EditText oldField = (EditText) view.findViewById(R.id.password_old);
+ final EditText newField = (EditText) view.findViewById(R.id.password_new);
+ final EditText confirmField = (EditText) view.findViewById(R.id.password_confirm);
+ mSubmit = (Button) view.findViewById(R.id.submit_password);
+ mError = (TextView) view.findViewById(R.id.error);
+
+ mSubmit.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ String oldPassword = oldField.getText().toString();
+ String newPassword = newField.getText().toString();
+ String confirmNewPassword = confirmField.getText().toString();
+
+ InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(newField.getWindowToken(), 0);
+
+ mSubmit.setEnabled(false);
+ mError.setText("");
+
+ PasswordWaiterFrag f = PasswordWaiterFrag.newInstance(oldPassword, newPassword, confirmNewPassword);
+ f.setTask(new PasswordWaiter());
+ f.setTargetFragment(SetPasswordFragment.this, PASSWORD_WAITER);
+ mFM.beginTransaction()
+ .replace(R.id.password_waiter_frag, f, PASSWORD_WAITER_TAG)
+ .addToBackStack(null)
+ .commit();
+ }
+ });
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == PASSWORD_WAITER) {
+ if (resultCode == Activity.RESULT_OK) {
+ Toast.makeText(getActivity(), R.string.password_changed,
+ Toast.LENGTH_SHORT).show();
+ getActivity().finish();
+ } else if (resultCode == Activity.RESULT_CANCELED) {
+ mSubmit.setEnabled(true);
+ mError.setText(data.getStringExtra("error"));
+ }
+ }
+ }
+
+ public static class PasswordWaiterFrag extends TaskFragment {
+ TextView mStatus;
+
+ public static PasswordWaiterFrag newInstance(String... params) {
+ PasswordWaiterFrag f = new PasswordWaiterFrag();
+ Bundle args = new Bundle();
+ args.putStringArray("params", params);
+ f.setArguments(args);
+ return f;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.dialog_status, container, false);
+ mStatus = (TextView) v.findViewById(R.id.status);
+
+ return v;
+ }
+
+ @Override
+ public String[] getParams() {
+ Bundle args = getArguments();
+ return args.getStringArray("params");
+ }
+
+ @Override
+ public void updateProgress(String... values) {
+ mStatus.setText(values[0]);
+ }
+
+ @Override
+ public void taskFinished(String result) {
+ super.taskFinished(result);
+
+ if (getTargetFragment() != null) {
+ Intent i = new Intent();
+ i.putExtra("result", result);
+ getTargetFragment().onActivityResult(
+ getTargetRequestCode(), Activity.RESULT_OK, i);
+ }
+ }
+
+ @Override
+ public void taskCancelled(String error) {
+ super.taskCancelled(error);
+
+ if (getTargetFragment() != null) {
+ Intent i = new Intent();
+ i.putExtra("error", error);
+ getTargetFragment().onActivityResult(
+ getTargetRequestCode(), Activity.RESULT_CANCELED, i);
+ }
+ }
+ }
+
+ private class PasswordWaiter extends RobustAsyncTask {
+ protected String doInBackground(String... params) {
+ StatusListener lsnr = new StatusListener() {
+ public void updateStatus(String status) {
+ publishProgress(status);
+ }
+ };
+ try {
+ I2PBote.getInstance().changePassword(
+ params[0].getBytes(),
+ params[1].getBytes(),
+ params[2].getBytes(),
+ lsnr);
+ return null;
+ } catch (Throwable e) {
+ cancel(false);
+ return e.getMessage();
+ }
+ }
+ }
+}
diff --git a/src/i2p/bote/util/RobustAsyncTask.java b/src/i2p/bote/util/RobustAsyncTask.java
new file mode 100644
index 0000000..fee7a17
--- /dev/null
+++ b/src/i2p/bote/util/RobustAsyncTask.java
@@ -0,0 +1,30 @@
+package i2p.bote.util;
+
+import android.os.AsyncTask;
+
+public abstract class RobustAsyncTask extends
+ AsyncTask {
+ TaskFragment mDialog;
+
+ void setFragment(TaskFragment fragment) {
+ mDialog = fragment;
+ }
+
+ @Override
+ protected void onProgressUpdate(Progress... values) {
+ if (mDialog != null)
+ mDialog.updateProgress(values);
+ }
+
+ @Override
+ protected void onPostExecute(Result result) {
+ if (mDialog != null)
+ mDialog.taskFinished(result);
+ }
+
+ @Override
+ protected void onCancelled(Result result) {
+ if (mDialog != null)
+ mDialog.taskCancelled(result);
+ }
+}
diff --git a/src/i2p/bote/util/TaskFragment.java b/src/i2p/bote/util/TaskFragment.java
new file mode 100644
index 0000000..762e9e6
--- /dev/null
+++ b/src/i2p/bote/util/TaskFragment.java
@@ -0,0 +1,69 @@
+package i2p.bote.util;
+
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+
+public class TaskFragment extends DialogFragment {
+ RobustAsyncTask mTask;
+
+ public void setTask(RobustAsyncTask task) {
+ mTask = task;
+ mTask.setFragment(this);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Retain this instance so it isn't destroyed
+ setRetainInstance(true);
+
+ // Start the task
+ if (mTask != null)
+ mTask.execute(getParams());
+ }
+
+ // This is to work around what is apparently a bug. If you don't have it
+ // here the dialog will be dismissed on rotation, so tell it not to dismiss.
+ @Override
+ public void onDestroyView() {
+ if (getDialog() != null && getRetainInstance())
+ getDialog().setDismissMessage(null);
+ super.onDestroyView();
+ }
+
+ @Override
+ public void onResume()
+ {
+ super.onResume();
+ // This is a little hacky, but we will see if the task has finished
+ // while we weren't in this activity, and then we can dismiss ourselves.
+ if (mTask == null)
+ dismiss();
+ }
+
+ public Params[] getParams() {
+ return null;
+ }
+
+ public void updateProgress(Progress... values) {}
+
+ public void taskFinished(Result result) {
+ finishTask();
+ }
+
+ public void taskCancelled(Result result) {
+ finishTask();
+ }
+
+ private void finishTask() {
+ // Make sure we check if it is resumed because we will crash if trying
+ // to dismiss the dialog after the user has switched to another app.
+ if (isResumed())
+ dismiss();
+
+ // If we aren't resumed, setting the task to null will allow us to
+ // dismiss ourselves in onResume().
+ mTask = null;
+ }
+}