conversations-classic/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java
Daniel Gultsch 75c20a7a2b handle on-device contacts with unstable system uri
on device contacts (contacts not synced) have an unstable system uri.
For quicksy.im contacts we can identify the contact based on the phone number
instead.

fixes #4174
2021-09-21 10:20:23 +02:00

732 lines
30 KiB
Java

/*
* Copyright (c) 2018, Daniel Gultsch All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package eu.siacs.conversations.ui;
import static eu.siacs.conversations.ui.ConversationFragment.REQUEST_DECRYPT_PGP;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import org.openintents.openpgp.util.OpenPgpApi;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.OmemoSetting;
import eu.siacs.conversations.databinding.ActivityConversationsBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Conversational;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.interfaces.OnBackendConnected;
import eu.siacs.conversations.ui.interfaces.OnConversationArchived;
import eu.siacs.conversations.ui.interfaces.OnConversationRead;
import eu.siacs.conversations.ui.interfaces.OnConversationSelected;
import eu.siacs.conversations.ui.interfaces.OnConversationsListItemUpdated;
import eu.siacs.conversations.ui.util.ActionBarUtil;
import eu.siacs.conversations.ui.util.ActivityResult;
import eu.siacs.conversations.ui.util.ConversationMenuConfigurator;
import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
import eu.siacs.conversations.ui.util.PendingItem;
import eu.siacs.conversations.utils.EmojiWrapper;
import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.utils.SignupUtils;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
public class ConversationsActivity extends XmppActivity implements OnConversationSelected, OnConversationArchived, OnConversationsListItemUpdated, OnConversationRead, XmppConnectionService.OnAccountUpdate, XmppConnectionService.OnConversationUpdate, XmppConnectionService.OnRosterUpdate, OnUpdateBlocklist, XmppConnectionService.OnShowErrorToast, XmppConnectionService.OnAffiliationChanged {
public static final String ACTION_VIEW_CONVERSATION = "eu.siacs.conversations.action.VIEW";
public static final String EXTRA_CONVERSATION = "conversationUuid";
public static final String EXTRA_DOWNLOAD_UUID = "eu.siacs.conversations.download_uuid";
public static final String EXTRA_AS_QUOTE = "eu.siacs.conversations.as_quote";
public static final String EXTRA_NICK = "nick";
public static final String EXTRA_IS_PRIVATE_MESSAGE = "pm";
public static final String EXTRA_DO_NOT_APPEND = "do_not_append";
public static final String EXTRA_POST_INIT_ACTION = "post_init_action";
public static final String POST_ACTION_RECORD_VOICE = "record_voice";
private static final List<String> VIEW_AND_SHARE_ACTIONS = Arrays.asList(
ACTION_VIEW_CONVERSATION,
Intent.ACTION_SEND,
Intent.ACTION_SEND_MULTIPLE
);
public static final int REQUEST_OPEN_MESSAGE = 0x9876;
public static final int REQUEST_PLAY_PAUSE = 0x5432;
//secondary fragment (when holding the conversation, must be initialized before refreshing the overview fragment
private static final @IdRes
int[] FRAGMENT_ID_NOTIFICATION_ORDER = {R.id.secondary_fragment, R.id.main_fragment};
private final PendingItem<Intent> pendingViewIntent = new PendingItem<>();
private final PendingItem<ActivityResult> postponedActivityResult = new PendingItem<>();
private ActivityConversationsBinding binding;
private boolean mActivityPaused = true;
private final AtomicBoolean mRedirectInProcess = new AtomicBoolean(false);
private static boolean isViewOrShareIntent(Intent i) {
Log.d(Config.LOGTAG, "action: " + (i == null ? null : i.getAction()));
return i != null && VIEW_AND_SHARE_ACTIONS.contains(i.getAction()) && i.hasExtra(EXTRA_CONVERSATION);
}
private static Intent createLauncherIntent(Context context) {
final Intent intent = new Intent(context, ConversationsActivity.class);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
return intent;
}
@Override
protected void refreshUiReal() {
invalidateOptionsMenu();
for (@IdRes int id : FRAGMENT_ID_NOTIFICATION_ORDER) {
refreshFragment(id);
}
}
@Override
void onBackendConnected() {
if (performRedirectIfNecessary(true)) {
return;
}
xmppConnectionService.getNotificationService().setIsInForeground(true);
Intent intent = pendingViewIntent.pop();
if (intent != null) {
if (processViewIntent(intent)) {
if (binding.secondaryFragment != null) {
notifyFragmentOfBackendConnected(R.id.main_fragment);
}
invalidateActionBarTitle();
return;
}
}
for (@IdRes int id : FRAGMENT_ID_NOTIFICATION_ORDER) {
notifyFragmentOfBackendConnected(id);
}
ActivityResult activityResult = postponedActivityResult.pop();
if (activityResult != null) {
handleActivityResult(activityResult);
}
invalidateActionBarTitle();
if (binding.secondaryFragment != null && ConversationFragment.getConversation(getSupportFragmentManager()) == null) {
Conversation conversation = ConversationsOverviewFragment.getSuggestion(getSupportFragmentManager());
if (conversation != null) {
openConversation(conversation, null);
}
}
showDialogsIfMainIsOverview();
}
private boolean performRedirectIfNecessary(boolean noAnimation) {
return performRedirectIfNecessary(null, noAnimation);
}
private boolean performRedirectIfNecessary(final Conversation ignore, final boolean noAnimation) {
if (xmppConnectionService == null) {
return false;
}
boolean isConversationsListEmpty = xmppConnectionService.isConversationsListEmpty(ignore);
if (isConversationsListEmpty && mRedirectInProcess.compareAndSet(false, true)) {
final Intent intent = SignupUtils.getRedirectionIntent(this);
if (noAnimation) {
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
}
runOnUiThread(() -> {
startActivity(intent);
if (noAnimation) {
overridePendingTransition(0, 0);
}
});
}
return mRedirectInProcess.get();
}
private void showDialogsIfMainIsOverview() {
if (xmppConnectionService == null) {
return;
}
final Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_fragment);
if (fragment instanceof ConversationsOverviewFragment) {
if (ExceptionHelper.checkForCrash(this)) {
return;
}
openBatteryOptimizationDialogIfNeeded();
}
}
private String getBatteryOptimizationPreferenceKey() {
@SuppressLint("HardwareIds") String device = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
return "show_battery_optimization" + (device == null ? "" : device);
}
private void setNeverAskForBatteryOptimizationsAgain() {
getPreferences().edit().putBoolean(getBatteryOptimizationPreferenceKey(), false).apply();
}
private void openBatteryOptimizationDialogIfNeeded() {
if (hasAccountWithoutPush()
&& isOptimizingBattery()
&& android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M
&& getPreferences().getBoolean(getBatteryOptimizationPreferenceKey(), true)) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.battery_optimizations_enabled);
builder.setMessage(getString(R.string.battery_optimizations_enabled_dialog, getString(R.string.app_name)));
builder.setPositiveButton(R.string.next, (dialog, which) -> {
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
Uri uri = Uri.parse("package:" + getPackageName());
intent.setData(uri);
try {
startActivityForResult(intent, REQUEST_BATTERY_OP);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, R.string.device_does_not_support_battery_op, Toast.LENGTH_SHORT).show();
}
});
builder.setOnDismissListener(dialog -> setNeverAskForBatteryOptimizationsAgain());
final AlertDialog dialog = builder.create();
dialog.setCanceledOnTouchOutside(false);
dialog.show();
}
}
private boolean hasAccountWithoutPush() {
for (Account account : xmppConnectionService.getAccounts()) {
if (account.getStatus() == Account.State.ONLINE && !xmppConnectionService.getPushManagementService().available(account)) {
return true;
}
}
return false;
}
private void notifyFragmentOfBackendConnected(@IdRes int id) {
final Fragment fragment = getSupportFragmentManager().findFragmentById(id);
if (fragment instanceof OnBackendConnected) {
((OnBackendConnected) fragment).onBackendConnected();
}
}
private void refreshFragment(@IdRes int id) {
final Fragment fragment = getSupportFragmentManager().findFragmentById(id);
if (fragment instanceof XmppFragment) {
((XmppFragment) fragment).refresh();
}
}
private boolean processViewIntent(Intent intent) {
final String uuid = intent.getStringExtra(EXTRA_CONVERSATION);
final Conversation conversation = uuid != null ? xmppConnectionService.findConversationByUuid(uuid) : null;
if (conversation == null) {
Log.d(Config.LOGTAG, "unable to view conversation with uuid:" + uuid);
return false;
}
openConversation(conversation, intent.getExtras());
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
UriHandlerActivity.onRequestPermissionResult(this, requestCode, grantResults);
if (grantResults.length > 0) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
switch (requestCode) {
case REQUEST_OPEN_MESSAGE:
refreshUiReal();
ConversationFragment.openPendingMessage(getSupportFragmentManager());
break;
case REQUEST_PLAY_PAUSE:
ConversationFragment.startStopPending(getSupportFragmentManager());
break;
}
}
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
ActivityResult activityResult = ActivityResult.of(requestCode, resultCode, data);
if (xmppConnectionService != null) {
handleActivityResult(activityResult);
} else {
this.postponedActivityResult.push(activityResult);
}
}
private void handleActivityResult(ActivityResult activityResult) {
if (activityResult.resultCode == Activity.RESULT_OK) {
handlePositiveActivityResult(activityResult.requestCode, activityResult.data);
} else {
handleNegativeActivityResult(activityResult.requestCode);
}
}
private void handleNegativeActivityResult(int requestCode) {
Conversation conversation = ConversationFragment.getConversationReliable(getSupportFragmentManager());
switch (requestCode) {
case REQUEST_DECRYPT_PGP:
if (conversation == null) {
break;
}
conversation.getAccount().getPgpDecryptionService().giveUpCurrentDecryption();
break;
case REQUEST_BATTERY_OP:
setNeverAskForBatteryOptimizationsAgain();
break;
}
}
private void handlePositiveActivityResult(int requestCode, final Intent data) {
Conversation conversation = ConversationFragment.getConversationReliable(getSupportFragmentManager());
if (conversation == null) {
Log.d(Config.LOGTAG, "conversation not found");
return;
}
switch (requestCode) {
case REQUEST_DECRYPT_PGP:
conversation.getAccount().getPgpDecryptionService().continueDecryption(data);
break;
case REQUEST_CHOOSE_PGP_ID:
long id = data.getLongExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, 0);
if (id != 0) {
conversation.getAccount().setPgpSignId(id);
announcePgp(conversation.getAccount(), null, null, onOpenPGPKeyPublished);
} else {
choosePgpSignId(conversation.getAccount());
}
break;
case REQUEST_ANNOUNCE_PGP:
announcePgp(conversation.getAccount(), conversation, data, onOpenPGPKeyPublished);
break;
}
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ConversationMenuConfigurator.reloadFeatures(this);
OmemoSetting.load(this);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_conversations);
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
this.getSupportFragmentManager().addOnBackStackChangedListener(this::invalidateActionBarTitle);
this.getSupportFragmentManager().addOnBackStackChangedListener(this::showDialogsIfMainIsOverview);
this.initializeFragments();
this.invalidateActionBarTitle();
final Intent intent;
if (savedInstanceState == null) {
intent = getIntent();
} else {
intent = savedInstanceState.getParcelable("intent");
}
if (isViewOrShareIntent(intent)) {
pendingViewIntent.push(intent);
setIntent(createLauncherIntent(this));
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_conversations, menu);
final MenuItem qrCodeScanMenuItem = menu.findItem(R.id.action_scan_qr_code);
if (qrCodeScanMenuItem != null) {
if (isCameraFeatureAvailable()) {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_fragment);
boolean visible = getResources().getBoolean(R.bool.show_qr_code_scan)
&& fragment instanceof ConversationsOverviewFragment;
qrCodeScanMenuItem.setVisible(visible);
} else {
qrCodeScanMenuItem.setVisible(false);
}
}
return super.onCreateOptionsMenu(menu);
}
@Override
public void onConversationSelected(Conversation conversation) {
clearPendingViewIntent();
if (ConversationFragment.getConversation(getSupportFragmentManager()) == conversation) {
Log.d(Config.LOGTAG, "ignore onConversationSelected() because conversation is already open");
return;
}
openConversation(conversation, null);
}
public void clearPendingViewIntent() {
if (pendingViewIntent.clear()) {
Log.e(Config.LOGTAG, "cleared pending view intent");
}
}
private void displayToast(final String msg) {
runOnUiThread(() -> Toast.makeText(ConversationsActivity.this, msg, Toast.LENGTH_SHORT).show());
}
@Override
public void onAffiliationChangedSuccessful(Jid jid) {
}
@Override
public void onAffiliationChangeFailed(Jid jid, int resId) {
displayToast(getString(resId, jid.asBareJid().toString()));
}
private void openConversation(Conversation conversation, Bundle extras) {
final FragmentManager fragmentManager = getSupportFragmentManager();
executePendingTransactions(fragmentManager);
ConversationFragment conversationFragment = (ConversationFragment) fragmentManager.findFragmentById(R.id.secondary_fragment);
final boolean mainNeedsRefresh;
if (conversationFragment == null) {
mainNeedsRefresh = false;
final Fragment mainFragment = fragmentManager.findFragmentById(R.id.main_fragment);
if (mainFragment instanceof ConversationFragment) {
conversationFragment = (ConversationFragment) mainFragment;
} else {
conversationFragment = new ConversationFragment();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.main_fragment, conversationFragment);
fragmentTransaction.addToBackStack(null);
try {
fragmentTransaction.commit();
} catch (IllegalStateException e) {
Log.w(Config.LOGTAG, "sate loss while opening conversation", e);
//allowing state loss is probably fine since view intents et all are already stored and a click can probably be 'ignored'
return;
}
}
} else {
mainNeedsRefresh = true;
}
conversationFragment.reInit(conversation, extras == null ? new Bundle() : extras);
if (mainNeedsRefresh) {
refreshFragment(R.id.main_fragment);
} else {
invalidateActionBarTitle();
}
}
private static void executePendingTransactions(final FragmentManager fragmentManager) {
try {
fragmentManager.executePendingTransactions();
} catch (final Exception e) {
Log.e(Config.LOGTAG,"unable to execute pending fragment transactions");
}
}
public boolean onXmppUriClicked(Uri uri) {
XmppUri xmppUri = new XmppUri(uri);
if (xmppUri.isValidJid() && !xmppUri.hasFingerprints()) {
final Conversation conversation = xmppConnectionService.findUniqueConversationByJid(xmppUri);
if (conversation != null) {
openConversation(conversation, null);
return true;
}
}
return false;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (MenuDoubleTabUtil.shouldIgnoreTap()) {
return false;
}
switch (item.getItemId()) {
case android.R.id.home:
FragmentManager fm = getSupportFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
try {
fm.popBackStack();
} catch (IllegalStateException e) {
Log.w(Config.LOGTAG, "Unable to pop back stack after pressing home button");
}
return true;
}
break;
case R.id.action_scan_qr_code:
UriHandlerActivity.scan(this);
return true;
case R.id.action_search_all_conversations:
startActivity(new Intent(this, SearchActivity.class));
return true;
case R.id.action_search_this_conversation:
final Conversation conversation = ConversationFragment.getConversation(getSupportFragmentManager());
if (conversation == null) {
return true;
}
final Intent intent = new Intent(this, SearchActivity.class);
intent.putExtra(SearchActivity.EXTRA_CONVERSATION_UUID, conversation.getUuid());
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onKeyDown(final int keyCode, final KeyEvent keyEvent) {
if (keyCode == KeyEvent.KEYCODE_DPAD_UP && keyEvent.isCtrlPressed()) {
final ConversationFragment conversationFragment = ConversationFragment.get(getSupportFragmentManager());
if (conversationFragment != null && conversationFragment.onArrowUpCtrlPressed()) {
return true;
}
}
return super.onKeyDown(keyCode, keyEvent);
}
@Override
public void onSaveInstanceState(final Bundle savedInstanceState) {
final Intent pendingIntent = pendingViewIntent.peek();
savedInstanceState.putParcelable("intent", pendingIntent != null ? pendingIntent : getIntent());
super.onSaveInstanceState(savedInstanceState);
}
@Override
protected void onStart() {
super.onStart();
final int theme = findTheme();
if (this.mTheme != theme) {
this.mSkipBackgroundBinding = true;
recreate();
} else {
this.mSkipBackgroundBinding = false;
}
mRedirectInProcess.set(false);
}
@Override
protected void onNewIntent(final Intent intent) {
super.onNewIntent(intent);
if (isViewOrShareIntent(intent)) {
if (xmppConnectionService != null) {
clearPendingViewIntent();
processViewIntent(intent);
} else {
pendingViewIntent.push(intent);
}
}
setIntent(createLauncherIntent(this));
}
@Override
public void onPause() {
this.mActivityPaused = true;
super.onPause();
}
@Override
public void onResume() {
super.onResume();
this.mActivityPaused = false;
}
private void initializeFragments() {
final FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
final Fragment mainFragment = fragmentManager.findFragmentById(R.id.main_fragment);
final Fragment secondaryFragment = fragmentManager.findFragmentById(R.id.secondary_fragment);
if (mainFragment != null) {
if (binding.secondaryFragment != null) {
if (mainFragment instanceof ConversationFragment) {
getSupportFragmentManager().popBackStack();
transaction.remove(mainFragment);
transaction.commit();
fragmentManager.executePendingTransactions();
transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.secondary_fragment, mainFragment);
transaction.replace(R.id.main_fragment, new ConversationsOverviewFragment());
transaction.commit();
return;
}
} else {
if (secondaryFragment instanceof ConversationFragment) {
transaction.remove(secondaryFragment);
transaction.commit();
getSupportFragmentManager().executePendingTransactions();
transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.main_fragment, secondaryFragment);
transaction.addToBackStack(null);
transaction.commit();
return;
}
}
} else {
transaction.replace(R.id.main_fragment, new ConversationsOverviewFragment());
}
if (binding.secondaryFragment != null && secondaryFragment == null) {
transaction.replace(R.id.secondary_fragment, new ConversationFragment());
}
transaction.commit();
}
private void invalidateActionBarTitle() {
final ActionBar actionBar = getSupportActionBar();
if (actionBar == null) {
return;
}
final FragmentManager fragmentManager = getSupportFragmentManager();
final Fragment mainFragment = fragmentManager.findFragmentById(R.id.main_fragment);
if (mainFragment instanceof ConversationFragment) {
final Conversation conversation = ((ConversationFragment) mainFragment).getConversation();
if (conversation != null) {
actionBar.setTitle(EmojiWrapper.transform(conversation.getName()));
actionBar.setDisplayHomeAsUpEnabled(true);
ActionBarUtil.setActionBarOnClickListener(
binding.toolbar,
(v) -> openConversationDetails(conversation)
);
return;
}
}
actionBar.setTitle(R.string.app_name);
actionBar.setDisplayHomeAsUpEnabled(false);
ActionBarUtil.resetActionBarOnClickListeners(binding.toolbar);
}
private void openConversationDetails(final Conversation conversation) {
if (conversation.getMode() == Conversational.MODE_MULTI) {
ConferenceDetailsActivity.open(this, conversation);
} else {
final Contact contact = conversation.getContact();
if (contact.isSelf()) {
switchToAccount(conversation.getAccount());
} else {
switchToContactDetails(contact);
}
}
}
@Override
public void onConversationArchived(Conversation conversation) {
if (performRedirectIfNecessary(conversation, false)) {
return;
}
final FragmentManager fragmentManager = getSupportFragmentManager();
final Fragment mainFragment = fragmentManager.findFragmentById(R.id.main_fragment);
if (mainFragment instanceof ConversationFragment) {
try {
fragmentManager.popBackStack();
} catch (final IllegalStateException e) {
Log.w(Config.LOGTAG, "state loss while popping back state after archiving conversation", e);
//this usually means activity is no longer active; meaning on the next open we will run through this again
}
return;
}
final Fragment secondaryFragment = fragmentManager.findFragmentById(R.id.secondary_fragment);
if (secondaryFragment instanceof ConversationFragment) {
if (((ConversationFragment) secondaryFragment).getConversation() == conversation) {
Conversation suggestion = ConversationsOverviewFragment.getSuggestion(getSupportFragmentManager(), conversation);
if (suggestion != null) {
openConversation(suggestion, null);
}
}
}
}
@Override
public void onConversationsListItemUpdated() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_fragment);
if (fragment instanceof ConversationsOverviewFragment) {
((ConversationsOverviewFragment) fragment).refresh();
}
}
@Override
public void switchToConversation(Conversation conversation) {
Log.d(Config.LOGTAG, "override");
openConversation(conversation, null);
}
@Override
public void onConversationRead(Conversation conversation, String upToUuid) {
if (!mActivityPaused && pendingViewIntent.peek() == null) {
xmppConnectionService.sendReadMarker(conversation, upToUuid);
} else {
Log.d(Config.LOGTAG, "ignoring read callback. mActivityPaused=" + mActivityPaused);
}
}
@Override
public void onAccountUpdate() {
this.refreshUi();
}
@Override
public void onConversationUpdate() {
if (performRedirectIfNecessary(false)) {
return;
}
this.refreshUi();
}
@Override
public void onRosterUpdate() {
this.refreshUi();
}
@Override
public void OnUpdateBlocklist(OnUpdateBlocklist.Status status) {
this.refreshUi();
}
@Override
public void onShowErrorToast(int resId) {
runOnUiThread(() -> Toast.makeText(this, resId, Toast.LENGTH_SHORT).show());
}
}