diff --git a/briar-android/src/org/briarproject/android/BaseActivity.java b/briar-android/src/org/briarproject/android/BaseActivity.java index 02395fbf10775009a93b15cc21c7c8f0c587e01e..d1899b64095f0446586d431b26c5cdd1a956acdb 100644 --- a/briar-android/src/org/briarproject/android/BaseActivity.java +++ b/briar-android/src/org/briarproject/android/BaseActivity.java @@ -2,12 +2,16 @@ package org.briarproject.android; import android.os.Bundle; import android.os.IBinder; +import android.support.annotation.CallSuper; import android.support.annotation.Nullable; +import android.support.annotation.UiThread; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.inputmethod.InputMethodManager; import org.briarproject.android.controller.ActivityLifecycleController; +import org.briarproject.android.controller.handler.ContextResultHandler; +import org.briarproject.android.controller.handler.DestroyableContextManager; import org.briarproject.android.forum.ForumModule; import java.util.ArrayList; @@ -18,12 +22,14 @@ import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT; import static org.briarproject.android.TestingConstants.PREVENT_SCREENSHOTS; public abstract class BaseActivity extends AppCompatActivity - implements DestroyableContext { + implements DestroyableContext, DestroyableContextManager { protected ActivityComponent activityComponent; private final List<ActivityLifecycleController> lifecycleControllers = new ArrayList<>(); + private List<ContextResultHandler> contextResultHandlers = + new ArrayList<>(); private boolean destroyed = false; public abstract void injectActivity(ActivityComponent component); @@ -32,6 +38,7 @@ public abstract class BaseActivity extends AppCompatActivity lifecycleControllers.add(alc); } + @SuppressWarnings("unchecked") @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -52,6 +59,39 @@ public abstract class BaseActivity extends AppCompatActivity for (ActivityLifecycleController alc : lifecycleControllers) { alc.onActivityCreate(this); } + + if (getLastCustomNonConfigurationInstance() != null) { + contextResultHandlers = + (List<ContextResultHandler>) getLastCustomNonConfigurationInstance(); + for (ContextResultHandler crh : contextResultHandlers) + crh.setDestroyableContextManager(this); + } + + } + + @UiThread + public void addContextResultHandler(ContextResultHandler crh) { + contextResultHandlers.add(crh); + } + + + @UiThread + public void removeContextResultHandler(String tag) { + List<ContextResultHandler> handlersToRemove = new ArrayList<>(); + for (ContextResultHandler crh : contextResultHandlers) { + if (crh.getTag().equals(tag)) + contextResultHandlers.remove(crh); + handlersToRemove.add(crh); + } + contextResultHandlers.removeAll(handlersToRemove); + } + + @UiThread + public boolean containsContextResultHandler(String tag) { + for (ContextResultHandler crh : contextResultHandlers) { + if (crh.getTag().equals(tag)) return true; + } + return false; } public ActivityComponent getActivityComponent() { @@ -67,6 +107,12 @@ public abstract class BaseActivity extends AppCompatActivity return new ForumModule(); } + @CallSuper + @Override + public Object onRetainCustomNonConfigurationInstance() { + return contextResultHandlers; + } + @Override protected void onStart() { super.onStart(); @@ -87,6 +133,9 @@ public abstract class BaseActivity extends AppCompatActivity protected void onDestroy() { super.onDestroy(); destroyed = true; + for (ContextResultHandler crh : contextResultHandlers) { + crh.setDestroyableContextManager(null); + } for (ActivityLifecycleController alc : lifecycleControllers) { alc.onActivityDestroy(); } diff --git a/briar-android/src/org/briarproject/android/BriarActivity.java b/briar-android/src/org/briarproject/android/BriarActivity.java index 9d162b62d6702b4863c888f1afafd51041235d14..66e991ab714eeb8e381d9e8a9c896aced276aff5 100644 --- a/briar-android/src/org/briarproject/android/BriarActivity.java +++ b/briar-android/src/org/briarproject/android/BriarActivity.java @@ -3,10 +3,12 @@ package org.briarproject.android; import android.annotation.SuppressLint; import android.content.Intent; import android.os.Build; +import android.support.annotation.NonNull; import org.briarproject.android.controller.BriarController; import org.briarproject.android.controller.DbController; -import org.briarproject.android.controller.handler.UiResultHandler; +import org.briarproject.android.controller.handler.DestroyableContextManager; +import org.briarproject.android.controller.handler.UiContextResultHandler; import org.briarproject.android.panic.ExitActivity; import java.util.logging.Logger; @@ -28,6 +30,8 @@ public abstract class BriarActivity extends BaseActivity { public static final int REQUEST_PASSWORD = 1; + protected static final String TAG_SIGN_OUT = "briar.SIGN_OUT"; + private static final Logger LOG = Logger.getLogger(BriarActivity.class.getName()); @@ -58,13 +62,18 @@ public abstract class BriarActivity extends BaseActivity { } protected void signOut(final boolean removeFromRecentApps) { - briarController.signOut(new UiResultHandler<Void>(this) { - @Override - public void onResultUi(Void result) { - if (removeFromRecentApps) startExitActivity(); - else finishAndExit(); - } - }); + briarController + .signOut(new UiContextResultHandler<Void>(this, TAG_SIGN_OUT) { + @Override + public void onResultUi(@NonNull Void result, + @NonNull DestroyableContextManager context) { + if (removeFromRecentApps) { + ((BriarActivity) context).startExitActivity(); + } else { + ((BriarActivity)context).finishAndExit(); + } + } + }); } protected void signOut() { diff --git a/briar-android/src/org/briarproject/android/ChangePasswordActivity.java b/briar-android/src/org/briarproject/android/ChangePasswordActivity.java index 4c93924ea80b997bd8637596b80d1cc327fbddc4..565eadb1551c4e9a5fd382d5c6ba2629fd62eb6f 100644 --- a/briar-android/src/org/briarproject/android/ChangePasswordActivity.java +++ b/briar-android/src/org/briarproject/android/ChangePasswordActivity.java @@ -18,7 +18,8 @@ import android.widget.Toast; import org.briarproject.R; import org.briarproject.android.controller.PasswordController; import org.briarproject.android.controller.SetupController; -import org.briarproject.android.controller.handler.UiResultHandler; +import org.briarproject.android.controller.handler.DestroyableContextManager; +import org.briarproject.android.controller.handler.UiContextResultHandler; import org.briarproject.android.util.AndroidUtils; import org.briarproject.android.util.StrengthMeter; @@ -32,6 +33,8 @@ public class ChangePasswordActivity extends BaseActivity implements OnClickListener, OnEditorActionListener { + private static final String TAG_PASSWORD_CHANGE = "briar.PASSWORD_CHANGE"; + @Inject protected PasswordController passwordController; @Inject @@ -91,6 +94,11 @@ public class ChangePasswordActivity extends BaseActivity newPasswordConfirmation.addTextChangedListener(tw); newPasswordConfirmation.setOnEditorActionListener(this); changePasswordButton.setOnClickListener(this); + + if (containsContextResultHandler(TAG_PASSWORD_CHANGE)) { + changePasswordButton.setVisibility(INVISIBLE); + progress.setVisibility(VISIBLE); + } } @Override @@ -131,22 +139,27 @@ public class ChangePasswordActivity extends BaseActivity // Replace the button with a progress bar changePasswordButton.setVisibility(INVISIBLE); progress.setVisibility(VISIBLE); + passwordController.changePassword(currentPassword.getText().toString(), newPassword.getText().toString(), - new UiResultHandler<Boolean>(this) { + new UiContextResultHandler<Boolean>(this, TAG_PASSWORD_CHANGE) { @Override - public void onResultUi(@NonNull Boolean result) { + public void onResultUi(@NonNull Boolean result, + @NonNull DestroyableContextManager context) { + ChangePasswordActivity cpa = + (ChangePasswordActivity) getContextManager(); if (result) { - Toast.makeText(ChangePasswordActivity.this, - R.string.password_changed, + Toast.makeText(cpa, R.string.password_changed, Toast.LENGTH_LONG).show(); - setResult(RESULT_OK); - finish(); + cpa.setResult(RESULT_OK); + cpa.finish(); } else { - tryAgain(); + cpa.tryAgain(); } } + }); + } private void tryAgain() { diff --git a/briar-android/src/org/briarproject/android/NavDrawerActivity.java b/briar-android/src/org/briarproject/android/NavDrawerActivity.java index c80310aa0cac726e87c3c3801544a8cd611018f3..571a2251311bc4ee875ee29c9fdab73cef672a99 100644 --- a/briar-android/src/org/briarproject/android/NavDrawerActivity.java +++ b/briar-android/src/org/briarproject/android/NavDrawerActivity.java @@ -129,6 +129,12 @@ public class NavDrawerActivity extends BriarFragmentActivity implements if (getIntent() != null) { onNewIntent(getIntent()); } + + if (containsContextResultHandler(TAG_SIGN_OUT)) { + // User is signing out of Briar and rotated the device before the + // operation could finish, restore the UI state + showLoadingScreen(true, R.string.progress_title_logout); + } } private void welcomeMessageCheck() { diff --git a/briar-android/src/org/briarproject/android/PasswordActivity.java b/briar-android/src/org/briarproject/android/PasswordActivity.java index 751b6adcdb97b7dff491fdefc13a3f1dea512786..ea8b634dba908d8e4042ecd77fa8036846a57f3e 100644 --- a/briar-android/src/org/briarproject/android/PasswordActivity.java +++ b/briar-android/src/org/briarproject/android/PasswordActivity.java @@ -18,9 +18,12 @@ import android.widget.TextView.OnEditorActionListener; import org.briarproject.R; import org.briarproject.android.controller.PasswordController; -import org.briarproject.android.controller.handler.UiResultHandler; +import org.briarproject.android.controller.handler.DestroyableContextManager; +import org.briarproject.android.controller.handler.UiContextResultHandler; import org.briarproject.android.util.AndroidUtils; +import java.util.logging.Logger; + import javax.inject.Inject; import static android.content.Intent.ACTION_MAIN; @@ -30,6 +33,11 @@ import static android.view.View.VISIBLE; public class PasswordActivity extends BaseActivity { + private static final String TAG_PASSWORD = "briar.PASSWORD"; + + private static final Logger LOG = + Logger.getLogger(NavDrawerActivity.class.getName()); + @Inject protected PasswordController passwordController; @@ -77,6 +85,12 @@ public class PasswordActivity extends BaseActivity { public void afterTextChanged(Editable s) { } }); + if (containsContextResultHandler(TAG_PASSWORD)) { + signInButton.setVisibility(INVISIBLE); + progress.setVisibility(VISIBLE); + } + + LOG.info("not tryAgain() " + this.hashCode()); } @Override @@ -125,21 +139,28 @@ public class PasswordActivity extends BaseActivity { hideSoftKeyboard(password); signInButton.setVisibility(INVISIBLE); progress.setVisibility(VISIBLE); - passwordController.validatePassword(password.getText().toString(), - new UiResultHandler<Boolean>(this) { + + UiContextResultHandler<Boolean> crh = + new UiContextResultHandler<Boolean>(this, TAG_PASSWORD) { @Override - public void onResultUi(@NonNull Boolean result) { + public void onResultUi(@NonNull Boolean result, + @NonNull DestroyableContextManager context) { + PasswordActivity pa = + ((PasswordActivity) getContextManager()); if (result) { - setResult(RESULT_OK); - finish(); + pa.setResult(RESULT_OK); + pa.finish(); } else { - tryAgain(); + pa.tryAgain(); } } - }); + + }; + passwordController.validatePassword(password.getText().toString(), crh); } private void tryAgain() { + LOG.info("tryAgain() " + this.hashCode()); AndroidUtils.setError(input, getString(R.string.try_again), true); signInButton.setVisibility(VISIBLE); progress.setVisibility(INVISIBLE); diff --git a/briar-android/src/org/briarproject/android/SetupActivity.java b/briar-android/src/org/briarproject/android/SetupActivity.java index 0dcce3d72a28a3d4eeed9bee8584cf1c97e38a99..92bfefbdd182ffd3e28b1fe7bd157880e65c595f 100644 --- a/briar-android/src/org/briarproject/android/SetupActivity.java +++ b/briar-android/src/org/briarproject/android/SetupActivity.java @@ -2,6 +2,7 @@ package org.briarproject.android; import android.content.Intent; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.design.widget.TextInputLayout; import android.text.Editable; import android.text.TextWatcher; @@ -16,7 +17,8 @@ import android.widget.TextView.OnEditorActionListener; import org.briarproject.R; import org.briarproject.android.controller.SetupController; -import org.briarproject.android.controller.handler.UiResultHandler; +import org.briarproject.android.controller.handler.DestroyableContextManager; +import org.briarproject.android.controller.handler.UiContextResultHandler; import org.briarproject.android.util.AndroidUtils; import org.briarproject.android.util.StrengthMeter; import org.briarproject.util.StringUtils; @@ -33,6 +35,8 @@ import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENG public class SetupActivity extends BaseActivity implements OnClickListener, OnEditorActionListener { + protected static final String TAG_SETUP = "briar.SETUP"; + @Inject protected SetupController setupController; @@ -87,6 +91,14 @@ public class SetupActivity extends BaseActivity implements OnClickListener, passwordConfirmation.addTextChangedListener(tw); passwordConfirmation.setOnEditorActionListener(this); createAccountButton.setOnClickListener(this); + + if (containsContextResultHandler(TAG_SETUP)) { + // Activity has been re-created due to an orientation change, + // update the result handler with the current context and restore + // the UI state + createAccountButton.setVisibility(INVISIBLE); + progress.setVisibility(VISIBLE); + } } @Override @@ -135,13 +147,16 @@ public class SetupActivity extends BaseActivity implements OnClickListener, String nickname = nicknameEntry.getText().toString(); String password = passwordEntry.getText().toString(); - setupController.storeAuthorInfo(nickname, password, - new UiResultHandler<Void>(this) { - @Override - public void onResultUi(Void result) { - showMain(); - } - }); + setupController + .storeAuthorInfo(nickname, password, + new UiContextResultHandler<Void>(this, TAG_SETUP) { + @Override + public void onResultUi(@NonNull Void result, + @NonNull DestroyableContextManager context) { + ((SetupActivity)context).showMain(); + } + + }); } private void showMain() { diff --git a/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java b/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java index f49d6485f7b58e4673e06f4f40e1125275e85610..b3d834c54c731910ebfa754b388b7fc76aa4c7cf 100644 --- a/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java +++ b/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java @@ -71,6 +71,7 @@ public class BriarControllerImpl implements BriarController { @Override public void run() { try { + Thread.sleep(5000); // Wait for the service to finish starting up IBinder binder = serviceConnection.waitForBinder(); BriarService service = diff --git a/briar-android/src/org/briarproject/android/controller/handler/ContextResultHandler.java b/briar-android/src/org/briarproject/android/controller/handler/ContextResultHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..94fc446afc2a85b4c1357ae9571112ee19be9d91 --- /dev/null +++ b/briar-android/src/org/briarproject/android/controller/handler/ContextResultHandler.java @@ -0,0 +1,7 @@ +package org.briarproject.android.controller.handler; + +public interface ContextResultHandler<R> extends ResultHandler<R> { + void setDestroyableContextManager(DestroyableContextManager listener); + String getTag(); + DestroyableContextManager getContextManager(); +} diff --git a/briar-android/src/org/briarproject/android/controller/handler/DestroyableContextManager.java b/briar-android/src/org/briarproject/android/controller/handler/DestroyableContextManager.java new file mode 100644 index 0000000000000000000000000000000000000000..c5d0652f3f2d61a18ca4fc97f28456c8a5e33399 --- /dev/null +++ b/briar-android/src/org/briarproject/android/controller/handler/DestroyableContextManager.java @@ -0,0 +1,12 @@ +package org.briarproject.android.controller.handler; + +import org.briarproject.android.DestroyableContext; + +public interface DestroyableContextManager extends DestroyableContext { + + void addContextResultHandler(ContextResultHandler crh); + + void removeContextResultHandler(String tag); + + boolean containsContextResultHandler(String tag); +} diff --git a/briar-android/src/org/briarproject/android/controller/handler/UiContextExceptionResultHandler.java b/briar-android/src/org/briarproject/android/controller/handler/UiContextExceptionResultHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..dca6213f333adbbbc049c6d9337f4e0935ac7be9 --- /dev/null +++ b/briar-android/src/org/briarproject/android/controller/handler/UiContextExceptionResultHandler.java @@ -0,0 +1,68 @@ +package org.briarproject.android.controller.handler; + +import android.support.annotation.Nullable; +import android.support.annotation.UiThread; + +import org.briarproject.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +/** + * This class defines a result handler with a callback that runs on the UI thread + * and is retained when orientation changes occur. It ensures that the callback + * is always run in the latest context. + * <p> + * Note that this event handler should be used carefully with callbacks that + * depend on global variables as those variables might be destroyed or lose their + * state during the orientation change. + * + * @param <R> The result's object type + */ +@Immutable +@NotNullByDefault +public abstract class UiContextExceptionResultHandler<R, E extends Exception> + extends UiContextResultHandler<R> + implements ResultExceptionHandler<R, E> { + + @Nullable + private E exception; + + protected UiContextExceptionResultHandler( + DestroyableContextManager listener, String tag) { + super(listener, tag); + } + + @Override + public void setDestroyableContextManager( + DestroyableContextManager listener) { + boolean isSwitchingFromNullToNonNull = + this.listener == null && listener != null; + super.setDestroyableContextManager(listener); + if (isSwitchingFromNullToNonNull) + runException(); + } + + @Override + public void onException(final E exception) { + this.exception = exception; + listener.runOnUiThreadUnlessDestroyed(new Runnable() { + @Override + public void run() { + runException(); + } + }); + } + + @UiThread + private void runException() { + if (exception != null && listener != null) { + onExceptionUi(exception, listener); + listener.removeContextResultHandler(getTag()); + exception = null; + } + } + + @UiThread + public abstract void onExceptionUi(E exception, + DestroyableContextManager context); +} diff --git a/briar-android/src/org/briarproject/android/controller/handler/UiContextResultHandler.java b/briar-android/src/org/briarproject/android/controller/handler/UiContextResultHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..e6a3f2df0f6943560908e2bdb7e19ccaa811571a --- /dev/null +++ b/briar-android/src/org/briarproject/android/controller/handler/UiContextResultHandler.java @@ -0,0 +1,84 @@ +package org.briarproject.android.controller.handler; + +import android.support.annotation.Nullable; +import android.support.annotation.UiThread; + +import org.briarproject.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +/** + * This class defines a result handler with a callback that runs on the UI thread + * and is retained when orientation changes occur. It ensures that the callback + * is always run in the latest context. + * <p> + * Note that this event handler should be used carefully with callbacks that + * depend on global variables as those variables might be destroyed or lose their + * state during the orientation change. + * + * @param <R> The result's object type + */ +@Immutable +@NotNullByDefault +public abstract class UiContextResultHandler<R> + implements ContextResultHandler<R> { + + private final String tag; + protected DestroyableContextManager listener; + @Nullable + private R result; + + @UiThread + protected UiContextResultHandler(DestroyableContextManager listener, + String tag) { + this.listener = listener; + this.tag = tag; + listener.addContextResultHandler(this); + } + + @UiThread + @Override + public void setDestroyableContextManager( + DestroyableContextManager listener) { + // Check if the listener is switching from null to non null + boolean isSwitchingFromNullToNonNull = + this.listener == null && listener != null; + this.listener = listener; + if (isSwitchingFromNullToNonNull) + runResult(); + } + + @Override + public String getTag() { + return tag; + } + + @Override + public DestroyableContextManager getContextManager() { + return listener; + } + + @Override + public void onResult(final R result) { + this.result = result; + listener.runOnUiThreadUnlessDestroyed(new Runnable() { + @Override + public void run() { + runResult(); + } + }); + } + + @UiThread + private void runResult() { + if (result != null && listener != null) { + onResultUi(result, listener); + listener.removeContextResultHandler(tag); + result = null; + } + } + + @UiThread + public abstract void onResultUi(R result, + DestroyableContextManager context); +} diff --git a/briar-android/src/org/briarproject/android/forum/ForumActivity.java b/briar-android/src/org/briarproject/android/forum/ForumActivity.java index 0fe164367f3e1b8c26bd18f64e15ad88d59e8cf9..941ce6c7f7950219f0cf8a28eea7c643724c983e 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumActivity.java +++ b/briar-android/src/org/briarproject/android/forum/ForumActivity.java @@ -18,7 +18,8 @@ import android.widget.Toast; import org.briarproject.R; import org.briarproject.android.ActivityComponent; -import org.briarproject.android.controller.handler.UiResultExceptionHandler; +import org.briarproject.android.controller.handler.DestroyableContextManager; +import org.briarproject.android.controller.handler.UiContextExceptionResultHandler; import org.briarproject.android.sharing.ForumSharingStatusActivity; import org.briarproject.android.sharing.ShareForumActivity; import org.briarproject.android.threaded.ThreadItemAdapter; @@ -44,6 +45,7 @@ public class ForumActivity extends ThreadListActivity<Forum, ThreadItemAdapter<ForumItem>, ForumItem, ForumPostHeader> { private static final int REQUEST_FORUM_SHARED = 3; + private static final String TAG_FORUM = "briar.FORUM"; @Inject ForumController forumController; @@ -168,19 +170,22 @@ public class ForumActivity extends private void deleteForum() { forumController.deleteNamedGroup( - new UiResultExceptionHandler<Void, DbException>(this) { + new UiContextExceptionResultHandler<Void, DbException>(this, + TAG_FORUM) { @Override - public void onResultUi(Void v) { - Toast.makeText(ForumActivity.this, + public void onResultUi(Void result, + DestroyableContextManager context) { + Toast.makeText((ForumActivity)context, R.string.forum_left_toast, LENGTH_SHORT).show(); } @Override - public void onExceptionUi(DbException exception) { - // TODO proper error handling - finish(); + public void onExceptionUi(DbException exception, + DestroyableContextManager context) { + ((ForumActivity)context).finish(); } }); + } } diff --git a/briar-android/src/org/briarproject/android/privategroup/creation/BaseGroupInviteActivity.java b/briar-android/src/org/briarproject/android/privategroup/creation/BaseGroupInviteActivity.java index 2f7125331bd0182ae0d897723fe662c6ef726414..1b4c81eb0c6b47e6280d0ed3780e54dc6ce4d446 100644 --- a/briar-android/src/org/briarproject/android/privategroup/creation/BaseGroupInviteActivity.java +++ b/briar-android/src/org/briarproject/android/privategroup/creation/BaseGroupInviteActivity.java @@ -2,7 +2,8 @@ package org.briarproject.android.privategroup.creation; import org.briarproject.R; import org.briarproject.android.contactselection.ContactSelectorActivity; -import org.briarproject.android.controller.handler.UiResultExceptionHandler; +import org.briarproject.android.controller.handler.DestroyableContextManager; +import org.briarproject.android.controller.handler.UiContextExceptionResultHandler; import org.briarproject.android.sharing.BaseMessageFragment.MessageFragmentListener; import org.briarproject.api.contact.ContactId; import org.briarproject.api.db.DbException; @@ -21,6 +22,8 @@ import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_ public abstract class BaseGroupInviteActivity extends ContactSelectorActivity implements MessageFragmentListener { + private static final String TAG_GROUP_INVITEE = "briar.GROUP_INVITEE"; + @Inject CreateGroupController controller; @@ -43,19 +46,26 @@ public abstract class BaseGroupInviteActivity public boolean onButtonClick(@NotNull String message) { if (groupId == null) throw new IllegalStateException("GroupId was not initialized"); + controller.sendInvitation(groupId, contacts, message, - new UiResultExceptionHandler<Void, DbException>(this) { + new UiContextExceptionResultHandler<Void, DbException>(this, + TAG_GROUP_INVITEE) { @Override - public void onResultUi(Void result) { - setResult(RESULT_OK); - supportFinishAfterTransition(); + public void onExceptionUi(DbException exception, + DestroyableContextManager context) { + ((BaseGroupInviteActivity) context) + .setResult(RESULT_CANCELED); + ((BaseGroupInviteActivity) context) + .finish(); } @Override - public void onExceptionUi(DbException exception) { - // TODO proper error handling - setResult(RESULT_CANCELED); - finish(); + public void onResultUi(Void result, + DestroyableContextManager context) { + ((BaseGroupInviteActivity) context) + .setResult(RESULT_OK); + ((BaseGroupInviteActivity) context) + .supportFinishAfterTransition(); } }); return true; diff --git a/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupActivity.java b/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupActivity.java index 461989c81c91c04d433a5bf65facb72f52346b85..7ecb06c4c8a376cac7d7e53c04d02bee3c4d5b1e 100644 --- a/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupActivity.java +++ b/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupActivity.java @@ -7,7 +7,8 @@ import android.support.v4.app.ActivityOptionsCompat; import org.briarproject.R; import org.briarproject.android.ActivityComponent; -import org.briarproject.android.controller.handler.UiResultExceptionHandler; +import org.briarproject.android.controller.handler.DestroyableContextManager; +import org.briarproject.android.controller.handler.UiContextExceptionResultHandler; import org.briarproject.android.privategroup.conversation.GroupActivity; import org.briarproject.android.sharing.BaseMessageFragment.MessageFragmentListener; import org.briarproject.api.db.DbException; @@ -18,6 +19,8 @@ import static android.support.v4.app.ActivityOptionsCompat.makeCustomAnimation; public class CreateGroupActivity extends BaseGroupInviteActivity implements CreateGroupListener, MessageFragmentListener { + private static final String TAG_CREATE_GROUP = "briar.CREATE_GROUP"; + @Override public void injectActivity(ActivityComponent component) { component.inject(this); @@ -49,17 +52,20 @@ public class CreateGroupActivity extends BaseGroupInviteActivity implements @Override public void onGroupNameChosen(String name) { controller.createGroup(name, - new UiResultExceptionHandler<GroupId, DbException>(this) { + new UiContextExceptionResultHandler<GroupId, DbException>(this, + TAG_CREATE_GROUP) { @Override - public void onResultUi(GroupId g) { - groupId = g; - switchToContactSelectorFragment(g); + public void onExceptionUi(DbException exception, + DestroyableContextManager context) { + ((CreateGroupActivity) context).finish(); } @Override - public void onExceptionUi(DbException exception) { - // TODO proper error handling - finish(); + public void onResultUi(GroupId g, + DestroyableContextManager context) { + ((CreateGroupActivity) context).groupId = g; + ((CreateGroupActivity) context) + .switchToContactSelectorFragment(g); } }); }