Detailed changes
@@ -359,6 +359,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
private void enableAccount(Account account) {
account.setOption(Account.OPTION_DISABLED, false);
+ account.setOption(Account.OPTION_SOFT_DISABLED, false);
final XmppConnection connection = account.getXmppConnection();
if (connection != null) {
connection.resetEverything();
@@ -70,6 +70,7 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
public static final int OPTION_UNVERIFIED = 8;
public static final int OPTION_FIXED_USERNAME = 9;
public static final int OPTION_QUICKSTART_AVAILABLE = 10;
+ public static final int OPTION_SOFT_DISABLED = 11;
private static final String KEY_PGP_SIGNATURE = "pgp_signature";
private static final String KEY_PGP_ID = "pgp_id";
@@ -248,6 +249,10 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
return !isOptionSet(Account.OPTION_DISABLED);
}
+ public boolean isConnectionEnabled() {
+ return !isOptionSet(Account.OPTION_DISABLED) && !isOptionSet(Account.OPTION_SOFT_DISABLED);
+ }
+
public boolean isOptionSet(final int option) {
return ((options & (1 << option)) != 0);
}
@@ -322,6 +327,8 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
public State getStatus() {
if (isOptionSet(OPTION_DISABLED)) {
return State.DISABLED;
+ } else if (isOptionSet(OPTION_SOFT_DISABLED)) {
+ return State.LOGGED_OUT;
} else {
return this.status;
}
@@ -765,6 +772,7 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
public enum State {
DISABLED(false, false),
+ LOGGED_OUT(false,false),
OFFLINE(false),
CONNECTING(false),
ONLINE(false),
@@ -824,6 +832,8 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
switch (this) {
case DISABLED:
return R.string.account_status_disabled;
+ case LOGGED_OUT:
+ return R.string.account_state_logged_out;
case ONLINE:
return R.string.account_status_online;
case CONNECTING:
@@ -22,6 +22,7 @@ import android.os.Build;
import android.os.SystemClock;
import android.os.Vibrator;
import android.preference.PreferenceManager;
+import android.provider.Settings;
import android.text.SpannableString;
import android.text.style.StyleSpan;
import android.util.DisplayMetrics;
@@ -40,6 +41,7 @@ import androidx.core.graphics.drawable.IconCompat;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import java.io.File;
@@ -1661,51 +1663,26 @@ public class NotificationService {
}
private PendingIntent createCallAction(String sessionId, final String action, int requestCode) {
- final Intent intent = new Intent(mXmppConnectionService, XmppConnectionService.class);
- intent.setAction(action);
- intent.setPackage(mXmppConnectionService.getPackageName());
- intent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, sessionId);
- return PendingIntent.getService(
- mXmppConnectionService,
- requestCode,
- intent,
- s()
- ? PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
- : PendingIntent.FLAG_UPDATE_CURRENT);
+ return pendingServiceIntent(mXmppConnectionService, action, requestCode, ImmutableMap.of(RtpSessionActivity.EXTRA_SESSION_ID, sessionId));
}
- private PendingIntent createSnoozeIntent(Conversation conversation) {
- final Intent intent = new Intent(mXmppConnectionService, XmppConnectionService.class);
- intent.setAction(XmppConnectionService.ACTION_SNOOZE);
- intent.putExtra("uuid", conversation.getUuid());
- intent.setPackage(mXmppConnectionService.getPackageName());
- return PendingIntent.getService(
- mXmppConnectionService,
- generateRequestCode(conversation, 22),
- intent,
- s()
- ? PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
- : PendingIntent.FLAG_UPDATE_CURRENT);
+ private PendingIntent createSnoozeIntent(final Conversation conversation) {
+ return pendingServiceIntent(mXmppConnectionService, XmppConnectionService.ACTION_SNOOZE, generateRequestCode(conversation,22),ImmutableMap.of("uuid",conversation.getUuid()));
}
- private PendingIntent createTryAgainIntent() {
- final Intent intent = new Intent(mXmppConnectionService, XmppConnectionService.class);
- intent.setAction(XmppConnectionService.ACTION_TRY_AGAIN);
- return PendingIntent.getService(
- mXmppConnectionService,
- 45,
- intent,
- s()
- ? PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
- : PendingIntent.FLAG_UPDATE_CURRENT);
+ private static PendingIntent pendingServiceIntent(final Context context, final String action, final int requestCode) {
+ return pendingServiceIntent(context, action, requestCode, ImmutableMap.of());
}
- private PendingIntent createDismissErrorIntent() {
- final Intent intent = new Intent(mXmppConnectionService, XmppConnectionService.class);
- intent.setAction(XmppConnectionService.ACTION_DISMISS_ERROR_NOTIFICATIONS);
+ private static PendingIntent pendingServiceIntent(final Context context, final String action, final int requestCode, final Map<String,String> extras) {
+ final Intent intent = new Intent(context, XmppConnectionService.class);
+ intent.setAction(action);
+ for(final Map.Entry<String,String> entry : extras.entrySet()) {
+ intent.putExtra(entry.getKey(), entry.getValue());
+ }
return PendingIntent.getService(
- mXmppConnectionService,
- 69,
+ context,
+ requestCode,
intent,
s()
? PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
@@ -1756,17 +1733,15 @@ public class NotificationService {
final Notification.Builder mBuilder = new Notification.Builder(mXmppConnectionService);
mBuilder.setContentTitle(mXmppConnectionService.getString(R.string.app_name));
final List<Account> accounts = mXmppConnectionService.getAccounts();
- int enabled = 0;
- int connected = 0;
- if (accounts != null) {
- for (Account account : accounts) {
- if (account.isOnlineAndConnected()) {
- connected++;
- enabled++;
- } else if (account.isEnabled()) {
- enabled++;
- }
- }
+ final int enabled;
+ final int connected;
+ if (accounts == null) {
+ enabled = 0;
+ connected = 0;
+ } else {
+ enabled = Iterables.size(Iterables.filter(accounts, Account::isEnabled));
+ connected =
+ Iterables.size(Iterables.filter(accounts, Account::isOnlineAndConnected));
}
mBuilder.setContentText(
mXmppConnectionService.getString(R.string.connected_accounts, connected, enabled));
@@ -1784,11 +1759,36 @@ public class NotificationService {
if (Compatibility.runsTwentySix()) {
mBuilder.setChannelId("foreground");
+ mBuilder.addAction(
+ R.drawable.ic_logout_white_24dp,
+ mXmppConnectionService.getString(R.string.log_out),
+ pendingServiceIntent(
+ mXmppConnectionService,
+ XmppConnectionService.ACTION_TEMPORARILY_DISABLE,
+ 87));
+ mBuilder.addAction(
+ R.drawable.ic_notifications_off_white_24dp,
+ mXmppConnectionService.getString(R.string.hide_notification),
+ pendingNotificationSettingsIntent(mXmppConnectionService));
}
return mBuilder.build();
}
+ @RequiresApi(api = Build.VERSION_CODES.O)
+ private static PendingIntent pendingNotificationSettingsIntent(final Context context) {
+ final Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
+ intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
+ intent.putExtra(Settings.EXTRA_CHANNEL_ID, "foreground");
+ return PendingIntent.getActivity(
+ context,
+ 89,
+ intent,
+ s()
+ ? PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
+ : PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
private PendingIntent createOpenConversationsIntent() {
try {
return PendingIntent.getActivity(
@@ -1839,7 +1839,7 @@ public class NotificationService {
mBuilder.addAction(
R.drawable.ic_autorenew_white_24dp,
mXmppConnectionService.getString(R.string.try_again),
- createTryAgainIntent());
+ pendingServiceIntent(mXmppConnectionService, XmppConnectionService.ACTION_TRY_AGAIN, 45));
if (torNotAvailable) {
if (TorServiceUtils.isOrbotInstalled(mXmppConnectionService)) {
mBuilder.addAction(
@@ -1867,7 +1867,7 @@ public class NotificationService {
: PendingIntent.FLAG_UPDATE_CURRENT));
}
}
- mBuilder.setDeleteIntent(createDismissErrorIntent());
+ mBuilder.setDeleteIntent(pendingServiceIntent(mXmppConnectionService,XmppConnectionService.ACTION_DISMISS_ERROR_NOTIFICATIONS, 69));
mBuilder.setVisibility(Notification.VISIBILITY_PRIVATE);
mBuilder.setSmallIcon(R.drawable.ic_warning_white_24dp);
mBuilder.setLocalOnly(true);
@@ -184,6 +184,8 @@ public class XmppConnectionService extends Service {
public static final String ACTION_CLEAR_MISSED_CALL_NOTIFICATION = "clear_missed_call_notification";
public static final String ACTION_DISMISS_ERROR_NOTIFICATIONS = "dismiss_error";
public static final String ACTION_TRY_AGAIN = "try_again";
+
+ public static final String ACTION_TEMPORARILY_DISABLE = "temporarily_disable";
public static final String ACTION_IDLE_PING = "idle_ping";
public static final String ACTION_FCM_TOKEN_REFRESH = "fcm_token_refresh";
public static final String ACTION_FCM_MESSAGE_RECEIVED = "fcm_message_received";
@@ -452,9 +454,9 @@ public class XmppConnectionService extends Service {
joinMuc(conversation);
}
scheduleWakeUpCall(Config.PING_MAX_INTERVAL, account.getUuid().hashCode());
- } else if (account.getStatus() == Account.State.OFFLINE || account.getStatus() == Account.State.DISABLED) {
+ } else if (account.getStatus() == Account.State.OFFLINE || account.getStatus() == Account.State.DISABLED || account.getStatus() == Account.State.LOGGED_OUT) {
resetSendingToWaiting(account);
- if (account.isEnabled() && isInLowPingTimeoutMode(account)) {
+ if (account.isConnectionEnabled() && isInLowPingTimeoutMode(account)) {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": went into offline state during low ping mode. reconnecting now");
reconnectAccount(account, true, false);
} else {
@@ -846,6 +848,9 @@ public class XmppConnectionService extends Service {
Log.d(Config.LOGTAG, "received uri permission for " + uri);
}
return START_STICKY;
+ case ACTION_TEMPORARILY_DISABLE:
+ toggleSoftDisabled(true);
+ return START_NOT_STICKY;
}
}
synchronized (this) {
@@ -961,6 +966,16 @@ public class XmppConnectionService extends Service {
return pingNow;
}
+ private void toggleSoftDisabled(final boolean softDisabled) {
+ for(final Account account : this.accounts) {
+ if (account.isEnabled()) {
+ if (account.setOption(Account.OPTION_SOFT_DISABLED, softDisabled)) {
+ updateAccount(account);
+ }
+ }
+ }
+ }
+
public boolean processUnifiedPushMessage(final Account account, final Jid transport, final Element push) {
return unifiedPushBroker.processPushMessage(account, transport, push);
}
@@ -1449,7 +1464,7 @@ public class XmppConnectionService extends Service {
private void logoutAndSave(boolean stop) {
int activeAccounts = 0;
for (final Account account : accounts) {
- if (account.getStatus() != Account.State.DISABLED) {
+ if (account.isConnectionEnabled()) {
databaseBackend.writeRoster(account.getRoster());
activeAccounts++;
}
@@ -2808,6 +2823,7 @@ public class XmppConnectionService extends Service {
}
private void switchToForeground() {
+ toggleSoftDisabled(false);
final boolean broadcastLastActivity = broadcastLastActivity();
for (Conversation conversation : getConversations()) {
if (conversation.getMode() == Conversation.MODE_MULTI) {
@@ -3188,8 +3204,8 @@ public class XmppConnectionService extends Service {
if (this.accounts == null) {
return false;
}
- for (Account account : this.accounts) {
- if (account.isEnabled()) {
+ for (final Account account : this.accounts) {
+ if (account.isConnectionEnabled()) {
return true;
}
}
@@ -3587,23 +3603,23 @@ public class XmppConnectionService extends Service {
});
}
- private void disconnect(Account account, boolean force) {
- if ((account.getStatus() == Account.State.ONLINE)
- || (account.getStatus() == Account.State.DISABLED)) {
- final XmppConnection connection = account.getXmppConnection();
- if (!force) {
- List<Conversation> conversations = getConversations();
- for (Conversation conversation : conversations) {
- if (conversation.getAccount() == account) {
- if (conversation.getMode() == Conversation.MODE_MULTI) {
- leaveMuc(conversation, true);
- }
+ private void disconnect(final Account account, boolean force) {
+ final XmppConnection connection = account.getXmppConnection();
+ if (connection == null) {
+ return;
+ }
+ if (!force) {
+ final List<Conversation> conversations = getConversations();
+ for (Conversation conversation : conversations) {
+ if (conversation.getAccount() == account) {
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ leaveMuc(conversation, true);
}
}
- sendOfflinePresence(account);
}
- connection.disconnect(force);
+ sendOfflinePresence(account);
}
+ connection.disconnect(force);
}
@Override
@@ -4093,7 +4109,7 @@ public class XmppConnectionService extends Service {
account.setXmppConnection(connection);
}
boolean hasInternet = hasInternetConnection();
- if (account.isEnabled() && hasInternet) {
+ if (account.isConnectionEnabled() && hasInternet) {
if (!force) {
disconnect(account, false);
}
@@ -4581,7 +4597,7 @@ public class XmppConnectionService extends Service {
public void refreshAllPresences() {
boolean includeIdleTimestamp = checkListeners() && broadcastLastActivity();
for (Account account : getAccounts()) {
- if (account.isEnabled()) {
+ if (account.isConnectionEnabled()) {
sendPresence(account, includeIdleTimestamp);
}
}
@@ -270,7 +270,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
return;
}
for (final Account account : xmppConnectionService.getAccounts()) {
- if (account.getStatus() != Account.State.DISABLED) {
+ if (account.isEnabled()) {
for (final Contact contact : account.getRoster().getContacts()) {
if (contact.showInContactList() &&
!filterContacts.contains(contact.getJid().asBareJid().toString())
@@ -362,7 +362,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
filterContacts();
this.mActivatedAccounts.clear();
for (Account account : xmppConnectionService.getAccounts()) {
- if (account.getStatus() != Account.State.DISABLED) {
+ if (account.isEnabled()) {
if (Config.DOMAIN_LOCK != null) {
this.mActivatedAccounts.add(account.getJid().getEscapedLocal());
} else {
@@ -382,6 +382,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
ScanActivity.onRequestPermissionResult(this, requestCode, grantResults);
}
@@ -416,6 +416,7 @@ public class ConversationFragment extends XmppFragment
public void onClick(View v) {
final Account account = conversation == null ? null : conversation.getAccount();
if (account != null) {
+ account.setOption(Account.OPTION_SOFT_DISABLED, false);
account.setOption(Account.OPTION_DISABLED, false);
activity.xmppConnectionService.updateAccount(account);
}
@@ -2660,6 +2661,8 @@ public class ConversationFragment extends XmppFragment
R.string.this_account_is_disabled,
R.string.enable,
this.mEnableAccountListener);
+ } else if (account.getStatus() == Account.State.LOGGED_OUT) {
+ showSnackbar(R.string.this_account_is_logged_out,R.string.log_in,this.mEnableAccountListener);
} else if (conversation.isBlocked()) {
showSnackbar(R.string.contact_blocked, R.string.unblock, this.mUnblockClickListener);
} else if (contact != null
@@ -149,7 +149,8 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
if (mInitMode && mAccount != null) {
mAccount.setOption(Account.OPTION_DISABLED, false);
}
- if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED && !accountInfoEdited) {
+ if (mAccount != null && Arrays.asList(Account.State.DISABLED, Account.State.LOGGED_OUT).contains(mAccount.getStatus()) && !accountInfoEdited) {
+ mAccount.setOption(Account.OPTION_SOFT_DISABLED, false);
mAccount.setOption(Account.OPTION_DISABLED, false);
if (!xmppConnectionService.updateAccount(mAccount)) {
Toast.makeText(EditAccountActivity.this, R.string.unable_to_update_account, Toast.LENGTH_SHORT).show();
@@ -61,7 +61,7 @@ public class ShortcutActivity extends AbstractSearchableListItemActivity {
return;
}
for (final Account account : xmppConnectionService.getAccounts()) {
- if (account.getStatus() != Account.State.DISABLED) {
+ if (account.isEnabled()) {
for (final Contact contact : account.getRoster().getContacts()) {
if (contact.showInContactList()
&& contact.match(this, needle)) {
@@ -971,8 +971,8 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
protected void filterContacts(String needle) {
this.contacts.clear();
final List<Account> accounts = xmppConnectionService.getAccounts();
- for (Account account : accounts) {
- if (account.getStatus() != Account.State.DISABLED) {
+ for (final Account account : accounts) {
+ if (account.isEnabled()) {
for (Contact contact : account.getRoster().getContacts()) {
Presence.Status s = contact.getShownStatus();
if (contact.showInContactList() && contact.match(this, needle)
@@ -991,7 +991,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
protected void filterConferences(String needle) {
this.conferences.clear();
for (final Account account : xmppConnectionService.getAccounts()) {
- if (account.getStatus() != Account.State.DISABLED) {
+ if (account.isEnabled()) {
for (final Bookmark bookmark : account.getBookmarks()) {
if (bookmark.match(this, needle)) {
this.conferences.add(bookmark);
@@ -59,6 +59,7 @@ public class AccountAdapter extends ArrayAdapter<Account> {
viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorOnline));
break;
case DISABLED:
+ case LOGGED_OUT:
case CONNECTING:
viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, android.R.attr.textColorSecondary));
break;
@@ -60,7 +60,7 @@ public class AccountUtils {
public static List<String> getEnabledAccounts(final XmppConnectionService service) {
final ArrayList<String> accounts = new ArrayList<>();
for (final Account account : service.getAccounts()) {
- if (account.getStatus() != Account.State.DISABLED) {
+ if (account.isEnabled()) {
if (Config.DOMAIN_LOCK != null) {
accounts.add(account.getJid().getEscapedLocal());
} else {
@@ -233,10 +233,11 @@ public class XmppConnection implements Runnable {
return;
}
if (account.getStatus() != nextStatus) {
- if ((nextStatus == Account.State.OFFLINE)
- && (account.getStatus() != Account.State.CONNECTING)
- && (account.getStatus() != Account.State.ONLINE)
- && (account.getStatus() != Account.State.DISABLED)) {
+ if (nextStatus == Account.State.OFFLINE
+ && account.getStatus() != Account.State.CONNECTING
+ && account.getStatus() != Account.State.ONLINE
+ && account.getStatus() != Account.State.DISABLED
+ && account.getStatus() != Account.State.LOGGED_OUT) {
return;
}
if (nextStatus == Account.State.ONLINE) {
@@ -0,0 +1,5 @@
+<vector android:autoMirrored="true" android:height="24dp"
+ android:tint="#FFFFFF" android:viewportHeight="24"
+ android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="@android:color/white" android:pathData="M17,7l-1.41,1.41L18.17,11H8v2h10.17l-2.58,2.58L17,17l5,-5zM4,5h8V3H4c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h8v-2H4V5z"/>
+</vector>
@@ -153,6 +153,7 @@
<string name="error_security_exception">The app you used to share this file did not provide enough permissions.</string>
<string name="account_status_unknown">Unknown</string>
<string name="account_status_disabled">Temporarily disabled</string>
+ <string name="account_state_logged_out">Logged out</string>
<string name="account_status_online">Online</string>
<string name="account_status_connecting">Connecting\u2026</string>
<string name="account_status_offline">Offline</string>
@@ -538,6 +539,7 @@
<string name="send_corrected_message">Send corrected message</string>
<string name="no_keys_just_confirm">You have already validated this persons fingerprint securely to confirm trust. By selecting βDoneβ you are just confirming that %s is part of this group chat.</string>
<string name="this_account_is_disabled">You have disabled this account</string>
+ <string name="this_account_is_logged_out">You have logged out of this account</string>
<string name="security_error_invalid_file_access">Security error: Invalid file access!</string>
<string name="no_application_to_share_uri">No app found to share URI</string>
<string name="share_uri_with">Share URI withβ¦</string>
@@ -1013,5 +1015,7 @@
<string name="decline">Decline</string>
<string name="delete_from_server">Remove account from server</string>
<string name="could_not_delete_account_from_server">Could not delete account from server</string>
-
+ <string name="hide_notification">Hide notification</string>
+ <string name="log_out">Log out</string>
+ <string name="log_in">Log in</string>
</resources>