From 3f5c03f1efabe71b6dad024fbebc8374ee544c77 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 29 Apr 2021 13:54:41 +0200 Subject: [PATCH 1/4] Start the reauth webview also when there is no getParentController() Signed-off-by: Joas Schilling --- .../talk/controllers/ConversationsListController.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java b/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java index 3c2e47718..d91d7f013 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java @@ -23,6 +23,7 @@ package com.nextcloud.talk.controllers; import android.animation.AnimatorInflater; +import android.annotation.SuppressLint; import android.app.SearchManager; import android.content.Context; import android.content.Intent; @@ -32,6 +33,7 @@ import android.os.Bundle; import android.os.Handler; import android.text.InputType; import android.text.TextUtils; +import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -400,6 +402,7 @@ public class ConversationsListController extends BaseController implements Searc searchItem.expandActionView(); } + @SuppressLint("LongLogTag") private void fetchData(boolean fromBottomSheet) { dispose(null); @@ -478,11 +481,18 @@ public class ConversationsListController extends BaseController implements Searc case 401: if (getParentController() != null && getParentController().getRouter() != null) { + Log.d(TAG, "Starting reauth webview via getParentController()"); getParentController().getRouter().pushController((RouterTransaction.with (new WebViewLoginController(currentUser.getBaseUrl(), true)) .pushChangeHandler(new VerticalChangeHandler()) .popChangeHandler(new VerticalChangeHandler()))); + } else { + Log.d(TAG, "Starting reauth webview via ConversationsListController"); + getRouter().pushController(RouterTransaction.with( + new WebViewLoginController(currentUser.getBaseUrl(), true)) + .pushChangeHandler(new VerticalChangeHandler()) + .popChangeHandler(new VerticalChangeHandler())); } break; default: From cb11c3640047909dd6c9026a6149d87a84d611ea Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 29 Apr 2021 16:13:23 +0200 Subject: [PATCH 2/4] Pop a dialog to log in again or delete the account Signed-off-by: Joas Schilling --- .../ConversationsListController.java | 71 +++++++++++++++---- .../controllers/WebViewLoginController.java | 13 +++- app/src/main/res/values/strings.xml | 2 + 3 files changed, 68 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java b/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java index d91d7f013..047941946 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java @@ -87,6 +87,7 @@ import com.nextcloud.talk.events.BottomSheetLockEvent; import com.nextcloud.talk.events.EventStatus; import com.nextcloud.talk.events.MoreMenuClickEvent; import com.nextcloud.talk.interfaces.ConversationMenuInterface; +import com.nextcloud.talk.jobs.AccountRemovalWorker; import com.nextcloud.talk.jobs.ContactAddressBookWorker; import com.nextcloud.talk.jobs.DeleteConversationWorker; import com.nextcloud.talk.models.database.UserEntity; @@ -234,7 +235,7 @@ public class ConversationsListController extends BaseController implements Searc } ImageRequest imageRequest = DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithNameAndPixels(currentUser.getBaseUrl(), - currentUser.getUserId(), avatarSize), currentUser); + currentUser.getUserId(), avatarSize), currentUser); ImagePipeline imagePipeline = Fresco.getImagePipeline(); DataSource> dataSource = imagePipeline.fetchDecodedImage(imageRequest, null); @@ -333,7 +334,7 @@ public class ConversationsListController extends BaseController implements Searc DisplayUtils.applyColorToStatusBar( activity, ResourcesCompat.getColor(getResources(), R.color.appbar, null) - ); + ); } }); } @@ -345,7 +346,7 @@ public class ConversationsListController extends BaseController implements Searc DisplayUtils.applyColorToStatusBar( activity, ResourcesCompat.getColor(getResources(), R.color.bg_default, null) - ); + ); } } else { searchView.post(() -> searchView.setQuery("", true)); @@ -367,19 +368,19 @@ public class ConversationsListController extends BaseController implements Searc activity.appBar.setStateListAnimator(AnimatorInflater.loadStateListAnimator( activity.appBar.getContext(), R.animator.appbar_elevation_off) - ); + ); activity.toolbar.setVisibility(View.GONE); activity.searchCardView.setVisibility(View.VISIBLE); if (getResources() != null) { DisplayUtils.applyColorToStatusBar( activity, ResourcesCompat.getColor(getResources(), R.color.bg_default, null) - ); + ); } } SmoothScrollLinearLayoutManager layoutManager = (SmoothScrollLinearLayoutManager) recyclerView.getLayoutManager(); - if (layoutManager!=null) { + if (layoutManager != null) { layoutManager.scrollToPositionWithOffset(0, 0); } return true; @@ -465,7 +466,7 @@ public class ConversationsListController extends BaseController implements Searc } else { Collections.sort(callItems, (callItem, t1) -> Long.compare(((CallItem) t1).getModel().getLastPing(), - ((CallItem) callItem).getModel().getLastPing())); + ((CallItem) callItem).getModel().getLastPing())); } adapter.updateDataSet(callItems, false); @@ -484,15 +485,12 @@ public class ConversationsListController extends BaseController implements Searc Log.d(TAG, "Starting reauth webview via getParentController()"); getParentController().getRouter().pushController((RouterTransaction.with (new WebViewLoginController(currentUser.getBaseUrl(), - true)) + true)) .pushChangeHandler(new VerticalChangeHandler()) .popChangeHandler(new VerticalChangeHandler()))); } else { Log.d(TAG, "Starting reauth webview via ConversationsListController"); - getRouter().pushController(RouterTransaction.with( - new WebViewLoginController(currentUser.getBaseUrl(), true)) - .pushChangeHandler(new VerticalChangeHandler()) - .popChangeHandler(new VerticalChangeHandler())); + showUnauthorizedDialog(); } break; default: @@ -736,7 +734,7 @@ public class ConversationsListController extends BaseController implements Searc if (currentUser.hasSpreedFeatureCapability("chat-v2")) { bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(), Parcels.wrap(conversation)); ConductorRemapping.INSTANCE.remapChatController(getRouter(), currentUser.getId(), - conversation.getToken(), bundle, false); + conversation.getToken(), bundle, false); } else { overridePushHandler(new NoOpControllerChangeHandler()); overridePopHandler(new NoOpControllerChangeHandler()); @@ -793,7 +791,7 @@ public class ConversationsListController extends BaseController implements Searc new LovelyStandardDialog(getActivity(), LovelyStandardDialog.ButtonLayout.HORIZONTAL) .setTopColorRes(R.color.nc_darkRed) .setIcon(DisplayUtils.getTintedDrawable(context.getResources(), - R.drawable.ic_delete_black_24dp, R.color.bg_default)) + R.drawable.ic_delete_black_24dp, R.color.bg_default)) .setPositiveButtonColor(context.getResources().getColor(R.color.nc_darkRed)) .setTitle(R.string.nc_delete_call) .setMessage(conversation.getDeleteWarningMessage()) @@ -802,7 +800,7 @@ public class ConversationsListController extends BaseController implements Searc public void onClick(View v) { Data.Builder data = new Data.Builder(); data.putLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), - conversationMenuBundle.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID())); + conversationMenuBundle.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID())); data.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), conversation.getToken()); conversationMenuBundle = null; deleteConversation(data.build()); @@ -821,6 +819,49 @@ public class ConversationsListController extends BaseController implements Searc } } + private void showUnauthorizedDialog() { + if (getActivity() != null) { + + new LovelyStandardDialog(getActivity(), LovelyStandardDialog.ButtonLayout.HORIZONTAL) + .setTopColorRes(R.color.nc_darkRed) + .setIcon(DisplayUtils.getTintedDrawable(context.getResources(), + R.drawable.ic_delete_black_24dp, R.color.bg_default)) + .setPositiveButtonColor(context.getResources().getColor(R.color.nc_darkRed)) + .setTitle(R.string.nc_dialog_invalid_password) + .setMessage(R.string.nc_dialog_reauth_or_delete) + .setPositiveButton(R.string.nc_delete, new View.OnClickListener() { + @Override + public void onClick(View v) { + boolean otherUserExists = userUtils.scheduleUserForDeletionWithId(currentUser.getId()); + + OneTimeWorkRequest accountRemovalWork = new OneTimeWorkRequest.Builder(AccountRemovalWorker.class).build(); + WorkManager.getInstance().enqueue(accountRemovalWork); + + if (otherUserExists && getView() != null) { + onViewBound(getView()); + onAttach(getView()); + } else if (!otherUserExists) { + getRouter().setRoot(RouterTransaction.with( + new ServerSelectionController()) + .pushChangeHandler(new VerticalChangeHandler()) + .popChangeHandler(new VerticalChangeHandler())); + } + } + }) + .setNegativeButton(R.string.nc_settings_reauthorize, new View.OnClickListener() { + @Override + public void onClick(View v) { + getRouter().pushController(RouterTransaction.with( + new WebViewLoginController(currentUser.getBaseUrl(), true)) + .pushChangeHandler(new VerticalChangeHandler()) + .popChangeHandler(new VerticalChangeHandler())); + } + }) + .setInstanceStateHandler(ID_DELETE_CONVERSATION_DIALOG, saveStateHandler) + .show(); + } + } + private void deleteConversation(Data data) { OneTimeWorkRequest deleteConversationWorker = new OneTimeWorkRequest.Builder(DeleteConversationWorker.class).setInputData(data).build(); diff --git a/app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.java b/app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.java index 11ac36f9a..a3e4f560b 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.java @@ -35,6 +35,7 @@ import android.view.View; import android.view.ViewGroup; import android.webkit.*; import android.widget.ProgressBar; + import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.res.ResourcesCompat; @@ -42,6 +43,7 @@ import androidx.work.OneTimeWorkRequest; import androidx.work.WorkManager; import autodagger.AutoInjector; import butterknife.BindView; + import com.bluelinelabs.conductor.RouterTransaction; import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; import com.nextcloud.talk.R; @@ -64,9 +66,11 @@ import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; import io.requery.Persistable; import io.requery.reactivex.ReactiveEntityStore; + import org.greenrobot.eventbus.EventBus; import javax.inject.Inject; + import java.lang.reflect.Field; import java.net.CookieManager; import java.net.URLDecoder; @@ -233,9 +237,9 @@ public class WebViewLoginController extends BaseController { webView.loadUrl("javascript:var justStore = document.getElementById('user').value = '" + username + "';"); } else { webView.loadUrl("javascript: {" + - "document.getElementById('user').value = '" + username + "';" + - "document.getElementById('password').value = '" + password + "';" + - "document.getElementById('submit').click(); };"); + "document.getElementById('user').value = '" + username + "';" + + "document.getElementById('password').value = '" + password + "';" + + "document.getElementById('submit').click(); };"); } } } @@ -406,6 +410,9 @@ public class WebViewLoginController extends BaseController { } } else { if (finalMessageType != null) { + // FIXME when the user registers a new account that was setup before (aka + // ApplicationWideMessageHolder.MessageType.ACCOUNT_UPDATED_NOT_ADDED) + // The token is not updated in the database and therefor the account not visible/usable ApplicationWideMessageHolder.getInstance().setMessageType(finalMessageType); } getRouter().popToRoot(); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 33297aa52..0c1b0632d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -409,4 +409,6 @@ Failed to save %1$s selected %1$s (%2$d) + Invalid password + Do you want to reauthorize or delete this account? From c2032b65541ab3776592a7085c73a5451ea498a5 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 30 Apr 2021 14:46:25 +0200 Subject: [PATCH 3/4] extract methods and add log commands in AccountRemovalWorker Signed-off-by: Marcel Hibbe --- .../talk/jobs/AccountRemovalWorker.java | 205 ++++++++---------- 1 file changed, 91 insertions(+), 114 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/AccountRemovalWorker.java b/app/src/main/java/com/nextcloud/talk/jobs/AccountRemovalWorker.java index aec901033..4b526c8e7 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/AccountRemovalWorker.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/AccountRemovalWorker.java @@ -96,7 +96,6 @@ public class AccountRemovalWorker extends Worker { ncApi = retrofit.newBuilder().client(okHttpClient.newBuilder().cookieJar(new JavaNetCookieJar(new CookieManager())).build()).build().create(NcApi.class); - String finalCredentials = credentials; ncApi.unregisterDeviceForNotificationsWithNextcloud(credentials, ApiUtils.getUrlNextcloudPush(userEntity .getBaseUrl())) .blockingSubscribe(new Observer() { @@ -114,90 +113,13 @@ public class AccountRemovalWorker extends Worker { queryMap.put("userPublicKey", finalPushConfigurationState.getUserPublicKey()); queryMap.put("deviceIdentifierSignature", finalPushConfigurationState.getDeviceIdentifierSignature()); - - ncApi.unregisterDeviceForNotificationsWithProxy - (ApiUtils.getUrlPushProxy(), queryMap) - .subscribe(new Observer() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onNext(Void aVoid) { - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - String groupName = String.format(getApplicationContext().getResources() - .getString(R.string - .nc_notification_channel), userEntity.getUserId(), userEntity.getBaseUrl()); - CRC32 crc32 = new CRC32(); - crc32.update(groupName.getBytes()); - NotificationManager notificationManager = - (NotificationManager) getApplicationContext().getSystemService - (Context.NOTIFICATION_SERVICE); - - if (notificationManager != null) { - notificationManager.deleteNotificationChannelGroup(Long - .toString(crc32.getValue())); - } - } - - WebSocketConnectionHelper.deleteExternalSignalingInstanceForUserEntity(userEntity.getId()); - - arbitraryStorageUtils.deleteAllEntriesForAccountIdentifier(userEntity.getId()).subscribe(new Observer() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onNext(Object o) { - userUtils.deleteUser(userEntity.getId()).subscribe(new CompletableObserver() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onComplete() { - - } - - @Override - public void onError(Throwable e) { - - } - }); - } - - @Override - public void onError(Throwable e) { - - } - - @Override - public void onComplete() { - - } - }); - } - - @Override - public void onError(Throwable e) { - - } - - @Override - public void onComplete() { - - } - }); + unregisterDeviceForNotificationWithProxy(queryMap, userEntity); } } @Override public void onError(Throwable e) { - + Log.e(TAG, "error while trying to unregister Device For Notifications", e); } @Override @@ -206,46 +128,101 @@ public class AccountRemovalWorker extends Worker { } }); } else { - userUtils.deleteUser(userEntity.getId()) - .subscribe(new CompletableObserver() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onComplete() { - - } - - @Override - public void onError(Throwable e) { - - } - }); + deleteUser(userEntity); } } catch (IOException e) { Log.d(TAG, "Something went wrong while removing job at parsing PushConfigurationState"); - userUtils.deleteUser(userEntity.getId()) - .subscribe(new CompletableObserver() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onComplete() { - - } - - @Override - public void onError(Throwable e) { - - } - }); + deleteUser(userEntity); } } return Result.success(); } + + private void unregisterDeviceForNotificationWithProxy(HashMap queryMap, UserEntity userEntity) { + ncApi.unregisterDeviceForNotificationsWithProxy + (ApiUtils.getUrlPushProxy(), queryMap) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(Void aVoid) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + String groupName = String.format(getApplicationContext().getResources() + .getString(R.string + .nc_notification_channel), userEntity.getUserId(), userEntity.getBaseUrl()); + CRC32 crc32 = new CRC32(); + crc32.update(groupName.getBytes()); + NotificationManager notificationManager = + (NotificationManager) getApplicationContext().getSystemService + (Context.NOTIFICATION_SERVICE); + + if (notificationManager != null) { + notificationManager.deleteNotificationChannelGroup(Long + .toString(crc32.getValue())); + } + } + WebSocketConnectionHelper.deleteExternalSignalingInstanceForUserEntity(userEntity.getId()); + deleteAllEntriesForAccountIdentifier(userEntity); + } + + @Override + public void onError(Throwable e) { + Log.e(TAG, "error while trying to unregister Device For Notification With Proxy", e); + } + + @Override + public void onComplete() { + + } + }); + } + + private void deleteAllEntriesForAccountIdentifier(UserEntity userEntity) { + arbitraryStorageUtils.deleteAllEntriesForAccountIdentifier(userEntity.getId()).subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(Object o) { + deleteUser(userEntity); + } + + @Override + public void onError(Throwable e) { + Log.e(TAG, "error while trying to delete All Entries For Account Identifier", e); + } + + @Override + public void onComplete() { + + } + }); + } + + private void deleteUser(UserEntity userEntity) { + String username = userEntity.getUsername(); + userUtils.deleteUser(userEntity.getId()) + .subscribe(new CompletableObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onComplete() { + Log.d(TAG, "deleted user: " + username); + } + + @Override + public void onError(Throwable e) { + Log.e(TAG, "error while trying to delete user", e); + } + }); + } } From 4f0a813512abc784d75309aa3259cb2e190c04c3 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 30 Apr 2021 15:35:20 +0200 Subject: [PATCH 4/4] set showUnauthorizedDialog to modal avoid crash when login view is shown after coming from showUnauthorizedDialog Signed-off-by: Marcel Hibbe --- .../talk/controllers/ConversationsListController.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java b/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java index 047941946..95b7e665d 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java @@ -263,7 +263,9 @@ public class ConversationsListController extends BaseController implements Searc @Override protected void onAttach(@NonNull View view) { super.onAttach(view); - eventBus.register(this); + if (!eventBus.isRegistered(this)) { + eventBus.register(this); + } currentUser = userUtils.getCurrentUser(); @@ -480,12 +482,10 @@ public class ConversationsListController extends BaseController implements Searc HttpException exception = (HttpException) throwable; switch (exception.code()) { case 401: - if (getParentController() != null && - getParentController().getRouter() != null) { + if (getParentController() != null && getParentController().getRouter() != null) { Log.d(TAG, "Starting reauth webview via getParentController()"); getParentController().getRouter().pushController((RouterTransaction.with - (new WebViewLoginController(currentUser.getBaseUrl(), - true)) + (new WebViewLoginController(currentUser.getBaseUrl(), true)) .pushChangeHandler(new VerticalChangeHandler()) .popChangeHandler(new VerticalChangeHandler()))); } else { @@ -827,6 +827,7 @@ public class ConversationsListController extends BaseController implements Searc .setIcon(DisplayUtils.getTintedDrawable(context.getResources(), R.drawable.ic_delete_black_24dp, R.color.bg_default)) .setPositiveButtonColor(context.getResources().getColor(R.color.nc_darkRed)) + .setCancelable(false) .setTitle(R.string.nc_dialog_invalid_password) .setMessage(R.string.nc_dialog_reauth_or_delete) .setPositiveButton(R.string.nc_delete, new View.OnClickListener() {