From 39bb45c0f219fd2b97f312f6e64d2bfe1ad0d9cc Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 2 Apr 2019 15:31:28 +0500 Subject: [PATCH 001/237] Start work on push notifications for xmpp messages --- .../com/xabber/android/data/Application.java | 2 + .../xabber/android/data/http/IPushApi.java | 18 +++++ .../android/data/http/PushApiClient.java | 50 ++++++++++++ .../xabber/android/data/push/PushManager.java | 81 +++++++++++++++++++ .../android/data/xaccount/HttpApiManager.java | 38 +++++++++ 5 files changed, 189 insertions(+) create mode 100644 xabber/src/main/java/com/xabber/android/data/http/IPushApi.java create mode 100644 xabber/src/main/java/com/xabber/android/data/http/PushApiClient.java create mode 100644 xabber/src/main/java/com/xabber/android/data/push/PushManager.java diff --git a/xabber/src/main/java/com/xabber/android/data/Application.java b/xabber/src/main/java/com/xabber/android/data/Application.java index 6cd0bf4f21..81d73bf93d 100644 --- a/xabber/src/main/java/com/xabber/android/data/Application.java +++ b/xabber/src/main/java/com/xabber/android/data/Application.java @@ -58,6 +58,7 @@ import com.xabber.android.data.message.phrase.PhraseManager; import com.xabber.android.data.notification.NotificationManager; import com.xabber.android.data.notification.custom_notification.CustomNotifyPrefsManager; +import com.xabber.android.data.push.PushManager; import com.xabber.android.data.roster.GroupManager; import com.xabber.android.data.roster.PresenceManager; import com.xabber.android.data.roster.RosterManager; @@ -386,6 +387,7 @@ private void addManagers() { addManager(MamManager.getInstance()); addManager(CertificateManager.getInstance()); addManager(XMPPAuthManager.getInstance()); + addManager(PushManager.getInstance()); } /** diff --git a/xabber/src/main/java/com/xabber/android/data/http/IPushApi.java b/xabber/src/main/java/com/xabber/android/data/http/IPushApi.java new file mode 100644 index 0000000000..f73d5dfb38 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/http/IPushApi.java @@ -0,0 +1,18 @@ +package com.xabber.android.data.http; + +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.HTTP; +import retrofit2.http.Header; +import retrofit2.http.POST; +import rx.Single; + +public interface IPushApi { + + @POST("jid/endpoints/") + Single registerEndpoint(@Header("Authorization") String key, @Body PushApiClient.Endpoint endpoint); + + @HTTP(method = "DELETE", path = "jid/endpoints/", hasBody = true) + Single deleteEndpoint(@Header("Authorization") String key, @Body PushApiClient.Endpoint endpoint); + +} diff --git a/xabber/src/main/java/com/xabber/android/data/http/PushApiClient.java b/xabber/src/main/java/com/xabber/android/data/http/PushApiClient.java new file mode 100644 index 0000000000..c847282b15 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/http/PushApiClient.java @@ -0,0 +1,50 @@ +package com.xabber.android.data.http; + +import com.xabber.android.R; +import com.xabber.android.data.Application; +import com.xabber.android.data.xaccount.HttpApiManager; + +import okhttp3.ResponseBody; +import rx.Single; + +public class PushApiClient { + + private static final String DEFAULT_PUSH_PROVIDER = "fcm"; + + private static PushApiClient instance; + + public static PushApiClient getInstance() { + if (instance == null) + instance = new PushApiClient(); + return instance; + } + + public static Single registerEndpoint(String endpoint, String jid) { + if (getAPIKey().length() < 36) return Single.error(new Throwable("API key not provided")); + return HttpApiManager.getPushApi().registerEndpoint(getAPIKey(), + new Endpoint(endpoint, DEFAULT_PUSH_PROVIDER, jid)); + } + + public static Single deleteEndpoint(String endpoint, String jid) { + if (getAPIKey().length() < 36) return Single.error(new Throwable("API key not provided")); + return HttpApiManager.getPushApi().deleteEndpoint(getAPIKey(), + new Endpoint(endpoint, DEFAULT_PUSH_PROVIDER, jid)); + } + + private static String getAPIKey() { + return "Key " + Application.getInstance().getResources().getString(R.string.PUSH_API_KEY); + } + + public static class Endpoint { + final String endpoint_key; + final String provider; + final String target; + + public Endpoint(String endpoint_key, String provider, String target) { + this.endpoint_key = endpoint_key; + this.provider = provider; + this.target = target; + } + } + +} diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java new file mode 100644 index 0000000000..255b94a989 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -0,0 +1,81 @@ +package com.xabber.android.data.push; + +import android.util.Log; + +import com.google.firebase.iid.FirebaseInstanceId; +import com.xabber.android.data.Application; +import com.xabber.android.data.connection.ConnectionItem; +import com.xabber.android.data.connection.listeners.OnConnectedListener; +import com.xabber.android.data.entity.AccountJid; +import com.xabber.android.data.http.PushApiClient; + +import okhttp3.ResponseBody; +import rx.android.schedulers.AndroidSchedulers; +import rx.functions.Action1; +import rx.schedulers.Schedulers; +import rx.subscriptions.CompositeSubscription; + +public class PushManager implements OnConnectedListener { + + private static final String LOG_TAG = PushManager.class.getSimpleName(); + + private static PushManager instance; + + public static PushManager getInstance() { + if (instance == null) + instance = new PushManager(); + return instance; + } + + private CompositeSubscription compositeSubscription = new CompositeSubscription(); + + @Override + public void onConnected(final ConnectionItem connection) { + Application.getInstance().runInBackground(new Runnable() { + @Override + public void run() { + AccountJid accountJid = connection.getAccount(); + registerEndpoint(accountJid); + } + }); + } + + public void registerEndpoint(AccountJid accountJid) { + compositeSubscription.add( + PushApiClient.registerEndpoint( + FirebaseInstanceId.getInstance().getToken(), accountJid.toString()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Action1() { + @Override + public void call(ResponseBody responseBody) { + Log.d(LOG_TAG, "Endpoint successfully registered"); + } + }, new Action1() { + @Override + public void call(Throwable throwable) { + Log.d(LOG_TAG, "Endpoint register failed: " + throwable.toString()); + } + })); + } + + public void deleteEndpoint(AccountJid accountJid) { + compositeSubscription.add( + PushApiClient.deleteEndpoint( + FirebaseInstanceId.getInstance().getToken(), accountJid.toString()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Action1() { + @Override + public void call(ResponseBody responseBody) { + Log.d(LOG_TAG, "Endpoint successfully unregistered"); + } + }, new Action1() { + @Override + public void call(Throwable throwable) { + Log.d(LOG_TAG, "Endpoint unregister failed: " + throwable.toString()); + } + })); + } + +} diff --git a/xabber/src/main/java/com/xabber/android/data/xaccount/HttpApiManager.java b/xabber/src/main/java/com/xabber/android/data/xaccount/HttpApiManager.java index e3522e1666..8a2411758f 100644 --- a/xabber/src/main/java/com/xabber/android/data/xaccount/HttpApiManager.java +++ b/xabber/src/main/java/com/xabber/android/data/xaccount/HttpApiManager.java @@ -5,6 +5,7 @@ import com.xabber.android.BuildConfig; import com.xabber.android.data.SettingsManager; import com.xabber.android.data.http.ICrowdfundingApi; +import com.xabber.android.data.http.IPushApi; import com.xabber.android.data.http.IXabberCom; import okhttp3.OkHttpClient; @@ -26,16 +27,19 @@ public class HttpApiManager { public static final String XABBER_API_URL = "https://api.xabber.com/api/v2/"; public static final String XABBER_DEV_API_URL = "https://api.dev.xabber.com/api/v2/"; private static final String XABBER_COM_URL = "https://www.xabber.com/"; + private static final String XABBER_PUSH_API_URL = "https://push.xabber.com/api/"; private static final String CROWDFUNDING_URL = "https://crowdfunding.xabber.com/api/v1/"; private static final String CROWDFUNDING_DEV_URL = "https://crowdfunding.dev.xabber.com/api/v1/"; private static IXabberApi xabberApi; private static IXabberCom xabberCom; private static ICrowdfundingApi crowdfundingApi; + private static IPushApi pushApi; private static Retrofit retrofit; private static Retrofit retrofitXabberCom; private static Retrofit retrofitCrowdfunding; + private static Retrofit retrofitPush; public static IXabberApi getXabberApi() { if (xabberApi == null) @@ -55,6 +59,12 @@ public static ICrowdfundingApi getCrowdfundingApi() { return crowdfundingApi; } + public static IPushApi getPushApi() { + if (pushApi == null) + pushApi = getPushRetrofit().create(IPushApi.class); + return pushApi; + } + public static Retrofit getRetrofit() { if (retrofit == null) { @@ -143,5 +153,33 @@ private static Retrofit getCrowdfundingRetrofit() { } return retrofitCrowdfunding; } + + private static Retrofit getPushRetrofit() { + if (retrofitPush == null) { + + HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); + loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); + + OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); + + // if debug enable http logging + if (BuildConfig.DEBUG) + httpClientBuilder.addInterceptor(loggingInterceptor); + + OkHttpClient httpClient = httpClientBuilder.build(); + + Gson gson = new GsonBuilder() + .setLenient() + .create(); + + retrofitPush = new Retrofit.Builder() + .baseUrl(XABBER_PUSH_API_URL) + .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) + .addConverterFactory(GsonConverterFactory.create(gson)) + .client(httpClient) + .build(); + } + return retrofitPush; + } } From 9c81b379236c3ca48080468e751cdbefdb223280 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 2 Apr 2019 16:14:06 +0500 Subject: [PATCH 002/237] Work on push notifications for xmpp messages --- .../xabber/android/data/push/PushManager.java | 7 ++ .../xabber/android/service/PushService.java | 102 +++++++++++++----- 2 files changed, 83 insertions(+), 26 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index 255b94a989..806e8800d3 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -35,11 +35,18 @@ public void onConnected(final ConnectionItem connection) { @Override public void run() { AccountJid accountJid = connection.getAccount(); + + // TODO: 02.04.19 check push support + registerEndpoint(accountJid); } }); } + public void onEndpointRegistered(String jid, String node) { + + } + public void registerEndpoint(AccountJid accountJid) { compositeSubscription.add( PushApiClient.registerEndpoint( diff --git a/xabber/src/main/java/com/xabber/android/service/PushService.java b/xabber/src/main/java/com/xabber/android/service/PushService.java index 2afb8391c3..4483754d96 100644 --- a/xabber/src/main/java/com/xabber/android/service/PushService.java +++ b/xabber/src/main/java/com/xabber/android/service/PushService.java @@ -6,6 +6,7 @@ import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; import com.google.gson.Gson; +import com.xabber.android.data.push.PushManager; import com.xabber.android.data.xaccount.XabberAccount; import com.xabber.android.data.xaccount.XabberAccountManager; @@ -14,11 +15,12 @@ public class PushService extends FirebaseMessagingService { private static final String FIELD_TARGET_TYPE = "target_type"; - private static final String FIELD_TARGET = "target"; private static final String FIELD_BODY = "body"; private static final String ACTION_SETTINGS_UPDATED = "settings_updated"; private static final String ACTION_ACCOUNT_UPDATED = "account_updated"; + private static final String ACTION_REGJID = "regjid"; + private static final String ACTION_MESSAGE = "message"; private static final String TARGET_TYPE_XACCOUNT = "xaccount"; private static final String TARGET_TYPE_NODE = "node"; @@ -31,18 +33,17 @@ public void onMessageReceived(RemoteMessage remoteMessage) { if (remoteMessage.getData().size() > 0) { Map data = remoteMessage.getData(); String targetType = data.get(FIELD_TARGET_TYPE); - String target = data.get(FIELD_TARGET); String encodedBody = data.get(FIELD_BODY); - if (targetType != null && target != null && encodedBody != null) { + if (targetType != null && encodedBody != null) { String decodedBody = new String(Base64.decode(encodedBody, Base64.NO_WRAP)); switch (targetType) { case TARGET_TYPE_XACCOUNT: - onXAccountPushReceived(target, decodedBody); + onXAccountPushReceived(decodedBody); break; case TARGET_TYPE_NODE: - onXMPPPushReceived(target, decodedBody); + onXMPPPushReceived(decodedBody); break; default: Log.d(PushService.class.getSimpleName(), "Unexpected target type - " + targetType); @@ -51,32 +52,45 @@ public void onMessageReceived(RemoteMessage remoteMessage) { } } - private void onXAccountPushReceived(String target, String body) { + private void onXAccountPushReceived(String body) { + XAccountPushData data = gson.fromJson(body, XAccountPushData.class); XabberAccount xabberAccount = XabberAccountManager.getInstance().getAccount(); - if (xabberAccount != null && xabberAccount.getFullUsername().equals(target)) { - XAccountPushData data = gson.fromJson(body, XAccountPushData.class); - - if (data != null && xabberAccount.getFullUsername().equals(data.getUsername()) - && !xabberAccount.getToken().equals(data.getFromToken())) { - switch (data.getAction()) { - case ACTION_SETTINGS_UPDATED: - XabberAccountManager.getInstance().updateAccountSettings(); - // used async function updateAccountSettings - // inside function exist check that prevents simultaneous calls - break; - case ACTION_ACCOUNT_UPDATED: - XabberAccountManager.getInstance().updateAccountInfo(); - break; - default: - Log.d(PushService.class.getSimpleName(), - "Unexpected action in Xabber Account push - " + data.getAction()); - } + + if (xabberAccount != null && data != null + && xabberAccount.getFullUsername().equals(data.getUsername()) + && !xabberAccount.getToken().equals(data.getFromToken())) { + + switch (data.getAction()) { + case ACTION_SETTINGS_UPDATED: + XabberAccountManager.getInstance().updateAccountSettings(); + // used async function updateAccountSettings + // inside function exist check that prevents simultaneous calls + break; + case ACTION_ACCOUNT_UPDATED: + XabberAccountManager.getInstance().updateAccountInfo(); + break; + default: + Log.d(PushService.class.getSimpleName(), + "Unexpected action in Xabber Account push - " + data.getAction()); } } } - private void onXMPPPushReceived(String target, String body) { - /** Will be used for XMPP pushes */ + private void onXMPPPushReceived(String body) { + EndpointRegPushData data = gson.fromJson(body, EndpointRegPushData.class); + if (data != null) { + switch (data.getAction()) { + case ACTION_REGJID: + PushManager.getInstance().onEndpointRegistered(data.getJid(), data.getNode()); + break; + case ACTION_MESSAGE: + /* on new message push */ + break; + default: + Log.d(PushService.class.getSimpleName(), + "Unexpected action in Node push - " + data.getAction()); + } + } } private static class XAccountPushData { @@ -102,4 +116,40 @@ public String getFromToken() { return from_token; } } + + private static class EndpointRegPushData { + private final String action; + private final String result; + private final String jid; + private final String node; + private final String service; + + public EndpointRegPushData(String action, String result, String jid, String node, String service) { + this.action = action; + this.result = result; + this.jid = jid; + this.node = node; + this.service = service; + } + + public String getAction() { + return action; + } + + public String getResult() { + return result; + } + + public String getJid() { + return jid; + } + + public String getNode() { + return node; + } + + public String getService() { + return service; + } + } } From 5d868c1c9fdc330f1bd30a30b93d17c01bd3a1f1 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 2 Apr 2019 16:16:08 +0500 Subject: [PATCH 003/237] Work on push notifications for xmpp messages --- .../main/java/com/xabber/android/data/push/PushManager.java | 4 ++++ .../src/main/java/com/xabber/android/service/PushService.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index 806e8800d3..b817c3f746 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -47,6 +47,10 @@ public void onEndpointRegistered(String jid, String node) { } + public void onNewMessagePush(String node) { + + } + public void registerEndpoint(AccountJid accountJid) { compositeSubscription.add( PushApiClient.registerEndpoint( diff --git a/xabber/src/main/java/com/xabber/android/service/PushService.java b/xabber/src/main/java/com/xabber/android/service/PushService.java index 4483754d96..9a11e83fd5 100644 --- a/xabber/src/main/java/com/xabber/android/service/PushService.java +++ b/xabber/src/main/java/com/xabber/android/service/PushService.java @@ -84,7 +84,7 @@ private void onXMPPPushReceived(String body) { PushManager.getInstance().onEndpointRegistered(data.getJid(), data.getNode()); break; case ACTION_MESSAGE: - /* on new message push */ + PushManager.getInstance().onNewMessagePush(data.getNode()); break; default: Log.d(PushService.class.getSimpleName(), From d9df580b95df481b2f0230dc1243319d798bd660 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 2 Apr 2019 17:17:34 +0500 Subject: [PATCH 004/237] Added saving push node to realm on receiving --- .../android/data/account/AccountItem.java | 10 ++++++++++ .../android/data/account/AccountManager.java | 6 ++++++ .../android/data/database/RealmManager.java | 9 ++++++++- .../data/database/realm/AccountRealm.java | 11 ++++++++++ .../data/database/sqlite/AccountTable.java | 1 + .../xabber/android/data/push/PushManager.java | 20 ++++++++++++++++++- .../xabber/android/service/PushService.java | 4 +++- 7 files changed, 58 insertions(+), 3 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java b/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java index ee932d25b3..20471ee3bf 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java @@ -116,6 +116,8 @@ public class AccountItem extends ConnectionItem implements Comparable System.currentTimeMillis(); } + + public String getPushNode() { + return pushNode; + } + + public void setPushNode(String pushNode) { + this.pushNode = pushNode; + } } diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java index 9f3e559ea0..9ae4711d5d 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java @@ -228,6 +228,7 @@ public void onLoad() { accountItem.setLoadHistorySettings(accountRealm.getLoadHistorySettings()); } accountItem.setSuccessfulConnectionHappened(accountRealm.isSuccessfulConnectionHappened()); + accountItem.setPushNode(accountRealm.getPushNode()); accountItems.add(accountItem); @@ -1208,4 +1209,9 @@ public void stopGracePeriod() { } } + public void setPushNode(AccountItem account, String pushNode) { + account.setPushNode(pushNode); + requestToWriteAccount(account); + } + } diff --git a/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java b/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java index 50de97fb6e..f354aa3f2f 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java +++ b/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java @@ -34,7 +34,7 @@ public class RealmManager { private static final String REALM_DATABASE_NAME = "realm_database.realm"; - private static final int REALM_DATABASE_VERSION = 21; + private static final int REALM_DATABASE_VERSION = 22; private static final String LOG_TAG = RealmManager.class.getSimpleName(); private final RealmConfiguration realmConfiguration; @@ -311,6 +311,13 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { oldVersion++; } + + if (oldVersion == 21) { + schema.get(AccountRealm.class.getSimpleName()) + .addField(AccountRealm.Fields.PUSH_NODE, String.class); + + oldVersion++; + } } }) .modules(new RealmDatabaseModule()) diff --git a/xabber/src/main/java/com/xabber/android/data/database/realm/AccountRealm.java b/xabber/src/main/java/com/xabber/android/data/database/realm/AccountRealm.java index 2fdf0bc842..f745e16220 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/realm/AccountRealm.java +++ b/xabber/src/main/java/com/xabber/android/data/database/realm/AccountRealm.java @@ -35,6 +35,7 @@ public static class Fields { public static final String MAM_DEFAULT_BEHAVIOR = "mamDefaultBehavior"; public static final String LOAD_HISTORY_SETTINGS = "loadHistorySettings"; public static final String SUCCESSFUL_CONNECTION_HAPPENED = "successfulConnectionHappened"; + public static final String PUSH_NODE = "pushNode"; } @PrimaryKey @@ -93,6 +94,8 @@ public static class Fields { */ private boolean successfulConnectionHappened; + private String pushNode; + public AccountRealm(String id) { this.id = id; } @@ -415,4 +418,12 @@ public boolean isSuccessfulConnectionHappened() { public void setSuccessfulConnectionHappened(boolean successfulConnectionHappened) { this.successfulConnectionHappened = successfulConnectionHappened; } + + public String getPushNode() { + return pushNode; + } + + public void setPushNode(String pushNode) { + this.pushNode = pushNode; + } } diff --git a/xabber/src/main/java/com/xabber/android/data/database/sqlite/AccountTable.java b/xabber/src/main/java/com/xabber/android/data/database/sqlite/AccountTable.java index fc34974e78..d35ea62b27 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/sqlite/AccountTable.java +++ b/xabber/src/main/java/com/xabber/android/data/database/sqlite/AccountTable.java @@ -483,6 +483,7 @@ private void saveAccountRealm(String id, AccountItem accountItem) { accountRealm.setMamDefaultBehavior(accountItem.getMamDefaultBehaviour()); accountRealm.setLoadHistorySettings(accountItem.getLoadHistorySettings()); accountRealm.setSuccessfulConnectionHappened(accountItem.isSuccessfulConnectionHappened()); + accountRealm.setPushNode(accountItem.getPushNode()); Realm realm = RealmManager.getInstance().getNewBackgroundRealm(); realm.beginTransaction(); diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index b817c3f746..8309ff872a 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -4,11 +4,15 @@ import com.google.firebase.iid.FirebaseInstanceId; import com.xabber.android.data.Application; +import com.xabber.android.data.account.AccountItem; +import com.xabber.android.data.account.AccountManager; import com.xabber.android.data.connection.ConnectionItem; import com.xabber.android.data.connection.listeners.OnConnectedListener; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.http.PushApiClient; +import org.jxmpp.stringprep.XmppStringprepException; + import okhttp3.ResponseBody; import rx.android.schedulers.AndroidSchedulers; import rx.functions.Action1; @@ -44,7 +48,21 @@ public void run() { } public void onEndpointRegistered(String jid, String node) { - + AccountJid accountJid; + try { + accountJid = AccountJid.from(jid); + } catch (XmppStringprepException e) { + Log.d(LOG_TAG, "Cannot parse jid: " + jid + " on endpoint registered"); + return; + } + + // save node to account + if (accountJid != null) { + AccountItem account = AccountManager.getInstance().getAccount(accountJid); + if (account != null) AccountManager.getInstance().setPushNode(account, node); + } + + // enable push on XMPP-server } public void onNewMessagePush(String node) { diff --git a/xabber/src/main/java/com/xabber/android/service/PushService.java b/xabber/src/main/java/com/xabber/android/service/PushService.java index 9a11e83fd5..96117c4469 100644 --- a/xabber/src/main/java/com/xabber/android/service/PushService.java +++ b/xabber/src/main/java/com/xabber/android/service/PushService.java @@ -23,6 +23,7 @@ public class PushService extends FirebaseMessagingService { private static final String ACTION_MESSAGE = "message"; private static final String TARGET_TYPE_XACCOUNT = "xaccount"; private static final String TARGET_TYPE_NODE = "node"; + private static final String REGJID_SUCCESS_RESULT = "success"; Gson gson = new Gson(); @@ -81,7 +82,8 @@ private void onXMPPPushReceived(String body) { if (data != null) { switch (data.getAction()) { case ACTION_REGJID: - PushManager.getInstance().onEndpointRegistered(data.getJid(), data.getNode()); + if (REGJID_SUCCESS_RESULT.equals(data.getResult())) + PushManager.getInstance().onEndpointRegistered(data.getJid(), data.getNode()); break; case ACTION_MESSAGE: PushManager.getInstance().onNewMessagePush(data.getNode()); From fd1684064f946a16203bd88f314014cdd8549d94 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 2 Apr 2019 18:08:42 +0500 Subject: [PATCH 005/237] Added sending enable push iq to XMPP server --- .../xabber/android/data/push/PushManager.java | 47 ++++++++++++++----- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index 8309ff872a..72eda1050e 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -11,7 +11,11 @@ import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.http.PushApiClient; -import org.jxmpp.stringprep.XmppStringprepException; +import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smackx.push_notifications.PushNotificationsManager; + +import java.util.Collection; import okhttp3.ResponseBody; import rx.android.schedulers.AndroidSchedulers; @@ -48,21 +52,26 @@ public void run() { } public void onEndpointRegistered(String jid, String node) { - AccountJid accountJid; - try { - accountJid = AccountJid.from(jid); - } catch (XmppStringprepException e) { - Log.d(LOG_TAG, "Cannot parse jid: " + jid + " on endpoint registered"); - return; + AccountJid accountJid = null; + Collection accounts = AccountManager.getInstance().getEnabledAccounts(); + for (AccountJid account : accounts) { + if (account.getFullJid().asBareJid().equals(jid)) { + accountJid = account; + break; + } } - // save node to account if (accountJid != null) { AccountItem account = AccountManager.getInstance().getAccount(accountJid); - if (account != null) AccountManager.getInstance().setPushNode(account, node); - } + if (account != null) { + + // save node to account + AccountManager.getInstance().setPushNode(account, node); - // enable push on XMPP-server + // enable push on XMPP-server + sendEnablePushIQ(account, accountJid, node); + } + } } public void onNewMessagePush(String node) { @@ -107,4 +116,20 @@ public void call(Throwable throwable) { })); } + private void sendEnablePushIQ(final AccountItem accountItem, final AccountJid jid, final String node) { + Application.getInstance().runInBackground(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(1000); + PushNotificationsManager.getInstanceFor(accountItem.getConnection()) + .enable(jid.getFullJid().asBareJid(), node); + } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException + | SmackException.NotConnectedException | InterruptedException e) { + Log.d(LOG_TAG, "Push notification enabling failed: " + e.toString()); + } + } + }); + } + } From aded8e58beeb063d8340deb4072cff7b2b5cf95e Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 3 Apr 2019 10:11:34 +0500 Subject: [PATCH 006/237] Fixed open flavour --- xabber/src/open/res/values/social_keys.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/xabber/src/open/res/values/social_keys.xml b/xabber/src/open/res/values/social_keys.xml index e42f1271e6..e107dbdad2 100644 --- a/xabber/src/open/res/values/social_keys.xml +++ b/xabber/src/open/res/values/social_keys.xml @@ -15,4 +15,5 @@ temp temp + temp \ No newline at end of file From 6d2b59f976e6664a3ee9916cca4266427d4495a1 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 3 Apr 2019 12:02:59 +0500 Subject: [PATCH 007/237] Fixed send push iq --- .../com/xabber/android/data/push/PushManager.java | 13 +++++++------ .../com/xabber/android/service/PushService.java | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index 72eda1050e..d5bf10b078 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -9,6 +9,7 @@ import com.xabber.android.data.connection.ConnectionItem; import com.xabber.android.data.connection.listeners.OnConnectedListener; import com.xabber.android.data.entity.AccountJid; +import com.xabber.android.data.entity.UserJid; import com.xabber.android.data.http.PushApiClient; import org.jivesoftware.smack.SmackException; @@ -51,7 +52,7 @@ public void run() { }); } - public void onEndpointRegistered(String jid, String node) { + public void onEndpointRegistered(String jid, String pushServiceJid, String node) { AccountJid accountJid = null; Collection accounts = AccountManager.getInstance().getEnabledAccounts(); for (AccountJid account : accounts) { @@ -69,13 +70,13 @@ public void onEndpointRegistered(String jid, String node) { AccountManager.getInstance().setPushNode(account, node); // enable push on XMPP-server - sendEnablePushIQ(account, accountJid, node); + sendEnablePushIQ(account, pushServiceJid, node); } } } public void onNewMessagePush(String node) { - + Log.d(LOG_TAG, "New message push from node: " + node); } public void registerEndpoint(AccountJid accountJid) { @@ -116,16 +117,16 @@ public void call(Throwable throwable) { })); } - private void sendEnablePushIQ(final AccountItem accountItem, final AccountJid jid, final String node) { + private void sendEnablePushIQ(final AccountItem accountItem, final String pushServiceJid, final String node) { Application.getInstance().runInBackground(new Runnable() { @Override public void run() { try { Thread.sleep(1000); PushNotificationsManager.getInstanceFor(accountItem.getConnection()) - .enable(jid.getFullJid().asBareJid(), node); + .enable(UserJid.from(pushServiceJid).getJid(), node); } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException - | SmackException.NotConnectedException | InterruptedException e) { + | SmackException.NotConnectedException | InterruptedException | UserJid.UserJidCreateException e) { Log.d(LOG_TAG, "Push notification enabling failed: " + e.toString()); } } diff --git a/xabber/src/main/java/com/xabber/android/service/PushService.java b/xabber/src/main/java/com/xabber/android/service/PushService.java index 96117c4469..2399cd8985 100644 --- a/xabber/src/main/java/com/xabber/android/service/PushService.java +++ b/xabber/src/main/java/com/xabber/android/service/PushService.java @@ -83,7 +83,7 @@ private void onXMPPPushReceived(String body) { switch (data.getAction()) { case ACTION_REGJID: if (REGJID_SUCCESS_RESULT.equals(data.getResult())) - PushManager.getInstance().onEndpointRegistered(data.getJid(), data.getNode()); + PushManager.getInstance().onEndpointRegistered(data.getJid(), data.getService(), data.getNode()); break; case ACTION_MESSAGE: PushManager.getInstance().onNewMessagePush(data.getNode()); From 9bcd9585bc73cd43fb47eaed3372ef859fe423c5 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 3 Apr 2019 16:44:29 +0500 Subject: [PATCH 008/237] Added starting Xabber Service on receive message push --- .../java/com/xabber/android/data/push/PushManager.java | 5 ++++- .../java/com/xabber/android/receiver/BootReceiver.java | 8 ++------ .../java/com/xabber/android/service/PushService.java | 2 +- xabber/src/main/java/com/xabber/android/utils/Utils.java | 9 +++++++++ 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index d5bf10b078..68372385d7 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -1,5 +1,6 @@ package com.xabber.android.data.push; +import android.content.Context; import android.util.Log; import com.google.firebase.iid.FirebaseInstanceId; @@ -11,6 +12,7 @@ import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.entity.UserJid; import com.xabber.android.data.http.PushApiClient; +import com.xabber.android.utils.Utils; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; @@ -75,8 +77,9 @@ public void onEndpointRegistered(String jid, String pushServiceJid, String node) } } - public void onNewMessagePush(String node) { + public void onNewMessagePush(Context context, String node) { Log.d(LOG_TAG, "New message push from node: " + node); + Utils.startXabberServiceCompat(context); } public void registerEndpoint(AccountJid accountJid) { diff --git a/xabber/src/main/java/com/xabber/android/receiver/BootReceiver.java b/xabber/src/main/java/com/xabber/android/receiver/BootReceiver.java index 31a34e77ab..8153c145a9 100644 --- a/xabber/src/main/java/com/xabber/android/receiver/BootReceiver.java +++ b/xabber/src/main/java/com/xabber/android/receiver/BootReceiver.java @@ -17,11 +17,9 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.os.Build; import com.xabber.android.data.SettingsManager; -import com.xabber.android.data.notification.NotificationManager; -import com.xabber.android.service.XabberService; +import com.xabber.android.utils.Utils; /** * Android boot receiver. @@ -33,9 +31,7 @@ public class BootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (SettingsManager.connectionStartAtBoot()) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) - context.startForegroundService(XabberService.createIntent(context)); - else context.startService(XabberService.createIntent(context)); + Utils.startXabberServiceCompat(context); } else { android.os.Process.killProcess(android.os.Process.myPid()); } diff --git a/xabber/src/main/java/com/xabber/android/service/PushService.java b/xabber/src/main/java/com/xabber/android/service/PushService.java index 2399cd8985..b3221f393a 100644 --- a/xabber/src/main/java/com/xabber/android/service/PushService.java +++ b/xabber/src/main/java/com/xabber/android/service/PushService.java @@ -86,7 +86,7 @@ private void onXMPPPushReceived(String body) { PushManager.getInstance().onEndpointRegistered(data.getJid(), data.getService(), data.getNode()); break; case ACTION_MESSAGE: - PushManager.getInstance().onNewMessagePush(data.getNode()); + PushManager.getInstance().onNewMessagePush(this, data.getNode()); break; default: Log.d(PushService.class.getSimpleName(), diff --git a/xabber/src/main/java/com/xabber/android/utils/Utils.java b/xabber/src/main/java/com/xabber/android/utils/Utils.java index 3e659e239d..cb1c67d75c 100644 --- a/xabber/src/main/java/com/xabber/android/utils/Utils.java +++ b/xabber/src/main/java/com/xabber/android/utils/Utils.java @@ -1,8 +1,11 @@ package com.xabber.android.utils; import android.content.Context; +import android.os.Build; import android.util.TypedValue; +import com.xabber.android.service.XabberService; + import java.util.Calendar; import java.util.Date; @@ -22,4 +25,10 @@ public static boolean isSameDay(Long date1, Long date2) { cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR); } + public static void startXabberServiceCompat(Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + context.startForegroundService(XabberService.createIntent(context)); + else context.startService(XabberService.createIntent(context)); + } + } From dfe08ac0d3a31d24209e5538b60a793d5ed5a867 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 4 Apr 2019 11:52:23 +0500 Subject: [PATCH 009/237] Added special pref to store enabled nodes --- .../xabber/android/data/SettingsManager.java | 8 ++++++++ .../android/data/account/AccountManager.java | 2 ++ .../xabber/android/data/push/PushManager.java | 20 +++++++++++++++++-- xabber/src/main/res/values/preferences.xml | 1 + 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/SettingsManager.java b/xabber/src/main/java/com/xabber/android/data/SettingsManager.java index 59e0ef1a60..8ab9522439 100644 --- a/xabber/src/main/java/com/xabber/android/data/SettingsManager.java +++ b/xabber/src/main/java/com/xabber/android/data/SettingsManager.java @@ -854,6 +854,14 @@ public static int getLastCrowdfundingPosition() { return getInteger(R.string.crowdfunding_last_position_key, 0); } + public static void setEnabledPushNodes(String enabledPushNodes) { + setString(R.string.enabled_push_nodes, enabledPushNodes); + } + + public static String getEnabledPushNodes() { + return getString(R.string.enabled_push_nodes, ""); + } + public static void resetPreferences(Context context, String preferencesName) { context.getSharedPreferences(preferencesName, Context.MODE_PRIVATE).edit().clear().apply(); } diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java index 9ae4711d5d..ade569ffbb 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java @@ -51,6 +51,7 @@ import com.xabber.android.data.log.LogManager; import com.xabber.android.data.notification.BaseAccountNotificationProvider; import com.xabber.android.data.notification.NotificationManager; +import com.xabber.android.data.push.PushManager; import com.xabber.android.data.roster.PresenceManager; import com.xabber.android.data.roster.RosterManager; import com.xabber.android.data.xaccount.XabberAccountManager; @@ -685,6 +686,7 @@ public void setEnabled(AccountJid account, boolean enabled) { accountItem.setEnabled(enabled); requestToWriteAccount(accountItem); + PushManager.getInstance().updateEnabledPushNodes(); } /** diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index 68372385d7..b6427456d8 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -5,6 +5,7 @@ import com.google.firebase.iid.FirebaseInstanceId; import com.xabber.android.data.Application; +import com.xabber.android.data.SettingsManager; import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.account.AccountManager; import com.xabber.android.data.connection.ConnectionItem; @@ -71,6 +72,9 @@ public void onEndpointRegistered(String jid, String pushServiceJid, String node) // save node to account AccountManager.getInstance().setPushNode(account, node); + // update push nodes + updateEnabledPushNodes(); + // enable push on XMPP-server sendEnablePushIQ(account, pushServiceJid, node); } @@ -78,8 +82,8 @@ public void onEndpointRegistered(String jid, String pushServiceJid, String node) } public void onNewMessagePush(Context context, String node) { - Log.d(LOG_TAG, "New message push from node: " + node); - Utils.startXabberServiceCompat(context); + if (SettingsManager.getEnabledPushNodes().contains(node)) + Utils.startXabberServiceCompat(context); } public void registerEndpoint(AccountJid accountJid) { @@ -136,4 +140,16 @@ public void run() { }); } + public void updateEnabledPushNodes() { + StringBuilder stringBuilder = new StringBuilder(); + for (AccountItem accountItem : AccountManager.getInstance().getAllAccountItems()) { + String node = accountItem.getPushNode(); + if (accountItem.isEnabled() && node != null && !node.isEmpty()) { + stringBuilder.append(node); + stringBuilder.append(" "); + } + } + SettingsManager.setEnabledPushNodes(stringBuilder.toString()); + } + } diff --git a/xabber/src/main/res/values/preferences.xml b/xabber/src/main/res/values/preferences.xml index 40d9cba7f2..b45277f52c 100644 --- a/xabber/src/main/res/values/preferences.xml +++ b/xabber/src/main/res/values/preferences.xml @@ -34,6 +34,7 @@ crowdfunding_leader_last_load_timestamp_key first_app_run_timestamp_key crowdfunding_last_position_key + enabled_push_nodes last_sync_date_key @string/last_sync_date_never From 627c75cbdeb046f2d9a4621c778ec2f5213be4d6 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 5 Apr 2019 17:12:39 +0500 Subject: [PATCH 010/237] Added sync mode to work around push notifications --- .../xabber/android/data/ActivityManager.java | 2 + .../com/xabber/android/data/Application.java | 2 + .../data/connection/ReconnectionManager.java | 4 +- .../message/BackpressureMessageSaver.java | 2 + .../notification/NotificationManager.java | 5 +- .../xabber/android/data/push/PushManager.java | 2 +- .../xabber/android/data/push/SyncManager.java | 86 +++++++++++++++++++ .../xabber/android/service/XabberService.java | 9 +- .../java/com/xabber/android/utils/Utils.java | 15 +++- 9 files changed, 119 insertions(+), 8 deletions(-) create mode 100644 xabber/src/main/java/com/xabber/android/data/push/SyncManager.java diff --git a/xabber/src/main/java/com/xabber/android/data/ActivityManager.java b/xabber/src/main/java/com/xabber/android/data/ActivityManager.java index 9c1947ed60..915f1d61e3 100644 --- a/xabber/src/main/java/com/xabber/android/data/ActivityManager.java +++ b/xabber/src/main/java/com/xabber/android/data/ActivityManager.java @@ -24,6 +24,7 @@ import com.xabber.android.data.account.AccountManager; import com.xabber.android.data.connection.CertificateManager; import com.xabber.android.data.log.LogManager; +import com.xabber.android.data.push.SyncManager; import com.xabber.android.ui.activity.AboutActivity; import com.xabber.android.ui.activity.ContactListActivity; import com.xabber.android.ui.activity.LoadActivity; @@ -221,6 +222,7 @@ public void onError(final int resourceId) { CertificateManager.getInstance().registerActivity(activity); AccountManager.getInstance().stopGracePeriod(); + SyncManager.getInstance().onActivityResume(); } /** diff --git a/xabber/src/main/java/com/xabber/android/data/Application.java b/xabber/src/main/java/com/xabber/android/data/Application.java index 81d73bf93d..4a4ad9259d 100644 --- a/xabber/src/main/java/com/xabber/android/data/Application.java +++ b/xabber/src/main/java/com/xabber/android/data/Application.java @@ -59,6 +59,7 @@ import com.xabber.android.data.notification.NotificationManager; import com.xabber.android.data.notification.custom_notification.CustomNotifyPrefsManager; import com.xabber.android.data.push.PushManager; +import com.xabber.android.data.push.SyncManager; import com.xabber.android.data.roster.GroupManager; import com.xabber.android.data.roster.PresenceManager; import com.xabber.android.data.roster.RosterManager; @@ -350,6 +351,7 @@ public void onCreate() { } private void addManagers() { + addManager(SyncManager.getInstance()); addManager(SettingsManager.getInstance()); addManager(LogManager.getInstance()); addManager(DatabaseManager.getInstance()); diff --git a/xabber/src/main/java/com/xabber/android/data/connection/ReconnectionManager.java b/xabber/src/main/java/com/xabber/android/data/connection/ReconnectionManager.java index 7bb5c4562d..26ce4f77d9 100644 --- a/xabber/src/main/java/com/xabber/android/data/connection/ReconnectionManager.java +++ b/xabber/src/main/java/com/xabber/android/data/connection/ReconnectionManager.java @@ -9,6 +9,7 @@ import com.xabber.android.data.connection.listeners.OnConnectedListener; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.log.LogManager; +import com.xabber.android.data.push.SyncManager; import java.util.Collection; import java.util.HashMap; @@ -96,7 +97,8 @@ private void checkConnection(AccountItem accountItem, ReconnectionInfo reconnect private boolean isAccountNeedConnection(AccountItem accountItem) { return accountItem.isEnabled() && accountItem.getRawStatusMode().isOnline() - && !accountItem.getConnection().isAuthenticated(); + && !accountItem.getConnection().isAuthenticated() + && SyncManager.getInstance().isAccountNeedConnection(accountItem); } private boolean isTimeToReconnect(ReconnectionInfo reconnectionInfo) { diff --git a/xabber/src/main/java/com/xabber/android/data/message/BackpressureMessageSaver.java b/xabber/src/main/java/com/xabber/android/data/message/BackpressureMessageSaver.java index 8e07d4e1d3..2faf5f84ae 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/BackpressureMessageSaver.java +++ b/xabber/src/main/java/com/xabber/android/data/message/BackpressureMessageSaver.java @@ -3,6 +3,7 @@ import com.xabber.android.data.database.MessageDatabaseManager; import com.xabber.android.data.database.messagerealm.MessageItem; import com.xabber.android.data.log.LogManager; +import com.xabber.android.data.push.SyncManager; import org.greenrobot.eventbus.EventBus; @@ -58,6 +59,7 @@ public void execute(Realm realm) { @Override public void onSuccess() { EventBus.getDefault().post(new NewMessageEvent()); + SyncManager.getInstance().onMessageSaved(); } }); } catch (Exception e) { diff --git a/xabber/src/main/java/com/xabber/android/data/notification/NotificationManager.java b/xabber/src/main/java/com/xabber/android/data/notification/NotificationManager.java index da804d1cb5..abc783ab49 100644 --- a/xabber/src/main/java/com/xabber/android/data/notification/NotificationManager.java +++ b/xabber/src/main/java/com/xabber/android/data/notification/NotificationManager.java @@ -269,7 +269,7 @@ public void startVibration() { } private void updatePersistentNotification() { - if (!SettingsManager.eventsPersistent()) { + if (!XabberService.getInstance().needForeground()) { return; } @@ -456,6 +456,7 @@ public Notification getPersistentNotification() { @Override public void onClose() { - notificationManager.cancelAll(); + //notificationManager.cancelAll(); + notificationManager.cancel(PERSISTENT_NOTIFICATION_ID); } } diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index b6427456d8..255e0016f6 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -83,7 +83,7 @@ public void onEndpointRegistered(String jid, String pushServiceJid, String node) public void onNewMessagePush(Context context, String node) { if (SettingsManager.getEnabledPushNodes().contains(node)) - Utils.startXabberServiceCompat(context); + Utils.startXabberServiceCompatWithSyncMode(context, node); } public void registerEndpoint(AccountJid accountJid) { diff --git a/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java b/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java new file mode 100644 index 0000000000..694b5fd94e --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java @@ -0,0 +1,86 @@ +package com.xabber.android.data.push; + +import android.content.Context; +import android.content.Intent; + +import com.xabber.android.data.OnTimerListener; +import com.xabber.android.data.account.AccountItem; +import com.xabber.android.service.XabberService; + +public class SyncManager implements OnTimerListener { + + private static final long SYNC_TIME = 15000; + public static final String SYNC_MODE = "SYNC_MODE"; + public static final String PUSH_NODE = "PUSH_NODE"; + + private static SyncManager instance; + private boolean syncMode; + private boolean syncPeriod; + + private long timestamp; + private String pushNode; + + public static SyncManager getInstance() { + if (instance == null) + instance = new SyncManager(); + return instance; + } + + @Override + public void onTimer() { + if (syncPeriod && syncMode && isTimeToShutdown()) { + stopSyncPeriod(); + XabberService.getInstance().changeForeground(); + } + } + + public void onMessageSaved() { + this.timestamp = System.currentTimeMillis(); + } + + public void onServiceStarted(Intent intent) { + if (intent.getBooleanExtra(SYNC_MODE, false)) + startSyncMode(intent.getStringExtra(PUSH_NODE)); + } + + public void onActivityResume() { + stopSyncMode(); + } + + public boolean isAccountNeedConnection(AccountItem accountItem) { + if (!syncMode || pushNode == null) return true; + return pushNode.equals(accountItem.getPushNode()); + } + + public boolean isSyncPeriod() { + return syncPeriod; + } + + public static Intent createXabberServiceIntentWithSyncMode(Context context, String pushNode) { + Intent intent = new Intent(context, XabberService.class); + intent.putExtra(SYNC_MODE, true); + intent.putExtra(PUSH_NODE, pushNode); + return intent; + } + + private void startSyncMode(String pushNode) { + this.syncMode = true; + this.timestamp = System.currentTimeMillis(); + this.pushNode = pushNode; + this.syncPeriod = true; + } + + private void stopSyncMode() { + this.syncMode = false; + this.pushNode = null; + this.syncPeriod = false; + } + + private void stopSyncPeriod() { + this.syncPeriod = false; + } + + private boolean isTimeToShutdown() { + return System.currentTimeMillis() > timestamp + SYNC_TIME; + } +} diff --git a/xabber/src/main/java/com/xabber/android/service/XabberService.java b/xabber/src/main/java/com/xabber/android/service/XabberService.java index 1bb68f3fff..7400b87f3c 100644 --- a/xabber/src/main/java/com/xabber/android/service/XabberService.java +++ b/xabber/src/main/java/com/xabber/android/service/XabberService.java @@ -22,8 +22,8 @@ import com.xabber.android.data.Application; import com.xabber.android.data.account.AccountManager; import com.xabber.android.data.log.LogManager; -import com.xabber.android.data.SettingsManager; import com.xabber.android.data.notification.NotificationManager; +import com.xabber.android.data.push.SyncManager; /** * Basic service to work in background. @@ -48,7 +48,7 @@ public void onCreate() { public void changeForeground() { LogManager.i(this, "changeForeground"); - if (SettingsManager.eventsPersistent() + if (needForeground() && Application.getInstance().isInitialized() && !AccountManager.getInstance().getEnabledAccounts().isEmpty()) { startForeground(NotificationManager.PERSISTENT_NOTIFICATION_ID, @@ -63,6 +63,7 @@ public int onStartCommand(Intent intent, int flags, int startId) { int result = super.onStartCommand(intent, flags, startId); LogManager.i(this, "onStartCommand"); Application.getInstance().onServiceStarted(); + SyncManager.getInstance().onServiceStarted(intent); return result; } @@ -83,4 +84,8 @@ public static Intent createIntent(Context context) { return new Intent(context, XabberService.class); } + public boolean needForeground() { + // TODO: 05.04.19 добавить обработку ситуации, когда есть аккаунты неподдерживающие push + return SyncManager.getInstance().isSyncPeriod(); + } } diff --git a/xabber/src/main/java/com/xabber/android/utils/Utils.java b/xabber/src/main/java/com/xabber/android/utils/Utils.java index cb1c67d75c..175f57f66d 100644 --- a/xabber/src/main/java/com/xabber/android/utils/Utils.java +++ b/xabber/src/main/java/com/xabber/android/utils/Utils.java @@ -1,9 +1,11 @@ package com.xabber.android.utils; import android.content.Context; +import android.content.Intent; import android.os.Build; import android.util.TypedValue; +import com.xabber.android.data.push.SyncManager; import com.xabber.android.service.XabberService; import java.util.Calendar; @@ -26,9 +28,18 @@ public static boolean isSameDay(Long date1, Long date2) { } public static void startXabberServiceCompat(Context context) { + startXabberServiceCompat(context, XabberService.createIntent(context)); + } + + public static void startXabberServiceCompatWithSyncMode(Context context, String pushNode) { + startXabberServiceCompat(context, + SyncManager.createXabberServiceIntentWithSyncMode(context, pushNode)); + } + + private static void startXabberServiceCompat(Context context, Intent intent) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) - context.startForegroundService(XabberService.createIntent(context)); - else context.startService(XabberService.createIntent(context)); + context.startForegroundService(intent); + else context.startService(intent); } } From 8006fb6aeed0b62ddfb2f049499b777d693f0c04 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 5 Apr 2019 17:18:40 +0500 Subject: [PATCH 011/237] Removed notification icon settings --- .../java/com/xabber/android/data/SettingsManager.java | 8 ++++---- xabber/src/main/res/xml/preference_connection.xml | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/SettingsManager.java b/xabber/src/main/java/com/xabber/android/data/SettingsManager.java index 8ab9522439..b7c22db2d4 100644 --- a/xabber/src/main/java/com/xabber/android/data/SettingsManager.java +++ b/xabber/src/main/java/com/xabber/android/data/SettingsManager.java @@ -327,10 +327,10 @@ public static boolean eventsLightningForMuc() { R.bool.events_lightning_default); } - public static boolean eventsPersistent() { - return getBoolean(R.string.events_persistent_key, - R.bool.events_persistent_default); - } +// public static boolean eventsPersistent() { +// return getBoolean(R.string.events_persistent_key, +// R.bool.events_persistent_default); +// } public static boolean eventsShowText() { return getNotifBoolean(R.string.events_show_text_key, diff --git a/xabber/src/main/res/xml/preference_connection.xml b/xabber/src/main/res/xml/preference_connection.xml index 033ab221db..aee7c5e468 100644 --- a/xabber/src/main/res/xml/preference_connection.xml +++ b/xabber/src/main/res/xml/preference_connection.xml @@ -4,11 +4,11 @@ - + + + + + Date: Fri, 5 Apr 2019 17:39:00 +0500 Subject: [PATCH 012/237] Fixed NPE in SyncManager --- .../main/java/com/xabber/android/data/push/SyncManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java b/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java index 694b5fd94e..5a8a0f9e96 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java @@ -9,7 +9,7 @@ public class SyncManager implements OnTimerListener { - private static final long SYNC_TIME = 15000; + private static final long SYNC_TIME = 60000; public static final String SYNC_MODE = "SYNC_MODE"; public static final String PUSH_NODE = "PUSH_NODE"; @@ -39,7 +39,7 @@ public void onMessageSaved() { } public void onServiceStarted(Intent intent) { - if (intent.getBooleanExtra(SYNC_MODE, false)) + if (intent != null && intent.getBooleanExtra(SYNC_MODE, false)) startSyncMode(intent.getStringExtra(PUSH_NODE)); } From 0ad1b37f2ca5d5d8a2d1bb2a778b982155634fa7 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 5 Apr 2019 17:45:07 +0500 Subject: [PATCH 013/237] Up version to 603 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 58aa0d9fa9..a8b95c3d94 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 601 - versionName '2.6.3(601)' + versionCode 603 + versionName '2.6.3(603)' } lintOptions { From 3cef0f743bab22ac129dd659faa32b8afa6e51ae Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 8 Apr 2019 10:20:10 +0500 Subject: [PATCH 014/237] Changes in push sync --- .../java/com/xabber/android/data/push/SyncManager.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java b/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java index 5a8a0f9e96..08b6c94631 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java @@ -16,6 +16,7 @@ public class SyncManager implements OnTimerListener { private static SyncManager instance; private boolean syncMode; private boolean syncPeriod; + private boolean messageSaved; private long timestamp; private String pushNode; @@ -28,14 +29,14 @@ public static SyncManager getInstance() { @Override public void onTimer() { - if (syncPeriod && syncMode && isTimeToShutdown()) { + if (syncPeriod && syncMode && isTimeToStopSyncPeriod()) { stopSyncPeriod(); XabberService.getInstance().changeForeground(); } } public void onMessageSaved() { - this.timestamp = System.currentTimeMillis(); + this.messageSaved = true; } public void onServiceStarted(Intent intent) { @@ -68,6 +69,7 @@ private void startSyncMode(String pushNode) { this.timestamp = System.currentTimeMillis(); this.pushNode = pushNode; this.syncPeriod = true; + this.messageSaved = false; } private void stopSyncMode() { @@ -80,7 +82,7 @@ private void stopSyncPeriod() { this.syncPeriod = false; } - private boolean isTimeToShutdown() { - return System.currentTimeMillis() > timestamp + SYNC_TIME; + private boolean isTimeToStopSyncPeriod() { + return messageSaved || System.currentTimeMillis() > timestamp + SYNC_TIME; } } From 619761325627c3d8209094de21660dfd06e63a86 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 8 Apr 2019 12:18:35 +0500 Subject: [PATCH 015/237] Added push state to account interface --- .../android/data/account/AccountItem.java | 17 +++++++++++ .../xabber/android/data/push/PushManager.java | 30 ++++++++++++++++--- .../xabber/android/data/push/PushState.java | 27 +++++++++++++++++ .../ui/activity/ServerInfoActivity.java | 4 +-- .../adapter/AccountListPreferenceAdapter.java | 6 ++++ .../layout/item_account_for_preference.xml | 11 +++++++ xabber/src/main/res/values/account_list.xml | 4 +++ 7 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 xabber/src/main/java/com/xabber/android/data/push/PushState.java diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java b/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java index 20471ee3bf..d88f95857e 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java @@ -24,6 +24,7 @@ import com.xabber.android.data.connection.ProxyType; import com.xabber.android.data.connection.TLSMode; import com.xabber.android.data.extension.mam.LoadHistorySettings; +import com.xabber.android.data.push.PushState; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Presence.Type; @@ -117,6 +118,7 @@ public class AccountItem extends ConnectionItem implements Comparable getServerInfo(ServiceDiscoveryManager serviceDiscoveryManager) { boolean carbons = org.jivesoftware.smackx.carbons.CarbonManager.getInstanceFor(connection).isSupportedByServer(); boolean mam = MamManager.getInstanceFor(connection).isSupportedByServer(); boolean csi = ClientStateIndicationManager.isSupported(connection); - boolean push = PushNotificationsManager.getInstanceFor(connection).isSupportedByServer(); + boolean push = PushManager.getInstance().isSupport(connection); boolean fileUpload = HttpFileUploadManager.getInstance().isFileUploadSupported(accountItem.getAccount()); boolean mucLight = !MultiUserChatLightManager.getInstanceFor(connection).getLocalServices().isEmpty(); boolean bookmarks = BookmarksManager.getInstance().isSupported(accountItem.getAccount()); diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/AccountListPreferenceAdapter.java b/xabber/src/main/java/com/xabber/android/ui/adapter/AccountListPreferenceAdapter.java index 3b34b15a2a..66b8b6e0a7 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/AccountListPreferenceAdapter.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/AccountListPreferenceAdapter.java @@ -23,6 +23,7 @@ import com.xabber.android.R; import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.account.AccountManager; +import com.xabber.android.data.connection.ConnectionState; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.extension.avatar.AvatarManager; import com.xabber.android.data.log.LogManager; @@ -113,6 +114,9 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { getAccountMainColor(accountItem.getAccount()) : defaultAccountNameColor); accountHolder.status.setText(accountItem.getState().getStringId()); + accountHolder.tvAccountPushStatus.setText(accountItem.getPushState().getStringId()); + accountHolder.tvAccountPushStatus.setVisibility( + accountItem.getState().equals(ConnectionState.connected) ? View.VISIBLE : View.GONE); accountHolder.enabledSwitch.setChecked(accountItem.isEnabled()); @@ -129,6 +133,7 @@ private class AccountViewHolder extends RecyclerView.ViewHolder implements View. TextView name; TextView status; SwitchCompat enabledSwitch; + TextView tvAccountPushStatus; AccountViewHolder(View itemView) { @@ -138,6 +143,7 @@ private class AccountViewHolder extends RecyclerView.ViewHolder implements View. name = (TextView) itemView.findViewById(R.id.item_account_name); status = (TextView) itemView.findViewById(R.id.item_account_status); enabledSwitch = (SwitchCompat) itemView.findViewById(R.id.item_account_switch); + tvAccountPushStatus = itemView.findViewById(R.id.tvAccountPushStatus); // I used on click listener instead of on checked change listener to avoid callback in onBindViewHolder enabledSwitch.setOnClickListener(this); diff --git a/xabber/src/main/res/layout/item_account_for_preference.xml b/xabber/src/main/res/layout/item_account_for_preference.xml index a3ffe8dfa6..2228e14f66 100644 --- a/xabber/src/main/res/layout/item_account_for_preference.xml +++ b/xabber/src/main/res/layout/item_account_for_preference.xml @@ -16,6 +16,7 @@ android:layout_width="match_parent" android:layout_height="@dimen/contact_list_item_height" xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" android:gravity="center_vertical" android:background="@drawable/ripple_background"> @@ -74,6 +75,16 @@ android:gravity="top" android:textColor="?android:attr/textColorSecondary" /> + Disconnecting Offline Waiting to reconnect + + Push not supported + Enabling push + Push enabled From 3192daaf706b846bdd695eb6596973d79d78da43 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 8 Apr 2019 15:15:15 +0500 Subject: [PATCH 016/237] Fixed crash on push received when service also started --- xabber/src/main/java/com/xabber/android/data/Application.java | 3 +++ .../main/java/com/xabber/android/data/push/PushManager.java | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/data/Application.java b/xabber/src/main/java/com/xabber/android/data/Application.java index 4a4ad9259d..f4855a3baa 100644 --- a/xabber/src/main/java/com/xabber/android/data/Application.java +++ b/xabber/src/main/java/com/xabber/android/data/Application.java @@ -607,4 +607,7 @@ public void runOnUiThreadDelay(final Runnable runnable, long delayMillis) { handler.postDelayed(runnable, delayMillis); } + public boolean isServiceStarted() { + return serviceStarted; + } } diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index b1c4b6f865..88e2994d43 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -91,7 +91,8 @@ public void onEndpointRegistered(String jid, String pushServiceJid, String node) } public void onNewMessagePush(Context context, String node) { - if (SettingsManager.getEnabledPushNodes().contains(node)) + if (!Application.getInstance().isServiceStarted() + && SettingsManager.getEnabledPushNodes().contains(node)) Utils.startXabberServiceCompatWithSyncMode(context, node); } From d0d213d05452433fe53862acc1af30894cb294ad Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 8 Apr 2019 15:44:10 +0500 Subject: [PATCH 017/237] Changes in push states --- .../com/xabber/android/data/account/AccountItem.java | 2 +- .../com/xabber/android/data/push/PushManager.java | 2 +- .../java/com/xabber/android/data/push/PushState.java | 11 +++++++---- .../xabber/android/ui/activity/AccountActivity.java | 2 ++ .../ui/adapter/AccountListPreferenceAdapter.java | 10 +++++++--- .../ui/adapter/accountoptions/AccountOption.java | 1 + xabber/src/main/res/values/account_editor.xml | 2 ++ xabber/src/main/res/values/account_list.xml | 7 ++++--- 8 files changed, 25 insertions(+), 12 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java b/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java index d88f95857e..c5120cb4a1 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java @@ -118,7 +118,7 @@ public class AccountItem extends ConnectionItem implements ComparableSynchronization Synchronization with Xabber Account + Push notifications + Server does not support bookmarks diff --git a/xabber/src/main/res/values/account_list.xml b/xabber/src/main/res/values/account_list.xml index 2369abf669..73c36bdbf1 100644 --- a/xabber/src/main/res/values/account_list.xml +++ b/xabber/src/main/res/values/account_list.xml @@ -13,7 +13,8 @@ Offline Waiting to reconnect - Push not supported - Enabling push - Push enabled + Push-notifications disabled + Push-notifications not supported + Connecting.. + Push-notifications enabled From d959f8f80c2a4cb3bd3a05ce063a2b228c7e7904 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 8 Apr 2019 17:49:14 +0500 Subject: [PATCH 018/237] Changes in push state interface --- xabber/src/main/AndroidManifest.xml | 1 + .../android/data/account/AccountItem.java | 9 + .../android/data/account/AccountManager.java | 6 + .../android/ui/activity/AccountActivity.java | 3 + .../ui/activity/AccountPushActivity.java | 155 ++++++++++++++++++ .../adapter/accountoptions/AccountOption.java | 2 +- .../activity_account_push_notifications.xml | 152 +++++++++++++++++ xabber/src/main/res/values/account_editor.xml | 1 + 8 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 xabber/src/main/java/com/xabber/android/ui/activity/AccountPushActivity.java create mode 100644 xabber/src/main/res/layout/activity_account_push_notifications.xml diff --git a/xabber/src/main/AndroidManifest.xml b/xabber/src/main/AndroidManifest.xml index 68d6000156..594d2d58ae 100644 --- a/xabber/src/main/AndroidManifest.xml +++ b/xabber/src/main/AndroidManifest.xml @@ -571,6 +571,7 @@ android:name="android.support.PARENT_ACTIVITY" android:value="com.xabber.android.ui.activity.ChatActivity" /> + \ No newline at end of file diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java b/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java index c5120cb4a1..7f0aeaddc2 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java @@ -117,6 +117,7 @@ public class AccountItem extends ConnectionItem implements Comparable accounts) { + updatePushStatus(); + updateSwitchButton(); + } + + private void updateSwitchButton() { + switchPush.setChecked(accountItem.isPushEnabled()); + } + + private void checkAccount() { + if (AccountManager.getInstance().getAccount(accountItem.getAccount()) == null) { + // in case if account was removed + finish(); + return; + } + } + + private void updateTitle() { + barPainter.updateWithAccountName(accountItem.getAccount()); + tvJid.setText(accountItem.getAccount().getFullJid().asBareJid().toString()); + } + + private void updatePushStatus() { + PushState pushState = accountItem.getPushState(); + tvStatus.setText(pushState.getStringId()); + + switch(pushState) { + case disabled: + ivStatus.setImageResource(R.drawable.ic_sync_disable); + ivStatus.setVisibility(View.VISIBLE); + progressBar.setVisibility(View.GONE); + break; + case notSupport: + ivStatus.setImageResource(R.drawable.ic_sync_disable); + ivStatus.setVisibility(View.VISIBLE); + progressBar.setVisibility(View.GONE); + break; + case connecting: + ivStatus.setVisibility(View.GONE); + progressBar.setVisibility(View.VISIBLE); + break; + case enabled: + ivStatus.setImageResource(R.drawable.ic_sync_done); + ivStatus.setVisibility(View.VISIBLE); + progressBar.setVisibility(View.GONE); + break; + } + } +} diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/accountoptions/AccountOption.java b/xabber/src/main/java/com/xabber/android/ui/adapter/accountoptions/AccountOption.java index b8ca677b1a..72bce044e9 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/accountoptions/AccountOption.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/accountoptions/AccountOption.java @@ -8,7 +8,7 @@ public enum AccountOption { CONNECTION_SETTINGS(R.drawable.ic_settings_grey600_24dp, R.string.account_connection_settings), SYNCHRONIZATION(R.drawable.ic_cloud_sync, R.string.account_sync), - PUSH_NOTIFICATIONS(R.drawable.ic_sync_download, R.string.account_push), + PUSH_NOTIFICATIONS(R.drawable.ic_sync_done, R.string.account_push), COLOR(R.drawable.ic_color_lens_grey600_24dp, R.string.account_color), BLOCK_LIST(R.drawable.ic_block_grey600_24dp, R.string.blocked_contacts), SERVER_INFO(R.drawable.ic_info_grey600_24dp, R.string.account_server_info), diff --git a/xabber/src/main/res/layout/activity_account_push_notifications.xml b/xabber/src/main/res/layout/activity_account_push_notifications.xml new file mode 100644 index 0000000000..b64b654c8e --- /dev/null +++ b/xabber/src/main/res/layout/activity_account_push_notifications.xml @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xabber/src/main/res/values/account_editor.xml b/xabber/src/main/res/values/account_editor.xml index bf98416417..edfeed8020 100644 --- a/xabber/src/main/res/values/account_editor.xml +++ b/xabber/src/main/res/values/account_editor.xml @@ -105,6 +105,7 @@ Synchronization with Xabber Account Push notifications + Enable push notifications Server does not support bookmarks From a015e4bc36881796e2dd7308b12ceff796921cdd Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 8 Apr 2019 18:02:31 +0500 Subject: [PATCH 019/237] Work on push notifications --- .../android/data/account/AccountManager.java | 1 + .../xabber/android/data/push/PushManager.java | 26 ++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java index 6dcc87292d..57bff5d52a 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java @@ -692,6 +692,7 @@ public void setEnabled(AccountJid account, boolean enabled) { public void setPushEnabled(AccountItem accountItem, boolean enabled) { accountItem.setPushEnabled(enabled); // TODO: 08.04.19 запись в бд + if (enabled) PushManager.getInstance().enablePushNotificationsIfNeed(accountItem); PushManager.getInstance().updateEnabledPushNodes(); } diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index adb2afa0e9..ad2c0eaa88 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -53,17 +53,29 @@ public void onConnected(final ConnectionItem connection) { public void run() { AccountJid accountJid = connection.getAccount(); AccountItem accountItem = AccountManager.getInstance().getAccount(accountJid); - - if (accountItem != null) { - if (isSupport(connection.getConnection())) { - accountItem.updatePushState(PushState.connecting); - registerEndpoint(accountJid); - } else accountItem.updatePushState(PushState.notSupport); - } + enablePushNotificationsIfNeed(accountItem); } }); } + public void enablePushNotificationsIfNeed(AccountItem accountItem) { + if (accountItem != null && accountItem.isPushEnabled()) { + if (isSupport(accountItem.getConnection())) { + accountItem.updatePushState(PushState.connecting); + registerEndpoint(accountItem.getAccount()); + } else accountItem.updatePushState(PushState.notSupport); + } + } + + public void disablePushNotification(AccountItem accountItem) { + if (accountItem != null && !accountItem.isPushEnabled()) { + if (isSupport(accountItem.getConnection())) { + accountItem.updatePushState(PushState.connecting); + deleteEndpoint(accountItem.getAccount()); + } else accountItem.updatePushState(PushState.notSupport); + } + } + public void onEndpointRegistered(String jid, String pushServiceJid, String node) { AccountJid accountJid = null; Collection accounts = AccountManager.getInstance().getEnabledAccounts(); From 5f0059f19db4e4be554aae4dc2fc0873f2bead27 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 9 Apr 2019 12:05:40 +0500 Subject: [PATCH 020/237] Changes in push notifications interface --- .../android/data/account/AccountItem.java | 21 +++++-------- .../xabber/android/data/push/PushManager.java | 9 +++--- .../xabber/android/data/push/PushState.java | 30 ------------------- .../android/ui/activity/AccountActivity.java | 3 +- .../ui/activity/AccountPushActivity.java | 26 +--------------- .../adapter/AccountListPreferenceAdapter.java | 5 ++-- xabber/src/main/res/values/account_list.xml | 1 - 7 files changed, 17 insertions(+), 78 deletions(-) delete mode 100644 xabber/src/main/java/com/xabber/android/data/push/PushState.java diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java b/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java index 7f0aeaddc2..5faf0e76b6 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java @@ -24,7 +24,6 @@ import com.xabber.android.data.connection.ProxyType; import com.xabber.android.data.connection.TLSMode; import com.xabber.android.data.extension.mam.LoadHistorySettings; -import com.xabber.android.data.push.PushState; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Presence.Type; @@ -117,9 +116,9 @@ public class AccountItem extends ConnectionItem implements ComparablePush-notifications disabled Push-notifications not supported - Connecting.. Push-notifications enabled From 61afae79a34319bfaa988110f2cabdb0987d869c Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 9 Apr 2019 13:57:15 +0500 Subject: [PATCH 021/237] Changes in push notifications --- .../android/data/account/AccountManager.java | 22 +++++++++++++------ .../android/data/database/RealmManager.java | 10 ++++++++- .../data/database/realm/AccountRealm.java | 20 +++++++++++++++++ .../data/database/sqlite/AccountTable.java | 2 ++ .../xabber/android/data/push/PushManager.java | 15 +++++++------ 5 files changed, 54 insertions(+), 15 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java index 57bff5d52a..cba4451acd 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java @@ -230,6 +230,8 @@ public void onLoad() { } accountItem.setSuccessfulConnectionHappened(accountRealm.isSuccessfulConnectionHappened()); accountItem.setPushNode(accountRealm.getPushNode()); + accountItem.setPushEnabled(accountRealm.isPushEnabled()); + accountItem.setPushWasEnabled(accountRealm.isPushWasEnabled()); accountItems.add(accountItem); @@ -689,13 +691,6 @@ public void setEnabled(AccountJid account, boolean enabled) { PushManager.getInstance().updateEnabledPushNodes(); } - public void setPushEnabled(AccountItem accountItem, boolean enabled) { - accountItem.setPushEnabled(enabled); - // TODO: 08.04.19 запись в бд - if (enabled) PushManager.getInstance().enablePushNotificationsIfNeed(accountItem); - PushManager.getInstance().updateEnabledPushNodes(); - } - /** * @return List of enabled accounts. */ @@ -1223,4 +1218,17 @@ public void setPushNode(AccountItem account, String pushNode) { requestToWriteAccount(account); } + public void setPushEnabled(AccountItem accountItem, boolean enabled) { + accountItem.setPushEnabled(enabled); + requestToWriteAccount(accountItem); + if (enabled) PushManager.getInstance().enablePushNotificationsIfNeed(accountItem); + PushManager.getInstance().updateEnabledPushNodes(); + } + + public void setPushWasEnabled(AccountItem accountItem, boolean enabled) { + accountItem.setPushWasEnabled(enabled); + requestToWriteAccount(accountItem); + PushManager.getInstance().updateEnabledPushNodes(); + } + } diff --git a/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java b/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java index f354aa3f2f..ad228f6e42 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java +++ b/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java @@ -34,7 +34,7 @@ public class RealmManager { private static final String REALM_DATABASE_NAME = "realm_database.realm"; - private static final int REALM_DATABASE_VERSION = 22; + private static final int REALM_DATABASE_VERSION = 23; private static final String LOG_TAG = RealmManager.class.getSimpleName(); private final RealmConfiguration realmConfiguration; @@ -318,6 +318,14 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { oldVersion++; } + + if (oldVersion == 22) { + schema.get(AccountRealm.class.getSimpleName()) + .addField(AccountRealm.Fields.PUSH_ENABLED, boolean.class) + .addField(AccountRealm.Fields.PUSH_WAS_ENABLED, boolean.class); + + oldVersion++; + } } }) .modules(new RealmDatabaseModule()) diff --git a/xabber/src/main/java/com/xabber/android/data/database/realm/AccountRealm.java b/xabber/src/main/java/com/xabber/android/data/database/realm/AccountRealm.java index f745e16220..98509fd73a 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/realm/AccountRealm.java +++ b/xabber/src/main/java/com/xabber/android/data/database/realm/AccountRealm.java @@ -36,6 +36,8 @@ public static class Fields { public static final String LOAD_HISTORY_SETTINGS = "loadHistorySettings"; public static final String SUCCESSFUL_CONNECTION_HAPPENED = "successfulConnectionHappened"; public static final String PUSH_NODE = "pushNode"; + public static final String PUSH_ENABLED = "pushEnabled"; + public static final String PUSH_WAS_ENABLED = "pushWasEnabled"; } @PrimaryKey @@ -95,6 +97,8 @@ public static class Fields { private boolean successfulConnectionHappened; private String pushNode; + private boolean pushEnabled; + private boolean pushWasEnabled; public AccountRealm(String id) { this.id = id; @@ -426,4 +430,20 @@ public String getPushNode() { public void setPushNode(String pushNode) { this.pushNode = pushNode; } + + public boolean isPushEnabled() { + return pushEnabled; + } + + public void setPushEnabled(boolean pushEnabled) { + this.pushEnabled = pushEnabled; + } + + public boolean isPushWasEnabled() { + return pushWasEnabled; + } + + public void setPushWasEnabled(boolean pushWasEnabled) { + this.pushWasEnabled = pushWasEnabled; + } } diff --git a/xabber/src/main/java/com/xabber/android/data/database/sqlite/AccountTable.java b/xabber/src/main/java/com/xabber/android/data/database/sqlite/AccountTable.java index d35ea62b27..35a93dc6e7 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/sqlite/AccountTable.java +++ b/xabber/src/main/java/com/xabber/android/data/database/sqlite/AccountTable.java @@ -484,6 +484,8 @@ private void saveAccountRealm(String id, AccountItem accountItem) { accountRealm.setLoadHistorySettings(accountItem.getLoadHistorySettings()); accountRealm.setSuccessfulConnectionHappened(accountItem.isSuccessfulConnectionHappened()); accountRealm.setPushNode(accountItem.getPushNode()); + accountRealm.setPushEnabled(accountItem.isPushEnabled()); + accountRealm.setPushWasEnabled(accountItem.isPushWasEnabled()); Realm realm = RealmManager.getInstance().getNewBackgroundRealm(); realm.beginTransaction(); diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index 05ea5ed2a1..ecf943688b 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -62,7 +62,7 @@ public void enablePushNotificationsIfNeed(AccountItem accountItem) { if (accountItem != null && accountItem.isPushEnabled()) { if (isSupport(accountItem.getConnection())) { registerEndpoint(accountItem.getAccount()); - } else accountItem.setPushWasEnabled(false); + } else AccountManager.getInstance().setPushWasEnabled(accountItem, false); } } @@ -70,7 +70,7 @@ public void disablePushNotification(AccountItem accountItem) { if (accountItem != null && !accountItem.isPushEnabled()) { if (isSupport(accountItem.getConnection())) { deleteEndpoint(accountItem.getAccount()); - } accountItem.setPushWasEnabled(false); + } AccountManager.getInstance().setPushWasEnabled(accountItem, false); } } @@ -106,7 +106,7 @@ public void onNewMessagePush(Context context, String node) { Utils.startXabberServiceCompatWithSyncMode(context, node); } - public void registerEndpoint(AccountJid accountJid) { + private void registerEndpoint(AccountJid accountJid) { compositeSubscription.add( PushApiClient.registerEndpoint( FirebaseInstanceId.getInstance().getToken(), accountJid.toString()) @@ -125,7 +125,7 @@ public void call(Throwable throwable) { })); } - public void deleteEndpoint(AccountJid accountJid) { + private void deleteEndpoint(AccountJid accountJid) { compositeSubscription.add( PushApiClient.deleteEndpoint( FirebaseInstanceId.getInstance().getToken(), accountJid.toString()) @@ -152,11 +152,11 @@ public void run() { Thread.sleep(1000); boolean success = PushNotificationsManager.getInstanceFor(accountItem.getConnection()) .enable(UserJid.from(pushServiceJid).getJid(), node); - accountItem.setPushWasEnabled(success); + AccountManager.getInstance().setPushWasEnabled(accountItem, success); } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | InterruptedException | UserJid.UserJidCreateException e) { Log.d(LOG_TAG, "Push notification enabling failed: " + e.toString()); - accountItem.setPushWasEnabled(false); + AccountManager.getInstance().setPushWasEnabled(accountItem, false); } } }); @@ -166,7 +166,8 @@ public void updateEnabledPushNodes() { StringBuilder stringBuilder = new StringBuilder(); for (AccountItem accountItem : AccountManager.getInstance().getAllAccountItems()) { String node = accountItem.getPushNode(); - if (accountItem.isEnabled() && node != null && !node.isEmpty()) { + if (accountItem.isEnabled() && accountItem.isPushEnabled() + && accountItem.isPushWasEnabled() && node != null && !node.isEmpty()) { stringBuilder.append(node); stringBuilder.append(" "); } From eecc07329367e92ed451b24323722d9a58e044ce Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 9 Apr 2019 14:19:12 +0500 Subject: [PATCH 022/237] Added disable push method --- .../android/data/account/AccountItem.java | 9 + .../android/data/account/AccountManager.java | 4 +- .../android/data/database/RealmManager.java | 9 +- .../data/database/realm/AccountRealm.java | 10 ++ .../data/database/sqlite/AccountTable.java | 1 + .../xabber/android/data/push/PushManager.java | 160 ++++++++++-------- 6 files changed, 123 insertions(+), 70 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java b/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java index 5faf0e76b6..23cf60994e 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java @@ -119,6 +119,7 @@ public class AccountItem extends ConnectionItem implements Comparable accounts = AccountManager.getInstance().getEnabledAccounts(); @@ -89,7 +75,7 @@ public void onEndpointRegistered(String jid, String pushServiceJid, String node) if (account != null) { // save node to account - AccountManager.getInstance().setPushNode(account, node); + AccountManager.getInstance().setPushNode(account, node, pushServiceJid); // update push nodes updateEnabledPushNodes(); @@ -106,60 +92,22 @@ public void onNewMessagePush(Context context, String node) { Utils.startXabberServiceCompatWithSyncMode(context, node); } - private void registerEndpoint(AccountJid accountJid) { - compositeSubscription.add( - PushApiClient.registerEndpoint( - FirebaseInstanceId.getInstance().getToken(), accountJid.toString()) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Action1() { - @Override - public void call(ResponseBody responseBody) { - Log.d(LOG_TAG, "Endpoint successfully registered"); - } - }, new Action1() { - @Override - public void call(Throwable throwable) { - Log.d(LOG_TAG, "Endpoint register failed: " + throwable.toString()); - } - })); - } + /** Api */ - private void deleteEndpoint(AccountJid accountJid) { - compositeSubscription.add( - PushApiClient.deleteEndpoint( - FirebaseInstanceId.getInstance().getToken(), accountJid.toString()) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Action1() { - @Override - public void call(ResponseBody responseBody) { - Log.d(LOG_TAG, "Endpoint successfully unregistered"); - } - }, new Action1() { - @Override - public void call(Throwable throwable) { - Log.d(LOG_TAG, "Endpoint unregister failed: " + throwable.toString()); - } - })); + public void enablePushNotificationsIfNeed(AccountItem accountItem) { + if (accountItem != null && accountItem.isPushEnabled()) { + if (isSupport(accountItem.getConnection())) { + registerEndpoint(accountItem.getAccount()); + } else AccountManager.getInstance().setPushWasEnabled(accountItem, false); + } } - private void sendEnablePushIQ(final AccountItem accountItem, final String pushServiceJid, final String node) { - Application.getInstance().runInBackground(new Runnable() { - @Override - public void run() { - try { - Thread.sleep(1000); - boolean success = PushNotificationsManager.getInstanceFor(accountItem.getConnection()) - .enable(UserJid.from(pushServiceJid).getJid(), node); - AccountManager.getInstance().setPushWasEnabled(accountItem, success); - } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException - | SmackException.NotConnectedException | InterruptedException | UserJid.UserJidCreateException e) { - Log.d(LOG_TAG, "Push notification enabling failed: " + e.toString()); - AccountManager.getInstance().setPushWasEnabled(accountItem, false); - } - } - }); + public void disablePushNotification(AccountItem accountItem) { + if (accountItem != null && !accountItem.isPushEnabled()) { + if (isSupport(accountItem.getConnection())) { + deleteEndpoint(accountItem); + } AccountManager.getInstance().setPushWasEnabled(accountItem, false); + } } public void updateEnabledPushNodes() { @@ -187,4 +135,80 @@ public boolean isSupport(XMPPTCPConnection connection) { } } + /** Private */ + + private void registerEndpoint(AccountJid accountJid) { + compositeSubscription.add( + PushApiClient.registerEndpoint( + FirebaseInstanceId.getInstance().getToken(), accountJid.toString()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Action1() { + @Override + public void call(ResponseBody responseBody) { + Log.d(LOG_TAG, "Endpoint successfully registered"); + } + }, new Action1() { + @Override + public void call(Throwable throwable) { + Log.d(LOG_TAG, "Endpoint register failed: " + throwable.toString()); + } + })); + } + + private void deleteEndpoint(final AccountItem accountItem) { + compositeSubscription.add( + PushApiClient.deleteEndpoint( + FirebaseInstanceId.getInstance().getToken(), accountItem.getAccount().toString()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Action1() { + @Override + public void call(ResponseBody responseBody) { + Log.d(LOG_TAG, "Endpoint successfully unregistered"); + sendDisablePushIQ(accountItem, accountItem.getPushServiceJid(), accountItem.getPushNode()); + } + }, new Action1() { + @Override + public void call(Throwable throwable) { + Log.d(LOG_TAG, "Endpoint unregister failed: " + throwable.toString()); + } + })); + } + + private void sendEnablePushIQ(final AccountItem accountItem, final String pushServiceJid, final String node) { + Application.getInstance().runInBackground(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(1000); + boolean success = PushNotificationsManager.getInstanceFor(accountItem.getConnection()) + .enable(UserJid.from(pushServiceJid).getJid(), node); + AccountManager.getInstance().setPushWasEnabled(accountItem, success); + } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException + | SmackException.NotConnectedException | InterruptedException | UserJid.UserJidCreateException e) { + Log.d(LOG_TAG, "Push notification enabling failed: " + e.toString()); + AccountManager.getInstance().setPushWasEnabled(accountItem, false); + } + } + }); + } + + private void sendDisablePushIQ(final AccountItem accountItem, final String pushServiceJid, final String node) { + Application.getInstance().runInBackground(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(1000); + boolean success = PushNotificationsManager.getInstanceFor(accountItem.getConnection()) + .disable(UserJid.from(pushServiceJid).getJid(), node); + AccountManager.getInstance().setPushWasEnabled(accountItem, !success); + } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException + | SmackException.NotConnectedException | InterruptedException | UserJid.UserJidCreateException e) { + Log.d(LOG_TAG, "Push notification enabling failed: " + e.toString()); + } + } + }); + } + } From c564a6ba77f27ba0f0526eb90e39a8360138b506 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 9 Apr 2019 14:35:34 +0500 Subject: [PATCH 023/237] Changes in push notifications --- .../android/data/account/AccountManager.java | 1 + .../ui/activity/AccountPushActivity.java | 22 +---- .../activity_account_push_notifications.xml | 87 +------------------ 3 files changed, 8 insertions(+), 102 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java index 3f021adde4..d878c01fa4 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java @@ -1224,6 +1224,7 @@ public void setPushEnabled(AccountItem accountItem, boolean enabled) { accountItem.setPushEnabled(enabled); requestToWriteAccount(accountItem); if (enabled) PushManager.getInstance().enablePushNotificationsIfNeed(accountItem); + else PushManager.getInstance().disablePushNotification(accountItem); PushManager.getInstance().updateEnabledPushNodes(); } diff --git a/xabber/src/main/java/com/xabber/android/ui/activity/AccountPushActivity.java b/xabber/src/main/java/com/xabber/android/ui/activity/AccountPushActivity.java index 69e48b8df2..9bbb564d5e 100644 --- a/xabber/src/main/java/com/xabber/android/ui/activity/AccountPushActivity.java +++ b/xabber/src/main/java/com/xabber/android/ui/activity/AccountPushActivity.java @@ -5,8 +5,6 @@ import android.os.Bundle; import android.support.v7.widget.Toolbar; import android.view.View; -import android.widget.ImageView; -import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.Switch; import android.widget.TextView; @@ -28,11 +26,7 @@ public class AccountPushActivity extends ManagedActivity implements OnAccountCha private BarPainter barPainter; private RelativeLayout rlPushSwitch; private Switch switchPush; - - private TextView tvJid; - private TextView tvStatus; - private ImageView ivStatus; - private ProgressBar progressBar; + private TextView tvPushState; private AccountItem accountItem; @@ -79,10 +73,7 @@ public void onClick(View v) { switchPush = findViewById(R.id.switchPush); rlPushSwitch = findViewById(R.id.rlPushSwitch); - tvJid = findViewById(R.id.tvJid); - tvStatus = findViewById(R.id.tvStatus); - ivStatus = findViewById(R.id.ivStatus); - progressBar = findViewById(R.id.progressBar); + tvPushState = findViewById(R.id.tvPushState); rlPushSwitch.setOnClickListener(new View.OnClickListener() { @Override @@ -99,17 +90,17 @@ protected void onResume() { checkAccount(); updateSwitchButton(); updateTitle(); - updatePushStatus(); } @Override public void onAccountsChanged(Collection accounts) { - updatePushStatus(); updateSwitchButton(); } private void updateSwitchButton() { switchPush.setChecked(accountItem.isPushEnabled()); + tvPushState.setText(accountItem.isPushWasEnabled() + ? R.string.account_push_state_enabled : R.string.account_push_state_disabled); } private void checkAccount() { @@ -122,10 +113,5 @@ private void checkAccount() { private void updateTitle() { barPainter.updateWithAccountName(accountItem.getAccount()); - tvJid.setText(accountItem.getAccount().getFullJid().asBareJid().toString()); - } - - private void updatePushStatus() { - } } diff --git a/xabber/src/main/res/layout/activity_account_push_notifications.xml b/xabber/src/main/res/layout/activity_account_push_notifications.xml index b64b654c8e..e0058e1f16 100644 --- a/xabber/src/main/res/layout/activity_account_push_notifications.xml +++ b/xabber/src/main/res/layout/activity_account_push_notifications.xml @@ -7,80 +7,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -119,11 +45,12 @@ /> @@ -139,14 +66,6 @@ android:clickable="false" /> - - \ No newline at end of file From 46d4f993fa0822fccd29ed6894fa4633648d275e Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 9 Apr 2019 15:05:15 +0500 Subject: [PATCH 024/237] Changes in push log --- .../src/main/java/com/xabber/android/data/push/PushManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index 5de3b68af5..9fd68a5b28 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -205,7 +205,7 @@ public void run() { AccountManager.getInstance().setPushWasEnabled(accountItem, !success); } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | InterruptedException | UserJid.UserJidCreateException e) { - Log.d(LOG_TAG, "Push notification enabling failed: " + e.toString()); + Log.d(LOG_TAG, "Push notification disabling failed: " + e.toString()); } } }); From 81cbf23ad15bc8641fc7d3e74515662cdcd76033 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 9 Apr 2019 16:34:43 +0500 Subject: [PATCH 025/237] Changes in persistent notification work --- .../data/notification/NotificationManager.java | 6 ++---- .../com/xabber/android/service/XabberService.java | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/notification/NotificationManager.java b/xabber/src/main/java/com/xabber/android/data/notification/NotificationManager.java index abc783ab49..13a74c2d3e 100644 --- a/xabber/src/main/java/com/xabber/android/data/notification/NotificationManager.java +++ b/xabber/src/main/java/com/xabber/android/data/notification/NotificationManager.java @@ -269,14 +269,12 @@ public void startVibration() { } private void updatePersistentNotification() { - if (!XabberService.getInstance().needForeground()) { - return; - } - if (XabberService.getInstance() == null) return; // we do not want to show persistent notification if there are no enabled accounts XabberService.getInstance().changeForeground(); + if (!XabberService.getInstance().needForeground()) return; + Collection accountList = AccountManager.getInstance().getEnabledAccounts(); if (accountList.isEmpty()) { return; diff --git a/xabber/src/main/java/com/xabber/android/service/XabberService.java b/xabber/src/main/java/com/xabber/android/service/XabberService.java index 7400b87f3c..a27a65ff63 100644 --- a/xabber/src/main/java/com/xabber/android/service/XabberService.java +++ b/xabber/src/main/java/com/xabber/android/service/XabberService.java @@ -20,7 +20,9 @@ import android.os.IBinder; import com.xabber.android.data.Application; +import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.account.AccountManager; +import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.notification.NotificationManager; import com.xabber.android.data.push.SyncManager; @@ -85,7 +87,15 @@ public static Intent createIntent(Context context) { } public boolean needForeground() { - // TODO: 05.04.19 добавить обработку ситуации, когда есть аккаунты неподдерживающие push - return SyncManager.getInstance().isSyncPeriod(); + if (SyncManager.getInstance().isSyncPeriod()) return true; + for (AccountJid accountJid : AccountManager.getInstance().getEnabledAccounts()) { + AccountItem accountItem = AccountManager.getInstance().getAccount(accountJid); + if (accountItem != null) { + if (!accountItem.isPushWasEnabled() + && SyncManager.getInstance().isAccountNeedConnection(accountItem)) + return true; + } + } + return false; } } From 87666b78e4e34326f6aaeb825448cfdb60a105f4 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 10 Apr 2019 11:54:41 +0500 Subject: [PATCH 026/237] Fixed blocking iq sending because timeout while vcard request --- .../extension/vcard/CustomVCardManager.java | 6 ++++ .../data/extension/vcard/VCardManager.java | 32 ++++++------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/vcard/CustomVCardManager.java b/xabber/src/main/java/com/xabber/android/data/extension/vcard/CustomVCardManager.java index 10a8374c1b..7f7ce718fe 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/vcard/CustomVCardManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/vcard/CustomVCardManager.java @@ -114,6 +114,12 @@ public VCard loadVCard(Jid jid) throws SmackException.NoResponseException, XMPPE return result; } + public void sendVCardRequest(Jid jid) throws SmackException.NotConnectedException, InterruptedException { + VCard vcardRequest = new VCard(); + vcardRequest.setTo(jid); + connection().sendStanza(vcardRequest); + } + /** * Returns true if the given entity understands the vCard-XML format and allows the exchange of such. * diff --git a/xabber/src/main/java/com/xabber/android/data/extension/vcard/VCardManager.java b/xabber/src/main/java/com/xabber/android/data/extension/vcard/VCardManager.java index 0f4d57ce75..4be1fa6589 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/vcard/VCardManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/vcard/VCardManager.java @@ -44,6 +44,7 @@ import org.jivesoftware.smack.AbstractXMPPConnection; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ.Type; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Stanza; @@ -325,6 +326,12 @@ public void onStanza(ConnectionItem connection, Stanza stanza) { } } } + + if (stanza instanceof VCard) { + Jid from = stanza.getFrom(); + if (from == null) return; + onVCardReceived(account, from, (VCard) stanza); + } } @SuppressWarnings("WeakerAccess") @@ -343,8 +350,6 @@ void getVCard(final AccountJid account, final Jid srcUser) { return; } - VCard vCard = null; - Collection blockedContacts = BlockingManager.getInstance().getBlockedContacts(account); for (UserJid blockedContact : blockedContacts) { if (blockedContact.getBareJid().equals(srcUser.asBareJid())) { @@ -357,17 +362,10 @@ void getVCard(final AccountJid account, final Jid srcUser) { if (entityBareJid != null) { vCardRequests.add(srcUser); try { - vCard = vCardManager.loadVCard(srcUser); - } catch (SmackException.NoResponseException | SmackException.NotConnectedException e) { + vCardManager.sendVCardRequest(srcUser); + } catch (SmackException.NotConnectedException e) { LogManager.exception(this, e); LogManager.w(this, "Error getting vCard: " + e.getMessage()); - } catch (XMPPException.XMPPErrorException e ) { - LogManager.exception(this, e); - LogManager.w(this, "XMPP error getting vCard: " + e.getMessage() + e.getXMPPError()); - - if (e.getXMPPError().getCondition() == XMPPError.Condition.item_not_found) { - vCard = new VCard(); - } } catch (ClassCastException e) { LogManager.exception(this, e); @@ -379,18 +377,6 @@ void getVCard(final AccountJid account, final Jid srcUser) { } vCardRequests.remove(srcUser); } - - final VCard finalVCard = vCard; - Application.getInstance().runOnUiThread(new Runnable() { - @Override - public void run() { - if (finalVCard == null) { - onVCardFailed(account, srcUser); - } else { - onVCardReceived(account, srcUser, finalVCard); - } - } - }); } public void saveVCard(final AccountJid account, final VCard vCard) { From 7074bab2c004810763bafda2c846e81794849835 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 10 Apr 2019 11:55:10 +0500 Subject: [PATCH 027/237] Fixed error on enabling push notifications at start --- .../java/com/xabber/android/data/push/PushManager.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index 9fd68a5b28..b194f6a994 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -53,6 +53,11 @@ public void onConnected(final ConnectionItem connection) { Application.getInstance().runInBackground(new Runnable() { @Override public void run() { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } AccountJid accountJid = connection.getAccount(); AccountItem accountItem = AccountManager.getInstance().getAccount(accountJid); enablePushNotificationsIfNeed(accountItem); @@ -181,7 +186,6 @@ private void sendEnablePushIQ(final AccountItem accountItem, final String pushSe @Override public void run() { try { - Thread.sleep(1000); boolean success = PushNotificationsManager.getInstanceFor(accountItem.getConnection()) .enable(UserJid.from(pushServiceJid).getJid(), node); AccountManager.getInstance().setPushWasEnabled(accountItem, success); @@ -199,7 +203,6 @@ private void sendDisablePushIQ(final AccountItem accountItem, final String pushS @Override public void run() { try { - Thread.sleep(1000); boolean success = PushNotificationsManager.getInstanceFor(accountItem.getConnection()) .disable(UserJid.from(pushServiceJid).getJid(), node); AccountManager.getInstance().setPushWasEnabled(accountItem, !success); From 56c76b820c0ed87931e491c7d485c0a9050d97ab Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 10 Apr 2019 12:15:02 +0500 Subject: [PATCH 028/237] Fixed updating ui in AccountPushActivity --- .../xabber/android/ui/activity/AccountPushActivity.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/xabber/src/main/java/com/xabber/android/ui/activity/AccountPushActivity.java b/xabber/src/main/java/com/xabber/android/ui/activity/AccountPushActivity.java index 9bbb564d5e..a770d060eb 100644 --- a/xabber/src/main/java/com/xabber/android/ui/activity/AccountPushActivity.java +++ b/xabber/src/main/java/com/xabber/android/ui/activity/AccountPushActivity.java @@ -4,6 +4,7 @@ import android.content.Intent; import android.os.Bundle; import android.support.v7.widget.Toolbar; +import android.util.Log; import android.view.View; import android.widget.RelativeLayout; import android.widget.Switch; @@ -87,11 +88,18 @@ public void onClick(View v) { @Override protected void onResume() { super.onResume(); + Application.getInstance().addUIListener(OnAccountChangedListener.class, this); checkAccount(); updateSwitchButton(); updateTitle(); } + @Override + protected void onPause() { + super.onPause(); + Application.getInstance().removeUIListener(OnAccountChangedListener.class, this); + } + @Override public void onAccountsChanged(Collection accounts) { updateSwitchButton(); From d24e221264f9bafafe48d887f1777ae9447d72e6 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 10 Apr 2019 17:40:28 +0500 Subject: [PATCH 029/237] Added accountJid to notification intent Added accountJid to syncMode Changes in notification action while app is background --- .../com/xabber/android/data/Application.java | 2 + .../DelayedNotificationActionManager.java | 55 +++++++++++++++++++ .../MessageNotificationCreator.java | 18 +++--- .../xabber/android/data/push/SyncManager.java | 31 +++++++++-- .../receiver/NotificationReceiver.java | 27 +++++++-- .../java/com/xabber/android/utils/Utils.java | 6 ++ 6 files changed, 122 insertions(+), 17 deletions(-) create mode 100644 xabber/src/main/java/com/xabber/android/data/notification/DelayedNotificationActionManager.java diff --git a/xabber/src/main/java/com/xabber/android/data/Application.java b/xabber/src/main/java/com/xabber/android/data/Application.java index f4855a3baa..28847449d7 100644 --- a/xabber/src/main/java/com/xabber/android/data/Application.java +++ b/xabber/src/main/java/com/xabber/android/data/Application.java @@ -56,6 +56,7 @@ import com.xabber.android.data.message.ReceiptManager; import com.xabber.android.data.message.chat.ChatManager; import com.xabber.android.data.message.phrase.PhraseManager; +import com.xabber.android.data.notification.DelayedNotificationActionManager; import com.xabber.android.data.notification.NotificationManager; import com.xabber.android.data.notification.custom_notification.CustomNotifyPrefsManager; import com.xabber.android.data.push.PushManager; @@ -390,6 +391,7 @@ private void addManagers() { addManager(CertificateManager.getInstance()); addManager(XMPPAuthManager.getInstance()); addManager(PushManager.getInstance()); + addManager(DelayedNotificationActionManager.getInstance()); } /** diff --git a/xabber/src/main/java/com/xabber/android/data/notification/DelayedNotificationActionManager.java b/xabber/src/main/java/com/xabber/android/data/notification/DelayedNotificationActionManager.java new file mode 100644 index 0000000000..fa7e7172f2 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/notification/DelayedNotificationActionManager.java @@ -0,0 +1,55 @@ +package com.xabber.android.data.notification; + +import android.content.Intent; +import com.xabber.android.data.Application; +import com.xabber.android.data.connection.ConnectionItem; +import com.xabber.android.data.connection.listeners.OnConnectedListener; +import com.xabber.android.receiver.NotificationReceiver; +import java.util.ArrayList; +import java.util.List; + +public class DelayedNotificationActionManager implements OnConnectedListener { + + private static DelayedNotificationActionManager instance; + private List delayedNotificationActions = new ArrayList<>(); + + public static DelayedNotificationActionManager getInstance() { + if (instance == null) + instance = new DelayedNotificationActionManager(); + return instance; + } + + @Override + public void onConnected(ConnectionItem connection) { + Application.getInstance().runInBackground(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + Application.getInstance().runOnUiThread(new Runnable() { + @Override + public void run() { + onLoaded(); + } + }); + } + }); + } + + private void onLoaded() { + for (Intent intent : delayedNotificationActions) { + NotificationReceiver.onNotificationAction(intent); + } + delayedNotificationActions.clear(); + } + + public void addAction(Intent intent) { + if (!delayedNotificationActions.contains(intent)) + delayedNotificationActions.add(intent); + } + +} diff --git a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationCreator.java b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationCreator.java index 5a2ebd9c17..8c9a9e5677 100644 --- a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationCreator.java +++ b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationCreator.java @@ -78,7 +78,7 @@ public void createNotification(MessageNotificationManager.Chat chat, boolean ale boolean showText = isNeedShowTextInNotification(chat); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - builder.addAction(createReplyAction(chat.getNotificationId())) + builder.addAction(createReplyAction(chat.getNotificationId(), chat.getAccountJid())) .setStyle(createMessageStyle(chat, showText)); } else { builder.setContentTitle(createTitleSingleChat(chat.getMessages().size(), chat.getChatTitle())) @@ -90,8 +90,8 @@ public void createNotification(MessageNotificationManager.Chat chat, boolean ale if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O && alert && !inGracePeriod(chat)) addEffects(builder, chat.getLastMessage().getMessageText().toString(), chat, context); - builder.addAction(createMarkAsReadAction(chat.getNotificationId())) - .addAction(createMuteAction(chat.getNotificationId())); + builder.addAction(createMarkAsReadAction(chat.getNotificationId(), chat.getAccountJid())) + .addAction(createMuteAction(chat.getNotificationId(), chat.getAccountJid())); sendNotification(builder, chat.getNotificationId()); } @@ -363,26 +363,26 @@ private boolean isAppInForeground(Context context) { /** ACTIONS */ - private NotificationCompat.Action createReplyAction(int notificationId) { + private NotificationCompat.Action createReplyAction(int notificationId, AccountJid accountJid) { RemoteInput remoteInput = new RemoteInput.Builder(NotificationReceiver.KEY_REPLY_TEXT) .setLabel(context.getString(R.string.chat_input_hint)) .build(); return new NotificationCompat.Action.Builder(R.drawable.ic_message_forwarded_14dp, - context.getString(R.string.action_reply), NotificationReceiver.createReplyIntent(context, notificationId)) + context.getString(R.string.action_reply), NotificationReceiver.createReplyIntent(context, notificationId, accountJid)) .addRemoteInput(remoteInput) .build(); } - private NotificationCompat.Action createMarkAsReadAction(int notificationId) { + private NotificationCompat.Action createMarkAsReadAction(int notificationId, AccountJid accountJid) { return new NotificationCompat.Action.Builder(R.drawable.ic_mark_as_read, - context.getString(R.string.action_mark_as_read), NotificationReceiver.createMarkAsReadIntent(context, notificationId)) + context.getString(R.string.action_mark_as_read), NotificationReceiver.createMarkAsReadIntent(context, notificationId, accountJid)) .build(); } - private NotificationCompat.Action createMuteAction(int notificationId) { + private NotificationCompat.Action createMuteAction(int notificationId, AccountJid accountJid) { return new NotificationCompat.Action.Builder(R.drawable.ic_snooze, - context.getString(R.string.action_snooze), NotificationReceiver.createMuteIntent(context, notificationId)) + context.getString(R.string.action_snooze), NotificationReceiver.createMuteIntent(context, notificationId, accountJid)) .build(); } diff --git a/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java b/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java index 08b6c94631..536c17f5a2 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java @@ -2,9 +2,11 @@ import android.content.Context; import android.content.Intent; +import android.os.Parcelable; import com.xabber.android.data.OnTimerListener; import com.xabber.android.data.account.AccountItem; +import com.xabber.android.data.entity.AccountJid; import com.xabber.android.service.XabberService; public class SyncManager implements OnTimerListener { @@ -12,6 +14,7 @@ public class SyncManager implements OnTimerListener { private static final long SYNC_TIME = 60000; public static final String SYNC_MODE = "SYNC_MODE"; public static final String PUSH_NODE = "PUSH_NODE"; + public static final String ACCOUNT_JID = "ACCOUNT_JID"; private static SyncManager instance; private boolean syncMode; @@ -20,6 +23,7 @@ public class SyncManager implements OnTimerListener { private long timestamp; private String pushNode; + private AccountJid accountJid; public static SyncManager getInstance() { if (instance == null) @@ -40,8 +44,10 @@ public void onMessageSaved() { } public void onServiceStarted(Intent intent) { - if (intent != null && intent.getBooleanExtra(SYNC_MODE, false)) - startSyncMode(intent.getStringExtra(PUSH_NODE)); + if (intent != null && intent.getBooleanExtra(SYNC_MODE, false)) { + if (intent.hasExtra(PUSH_NODE)) startSyncMode(intent.getStringExtra(PUSH_NODE)); + else if (intent.hasExtra(ACCOUNT_JID)) startSyncMode((AccountJid) intent.getParcelableExtra(ACCOUNT_JID)); + } } public void onActivityResume() { @@ -49,8 +55,9 @@ public void onActivityResume() { } public boolean isAccountNeedConnection(AccountItem accountItem) { - if (!syncMode || pushNode == null) return true; - return pushNode.equals(accountItem.getPushNode()); + if (!syncMode || (pushNode == null && accountJid == null)) return true; + if (pushNode != null) return pushNode.equals(accountItem.getPushNode()); + else return accountJid.equals(accountItem.getAccount()); } public boolean isSyncPeriod() { @@ -64,6 +71,13 @@ public static Intent createXabberServiceIntentWithSyncMode(Context context, Stri return intent; } + public static Intent createXabberServiceIntentWithSyncMode(Context context, AccountJid accountJid) { + Intent intent = new Intent(context, XabberService.class); + intent.putExtra(SYNC_MODE, true); + intent.putExtra(ACCOUNT_JID, (Parcelable) accountJid); + return intent; + } + private void startSyncMode(String pushNode) { this.syncMode = true; this.timestamp = System.currentTimeMillis(); @@ -72,9 +86,18 @@ private void startSyncMode(String pushNode) { this.messageSaved = false; } + private void startSyncMode(AccountJid accountJid) { + this.syncMode = true; + this.timestamp = System.currentTimeMillis(); + this.accountJid = accountJid; + this.syncPeriod = true; + this.messageSaved = false; + } + private void stopSyncMode() { this.syncMode = false; this.pushNode = null; + this.accountJid = null; this.syncPeriod = false; } diff --git a/xabber/src/main/java/com/xabber/android/receiver/NotificationReceiver.java b/xabber/src/main/java/com/xabber/android/receiver/NotificationReceiver.java index 69e907b81a..af677d3bba 100644 --- a/xabber/src/main/java/com/xabber/android/receiver/NotificationReceiver.java +++ b/xabber/src/main/java/com/xabber/android/receiver/NotificationReceiver.java @@ -5,13 +5,19 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.os.Parcelable; import android.support.v4.app.RemoteInput; +import com.xabber.android.data.Application; +import com.xabber.android.data.entity.AccountJid; +import com.xabber.android.data.notification.DelayedNotificationActionManager; import com.xabber.android.data.notification.MessageNotificationManager; +import com.xabber.android.utils.Utils; public class NotificationReceiver extends BroadcastReceiver { private static final String KEY_NOTIFICATION_ID = "KEY_NOTIFICATION_ID"; + private static final String KEY_ACCOUNT_JID = "KEY_ACCOUNT_JID"; public static final String KEY_REPLY_TEXT = "KEY_REPLY_TEXT"; private static final String ACTION_CANCEL = "ACTION_CANCEL"; @@ -21,11 +27,21 @@ public class NotificationReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { + AccountJid accountJid = intent.getParcelableExtra(KEY_ACCOUNT_JID); + + if (!Application.getInstance().isServiceStarted()) { + if (accountJid != null) { + Utils.startXabberServiceCompatWithSyncMode(context, accountJid); + DelayedNotificationActionManager.getInstance().addAction(intent); + } + } onNotificationAction(intent); + } + + public static void onNotificationAction(Intent intent) { String action = intent.getAction(); int notificationId = intent.getIntExtra(KEY_NOTIFICATION_ID, 1); if (action == null) return; - switch (action) { case ACTION_MUTE: MessageNotificationManager.getInstance().onNotificationMuted(notificationId); @@ -45,26 +61,29 @@ public void onReceive(Context context, Intent intent) { } } - public static PendingIntent createReplyIntent(Context context, int notificationId) { + public static PendingIntent createReplyIntent(Context context, int notificationId, AccountJid accountJid) { Intent intent = new Intent(context, NotificationReceiver.class); intent.setAction(NotificationReceiver.ACTION_REPLY); intent.putExtra(KEY_NOTIFICATION_ID, notificationId); + intent.putExtra(KEY_ACCOUNT_JID, (Parcelable) accountJid); return PendingIntent.getBroadcast(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT); } - public static PendingIntent createMarkAsReadIntent(Context context, int notificationId) { + public static PendingIntent createMarkAsReadIntent(Context context, int notificationId, AccountJid accountJid) { Intent intent = new Intent(context, NotificationReceiver.class); intent.setAction(NotificationReceiver.ACTION_MARK_AS_READ); intent.putExtra(KEY_NOTIFICATION_ID, notificationId); + intent.putExtra(KEY_ACCOUNT_JID, (Parcelable) accountJid); return PendingIntent.getBroadcast(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT); } - public static PendingIntent createMuteIntent(Context context, int notificationId) { + public static PendingIntent createMuteIntent(Context context, int notificationId, AccountJid accountJid) { Intent intent = new Intent(context, NotificationReceiver.class); intent.setAction(NotificationReceiver.ACTION_MUTE); intent.putExtra(KEY_NOTIFICATION_ID, notificationId); + intent.putExtra(KEY_ACCOUNT_JID, (Parcelable) accountJid); return PendingIntent.getBroadcast(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT); } diff --git a/xabber/src/main/java/com/xabber/android/utils/Utils.java b/xabber/src/main/java/com/xabber/android/utils/Utils.java index 175f57f66d..612a4c96a9 100644 --- a/xabber/src/main/java/com/xabber/android/utils/Utils.java +++ b/xabber/src/main/java/com/xabber/android/utils/Utils.java @@ -5,6 +5,7 @@ import android.os.Build; import android.util.TypedValue; +import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.push.SyncManager; import com.xabber.android.service.XabberService; @@ -36,6 +37,11 @@ public static void startXabberServiceCompatWithSyncMode(Context context, String SyncManager.createXabberServiceIntentWithSyncMode(context, pushNode)); } + public static void startXabberServiceCompatWithSyncMode(Context context, AccountJid accountJid) { + startXabberServiceCompat(context, + SyncManager.createXabberServiceIntentWithSyncMode(context, accountJid)); + } + private static void startXabberServiceCompat(Context context, Intent intent) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(intent); From d5cba46be2aa045ac558a9e8c86b9165505a98db Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 10 Apr 2019 17:56:08 +0500 Subject: [PATCH 030/237] Fixed NotificationReceived.onReceive --- .../java/com/xabber/android/receiver/NotificationReceiver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/receiver/NotificationReceiver.java b/xabber/src/main/java/com/xabber/android/receiver/NotificationReceiver.java index af677d3bba..187300c2cc 100644 --- a/xabber/src/main/java/com/xabber/android/receiver/NotificationReceiver.java +++ b/xabber/src/main/java/com/xabber/android/receiver/NotificationReceiver.java @@ -34,7 +34,7 @@ public void onReceive(Context context, Intent intent) { Utils.startXabberServiceCompatWithSyncMode(context, accountJid); DelayedNotificationActionManager.getInstance().addAction(intent); } - } onNotificationAction(intent); + } else onNotificationAction(intent); } public static void onNotificationAction(Intent intent) { From d5552c5f128ff0df62fd292f9af812f9ffcc0dd0 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 11 Apr 2019 16:54:35 +0500 Subject: [PATCH 031/237] Changes in delayed notification actions --- .../android/data/notification/Action.java | 39 ++++++ .../DelayedNotificationActionManager.java | 15 +-- .../android/data/notification/FullAction.java | 24 ++++ .../MessageNotificationManager.java | 114 ++++++++++-------- .../receiver/NotificationReceiver.java | 40 +++--- 5 files changed, 155 insertions(+), 77 deletions(-) create mode 100644 xabber/src/main/java/com/xabber/android/data/notification/Action.java create mode 100644 xabber/src/main/java/com/xabber/android/data/notification/FullAction.java diff --git a/xabber/src/main/java/com/xabber/android/data/notification/Action.java b/xabber/src/main/java/com/xabber/android/data/notification/Action.java new file mode 100644 index 0000000000..89eb6c1aae --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/notification/Action.java @@ -0,0 +1,39 @@ +package com.xabber.android.data.notification; + +public class Action { + private int notificationID; + private CharSequence replyText; + private ActionType actionType; + + public Action(int notificationID, CharSequence replyText, ActionType actionType) { + this.notificationID = notificationID; + this.replyText = replyText; + this.actionType = actionType; + } + + public Action(int notificationID, ActionType actionType) { + this.notificationID = notificationID; + this.actionType = actionType; + } + + public int getNotificationID() { + return notificationID; + } + + public CharSequence getReplyText() { + return replyText; + } + + public ActionType getActionType() { + return actionType; + } + + public enum ActionType { + reply, + read, + snooze, + cancel + } +} + + diff --git a/xabber/src/main/java/com/xabber/android/data/notification/DelayedNotificationActionManager.java b/xabber/src/main/java/com/xabber/android/data/notification/DelayedNotificationActionManager.java index fa7e7172f2..7b015dbac4 100644 --- a/xabber/src/main/java/com/xabber/android/data/notification/DelayedNotificationActionManager.java +++ b/xabber/src/main/java/com/xabber/android/data/notification/DelayedNotificationActionManager.java @@ -1,17 +1,15 @@ package com.xabber.android.data.notification; -import android.content.Intent; import com.xabber.android.data.Application; import com.xabber.android.data.connection.ConnectionItem; import com.xabber.android.data.connection.listeners.OnConnectedListener; -import com.xabber.android.receiver.NotificationReceiver; import java.util.ArrayList; import java.util.List; public class DelayedNotificationActionManager implements OnConnectedListener { private static DelayedNotificationActionManager instance; - private List delayedNotificationActions = new ArrayList<>(); + private List delayedActions = new ArrayList<>(); public static DelayedNotificationActionManager getInstance() { if (instance == null) @@ -41,15 +39,14 @@ public void run() { } private void onLoaded() { - for (Intent intent : delayedNotificationActions) { - NotificationReceiver.onNotificationAction(intent); + for (FullAction action : delayedActions) { + MessageNotificationManager.getInstance().performAction(action); } - delayedNotificationActions.clear(); + delayedActions.clear(); } - public void addAction(Intent intent) { - if (!delayedNotificationActions.contains(intent)) - delayedNotificationActions.add(intent); + public void addAction(FullAction action) { + delayedActions.add(action); } } diff --git a/xabber/src/main/java/com/xabber/android/data/notification/FullAction.java b/xabber/src/main/java/com/xabber/android/data/notification/FullAction.java new file mode 100644 index 0000000000..fd81fca17a --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/notification/FullAction.java @@ -0,0 +1,24 @@ +package com.xabber.android.data.notification; + +import com.xabber.android.data.entity.AccountJid; +import com.xabber.android.data.entity.UserJid; + +public class FullAction extends Action { + + private AccountJid accountJid; + private UserJid userJid; + + public FullAction(Action action, AccountJid accountJid, UserJid userJid) { + super(action.getNotificationID(), action.getReplyText(), action.getActionType()); + this.accountJid = accountJid; + this.userJid = userJid; + } + + public AccountJid getAccountJid() { + return accountJid; + } + + public UserJid getUserJid() { + return userJid; + } +} diff --git a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java index ed6dedc77c..47dda3dc7d 100644 --- a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java +++ b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java @@ -25,6 +25,7 @@ import com.xabber.android.data.roster.RosterManager; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -42,6 +43,7 @@ public class MessageNotificationManager implements OnLoadListener { private static MessageNotificationManager instance; private List chats = new ArrayList<>(); private Message lastMessage = null; + private HashMap delayedActions = new HashMap<>(); private MessageNotificationManager() { context = Application.getInstance(); @@ -71,58 +73,30 @@ public static MessageNotificationManager getInstance() { /** LISTENER */ - public void onNotificationReplied(int notificationId, final CharSequence replyText) { - final Chat chat = getChat(notificationId); - if (chat != null) { - // send message - MessageManager.getInstance().sendMessage( - chat.getAccountJid(), chat.getUserJid(), replyText.toString()); - - // update notification - addMessage(chat, "", replyText, false); - saveNotifChatToRealm(chat); - } - } - - public void onNotificationCanceled(int notificationId) { - if (notificationId == MESSAGE_BUNDLE_NOTIFICATION_ID) - removeAllMessageNotifications(); - else removeChat(notificationId); - } - - public void onNotificationMuted(int notificationId) { - Chat chatNotif = getChat(notificationId); - if (chatNotif != null) { - AbstractChat chat = MessageManager.getInstance().getChat( - chatNotif.getAccountJid(), chatNotif.getUserJid()); + public void onNotificationAction(Action action) { + if (action.getActionType() != Action.ActionType.cancel) { + Chat chat = getChat(action.getNotificationID()); if (chat != null) { - chat.setNotificationState(new NotificationState(NotificationState.NotificationMode.snooze2h, - (int) (System.currentTimeMillis() / 1000L)), true); - callUiUpdate(); + performAction(new FullAction(action, chat.getAccountJid(), chat.getUserJid())); + + // update notification + if (action.getActionType() == Action.ActionType.reply) { + addMessage(chat, "", action.getReplyText(), false); + saveNotifChatToRealm(chat); + } } } // cancel notification - notificationManager.cancel(notificationId); - onNotificationCanceled(notificationId); - } - - public void onNotificationMarkedAsRead(int notificationId) { - // mark chat as read - Chat chatNotif = getChat(notificationId); - if (chatNotif != null) { - AbstractChat chat = MessageManager.getInstance().getChat( - chatNotif.getAccountJid(), chatNotif.getUserJid()); - if (chat != null) { - AccountManager.getInstance().stopGracePeriod(chat.getAccount()); - chat.markAsReadAll(true); - callUiUpdate(); - } + if (action.getActionType() != Action.ActionType.reply) { + notificationManager.cancel(action.getNotificationID()); + onNotificationCanceled(action.getNotificationID()); } + } - // cancel notification - notificationManager.cancel(notificationId); - onNotificationCanceled(notificationId); + public void onDelayedNotificationAction(Action action) { + notificationManager.cancel(action.getNotificationID()); + delayedActions.put(action.getNotificationID(), action); } @Override @@ -214,10 +188,54 @@ public void rebuildAllNotifications() { /** PRIVATE METHODS */ + private void onNotificationCanceled(int notificationId) { + if (notificationId == MESSAGE_BUNDLE_NOTIFICATION_ID) + removeAllMessageNotifications(); + else removeChat(notificationId); + } + + public void performAction(FullAction action) { + AccountJid accountJid = action.getAccountJid(); + UserJid userJid = action.getUserJid(); + + switch (action.getActionType()) { + case read: + AbstractChat chat = MessageManager.getInstance().getChat(accountJid, userJid); + if (chat != null) { + AccountManager.getInstance().stopGracePeriod(chat.getAccount()); + chat.markAsReadAll(true); + callUiUpdate(); + } + break; + case snooze: + AbstractChat chat1 = MessageManager.getInstance().getChat(accountJid, userJid); + if (chat1 != null) { + chat1.setNotificationState(new NotificationState(NotificationState.NotificationMode.snooze2h, + (int) (System.currentTimeMillis() / 1000L)), true); + callUiUpdate(); + } + break; + case reply: + MessageManager.getInstance().sendMessage(accountJid, userJid, action.getReplyText().toString()); + } + } + private void onLoaded(List loadedChats) { - this.chats.addAll(loadedChats); - if (loadedChats != null && loadedChats.size() > 0) { - List messages = loadedChats.get(loadedChats.size() - 1).getMessages(); + for (Chat chat : loadedChats) { + if (delayedActions.containsKey(chat.notificationId)) { + Action action = delayedActions.get(chat.notificationId); + if (action != null) { + notificationManager.cancel(action.getNotificationID()); + DelayedNotificationActionManager.getInstance().addAction( + new FullAction(action, chat.getAccountJid(), chat.getUserJid())); + removeNotifChatFromRealm(chat.accountJid, chat.userJid); + } + } else chats.add(chat); + } + delayedActions.clear(); + + if (chats != null && chats.size() > 0) { + List messages = chats.get(chats.size() - 1).getMessages(); if (messages != null && messages.size() > 0) { lastMessage = messages.get(messages.size() - 1); rebuildAllNotifications(); diff --git a/xabber/src/main/java/com/xabber/android/receiver/NotificationReceiver.java b/xabber/src/main/java/com/xabber/android/receiver/NotificationReceiver.java index 187300c2cc..11479f0f12 100644 --- a/xabber/src/main/java/com/xabber/android/receiver/NotificationReceiver.java +++ b/xabber/src/main/java/com/xabber/android/receiver/NotificationReceiver.java @@ -10,7 +10,7 @@ import com.xabber.android.data.Application; import com.xabber.android.data.entity.AccountJid; -import com.xabber.android.data.notification.DelayedNotificationActionManager; +import com.xabber.android.data.notification.Action; import com.xabber.android.data.notification.MessageNotificationManager; import com.xabber.android.utils.Utils; @@ -28,36 +28,36 @@ public class NotificationReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { AccountJid accountJid = intent.getParcelableExtra(KEY_ACCOUNT_JID); - if (!Application.getInstance().isServiceStarted()) { - if (accountJid != null) { + MessageNotificationManager.getInstance().onDelayedNotificationAction(createAction(intent)); + if (accountJid != null) Utils.startXabberServiceCompatWithSyncMode(context, accountJid); - DelayedNotificationActionManager.getInstance().addAction(intent); - } - } else onNotificationAction(intent); + + } else MessageNotificationManager.getInstance().onNotificationAction(createAction(intent)); } - public static void onNotificationAction(Intent intent) { - String action = intent.getAction(); + private Action createAction(Intent intent) { int notificationId = intent.getIntExtra(KEY_NOTIFICATION_ID, 1); + String action = intent.getAction(); + + if (action == null) + return new Action(notificationId, Action.ActionType.cancel); - if (action == null) return; switch (action) { case ACTION_MUTE: - MessageNotificationManager.getInstance().onNotificationMuted(notificationId); - break; - case ACTION_CANCEL: - MessageNotificationManager.getInstance().onNotificationCanceled(notificationId); - break; + return new Action(notificationId, Action.ActionType.snooze); + case ACTION_REPLY: + CharSequence reply = null; Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); - if (remoteInput != null) - MessageNotificationManager.getInstance().onNotificationReplied(notificationId, - remoteInput.getCharSequence(KEY_REPLY_TEXT)); - break; + if (remoteInput != null) reply = remoteInput.getCharSequence(KEY_REPLY_TEXT); + return new Action(notificationId, reply, Action.ActionType.reply); + case ACTION_MARK_AS_READ: - MessageNotificationManager.getInstance().onNotificationMarkedAsRead(notificationId); - break; + return new Action(notificationId, Action.ActionType.read); + + default: // ACTION_CANCEL + return new Action(notificationId, Action.ActionType.cancel); } } From 247dfcc296993b8525682d41ff469ad92a2d8c32 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 11 Apr 2019 18:41:47 +0500 Subject: [PATCH 032/237] Up version to 604 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index a8b95c3d94..d327c26c36 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 603 - versionName '2.6.3(603)' + versionCode 604 + versionName '2.6.4(604)' } lintOptions { From 58ff7381ad0d1a1c1ce98a8a8081943acecdb349 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 12 Apr 2019 14:28:42 +0500 Subject: [PATCH 033/237] Added log to push receiving --- .../main/java/com/xabber/android/data/push/PushManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index b194f6a994..44d7fe2cce 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -13,6 +13,7 @@ import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.entity.UserJid; import com.xabber.android.data.http.PushApiClient; +import com.xabber.android.data.log.LogManager; import com.xabber.android.utils.Utils; import org.jivesoftware.smack.SmackException; @@ -93,8 +94,10 @@ public void onEndpointRegistered(String jid, String pushServiceJid, String node) public void onNewMessagePush(Context context, String node) { if (!Application.getInstance().isServiceStarted() - && SettingsManager.getEnabledPushNodes().contains(node)) + && SettingsManager.getEnabledPushNodes().contains(node)) { Utils.startXabberServiceCompatWithSyncMode(context, node); + LogManager.d(PushManager.class.getName(), "Received message push. Starting service."); + } else LogManager.d(PushManager.class.getName(), "Received message push. Service not started."); } /** Api */ From bb348a9b83bddeb889615c483f59b1bf618b9027 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 12 Apr 2019 16:14:34 +0500 Subject: [PATCH 034/237] Fixed push notifications for several accounts --- .../xabber/android/data/push/PushManager.java | 6 ++- .../xabber/android/data/push/SyncManager.java | 41 +++++++++++++++---- .../receiver/NotificationReceiver.java | 8 +++- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index 44d7fe2cce..48e7154140 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -97,7 +97,11 @@ public void onNewMessagePush(Context context, String node) { && SettingsManager.getEnabledPushNodes().contains(node)) { Utils.startXabberServiceCompatWithSyncMode(context, node); LogManager.d(PushManager.class.getName(), "Received message push. Starting service."); - } else LogManager.d(PushManager.class.getName(), "Received message push. Service not started."); + } else if (SyncManager.getInstance().isSyncMode()) { + LogManager.d(PushManager.class.getName(), "Received message push. Service also started. Add account to allowed accounts."); + SyncManager.getInstance().addAllowedAccount(node); + } + LogManager.d(PushManager.class.getName(), "Received message push. Service also started. Not a sync mode - account maybe connected."); } /** Api */ diff --git a/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java b/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java index 536c17f5a2..f6c3b4e8c3 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java @@ -9,6 +9,9 @@ import com.xabber.android.data.entity.AccountJid; import com.xabber.android.service.XabberService; +import java.util.ArrayList; +import java.util.List; + public class SyncManager implements OnTimerListener { private static final long SYNC_TIME = 60000; @@ -22,8 +25,8 @@ public class SyncManager implements OnTimerListener { private boolean messageSaved; private long timestamp; - private String pushNode; - private AccountJid accountJid; + private List pushNodes = new ArrayList<>(); + private List accountJids = new ArrayList<>(); public static SyncManager getInstance() { if (instance == null) @@ -55,15 +58,18 @@ public void onActivityResume() { } public boolean isAccountNeedConnection(AccountItem accountItem) { - if (!syncMode || (pushNode == null && accountJid == null)) return true; - if (pushNode != null) return pushNode.equals(accountItem.getPushNode()); - else return accountJid.equals(accountItem.getAccount()); + if (!syncMode || (pushNodes.isEmpty() && accountJids.isEmpty())) return true; + return pushNodes.contains(accountItem.getPushNode()) || accountJids.contains(accountItem.getAccount()); } public boolean isSyncPeriod() { return syncPeriod; } + public boolean isSyncMode() { + return syncMode; + } + public static Intent createXabberServiceIntentWithSyncMode(Context context, String pushNode) { Intent intent = new Intent(context, XabberService.class); intent.putExtra(SYNC_MODE, true); @@ -78,10 +84,26 @@ public static Intent createXabberServiceIntentWithSyncMode(Context context, Acco return intent; } + public boolean isAccountAllowed(AccountJid account) { + if (!syncMode) return true; + return accountJids.contains(account); + } + + public void addAllowedAccount(String node) { + startSyncMode(node); + XabberService.getInstance().changeForeground(); + } + + public void addAllowedAccount(AccountJid account) { + startSyncMode(account); + XabberService.getInstance().changeForeground(); + } + private void startSyncMode(String pushNode) { this.syncMode = true; this.timestamp = System.currentTimeMillis(); - this.pushNode = pushNode; + if (this.pushNodes != null && !this.pushNodes.contains(pushNode)) + this.pushNodes.add(pushNode); this.syncPeriod = true; this.messageSaved = false; } @@ -89,15 +111,16 @@ private void startSyncMode(String pushNode) { private void startSyncMode(AccountJid accountJid) { this.syncMode = true; this.timestamp = System.currentTimeMillis(); - this.accountJid = accountJid; + if (this.accountJids != null && !this.accountJids.contains(accountJid)) + this.accountJids.add(accountJid); this.syncPeriod = true; this.messageSaved = false; } private void stopSyncMode() { this.syncMode = false; - this.pushNode = null; - this.accountJid = null; + this.pushNodes.clear(); + this.accountJids.clear(); this.syncPeriod = false; } diff --git a/xabber/src/main/java/com/xabber/android/receiver/NotificationReceiver.java b/xabber/src/main/java/com/xabber/android/receiver/NotificationReceiver.java index 11479f0f12..ef7ddb9e37 100644 --- a/xabber/src/main/java/com/xabber/android/receiver/NotificationReceiver.java +++ b/xabber/src/main/java/com/xabber/android/receiver/NotificationReceiver.java @@ -12,6 +12,7 @@ import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.notification.Action; import com.xabber.android.data.notification.MessageNotificationManager; +import com.xabber.android.data.push.SyncManager; import com.xabber.android.utils.Utils; public class NotificationReceiver extends BroadcastReceiver { @@ -33,7 +34,12 @@ public void onReceive(Context context, Intent intent) { if (accountJid != null) Utils.startXabberServiceCompatWithSyncMode(context, accountJid); - } else MessageNotificationManager.getInstance().onNotificationAction(createAction(intent)); + } else { + if (!SyncManager.getInstance().isAccountAllowed(accountJid)) + SyncManager.getInstance().addAllowedAccount(accountJid); + + MessageNotificationManager.getInstance().onNotificationAction(createAction(intent)); + } } private Action createAction(Intent intent) { From aa15c74fd833766ae862da393f7833ef7bd8f0d3 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 12 Apr 2019 16:34:01 +0500 Subject: [PATCH 035/237] Foreground icon hides after performing delayed action --- .../notification/MessageNotificationManager.java | 2 ++ .../com/xabber/android/data/push/SyncManager.java | 14 +++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java index 47dda3dc7d..2dd2204f46 100644 --- a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java +++ b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java @@ -20,6 +20,7 @@ import com.xabber.android.data.message.AbstractChat; import com.xabber.android.data.message.MessageManager; import com.xabber.android.data.message.NotificationState; +import com.xabber.android.data.push.SyncManager; import com.xabber.android.data.roster.OnContactChangedListener; import com.xabber.android.data.roster.RosterContact; import com.xabber.android.data.roster.RosterManager; @@ -218,6 +219,7 @@ public void performAction(FullAction action) { case reply: MessageManager.getInstance().sendMessage(accountJid, userJid, action.getReplyText().toString()); } + SyncManager.getInstance().onDelayedNotificationActionDone(); } private void onLoaded(List loadedChats) { diff --git a/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java b/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java index f6c3b4e8c3..b8d89ae07b 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java @@ -22,7 +22,7 @@ public class SyncManager implements OnTimerListener { private static SyncManager instance; private boolean syncMode; private boolean syncPeriod; - private boolean messageSaved; + private boolean syncActionDone; private long timestamp; private List pushNodes = new ArrayList<>(); @@ -43,7 +43,11 @@ public void onTimer() { } public void onMessageSaved() { - this.messageSaved = true; + this.syncActionDone = true; + } + + public void onDelayedNotificationActionDone() { + this.syncActionDone = true; } public void onServiceStarted(Intent intent) { @@ -105,7 +109,7 @@ private void startSyncMode(String pushNode) { if (this.pushNodes != null && !this.pushNodes.contains(pushNode)) this.pushNodes.add(pushNode); this.syncPeriod = true; - this.messageSaved = false; + this.syncActionDone = false; } private void startSyncMode(AccountJid accountJid) { @@ -114,7 +118,7 @@ private void startSyncMode(AccountJid accountJid) { if (this.accountJids != null && !this.accountJids.contains(accountJid)) this.accountJids.add(accountJid); this.syncPeriod = true; - this.messageSaved = false; + this.syncActionDone = false; } private void stopSyncMode() { @@ -129,6 +133,6 @@ private void stopSyncPeriod() { } private boolean isTimeToStopSyncPeriod() { - return messageSaved || System.currentTimeMillis() > timestamp + SYNC_TIME; + return syncActionDone || System.currentTimeMillis() > timestamp + SYNC_TIME; } } From 98fcb837fe976b7d3fec6923d61b99e2bf43b403 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 12 Apr 2019 18:31:51 +0500 Subject: [PATCH 036/237] Fixed sending enable/disable push iq --- .../xabber/android/data/push/PushManager.java | 83 ++++++++++++------- 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index 48e7154140..de539411ff 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -10,6 +10,7 @@ import com.xabber.android.data.account.AccountManager; import com.xabber.android.data.connection.ConnectionItem; import com.xabber.android.data.connection.listeners.OnConnectedListener; +import com.xabber.android.data.connection.listeners.OnPacketListener; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.entity.UserJid; import com.xabber.android.data.http.PushApiClient; @@ -18,14 +19,18 @@ import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.tcp.XMPPTCPConnection; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; -import org.jivesoftware.smackx.push_notifications.PushNotificationsManager; +import org.jivesoftware.smackx.push_notifications.element.DisablePushNotificationsIQ; +import org.jivesoftware.smackx.push_notifications.element.EnablePushNotificationsIQ; import org.jivesoftware.smackx.push_notifications.element.PushNotificationsElements; import org.jxmpp.jid.EntityBareJid; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import okhttp3.ResponseBody; import rx.android.schedulers.AndroidSchedulers; @@ -33,7 +38,7 @@ import rx.schedulers.Schedulers; import rx.subscriptions.CompositeSubscription; -public class PushManager implements OnConnectedListener { +public class PushManager implements OnConnectedListener, OnPacketListener { private static final String LOG_TAG = PushManager.class.getSimpleName(); @@ -46,6 +51,7 @@ public static PushManager getInstance() { } private CompositeSubscription compositeSubscription = new CompositeSubscription(); + private HashMap waitingIQs = new HashMap<>(); /** Listeners */ @@ -67,6 +73,7 @@ public void run() { } public void onEndpointRegistered(String jid, String pushServiceJid, String node) { + LogManager.d(LOG_TAG, "Received endpoint-registered push. Send push enable iq."); AccountJid accountJid = null; Collection accounts = AccountManager.getInstance().getEnabledAccounts(); for (AccountJid account : accounts) { @@ -96,12 +103,28 @@ public void onNewMessagePush(Context context, String node) { if (!Application.getInstance().isServiceStarted() && SettingsManager.getEnabledPushNodes().contains(node)) { Utils.startXabberServiceCompatWithSyncMode(context, node); - LogManager.d(PushManager.class.getName(), "Received message push. Starting service."); + LogManager.d(LOG_TAG, "Received message push. Starting service."); } else if (SyncManager.getInstance().isSyncMode()) { - LogManager.d(PushManager.class.getName(), "Received message push. Service also started. Add account to allowed accounts."); + LogManager.d(LOG_TAG, "Received message push. Service also started. Add account to allowed accounts."); SyncManager.getInstance().addAllowedAccount(node); } - LogManager.d(PushManager.class.getName(), "Received message push. Service also started. Not a sync mode - account maybe connected."); + LogManager.d(LOG_TAG, "Received message push. Service also started. Not a sync mode - account maybe connected."); + } + + @Override + public void onStanza(ConnectionItem connection, Stanza packet) { + if (packet instanceof IQ && ((IQ) packet).getType() != IQ.Type.error) { + if (waitingIQs.containsKey(packet.getStanzaId())) { + + AccountJid account = connection.getAccount(); + AccountItem accountItem = AccountManager.getInstance().getAccount(account); + Boolean enable = waitingIQs.get(packet.getStanzaId()); + if (accountItem != null && enable != null) { + AccountManager.getInstance().setPushWasEnabled(accountItem, enable); + } + waitingIQs.remove(packet.getStanzaId()); + } + } } /** Api */ @@ -189,36 +212,32 @@ public void call(Throwable throwable) { } private void sendEnablePushIQ(final AccountItem accountItem, final String pushServiceJid, final String node) { - Application.getInstance().runInBackground(new Runnable() { - @Override - public void run() { - try { - boolean success = PushNotificationsManager.getInstanceFor(accountItem.getConnection()) - .enable(UserJid.from(pushServiceJid).getJid(), node); - AccountManager.getInstance().setPushWasEnabled(accountItem, success); - } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException - | SmackException.NotConnectedException | InterruptedException | UserJid.UserJidCreateException e) { - Log.d(LOG_TAG, "Push notification enabling failed: " + e.toString()); - AccountManager.getInstance().setPushWasEnabled(accountItem, false); - } - } - }); + String stanzaID = null; + try { + EnablePushNotificationsIQ enableIQ = new EnablePushNotificationsIQ( + UserJid.from(pushServiceJid).getJid(), node, null); + stanzaID = enableIQ.getStanzaId(); + waitingIQs.put(stanzaID, true); + accountItem.getConnection().sendStanza(enableIQ); + } catch (SmackException.NotConnectedException | InterruptedException | UserJid.UserJidCreateException e) { + Log.d(LOG_TAG, "Push notification enabling failed: " + e.toString()); + waitingIQs.remove(stanzaID); + AccountManager.getInstance().setPushWasEnabled(accountItem, false); + } } private void sendDisablePushIQ(final AccountItem accountItem, final String pushServiceJid, final String node) { - Application.getInstance().runInBackground(new Runnable() { - @Override - public void run() { - try { - boolean success = PushNotificationsManager.getInstanceFor(accountItem.getConnection()) - .disable(UserJid.from(pushServiceJid).getJid(), node); - AccountManager.getInstance().setPushWasEnabled(accountItem, !success); - } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException - | SmackException.NotConnectedException | InterruptedException | UserJid.UserJidCreateException e) { - Log.d(LOG_TAG, "Push notification disabling failed: " + e.toString()); - } - } - }); + String stanzaID = null; + try { + DisablePushNotificationsIQ disableIQ = new DisablePushNotificationsIQ( + UserJid.from(pushServiceJid).getJid(), node); + stanzaID = disableIQ.getStanzaId(); + waitingIQs.put(stanzaID, false); + accountItem.getConnection().sendStanza(disableIQ); + } catch (SmackException.NotConnectedException | InterruptedException | UserJid.UserJidCreateException e) { + Log.d(LOG_TAG, "Push notification enabling failed: " + e.toString()); + waitingIQs.remove(stanzaID); + } } } From 737db0940014863aa13f935899cd5864a31abf0b Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 12 Apr 2019 18:32:46 +0500 Subject: [PATCH 037/237] Up version to 605 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index d327c26c36..226aa2c170 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 604 - versionName '2.6.4(604)' + versionCode 605 + versionName '2.6.4(605)' } lintOptions { From 0c9db720128747e66b4c4a28812ebf8d990f5160 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 15 Apr 2019 11:53:22 +0500 Subject: [PATCH 038/237] Changed foreground notification for sync mode --- .../notification/NotificationManager.java | 20 +++++++++++++------ .../res/values-ru-rRU/notification_bar.xml | 1 + .../src/main/res/values/notification_bar.xml | 1 + 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/notification/NotificationManager.java b/xabber/src/main/java/com/xabber/android/data/notification/NotificationManager.java index 13a74c2d3e..1a17a233e5 100644 --- a/xabber/src/main/java/com/xabber/android/data/notification/NotificationManager.java +++ b/xabber/src/main/java/com/xabber/android/data/notification/NotificationManager.java @@ -40,6 +40,7 @@ import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.entity.UserJid; import com.xabber.android.data.log.LogManager; +import com.xabber.android.data.push.SyncManager; import com.xabber.android.service.XabberService; import com.xabber.android.ui.activity.ClearNotificationsActivity; import com.xabber.android.ui.activity.ContactListActivity; @@ -319,15 +320,22 @@ private void updatePersistentNotification() { persistentIntent = ContactListActivity.createPersistentIntent(application); - if (connected > 0) { - persistentNotificationBuilder.setColor(persistentNotificationColor); - persistentNotificationBuilder.setSmallIcon(R.drawable.ic_stat_online); - } else { + if (SyncManager.getInstance().isSyncMode()) { persistentNotificationBuilder.setColor(NotificationCompat.COLOR_DEFAULT); - persistentNotificationBuilder.setSmallIcon(R.drawable.ic_stat_offline); + persistentNotificationBuilder.setSmallIcon(R.drawable.ic_sync); + persistentNotificationBuilder.setContentText(application.getString(R.string.connection_state_sync)); + } else { + if (connected > 0) { + persistentNotificationBuilder.setColor(persistentNotificationColor); + persistentNotificationBuilder.setSmallIcon(R.drawable.ic_stat_online); + } else { + persistentNotificationBuilder.setColor(NotificationCompat.COLOR_DEFAULT); + persistentNotificationBuilder.setSmallIcon(R.drawable.ic_stat_offline); + } + + persistentNotificationBuilder.setContentText(getConnectionState(waiting, connecting, connected, accountList.size())); } - persistentNotificationBuilder.setContentText(getConnectionState(waiting, connecting, connected, accountList.size())); persistentNotificationBuilder.setContentIntent(PendingIntent.getActivity(application, 0, persistentIntent, PendingIntent.FLAG_UPDATE_CURRENT)); diff --git a/xabber/src/main/res/values-ru-rRU/notification_bar.xml b/xabber/src/main/res/values-ru-rRU/notification_bar.xml index e78bfa9b4b..05256fc23f 100644 --- a/xabber/src/main/res/values-ru-rRU/notification_bar.xml +++ b/xabber/src/main/res/values-ru-rRU/notification_bar.xml @@ -36,6 +36,7 @@ %1$d из %2$d %3$s ожидают переподключения %1$d %2$s не в сети + Выполняется синхронизация Вы хотите подключиться к конференции? Нажмите, чтобы прервать. Требуется ввести пароль diff --git a/xabber/src/main/res/values/notification_bar.xml b/xabber/src/main/res/values/notification_bar.xml index 5e33f5b0ed..1f4629cd06 100644 --- a/xabber/src/main/res/values/notification_bar.xml +++ b/xabber/src/main/res/values/notification_bar.xml @@ -35,6 +35,7 @@ - %1$d %2$s offline + Synchronization in progress Do you want to enter conference? Click here to abort it. Password required From 91c36bbeb2174ac4c6abdcf1902809fa1aa577ca Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 15 Apr 2019 12:21:26 +0500 Subject: [PATCH 039/237] Remove unused offline shadow --- .../ui/contactlist/viewobjects/AccountVO.java | 29 +--- .../viewobjects/AccountWithButtonsVO.java | 6 +- .../viewobjects/AccountWithContactsVO.java | 5 +- .../viewobjects/AccountWithGroupsVO.java | 5 +- .../ui/contactlist/viewobjects/ButtonVO.java | 31 +--- .../ui/contactlist/viewobjects/ChatVO.java | 5 +- .../viewobjects/ChatWithButtonVO.java | 5 +- .../ui/contactlist/viewobjects/ContactVO.java | 25 +-- .../contactlist/viewobjects/ExtContactVO.java | 5 +- .../ui/contactlist/viewobjects/GroupVO.java | 26 +--- .../adapter/AccountActionButtonsAdapter.java | 146 ------------------ .../layout/item_account_in_contact_list.xml | 2 - .../layout/item_button_in_contact_list.xml | 2 - .../res/layout/item_chat_in_contact_list.xml | 2 - .../main/res/layout/item_chat_with_button.xml | 2 - .../layout/item_contact_in_contact_list.xml | 2 - .../item_ext_contact_in_contact_list.xml | 2 - .../res/layout/item_group_in_contact_list.xml | 2 - xabber/src/main/res/layout/offline_shadow.xml | 7 - 19 files changed, 19 insertions(+), 290 deletions(-) delete mode 100644 xabber/src/main/java/com/xabber/android/ui/adapter/AccountActionButtonsAdapter.java delete mode 100644 xabber/src/main/res/layout/offline_shadow.xml diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/AccountVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/AccountVO.java index 91837173b8..81a151179a 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/AccountVO.java +++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/AccountVO.java @@ -16,7 +16,6 @@ import com.xabber.android.data.SettingsManager; import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.account.AccountManager; -import com.xabber.android.data.account.StatusMode; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.extension.avatar.AvatarManager; import com.xabber.android.data.notification.custom_notification.CustomNotifyPrefsManager; @@ -39,7 +38,6 @@ public class AccountVO extends AbstractHeaderItem { private int accountColorIndicator; private int accountColorIndicatorBack; - private boolean showOfflineShadow; private String name; private String jid; @@ -61,7 +59,7 @@ public interface AccountClickListener { void onAccountMenuClick(int adapterPosition, View view); } - public AccountVO(int accountColorIndicator, int accountColorIndicatorBack, boolean showOfflineShadow, + public AccountVO(int accountColorIndicator, int accountColorIndicatorBack, String name, String jid, String status, int statusLevel, int statusId, Drawable avatar, int offlineModeLevel, String contactCount, AccountJid accountJid, boolean isExpand, String groupName, boolean isCustomNotification, @@ -69,7 +67,6 @@ public AccountVO(int accountColorIndicator, int accountColorIndicatorBack, boole this.id = UUID.randomUUID().toString(); this.accountColorIndicator = accountColorIndicator; this.accountColorIndicatorBack = accountColorIndicatorBack; - this.showOfflineShadow = showOfflineShadow; this.name = name; this.jid = jid; this.status = status; @@ -108,11 +105,6 @@ public AccountVO.ViewHolder createViewHolder(View view, FlexibleAdapter adapter) public void bindViewHolder(FlexibleAdapter adapter, ViewHolder viewHolder, int position, List payloads) { Context context = viewHolder.itemView.getContext(); - /** bind OFFLINE SHADOW */ - if (isShowOfflineShadow()) - viewHolder.offlineShadow.setVisibility(View.VISIBLE); - else viewHolder.offlineShadow.setVisibility(View.GONE); - /** set up ACCOUNT COLOR indicator */ viewHolder.accountColorIndicator.setBackgroundColor(getAccountColorIndicator()); viewHolder.accountColorIndicatorBack.setBackgroundColor(getAccountColorIndicatorBack()); @@ -177,7 +169,6 @@ public static AccountVO convert(AccountConfiguration configuration, AccountClick int statusId; Drawable avatar; int offlineModeLevel; - boolean showOfflineShadow = false; int accountColorIndicator; int accountColorIndicatorBack; String contactCount; @@ -214,20 +205,11 @@ public static AccountVO convert(AccountConfiguration configuration, AccountClick offlineModeLevel = showOfflineMode.ordinal(); - - StatusMode statusMode = accountItem.getDisplayStatusMode(); - - if (statusMode == StatusMode.unavailable || statusMode == StatusMode.connection) { - showOfflineShadow = true; - } else { - showOfflineShadow = false; - } - // custom notification boolean isCustomNotification = CustomNotifyPrefsManager.getInstance(). isPrefsExist(Key.createKey(account)); - return new AccountVO(accountColorIndicator, accountColorIndicatorBack, showOfflineShadow, + return new AccountVO(accountColorIndicator, accountColorIndicatorBack, name, jid, status, statusLevel, statusId, avatar, offlineModeLevel, contactCount, configuration.getAccount(), configuration.isExpanded(), configuration.getGroup(), isCustomNotification, listener); @@ -289,11 +271,6 @@ public int getAccountColorIndicatorBack() { return accountColorIndicatorBack; } - - public boolean isShowOfflineShadow() { - return showOfflineShadow; - } - public class ViewHolder extends ExpandableViewHolder { final ImageView ivAvatar; @@ -304,7 +281,6 @@ public class ViewHolder extends ExpandableViewHolder { final TextView tvContactCount; final ImageView ivStatus; final ImageView ivMenu; - final ImageView offlineShadow; final View accountColorIndicator; final View accountColorIndicatorBack; final View backgroundView; @@ -327,7 +303,6 @@ public ViewHolder(View view, FlexibleAdapter adapter, AccountClickListener liste tvContactCount = (TextView) view.findViewById(R.id.tvContactCount); ivStatus = (ImageView) view.findViewById(R.id.ivStatus); ivStatus.setOnClickListener(this); - offlineShadow = (ImageView) view.findViewById(R.id.offline_shadow); accountColorIndicator = view.findViewById(R.id.accountColorIndicator); accountColorIndicatorBack = view.findViewById(R.id.accountColorIndicatorBack); ivMenu = (ImageView) view.findViewById(R.id.ivMenu); diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/AccountWithButtonsVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/AccountWithButtonsVO.java index 1a2c547847..0eab37059b 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/AccountWithButtonsVO.java +++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/AccountWithButtonsVO.java @@ -22,14 +22,13 @@ public class AccountWithButtonsVO extends AccountVO implements IExpandable mSubItems; - public AccountWithButtonsVO(int accountColorIndicator, int accountColorIndicatorBack, - boolean showOfflineShadow, String name, + public AccountWithButtonsVO(int accountColorIndicator, int accountColorIndicatorBack, String name, String jid, String status, int statusLevel, int statusId, Drawable avatar, int offlineModeLevel, String contactCount, AccountJid accountJid, boolean isExpand, String groupName, boolean isCustomNotification, AccountClickListener listener) { - super(accountColorIndicator, accountColorIndicatorBack, showOfflineShadow, name, jid, + super(accountColorIndicator, accountColorIndicatorBack, name, jid, status, statusLevel, statusId, avatar, offlineModeLevel, contactCount, accountJid, isExpand, groupName, isCustomNotification, listener); @@ -76,7 +75,6 @@ public static AccountWithButtonsVO convert(AccountConfiguration configuration, A AccountVO contactVO = AccountVO.convert(configuration, listener); return new AccountWithButtonsVO( contactVO.getAccountColorIndicator(), contactVO.getAccountColorIndicatorBack(), - contactVO.isShowOfflineShadow(), contactVO.getName(), contactVO.getJid(), contactVO.getStatus(), contactVO.getStatusLevel(), contactVO.getStatusId(), contactVO.getAvatar(), contactVO.getOfflineModeLevel(), contactVO.getContactCount(), diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/AccountWithContactsVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/AccountWithContactsVO.java index 41ee5d7668..2080142cca 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/AccountWithContactsVO.java +++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/AccountWithContactsVO.java @@ -24,13 +24,13 @@ public class AccountWithContactsVO extends AccountVO implements IExpandable mSubItems; public AccountWithContactsVO(int accountColorIndicator, int accountColorIndicatorBack, - boolean showOfflineShadow, String name, + String name, String jid, String status, int statusLevel, int statusId, Drawable avatar, int offlineModeLevel, String contactCount, AccountJid accountJid, boolean isExpand, String groupName, boolean isCustomNotification, AccountClickListener listener) { - super(accountColorIndicator, accountColorIndicatorBack, showOfflineShadow, name, jid, + super(accountColorIndicator, accountColorIndicatorBack, name, jid, status, statusLevel, statusId, avatar, offlineModeLevel, contactCount, accountJid, isExpand, groupName, isCustomNotification, listener); @@ -79,7 +79,6 @@ public static AccountWithContactsVO convert(AccountConfiguration configuration, AccountVO contactVO = AccountVO.convert(configuration, listener); return new AccountWithContactsVO( contactVO.getAccountColorIndicator(), contactVO.getAccountColorIndicatorBack(), - contactVO.isShowOfflineShadow(), contactVO.getName(), contactVO.getJid(), contactVO.getStatus(), contactVO.getStatusLevel(), contactVO.getStatusId(), contactVO.getAvatar(), contactVO.getOfflineModeLevel(), contactVO.getContactCount(), diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/AccountWithGroupsVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/AccountWithGroupsVO.java index 272d4389c4..eb32459704 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/AccountWithGroupsVO.java +++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/AccountWithGroupsVO.java @@ -23,13 +23,13 @@ public class AccountWithGroupsVO extends AccountVO implements IExpandable mSubItems; public AccountWithGroupsVO(int accountColorIndicator, int accountColorIndicatorBack, - boolean showOfflineShadow, String name, + String name, String jid, String status, int statusLevel, int statusId, Drawable avatar, int offlineModeLevel, String contactCount, AccountJid accountJid, boolean isExpand, String groupName, boolean isCustomNotification, AccountClickListener listener) { - super(accountColorIndicator, accountColorIndicatorBack, showOfflineShadow, name, jid, status, statusLevel, statusId, + super(accountColorIndicator, accountColorIndicatorBack, name, jid, status, statusLevel, statusId, avatar, offlineModeLevel, contactCount, accountJid, isExpand, groupName, isCustomNotification, listener); @@ -75,7 +75,6 @@ public static AccountWithGroupsVO convert(AccountConfiguration configuration, Ac AccountVO contactVO = AccountVO.convert(configuration, listener); return new AccountWithGroupsVO( contactVO.getAccountColorIndicator(), contactVO.getAccountColorIndicatorBack(), - contactVO.isShowOfflineShadow(), contactVO.getName(), contactVO.getJid(), contactVO.getStatus(), contactVO.getStatusLevel(), contactVO.getStatusId(), contactVO.getAvatar(), contactVO.getOfflineModeLevel(), contactVO.getContactCount(), diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ButtonVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ButtonVO.java index 54a510a112..72559566a6 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ButtonVO.java +++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ButtonVO.java @@ -3,12 +3,8 @@ import android.support.annotation.Nullable; import android.view.View; import android.widget.Button; -import android.widget.ImageView; import com.xabber.android.R; -import com.xabber.android.data.account.AccountItem; -import com.xabber.android.data.account.AccountManager; -import com.xabber.android.data.account.StatusMode; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.ui.adapter.contactlist.AccountConfiguration; import com.xabber.android.ui.color.ColorManager; @@ -31,18 +27,15 @@ public class ButtonVO extends AbstractFlexibleItem { private String id; private int accountColorIndicator; - private boolean showOfflineShadow; private String title; private String action; private AccountJid account; - public ButtonVO(int accountColorIndicator, boolean showOfflineShadow, - String title, String action, AccountJid account) { + public ButtonVO(int accountColorIndicator, String title, String action, AccountJid account) { this.id = UUID.randomUUID().toString(); this.accountColorIndicator = accountColorIndicator; - this.showOfflineShadow = showOfflineShadow; this.title = title; this.action = action; this.account = account; @@ -69,32 +62,18 @@ public ViewHolder createViewHolder(View view, FlexibleAdapter adapter) { @Override public void bindViewHolder(FlexibleAdapter adapter, ViewHolder holder, int position, List payloads) { - holder.btnListAction.setText(getTitle()); - - /** set up OFFLINE SHADOW */ - if (isShowOfflineShadow()) - holder.offlineShadow.setVisibility(View.VISIBLE); - else holder.offlineShadow.setVisibility(View.GONE); } public static ButtonVO convert(@Nullable AccountConfiguration configuration, String title, String action) { - boolean showOfflineShadow = false; int accountColorIndicator = ColorManager.getInstance().getAccountPainter().getDefaultMainColor(); AccountJid account = null; if (configuration != null) { account = configuration.getAccount(); accountColorIndicator = ColorManager.getInstance().getAccountPainter().getAccountMainColor(account); - - AccountItem accountItem = AccountManager.getInstance().getAccount(configuration.getAccount()); - if (accountItem != null) { - StatusMode statusMode = accountItem.getDisplayStatusMode(); - if (statusMode == StatusMode.unavailable || statusMode == StatusMode.connection) - showOfflineShadow = true; - } } - return new ButtonVO(accountColorIndicator, showOfflineShadow, title, action, account); + return new ButtonVO(accountColorIndicator, title, action, account); } public String getTitle() { @@ -105,10 +84,6 @@ public int getAccountColorIndicator() { return accountColorIndicator; } - public boolean isShowOfflineShadow() { - return showOfflineShadow; - } - public String getAction() { return action; } @@ -119,12 +94,10 @@ public AccountJid getAccount() { public class ViewHolder extends FlexibleViewHolder { final Button btnListAction; - final ImageView offlineShadow; public ViewHolder(View view, FlexibleAdapter adapter) { super(view, adapter); - offlineShadow = (ImageView) view.findViewById(R.id.offline_shadow); btnListAction = (Button) itemView.findViewById(R.id.btnListAction); btnListAction.setOnClickListener(this); } diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ChatVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ChatVO.java index 7f5be5d65e..d8c4c28d7a 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ChatVO.java +++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ChatVO.java @@ -35,7 +35,7 @@ public interface IsCurrentChatListener { boolean isCurrentChat(String account, String user); } - public ChatVO(int accountColorIndicator, int accountColorIndicatorBack, boolean showOfflineShadow, + public ChatVO(int accountColorIndicator, int accountColorIndicatorBack, String name, String status, int statusId, int statusLevel, Drawable avatar, int mucIndicatorLevel, UserJid userJid, AccountJid accountJid, int unreadCount, boolean mute, NotificationState.NotificationMode notificationMode, String messageText, @@ -44,7 +44,7 @@ public ChatVO(int accountColorIndicator, int accountColorIndicatorBack, boolean @Nullable IsCurrentChatListener currentChatListener, int forwardedCount, boolean isCustomNotification) { - super(accountColorIndicator, accountColorIndicatorBack, showOfflineShadow, name, status, + super(accountColorIndicator, accountColorIndicatorBack, name, status, statusId, statusLevel, avatar, mucIndicatorLevel, userJid, accountJid, unreadCount, mute, notificationMode, messageText, isOutgoing, time, messageStatus, messageOwner, archived, lastActivity, listener, forwardedCount, isCustomNotification); @@ -57,7 +57,6 @@ public static ChatVO convert(AbstractContact contact, ContactClickListener liste ExtContactVO contactVO = ExtContactVO.convert(contact, listener); return new ChatVO( contactVO.getAccountColorIndicator(), contactVO.getAccountColorIndicatorBack(), - contactVO.isShowOfflineShadow(), contactVO.getName(), contactVO.getStatus(), contactVO.getStatusId(), contactVO.getStatusLevel(), contactVO.getAvatar(), contactVO.getMucIndicatorLevel(), contactVO.getUserJid(), contactVO.getAccountJid(), contactVO.getUnreadCount(), diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ChatWithButtonVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ChatWithButtonVO.java index c1ad372ff4..3b3828d8c2 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ChatWithButtonVO.java +++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ChatWithButtonVO.java @@ -17,7 +17,6 @@ public class ChatWithButtonVO extends ExtContactVO { public ChatWithButtonVO(int accountColorIndicator, int accountColorIndicatorBack, - boolean showOfflineShadow, String name, String status, int statusId, int statusLevel, Drawable avatar, int mucIndicatorLevel, UserJid userJid, AccountJid accountJid, int unreadCount, boolean mute, NotificationState.NotificationMode notificationMode, String messageText, @@ -25,7 +24,7 @@ public ChatWithButtonVO(int accountColorIndicator, int accountColorIndicatorBack boolean archived, String lastActivity, ContactClickListener listener, int forwardedCount, boolean isCustomNotification) { - super(accountColorIndicator, accountColorIndicatorBack, showOfflineShadow, name, status, + super(accountColorIndicator, accountColorIndicatorBack, name, status, statusId, statusLevel, avatar, mucIndicatorLevel, userJid, accountJid, unreadCount, mute, notificationMode, messageText, isOutgoing, time, messageStatus, messageOwner, archived, lastActivity, listener, forwardedCount, isCustomNotification); @@ -35,7 +34,6 @@ public static ChatWithButtonVO convert(AbstractContact contact, ContactClickList ExtContactVO contactVO = ExtContactVO.convert(contact, listener); return new ChatWithButtonVO( contactVO.getAccountColorIndicator(), contactVO.getAccountColorIndicatorBack(), - contactVO.isShowOfflineShadow(), contactVO.getName(), contactVO.getStatus(), contactVO.getStatusId(), contactVO.getStatusLevel(), contactVO.getAvatar(), contactVO.getMucIndicatorLevel(), contactVO.getUserJid(), contactVO.getAccountJid(), contactVO.getUnreadCount(), @@ -48,7 +46,6 @@ public static ChatWithButtonVO convert(AbstractContact contact, ContactClickList public static ChatWithButtonVO convert(ChatVO chat) { return new ChatWithButtonVO( chat.getAccountColorIndicator(), chat.getAccountColorIndicatorBack(), - chat.isShowOfflineShadow(), chat.getName(), chat.getStatus(), chat.getStatusId(), chat.getStatusLevel(), chat.getAvatar(), chat.getMucIndicatorLevel(), chat.getUserJid(), chat.getAccountJid(), chat.getUnreadCount(), diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java index 65ffddbf6d..9867a8b8d9 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java +++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java @@ -59,7 +59,6 @@ public class ContactVO extends AbstractFlexibleItem { private int accountColorIndicator; private int accountColorIndicatorBack; - private boolean showOfflineShadow; private final String name; private final String status; @@ -91,7 +90,7 @@ public interface ContactClickListener { } protected ContactVO(int accountColorIndicator, int accountColorIndicatorBack, - boolean showOfflineShadow, String name, + String name, String status, int statusId, int statusLevel, Drawable avatar, int mucIndicatorLevel, UserJid userJid, AccountJid accountJid, int unreadCount, boolean mute, NotificationState.NotificationMode notificationMode, String messageText, @@ -101,7 +100,6 @@ protected ContactVO(int accountColorIndicator, int accountColorIndicatorBack, this.id = UUID.randomUUID().toString(); this.accountColorIndicator = accountColorIndicator; this.accountColorIndicatorBack = accountColorIndicatorBack; - this.showOfflineShadow = showOfflineShadow; this.name = name; this.status = status; this.statusId = statusId; @@ -126,7 +124,6 @@ protected ContactVO(int accountColorIndicator, int accountColorIndicatorBack, } public static ContactVO convert(AbstractContact contact, ContactClickListener listener) { - boolean showOfflineShadow; int accountColorIndicator; int accountColorIndicatorBack; Drawable avatar; @@ -139,13 +136,6 @@ public static ContactVO convert(AbstractContact contact, ContactClickListener li int forwardedCount = 0; String messageOwner = null; - AccountItem accountItem = AccountManager.getInstance().getAccount(contact.getAccount()); - if (accountItem != null && accountItem.getState() == ConnectionState.connected) { - showOfflineShadow = false; - } else { - showOfflineShadow = true; - } - accountColorIndicator = ColorManager.getInstance().getAccountPainter() .getAccountMainColor(contact.getAccount()); accountColorIndicatorBack = ColorManager.getInstance().getAccountPainter() @@ -228,7 +218,7 @@ public static ContactVO convert(AbstractContact contact, ContactClickListener li isPrefsExist(Key.createKey(contact.getAccount(), contact.getUser())); return new ContactVO(accountColorIndicator, accountColorIndicatorBack, - showOfflineShadow, name, statusText, statusId, + name, statusText, statusId, statusLevel, avatar, mucIndicatorLevel, contact.getUser(), contact.getAccount(), unreadCount, !chat.notifyAboutMessage(), mode, messageText, isOutgoing, time, messageStatus, messageOwner, chat.isArchived(), lastActivity, listener, forwardedCount, @@ -266,11 +256,6 @@ public ViewHolder createViewHolder(View view, FlexibleAdapter adapter) { public void bindViewHolder(FlexibleAdapter adapter, ViewHolder viewHolder, int position, List payloads) { Context context = viewHolder.itemView.getContext(); - /** set up OFFLINE SHADOW */ - if (isShowOfflineShadow()) - viewHolder.offlineShadow.setVisibility(View.VISIBLE); - else viewHolder.offlineShadow.setVisibility(View.GONE); - /** set up ACCOUNT COLOR indicator */ viewHolder.accountColorIndicator.setBackgroundColor(getAccountColorIndicator()); viewHolder.accountColorIndicatorBack.setBackgroundColor(getAccountColorIndicatorBack()); @@ -432,10 +417,6 @@ public int getAccountColorIndicatorBack() { return accountColorIndicatorBack; } - public boolean isShowOfflineShadow() { - return showOfflineShadow; - } - public String getLastActivity() { return lastActivity; } @@ -467,7 +448,6 @@ public class ViewHolder extends FlexibleViewHolder implements View.OnCreateConte final TextView tvMessageText; final TextView tvTime; final ImageView ivMessageStatus; - final ImageView offlineShadow; final TextView tvUnreadCount; public final TextView tvAction; public final TextView tvActionLeft; @@ -493,7 +473,6 @@ public ViewHolder(View view, FlexibleAdapter adapter, ContactClickListener liste tvMessageText = (TextView) view.findViewById(R.id.tvMessageText); tvTime = (TextView) view.findViewById(R.id.tvTime); ivMessageStatus = (ImageView) view.findViewById(R.id.ivMessageStatus); - offlineShadow = (ImageView) view.findViewById(R.id.offline_shadow); tvUnreadCount = (TextView) view.findViewById(R.id.tvUnreadCount); foregroundView = (LinearLayout) view.findViewById(R.id.foregroundView); tvAction = (TextView) view.findViewById(R.id.tvAction); diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ExtContactVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ExtContactVO.java index f7a79371ca..d5dc357b06 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ExtContactVO.java +++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ExtContactVO.java @@ -26,7 +26,7 @@ public class ExtContactVO extends ContactVO { public ExtContactVO(int accountColorIndicator, int accountColorIndicatorBack, - boolean showOfflineShadow, String name, + String name, String status, int statusId, int statusLevel, Drawable avatar, int mucIndicatorLevel, UserJid userJid, AccountJid accountJid, int unreadCount, boolean mute, NotificationState.NotificationMode notificationMode, String messageText, @@ -34,7 +34,7 @@ public ExtContactVO(int accountColorIndicator, int accountColorIndicatorBack, boolean archived, String lastActivity, ContactClickListener listener, int forwardedCount, boolean isCustomNotification) { - super(accountColorIndicator, accountColorIndicatorBack, showOfflineShadow, name, status, + super(accountColorIndicator, accountColorIndicatorBack, name, status, statusId, statusLevel, avatar, mucIndicatorLevel, userJid, accountJid, unreadCount, mute, notificationMode, messageText, isOutgoing, time, messageStatus, messageOwner, archived, lastActivity, listener, forwardedCount, @@ -45,7 +45,6 @@ public static ExtContactVO convert(AbstractContact contact, ContactClickListener ContactVO contactVO = ContactVO.convert(contact, listener); return new ExtContactVO( contactVO.getAccountColorIndicator(), contactVO.getAccountColorIndicatorBack(), - contactVO.isShowOfflineShadow(), contactVO.getName(), contactVO.getStatus(), contactVO.getStatusId(), contactVO.getStatusLevel(), contactVO.getAvatar(), contactVO.getMucIndicatorLevel(), contactVO.getUserJid(), contactVO.getAccountJid(), contactVO.getUnreadCount(), diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/GroupVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/GroupVO.java index 73f7b56c26..bc49409548 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/GroupVO.java +++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/GroupVO.java @@ -43,7 +43,6 @@ public class GroupVO extends AbstractFlexibleItem private int accountColorIndicator; private int accountColorIndicatorBack; - private boolean showOfflineShadow; private String title; private int offlineIndicatorLevel; @@ -63,7 +62,7 @@ public interface GroupClickListener { } public GroupVO(int accountColorIndicator, int accountColorIndicatorBack, - boolean showOfflineShadow, String title, + String title, boolean expanded, int offlineIndicatorLevel, String groupName, AccountJid accountJid, boolean firstInAccount, boolean isCustomNotification, GroupClickListener listener) { @@ -71,7 +70,6 @@ public GroupVO(int accountColorIndicator, int accountColorIndicatorBack, this.id = UUID.randomUUID().toString(); this.accountColorIndicator = accountColorIndicator; this.accountColorIndicatorBack = accountColorIndicatorBack; - this.showOfflineShadow = showOfflineShadow; this.title = title; this.mExpanded = expanded; this.offlineIndicatorLevel = offlineIndicatorLevel; @@ -104,11 +102,6 @@ public ViewHolder createViewHolder(View view, FlexibleAdapter adapter) { @Override public void bindViewHolder(FlexibleAdapter adapter, ViewHolder viewHolder, int position, List payloads) { - /** set up OFFLINE SHADOW */ - if (isShowOfflineShadow()) - viewHolder.offlineShadow.setVisibility(View.VISIBLE); - else viewHolder.offlineShadow.setVisibility(View.GONE); - /** set up ACCOUNT COLOR indicator */ viewHolder.accountColorIndicator.setBackgroundColor(getAccountColorIndicator()); viewHolder.accountColorIndicatorBack.setBackgroundColor(getAccountColorIndicatorBack()); @@ -182,7 +175,6 @@ public static GroupVO convert(GroupConfiguration configuration, boolean firstInA String name = GroupManager.getInstance().getGroupName(configuration.getAccount(), configuration.getGroup()); - boolean showOfflineShadow = false; int accountColorIndicator; int accountColorIndicatorBack; boolean expanded; @@ -207,15 +199,7 @@ public static GroupVO convert(GroupConfiguration configuration, boolean firstInA if (!name.equals(RECENT_CHATS_TITLE)) name = String.format("%s (%d/%d)", name, configuration.getOnline(), configuration.getTotal()); - AccountItem accountItem = AccountManager.getInstance().getAccount(configuration.getAccount()); - - if (accountItem != null) { - StatusMode statusMode = accountItem.getDisplayStatusMode(); - if (statusMode == StatusMode.unavailable || statusMode == StatusMode.connection) - showOfflineShadow = true; - } - - return new GroupVO(accountColorIndicator, accountColorIndicatorBack, showOfflineShadow, name, expanded, + return new GroupVO(accountColorIndicator, accountColorIndicatorBack, name, expanded, offlineIndicatorLevel, configuration.getGroup(), configuration.getAccount(), firstInAccount, isCustomNotification, listener); } @@ -248,16 +232,11 @@ public int getAccountColorIndicatorBack() { return accountColorIndicatorBack; } - public boolean isShowOfflineShadow() { - return showOfflineShadow; - } - public class ViewHolder extends ExpandableViewHolder implements View.OnCreateContextMenuListener { final ImageView indicator; final TextView name; final ImageView groupOfflineIndicator; - final ImageView offlineShadow; final View accountColorIndicator; final View accountColorIndicatorBack; final View line; @@ -273,7 +252,6 @@ public ViewHolder(View view, FlexibleAdapter adapter) { indicator = (ImageView) view.findViewById(R.id.indicator); name = (TextView) view.findViewById(R.id.name); groupOfflineIndicator = (ImageView) view.findViewById(R.id.group_offline_indicator); - offlineShadow = (ImageView) view.findViewById(R.id.offline_shadow); line = view.findViewById(R.id.line); } diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/AccountActionButtonsAdapter.java b/xabber/src/main/java/com/xabber/android/ui/adapter/AccountActionButtonsAdapter.java deleted file mode 100644 index 53ec4d14ee..0000000000 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/AccountActionButtonsAdapter.java +++ /dev/null @@ -1,146 +0,0 @@ -package com.xabber.android.ui.adapter; - -import android.app.Activity; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.LinearLayout; - -import com.melnykov.fab.FloatingActionButton; -import com.xabber.android.R; -import com.xabber.android.data.account.AccountItem; -import com.xabber.android.data.account.AccountManager; -import com.xabber.android.data.account.StatusMode; -import com.xabber.android.data.entity.AccountJid; -import com.xabber.android.data.extension.avatar.AvatarManager; -import com.xabber.android.data.xaccount.XMPPAccountSettings; -import com.xabber.android.data.xaccount.XabberAccountManager; -import com.xabber.android.ui.color.AccountPainter; -import com.xabber.android.ui.color.ColorManager; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import de.hdodenhof.circleimageview.CircleImageView; - - -public class AccountActionButtonsAdapter implements UpdatableAdapter { - - private final Activity activity; - - /** - * Listener for click on elements. - */ - private final View.OnClickListener onClickListener; - - /** - * Layout to be populated. - */ - private final LinearLayout linearLayout; - - /** - * List of accounts. - */ - private final ArrayList accounts; - - public AccountActionButtonsAdapter(Activity activity, - View.OnClickListener onClickListener, LinearLayout linearLayout) { - super(); - this.activity = activity; - this.onClickListener = onClickListener; - this.linearLayout = linearLayout; - accounts = new ArrayList<>(); - } - - /** - * Rebuild list of accounts. - *

- * Call it on account creation, deletion, enable or disable. - */ - public void rebuild() { - accounts.clear(); - accounts.addAll(AccountManager.getInstance().getEnabledAccounts()); - - Collections.sort(accounts); - final int size = accounts.size(); - final LayoutInflater inflater = (LayoutInflater) activity - .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); - - while (linearLayout.getChildCount() < size) { - View view = inflater.inflate(R.layout.account_action_button, linearLayout, false); - view.setOnClickListener(onClickListener); - linearLayout.addView(view); - } - - while (linearLayout.getChildCount() > size) { - linearLayout.removeViewAt(size); - } - onChange(); - } - - @Override - public void onChange() { - Collections.sort(accounts); - - for (int index = 0; index < accounts.size(); index++) { - View view = linearLayout.getChildAt(index); - - final CircleImageView circleImageView = (CircleImageView) view.findViewById(R.id.account_avatar); - final AccountJid account = accounts.get(index); - circleImageView.setImageDrawable(AvatarManager.getInstance().getAccountAvatar(account)); - - FloatingActionButton backgroundActionButton = (FloatingActionButton) view.findViewById(R.id.fab); - - final AccountPainter accountPainter = ColorManager.getInstance().getAccountPainter(); - backgroundActionButton.setColorNormal(accountPainter.getAccountMainColor(account)); - backgroundActionButton.setColorPressed(accountPainter.getAccountDarkColor(account)); - backgroundActionButton.setColorRipple(accountPainter.getAccountRippleColor(account)); - - AccountJid selectedAccount = AccountManager.getInstance().getSelectedAccount(); - - int shadowVisibility; - - if (selectedAccount == null) { - shadowVisibility = View.GONE; - } else { - shadowVisibility = View.VISIBLE; - if (selectedAccount.equals(account)) { - shadowVisibility = View.GONE; - } - } - - view.findViewById(R.id.account_unselected_shadow).setVisibility(shadowVisibility); - - int offlineShadowVisibility; - AccountItem accountItem = AccountManager.getInstance().getAccount(account); - StatusMode statusMode = null; - if (accountItem != null) { - statusMode = accountItem.getDisplayStatusMode(); - } - if (statusMode != null && (statusMode == StatusMode.connection || statusMode == StatusMode.unavailable)) { - offlineShadowVisibility = View.VISIBLE; - } else { - offlineShadowVisibility = View.GONE; - } - view.findViewById(R.id.account_offline_shadow).setVisibility(offlineShadowVisibility); - - } - } - - public int getCount() { - return accounts.size(); - } - - public Object getItem(int position) { - return accounts.get(position); - } - - public AccountJid getItemForView(View view) { - for (int index = 0; index < linearLayout.getChildCount(); index++) { - if (view == linearLayout.getChildAt(index)) { - return accounts.get(index); - } - } - return null; - } -} diff --git a/xabber/src/main/res/layout/item_account_in_contact_list.xml b/xabber/src/main/res/layout/item_account_in_contact_list.xml index 4bc60d19ac..850ae9e79b 100644 --- a/xabber/src/main/res/layout/item_account_in_contact_list.xml +++ b/xabber/src/main/res/layout/item_account_in_contact_list.xml @@ -91,8 +91,6 @@ android:clickable="true" /> - - diff --git a/xabber/src/main/res/layout/item_button_in_contact_list.xml b/xabber/src/main/res/layout/item_button_in_contact_list.xml index 8c464922ee..6470ac91b8 100644 --- a/xabber/src/main/res/layout/item_button_in_contact_list.xml +++ b/xabber/src/main/res/layout/item_button_in_contact_list.xml @@ -14,6 +14,4 @@ style="@style/Widget.AppCompat.Button.Borderless" /> - - \ No newline at end of file diff --git a/xabber/src/main/res/layout/item_chat_in_contact_list.xml b/xabber/src/main/res/layout/item_chat_in_contact_list.xml index c99bbb6a30..14aaf03d8b 100644 --- a/xabber/src/main/res/layout/item_chat_in_contact_list.xml +++ b/xabber/src/main/res/layout/item_chat_in_contact_list.xml @@ -160,6 +160,4 @@ - - \ No newline at end of file diff --git a/xabber/src/main/res/layout/item_chat_with_button.xml b/xabber/src/main/res/layout/item_chat_with_button.xml index 9ef7947f8b..5f48cb8ab0 100644 --- a/xabber/src/main/res/layout/item_chat_with_button.xml +++ b/xabber/src/main/res/layout/item_chat_with_button.xml @@ -187,6 +187,4 @@ - - \ No newline at end of file diff --git a/xabber/src/main/res/layout/item_contact_in_contact_list.xml b/xabber/src/main/res/layout/item_contact_in_contact_list.xml index f80e7beb38..d09c1b4f5b 100644 --- a/xabber/src/main/res/layout/item_contact_in_contact_list.xml +++ b/xabber/src/main/res/layout/item_contact_in_contact_list.xml @@ -72,7 +72,5 @@ android:text="1" /> - - \ No newline at end of file diff --git a/xabber/src/main/res/layout/item_ext_contact_in_contact_list.xml b/xabber/src/main/res/layout/item_ext_contact_in_contact_list.xml index 05a434e595..7b040116af 100644 --- a/xabber/src/main/res/layout/item_ext_contact_in_contact_list.xml +++ b/xabber/src/main/res/layout/item_ext_contact_in_contact_list.xml @@ -184,6 +184,4 @@ - - \ No newline at end of file diff --git a/xabber/src/main/res/layout/item_group_in_contact_list.xml b/xabber/src/main/res/layout/item_group_in_contact_list.xml index cdb76899b3..1e339dba7d 100644 --- a/xabber/src/main/res/layout/item_group_in_contact_list.xml +++ b/xabber/src/main/res/layout/item_group_in_contact_list.xml @@ -88,7 +88,5 @@ android:layout_marginLeft="2dp" /> - - \ No newline at end of file diff --git a/xabber/src/main/res/layout/offline_shadow.xml b/xabber/src/main/res/layout/offline_shadow.xml deleted file mode 100644 index f2daacff7b..0000000000 --- a/xabber/src/main/res/layout/offline_shadow.xml +++ /dev/null @@ -1,7 +0,0 @@ - - \ No newline at end of file From 509b70a21a8110104b7f8691a302826b41a44edf Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 15 Apr 2019 14:11:08 +0500 Subject: [PATCH 040/237] Fixed NPE --- .../main/java/com/xabber/android/data/push/PushManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index de539411ff..d57941df89 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -130,7 +130,7 @@ public void onStanza(ConnectionItem connection, Stanza packet) { /** Api */ public void enablePushNotificationsIfNeed(AccountItem accountItem) { - if (accountItem != null && accountItem.isPushEnabled()) { + if (accountItem != null && accountItem.isPushEnabled() && accountItem.getConnection().isConnected()) { if (isSupport(accountItem.getConnection())) { registerEndpoint(accountItem.getAccount()); } else AccountManager.getInstance().setPushWasEnabled(accountItem, false); @@ -138,7 +138,7 @@ public void enablePushNotificationsIfNeed(AccountItem accountItem) { } public void disablePushNotification(AccountItem accountItem) { - if (accountItem != null && !accountItem.isPushEnabled()) { + if (accountItem != null && !accountItem.isPushEnabled() && accountItem.getConnection().isConnected()) { if (isSupport(accountItem.getConnection())) { deleteEndpoint(accountItem); } AccountManager.getInstance().setPushWasEnabled(accountItem, false); From 909a3140ec5e59e1281bd426367f71ca05fed227 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 15 Apr 2019 14:34:33 +0500 Subject: [PATCH 041/237] Push notification switcher now available only while account is connected. --- .../com/xabber/android/ui/activity/AccountPushActivity.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xabber/src/main/java/com/xabber/android/ui/activity/AccountPushActivity.java b/xabber/src/main/java/com/xabber/android/ui/activity/AccountPushActivity.java index a770d060eb..95c41ee60b 100644 --- a/xabber/src/main/java/com/xabber/android/ui/activity/AccountPushActivity.java +++ b/xabber/src/main/java/com/xabber/android/ui/activity/AccountPushActivity.java @@ -106,6 +106,10 @@ public void onAccountsChanged(Collection accounts) { } private void updateSwitchButton() { + boolean enabled = accountItem.getConnection().isConnected(); + rlPushSwitch.setEnabled(enabled); + switchPush.setEnabled(enabled); + switchPush.setChecked(accountItem.isPushEnabled()); tvPushState.setText(accountItem.isPushWasEnabled() ? R.string.account_push_state_enabled : R.string.account_push_state_disabled); From 15e1e365380113732d6ed899c8229dae3c9144d1 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 15 Apr 2019 14:52:13 +0500 Subject: [PATCH 042/237] Fixed ui blocks in push notification activity --- .../xabber/android/data/account/AccountManager.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java index d878c01fa4..cca7e43796 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java @@ -1220,11 +1220,16 @@ public void setPushNode(AccountItem account, String pushNode, String pushService requestToWriteAccount(account); } - public void setPushEnabled(AccountItem accountItem, boolean enabled) { + public void setPushEnabled(final AccountItem accountItem, final boolean enabled) { accountItem.setPushEnabled(enabled); requestToWriteAccount(accountItem); - if (enabled) PushManager.getInstance().enablePushNotificationsIfNeed(accountItem); - else PushManager.getInstance().disablePushNotification(accountItem); + Application.getInstance().runInBackground(new Runnable() { + @Override + public void run() { + if (enabled) PushManager.getInstance().enablePushNotificationsIfNeed(accountItem); + else PushManager.getInstance().disablePushNotification(accountItem); + } + }); PushManager.getInstance().updateEnabledPushNodes(); } From 5eb02401bcdffeebced287ed2aa133fd93cc5e2e Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 15 Apr 2019 18:06:52 +0500 Subject: [PATCH 043/237] Remove rebuild notifications on start --- .../android/data/notification/MessageNotificationManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java index 2dd2204f46..95e7dd7752 100644 --- a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java +++ b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java @@ -240,7 +240,7 @@ private void onLoaded(List loadedChats) { List messages = chats.get(chats.size() - 1).getMessages(); if (messages != null && messages.size() > 0) { lastMessage = messages.get(messages.size() - 1); - rebuildAllNotifications(); + //rebuildAllNotifications(); } } } From 7c324245b9cca958caaad620654d98e185700dac Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 15 Apr 2019 18:21:12 +0500 Subject: [PATCH 044/237] Up version to 606 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 226aa2c170..15a3a13088 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 605 - versionName '2.6.4(605)' + versionCode 606 + versionName '2.6.4(606)' } lintOptions { From 7075ad7e0ab25466b0819461eff6fa708786de51 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 16 Apr 2019 14:41:09 +0500 Subject: [PATCH 045/237] Added disabling push notification in API and XMPP server on account disable --- .../android/data/account/AccountManager.java | 5 ++++- .../xabber/android/data/push/PushManager.java | 16 +++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java index cca7e43796..c14a245904 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java @@ -687,6 +687,9 @@ public void setEnabled(AccountJid account, boolean enabled) { return; } + // disable push + if (!enabled) PushManager.getInstance().disablePushNotification(getAccount(account), false); + accountItem.setEnabled(enabled); requestToWriteAccount(accountItem); PushManager.getInstance().updateEnabledPushNodes(); @@ -1227,7 +1230,7 @@ public void setPushEnabled(final AccountItem accountItem, final boolean enabled) @Override public void run() { if (enabled) PushManager.getInstance().enablePushNotificationsIfNeed(accountItem); - else PushManager.getInstance().disablePushNotification(accountItem); + else PushManager.getInstance().disablePushNotification(accountItem, true); } }); PushManager.getInstance().updateEnabledPushNodes(); diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index d57941df89..5e677f9932 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -137,11 +137,10 @@ public void enablePushNotificationsIfNeed(AccountItem accountItem) { } } - public void disablePushNotification(AccountItem accountItem) { - if (accountItem != null && !accountItem.isPushEnabled() && accountItem.getConnection().isConnected()) { - if (isSupport(accountItem.getConnection())) { - deleteEndpoint(accountItem); - } AccountManager.getInstance().setPushWasEnabled(accountItem, false); + public void disablePushNotification(AccountItem accountItem, boolean needConfirm) { + if (accountItem != null && accountItem.getConnection().isConnected()) { + deleteEndpoint(accountItem); + sendDisablePushIQ(accountItem, needConfirm); } } @@ -201,7 +200,6 @@ private void deleteEndpoint(final AccountItem accountItem) { @Override public void call(ResponseBody responseBody) { Log.d(LOG_TAG, "Endpoint successfully unregistered"); - sendDisablePushIQ(accountItem, accountItem.getPushServiceJid(), accountItem.getPushNode()); } }, new Action1() { @Override @@ -226,13 +224,13 @@ private void sendEnablePushIQ(final AccountItem accountItem, final String pushSe } } - private void sendDisablePushIQ(final AccountItem accountItem, final String pushServiceJid, final String node) { + private void sendDisablePushIQ(final AccountItem accountItem, boolean needConfirm) { String stanzaID = null; try { DisablePushNotificationsIQ disableIQ = new DisablePushNotificationsIQ( - UserJid.from(pushServiceJid).getJid(), node); + UserJid.from(accountItem.getPushServiceJid()).getJid(), accountItem.getPushNode()); stanzaID = disableIQ.getStanzaId(); - waitingIQs.put(stanzaID, false); + if (needConfirm) waitingIQs.put(stanzaID, false); accountItem.getConnection().sendStanza(disableIQ); } catch (SmackException.NotConnectedException | InterruptedException | UserJid.UserJidCreateException e) { Log.d(LOG_TAG, "Push notification enabling failed: " + e.toString()); From d441ed94bb73a416db484efa351df6053e38ba8d Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 16 Apr 2019 15:14:51 +0500 Subject: [PATCH 046/237] Added disabling push notification in API and XMPP server on account delete --- .../com/xabber/android/data/account/AccountManager.java | 3 +++ .../java/com/xabber/android/data/push/PushManager.java | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java index c14a245904..3a08cb816c 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java @@ -464,6 +464,9 @@ private void removeAccountWithoutCallback(final AccountJid account) { return; } + // disable push + PushManager.getInstance().disablePushNotification(getAccount(account), false); + boolean wasEnabled = accountItem.isEnabled(); accountItem.setEnabled(false); accountItem.disconnect(); diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index 5e677f9932..ec46200746 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -138,9 +138,12 @@ public void enablePushNotificationsIfNeed(AccountItem accountItem) { } public void disablePushNotification(AccountItem accountItem, boolean needConfirm) { - if (accountItem != null && accountItem.getConnection().isConnected()) { + if (accountItem != null) { deleteEndpoint(accountItem); - sendDisablePushIQ(accountItem, needConfirm); + + if (accountItem.getConnection().isConnected()) + sendDisablePushIQ(accountItem, needConfirm); + AccountManager.getInstance().setPushWasEnabled(accountItem, false); } } From f5dea66d0f30f76022edb35e861a236912138660 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 18 Apr 2019 14:26:37 +0500 Subject: [PATCH 047/237] Update gradle dependencies --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index a866675c2f..5da5213e5d 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { maven { url 'https://maven.fabric.io/public' } } dependencies { - classpath 'com.android.tools.build:gradle:3.3.2' + classpath 'com.android.tools.build:gradle:3.4.0' classpath "io.realm:realm-gradle-plugin:3.1.1" classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' classpath 'com.frogermcs.androiddevmetrics:androiddevmetrics-plugin:0.4' diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f83d2a335a..0d3fb51ff3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Feb 15 11:01:28 YEKT 2019 +#Thu Apr 18 14:07:31 YEKT 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip From 19904690cd1eec3e9b5f483fe7b79070c2e7942a Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 22 Apr 2019 17:56:49 +0500 Subject: [PATCH 048/237] First implementation of new message archive synchronization --- .../com/xabber/android/data/Application.java | 12 +- .../data/database/MessageDatabaseManager.java | 9 +- .../database/messagerealm/MessageItem.java | 20 + .../data/extension/mam/ArchivedHelper.java | 25 + .../data/extension/mam/NextMamManager.java | 608 ++++++++++++++++++ .../android/data/message/AbstractChat.java | 11 +- .../android/data/message/MessageManager.java | 2 +- .../android/data/message/RegularChat.java | 8 + .../android/ui/fragment/ChatFragment.java | 6 +- 9 files changed, 691 insertions(+), 10 deletions(-) create mode 100644 xabber/src/main/java/com/xabber/android/data/extension/mam/ArchivedHelper.java create mode 100644 xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java diff --git a/xabber/src/main/java/com/xabber/android/data/Application.java b/xabber/src/main/java/com/xabber/android/data/Application.java index 28847449d7..9ff1e5a7d8 100644 --- a/xabber/src/main/java/com/xabber/android/data/Application.java +++ b/xabber/src/main/java/com/xabber/android/data/Application.java @@ -45,6 +45,7 @@ import com.xabber.android.data.extension.cs.ChatStateManager; import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager; import com.xabber.android.data.extension.mam.MamManager; +import com.xabber.android.data.extension.mam.NextMamManager; import com.xabber.android.data.extension.muc.MUCManager; import com.xabber.android.data.extension.otr.OTRManager; import com.xabber.android.data.extension.ssn.SSNManager; @@ -333,10 +334,10 @@ public void onCreate() { AndroidDevMetrics.initWith(this); /** Strict Mode */ - StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() - .detectAll() - .penaltyLog() - .build()); +// StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() +// .detectAll() +// .penaltyLog() +// .build()); } /** Crashlytics */ @@ -387,7 +388,8 @@ private void addManagers() { addManager(CarbonManager.getInstance()); addManager(HttpFileUploadManager.getInstance()); addManager(BlockingManager.getInstance()); - addManager(MamManager.getInstance()); + //addManager(MamManager.getInstance()); + addManager(NextMamManager.getInstance()); addManager(CertificateManager.getInstance()); addManager(XMPPAuthManager.getInstance()); addManager(PushManager.getInstance()); diff --git a/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java b/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java index 3575aad815..5dd4c32166 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java +++ b/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java @@ -33,7 +33,7 @@ public class MessageDatabaseManager { private static final String REALM_MESSAGE_DATABASE_NAME = "xabber.realm"; - static final int REALM_MESSAGE_DATABASE_VERSION = 19; + static final int REALM_MESSAGE_DATABASE_VERSION = 20; private final RealmConfiguration realmConfiguration; private static MessageDatabaseManager instance; @@ -320,6 +320,13 @@ public void apply(DynamicRealmObject obj) { oldVersion++; } + if (oldVersion == 19) { + schema.get(MessageItem.class.getSimpleName()) + .addField(MessageItem.Fields.PREVIOUS_ID, String.class) + .addField(MessageItem.Fields.ARCHIVED_ID, String.class); + oldVersion++; + } + } }) .build(); diff --git a/xabber/src/main/java/com/xabber/android/data/database/messagerealm/MessageItem.java b/xabber/src/main/java/com/xabber/android/data/database/messagerealm/MessageItem.java index b9fddff349..816a064958 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/messagerealm/MessageItem.java +++ b/xabber/src/main/java/com/xabber/android/data/database/messagerealm/MessageItem.java @@ -74,6 +74,8 @@ public static class Fields { public static final String ORIGINAL_FROM = "originalFrom"; public static final String PARENT_MESSAGE_ID = "parentMessageId"; public static final String FROM_MUC = "fromMUC"; + public static final String PREVIOUS_ID = "previousId"; + public static final String ARCHIVED_ID = "archivedId"; } /** @@ -209,6 +211,8 @@ public static class Fields { private String originalFrom; private String parentMessageId; + private String previousId; + private String archivedId; private RealmList forwardedIds; @@ -555,6 +559,22 @@ public void setParentMessageId(String parentMessageId) { this.parentMessageId = parentMessageId; } + public String getPreviousId() { + return previousId; + } + + public void setPreviousId(String previousId) { + this.previousId = previousId; + } + + public String getArchivedId() { + return archivedId; + } + + public void setArchivedId(String archivedId) { + this.archivedId = archivedId; + } + public boolean isFromMUC() { return fromMUC; } diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/ArchivedHelper.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/ArchivedHelper.java new file mode 100644 index 0000000000..1da7197396 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/ArchivedHelper.java @@ -0,0 +1,25 @@ +package com.xabber.android.data.extension.mam; + +import org.jivesoftware.smack.packet.StandardExtensionElement; +import org.jivesoftware.smack.packet.Stanza; + +public class ArchivedHelper { + + private final static String ELEMENT_NAME = "archived"; + private final static String NAMESPACE = "urn:xmpp:mam:tmp"; + private final static String ATTRIBUTE_ID = "id"; + private final static String ATTRIBUTE_BY = "by"; + + public static String getArchivedId(Stanza stanza) { + StandardExtensionElement sidElement = stanza.getExtension(ELEMENT_NAME, NAMESPACE); + if (sidElement != null) return sidElement.getAttributeValue(ATTRIBUTE_ID); + else return null; + } + + public static String getArchivedBy(Stanza stanza) { + StandardExtensionElement sidElement = stanza.getExtension(ELEMENT_NAME, NAMESPACE); + if (sidElement != null) return sidElement.getAttributeValue(ATTRIBUTE_BY); + else return null; + } + +} diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java new file mode 100644 index 0000000000..8b5b17750e --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -0,0 +1,608 @@ +package com.xabber.android.data.extension.mam; + +import android.util.Log; + +import com.xabber.android.data.Application; +import com.xabber.android.data.account.AccountItem; +import com.xabber.android.data.account.AccountManager; +import com.xabber.android.data.database.MessageDatabaseManager; +import com.xabber.android.data.database.messagerealm.Attachment; +import com.xabber.android.data.database.messagerealm.ForwardId; +import com.xabber.android.data.database.messagerealm.MessageItem; +import com.xabber.android.data.entity.AccountJid; +import com.xabber.android.data.entity.UserJid; +import com.xabber.android.data.extension.file.FileManager; +import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager; +import com.xabber.android.data.extension.otr.OTRManager; +import com.xabber.android.data.log.LogManager; +import com.xabber.android.data.message.AbstractChat; +import com.xabber.android.data.message.ForwardManager; +import com.xabber.android.data.message.MessageManager; +import com.xabber.android.data.notification.NotificationManager; +import com.xabber.android.data.push.SyncManager; +import com.xabber.android.data.roster.OnRosterReceivedListener; +import com.xabber.android.data.roster.RosterContact; +import com.xabber.android.data.roster.RosterManager; + +import net.java.otr4j.io.SerializationUtils; +import net.java.otr4j.io.messages.PlainTextMessage; + +import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Stanza; +import org.jivesoftware.smack.tcp.XMPPTCPConnection; +import org.jivesoftware.smack.util.PacketParserUtils; +import org.jivesoftware.smackx.delay.packet.DelayInformation; +import org.jivesoftware.smackx.forward.packet.Forwarded; +import org.jivesoftware.smackx.mam.MamManager; +import org.jxmpp.jid.Jid; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import io.realm.Realm; +import io.realm.RealmList; +import io.realm.RealmResults; +import io.realm.Sort; + +public class NextMamManager implements OnRosterReceivedListener { + + private static final long ALL_MESSAGE_LOAD_INTERVAL = 1800000; + + private static NextMamManager instance; + + /** Timestamp начала работы приложения, + * сообщения с timestamp раньше этого считаются прочитанными, + * позднее - непрочитанными. + * */ + private long startHistoryTimestamp; + + public static NextMamManager getInstance() { + if (instance == null) + instance = new NextMamManager(); + return instance; + } + + @Override + public void onRosterReceived(AccountItem accountItem) { + onAccountConnected(accountItem); + } + + /** + * Thread: Smack-Cached Executor + * + * Если локальной истории еще нет: + * - Запрашиваем одно самое последнее сообщение из истории. + * Это сообщение считается прочитанным, а все сообщения полученные после него считать непрочитанными. + * - Запрашиваем 1 последнее сообщение в каждом чате. + * Иначе: + * - Если с момента получения последнего сообщения прошло больше 30 минут: + * - - Запрашиваем 1 последнее сообщение в каждом чате. + * - Иначе: + * - - Запрашиваем все новые сообщения в каждом чате. + */ + public void onAccountConnected(AccountItem accountItem) { + Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); + startHistoryTimestamp = getLastMessageTimestamp(accountItem, realm); + + if (startHistoryTimestamp == 0) { + initializeStartTimestamp(accountItem); + loadLastMessages(realm, accountItem); + } else { + if (isTimeToLoadAllNewMessages(accountItem, realm)) { + loadAllNewMessages(realm, accountItem); + } else loadLastMessages(realm, accountItem); + } + realm.close(); + } + +// public void onAccountDisconnected(AccountItem accountItem) { +// /** +// * Проставляем для всех чатов lastMessageArchiveID = null +// */ +// +// // для всех чатов +// // chat.setLastMessageArchiveID(null) +// } + + /** + * Проверяем наличие дыр в истории: + * - Берем все сообщения с previousID = null + * - Если сообщение M1 - не является самым первым в истории, то + * - - Выполняем заполнение истории для всех найденных дыр: + * - - requestMissedMessages(message) + */ + public void onChatOpen(final AbstractChat chat) { + Application.getInstance().runInBackground(new Runnable() { + @Override + public void run() { + Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); + AccountItem accountItem = AccountManager.getInstance().getAccount(chat.getAccount()); + List messages = findMissedMessages(realm, chat); + if (messages != null && !messages.isEmpty() && accountItem != null) { + for (MessageItem message : messages) { + loadMissedMessages(realm, accountItem, chat, message); + } + } + realm.close(); + } + }); + } + +// public void onScrollInChat(AbstractChat chat) { +// loadNextHistory(chat); +// } + + /** MAIN */ + + private void loadLastMessages(Realm realm, AccountItem accountItem) { + Collection contacts = RosterManager.getInstance() + .getAccountRosterContacts(accountItem.getAccount()); + + for (RosterContact contact : contacts) { + AbstractChat chat = MessageManager.getInstance() + .getOrCreateChat(contact.getAccount(), contact.getUser()); + loadLastMessage(realm, accountItem, chat); + } + } + + /** + * Запросить последнее сообщение в этом чате + * previousID = null + * setChatLastId(archivedID последнего сообщения в этом чате) + */ + private void loadLastMessage(Realm realm, AccountItem accountItem, AbstractChat chat) { + MamManager.MamQueryResult queryResult = requestLastMessage(accountItem, chat); + if (queryResult != null) { + List messages = new ArrayList<>(queryResult.forwardedMessages); + saveOrUpdateMessages(realm, chat, parseMessage(chat.getAccount(), chat.getUser(), messages, null)); + updateLastMessageId(chat, realm); + } + } + + private void loadAllNewMessages(Realm realm, AccountItem accountItem) { + Collection contacts = RosterManager.getInstance() + .getAccountRosterContacts(accountItem.getAccount()); + + for (RosterContact contact : contacts) { + AbstractChat chat = MessageManager.getInstance() + .getOrCreateChat(contact.getAccount(), contact.getUser()); + loadNewMessages(realm, accountItem, chat); + } + } + + /** + * Запросить все сообщения начиная со времени получения последнего сообщения. + * previousID первого нового сообщения = archivedID последнего сообщения. + * setChatLastId(archivedID последнего сообщения в этом чате) + */ + private void loadNewMessages(Realm realm, AccountItem accountItem, AbstractChat chat) { + String lastArchivedId = getLastMessageArchivedId(chat, realm); + if (lastArchivedId != null) { + + List messages = new ArrayList<>(); + boolean complete = false; + + String id = lastArchivedId; + while (!complete && id != null) { + MamManager.MamQueryResult queryResult = requestMessagesFromId(accountItem, chat, id); + if (queryResult != null) { + messages.addAll(queryResult.forwardedMessages); + complete = queryResult.mamFin.isComplete(); + id = getNextId(queryResult); + } else complete = true; + } + + if (!messages.isEmpty()) { + saveOrUpdateMessages(realm, chat, + parseMessage(chat.getAccount(), chat.getUser(), messages, chat.getLastMessageId())); + updateLastMessageId(chat, realm); + } + } + } + +// private void loadNextHistory(AbstractChat chat) { +// /** +// * Запросить страницу истории до самого первого сообщения в чате. +// * previousID сообщения на котором начиналась история = archivedID последнего полученного сообщения. +// * previousID первого полученного сообщения = null +// * +// * Если при запросе истории вернулась пустая страница, то +// * previousID сообщения на котором начиналась история = archivedID этого сообщения +// */ +// } + + /** + * Находим M2 - первое сообщение перед M1 с archivedID != null и previousID != null + * Выполняем запрос истории начиная от archivedID M2 и заканчивая archivedID M1 + * Используя полученные сообщения проставляем previousID для сообщений. + */ + private void loadMissedMessages(Realm realm, AccountItem accountItem, AbstractChat chat, MessageItem m1) { + + MessageItem m2 = getMessageForCloseMissedMessages(realm, m1); + if (m2 != null && !m2.getUniqueId().equals(m1.getUniqueId())) { + Log.d("VALERA_TEST", "m1 archived id: " + m1.getArchivedId() + " text: " + m1.getText()); + Log.d("VALERA_TEST", "m2 archived id: " + m2.getArchivedId() + " text: " + m2.getText()); + Date startDate = new Date(m2.getTimestamp()); + Date endDate = new Date(m1.getTimestamp()); + + List messages = new ArrayList<>(); + boolean complete = false; + + while (!complete && startDate != null) { + MamManager.MamQueryResult queryResult = requestMissedMessages(accountItem, chat, startDate, endDate); + if (queryResult != null) { + messages.addAll(queryResult.forwardedMessages); + complete = queryResult.mamFin.isComplete(); + startDate = getNextDate(queryResult); + } else complete = true; + } + + if (!messages.isEmpty()) { + List savedMessages = saveOrUpdateMessages(realm, chat, + parseMessage(chat.getAccount(), chat.getUser(), messages, m2.getArchivedId())); + + if (savedMessages != null && !savedMessages.isEmpty()) { + realm.beginTransaction(); + m1.setPreviousId(savedMessages.get(savedMessages.size() - 1).getArchivedId()); + realm.commitTransaction(); + } + + updateLastMessageId(chat, realm); + } + } + } + + /** Request most recent message from all history and save it timestamp to startHistoryTimestamp + * If message is null save current time to startHistoryTimestamp */ + private void initializeStartTimestamp(@Nonnull AccountItem accountItem) { + startHistoryTimestamp = System.currentTimeMillis(); + + MamManager.MamQueryResult queryResult = requestLastMessage(accountItem); + if (queryResult != null && !queryResult.forwardedMessages.isEmpty()) { + Forwarded forwarded = queryResult.forwardedMessages.get(0); + startHistoryTimestamp = forwarded.getDelayInformation().getStamp().getTime(); + } + } + + /** REQUESTS */ + + /** Request most recent message from all history */ + private @Nullable MamManager.MamQueryResult requestLastMessage(@Nonnull AccountItem accountItem) { + return requestLastMessage(accountItem, null); + } + + /** Request recent message from chat history */ + private @Nullable MamManager.MamQueryResult requestLastMessage(@Nonnull AccountItem accountItem, AbstractChat chat) { + MamManager.MamQueryResult queryResult = null; + XMPPTCPConnection connection = accountItem.getConnection(); + Jid chatJid = null; + if (chat != null) chatJid = chat.getUser().getJid(); + + if (connection.isAuthenticated()) { + MamManager mamManager = MamManager.getInstanceFor(connection); + try { + queryResult = mamManager.mostRecentPage(chatJid, 1); + } catch (SmackException.NotLoggedInException | InterruptedException + | SmackException.NotConnectedException | SmackException.NoResponseException + | XMPPException.XMPPErrorException e) { + LogManager.exception(this, e); + } + } + + return queryResult; + } + + /** Request messages started with archivedID from chat history */ + private @Nullable MamManager.MamQueryResult requestMessagesFromId( + @Nonnull AccountItem accountItem, @Nonnull AbstractChat chat, String archivedId) { + + MamManager.MamQueryResult queryResult = null; + XMPPTCPConnection connection = accountItem.getConnection(); + + if (connection.isAuthenticated()) { + MamManager mamManager = MamManager.getInstanceFor(connection); + try { + queryResult = mamManager.pageAfter(chat.getUser().getJid(), archivedId, 50); + } catch (SmackException.NotLoggedInException | InterruptedException + | SmackException.NotConnectedException | SmackException.NoResponseException + | XMPPException.XMPPErrorException e) { + LogManager.exception(this, e); + } + } + + return queryResult; + } + + /** Request messages started with startID and ending with endID from chat history */ + private @Nullable MamManager.MamQueryResult requestMissedMessages( + @Nonnull AccountItem accountItem, @Nonnull AbstractChat chat, Date startDate, Date endDate) { + + MamManager.MamQueryResult queryResult = null; + XMPPTCPConnection connection = accountItem.getConnection(); + + if (connection.isAuthenticated()) { + MamManager mamManager = MamManager.getInstanceFor(connection); + try { + queryResult = mamManager.queryArchive(50, startDate, endDate, chat.getUser().getJid(), null); + } catch (SmackException.NotLoggedInException | InterruptedException + | SmackException.NotConnectedException | SmackException.NoResponseException + | XMPPException.XMPPErrorException e) { + LogManager.exception(this, e); + } + } + + return queryResult; + } + + /** PARSING */ + + private List parseMessage(AccountJid account, UserJid user, + List forwardedMessages, String prevID) { + List messageItems = new ArrayList<>(); + for (Forwarded forwarded : forwardedMessages) { + MessageItem message = parseMessage(account, user, forwarded, prevID); + if (message != null) { + messageItems.add(message); + prevID = message.getArchivedId(); + } + } + return messageItems; + } + + private @Nullable MessageItem parseMessage(AccountJid account, UserJid user, Forwarded forwarded, String prevID) { + if (!(forwarded.getForwardedStanza() instanceof Message)) { + return null; + } + + Message message = (Message) forwarded.getForwardedStanza(); + + DelayInformation delayInformation = forwarded.getDelayInformation(); + + DelayInformation messageDelay = DelayInformation.from(message); + + String body = message.getBody(); + net.java.otr4j.io.messages.AbstractMessage otrMessage; + try { + otrMessage = SerializationUtils.toMessage(body); + } catch (IOException e) { + return null; + } + boolean encrypted = false; + if (otrMessage != null) { + if (otrMessage.messageType != net.java.otr4j.io.messages.AbstractMessage.MESSAGE_PLAINTEXT) { + encrypted = true; + try { + // this transforming just decrypt message if have keys. No action as injectMessage or something else + body = OTRManager.getInstance().transformReceivingIfSessionExist(account, user, body); + if (OTRManager.getInstance().isEncrypted(body)) { + return null; + } + } catch (Exception e) { + return null; + } + } + else body = ((PlainTextMessage) otrMessage).cleanText; + } + + boolean incoming = message.getFrom().asBareJid().equals(user.getJid().asBareJid()); + + String uid = UUID.randomUUID().toString(); + MessageItem messageItem = new MessageItem(uid); + messageItem.setPreviousId(prevID); + + String archivedId = ArchivedHelper.getArchivedId(forwarded.getForwardedStanza()); + if (archivedId != null) messageItem.setArchivedId(archivedId); + + long timestamp = delayInformation.getStamp().getTime(); + + messageItem.setAccount(account); + messageItem.setUser(user); + messageItem.setResource(user.getJid().getResourceOrNull()); + messageItem.setText(body); + messageItem.setTimestamp(timestamp); + if (messageDelay != null) { + messageItem.setDelayTimestamp(messageDelay.getStamp().getTime()); + } + messageItem.setIncoming(incoming); + messageItem.setStanzaId(message.getStanzaId()); + messageItem.setReceivedFromMessageArchive(true); + messageItem.setRead(timestamp < startHistoryTimestamp); + messageItem.setSent(true); + messageItem.setEncrypted(encrypted); + + // attachments + FileManager.processFileMessage(messageItem); + + RealmList attachments = HttpFileUploadManager.parseFileMessage(message); + if (attachments.size() > 0) + messageItem.setAttachments(attachments); + + // forwarded + messageItem.setOriginalStanza(message.toXML().toString()); + messageItem.setOriginalFrom(message.getFrom().toString()); + + return messageItem; + } + + /** SAVING */ + + private List saveOrUpdateMessages(Realm realm, AbstractChat chat, final Collection messages) { + List messagesToSave = new ArrayList<>(); + if (messages != null && !messages.isEmpty()) { + Iterator iterator = messages.iterator(); + while (iterator.hasNext()) { + MessageItem newMessage = determineSaveOrUpdate(realm, chat, iterator.next()); + if (newMessage != null) messagesToSave.add(newMessage); + } + } + realm.beginTransaction(); + realm.copyToRealm(messagesToSave); + realm.commitTransaction(); + SyncManager.getInstance().onMessageSaved(); + return messagesToSave; + } + + private MessageItem determineSaveOrUpdate(Realm realm, AbstractChat chat, final MessageItem message) { + // set text from comment to text in message for prevent doubling messages from MAM + Message originalMessage = null; + try { + originalMessage = (Message) PacketParserUtils.parseStanza(message.getOriginalStanza()); + String comment = ForwardManager.parseForwardComment(originalMessage); + if (comment != null) message.setText(comment); + } catch (Exception e) { + e.printStackTrace(); + } + + MessageItem localMessage = realm.where(MessageItem.class) + .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) + .equalTo(MessageItem.Fields.USER, chat.getUser().toString()) + .equalTo(MessageItem.Fields.STANZA_ID, message.getStanzaId()) + .equalTo(MessageItem.Fields.TEXT, message.getText()) + .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) + .findFirst(); + + if (localMessage == null) { + // forwarded + if (originalMessage != null) { + RealmList forwardIds = chat.parseForwardedMessage(false, originalMessage, message.getUniqueId()); + if (forwardIds != null && !forwardIds.isEmpty()) + message.setForwardedIds(forwardIds); + } + + // notify about new message + chat.enableNotificationsIfNeed(); + boolean notify = !message.getText().trim().isEmpty() && message.isIncoming() && chat.notifyAboutMessage(); + boolean visible = MessageManager.getInstance().isVisibleChat(chat); + if (notify && !visible) + NotificationManager.getInstance().onMessageNotification(message); + // + + return message; + } else { + realm.beginTransaction(); + localMessage.setArchivedId(message.getArchivedId()); + realm.commitTransaction(); + return null; + } + } + + /** UTILS */ + + private String getNextId(MamManager.MamQueryResult queryResult) { + String archivedId = null; + if (queryResult.forwardedMessages != null && !queryResult.forwardedMessages.isEmpty()) { + Forwarded forwarded = queryResult.forwardedMessages.get(queryResult.forwardedMessages.size() - 1); + archivedId = ArchivedHelper.getArchivedId(forwarded.getForwardedStanza()); + } + return archivedId; + } + + private Date getNextDate(MamManager.MamQueryResult queryResult) { + Date date = null; + if (queryResult.forwardedMessages != null && !queryResult.forwardedMessages.isEmpty()) { + Forwarded forwarded = queryResult.forwardedMessages.get(queryResult.forwardedMessages.size() - 1); + DelayInformation delayInformation = forwarded.getDelayInformation(); + date = new Date(delayInformation.getStamp().getTime() + 1); + } + return date; + } + + @Nullable private List findMissedMessages(Realm realm, AbstractChat chat) { + RealmResults results = realm.where(MessageItem.class) + .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) + .equalTo(MessageItem.Fields.USER, chat.getUser().toString()) + .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) + .isNotNull(MessageItem.Fields.ARCHIVED_ID) + .isNull(MessageItem.Fields.PREVIOUS_ID) + .findAllSorted(MessageItem.Fields.TIMESTAMP, Sort.DESCENDING); + + if (results != null && !results.isEmpty()) { + return new ArrayList<>(results); + } else return null; + } + + private MessageItem getMessageForCloseMissedMessages(Realm realm, MessageItem messageItem) { + RealmResults results = realm.where(MessageItem.class) + .equalTo(MessageItem.Fields.ACCOUNT, messageItem.getAccount().toString()) + .equalTo(MessageItem.Fields.USER, messageItem.getUser().toString()) + .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) + .isNotNull(MessageItem.Fields.ARCHIVED_ID) + .lessThan(MessageItem.Fields.TIMESTAMP, messageItem.getTimestamp()) + .findAllSorted(MessageItem.Fields.TIMESTAMP, Sort.DESCENDING); + + if (results != null && !results.isEmpty()) { + return results.first(); + } else return null; + } + + private boolean isTimeToLoadAllNewMessages(AccountItem account, Realm realm) { + RealmResults results = realm.where(MessageItem.class) + .equalTo(MessageItem.Fields.ACCOUNT, account.getAccount().toString()) + .findAllSorted(MessageItem.Fields.TIMESTAMP, Sort.ASCENDING); + + if (results != null && !results.isEmpty()) { + MessageItem lastMessage = results.last(); + return System.currentTimeMillis() < lastMessage.getTimestamp() + ALL_MESSAGE_LOAD_INTERVAL; + } else return false; + } + + private boolean historyIsEmpty(AccountItem account) { + Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); + MessageItem messageItem = realm.where(MessageItem.class) + .equalTo(MessageItem.Fields.ACCOUNT, account.getAccount().toString()) + .findFirst(); + realm.close(); + return messageItem == null; + } + + private String getLastMessageArchivedId(AbstractChat chat, Realm realm) { + RealmResults results = realm.where(MessageItem.class) + .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) + .equalTo(MessageItem.Fields.USER, chat.getUser().toString()) + .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) + .isNotNull(MessageItem.Fields.ARCHIVED_ID) + .findAllSorted(MessageItem.Fields.TIMESTAMP, Sort.ASCENDING); + + if (results != null && !results.isEmpty()) { + MessageItem lastMessage = results.last(); + return lastMessage.getArchivedId(); + } else return null; + } + + private long getLastMessageTimestamp(AccountItem account, Realm realm) { + RealmResults results = realm.where(MessageItem.class) + .equalTo(MessageItem.Fields.ACCOUNT, account.getAccount().toString()) + .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) + .findAllSorted(MessageItem.Fields.TIMESTAMP, Sort.ASCENDING); + + if (results != null && !results.isEmpty()) { + MessageItem lastMessage = results.last(); + return lastMessage.getTimestamp(); + } else return 0; + } + + private void updateLastMessageId(AbstractChat chat, Realm realm) { + RealmResults results = realm.where(MessageItem.class) + .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) + .equalTo(MessageItem.Fields.USER, chat.getUser().toString()) + .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) + .findAllSorted(MessageItem.Fields.TIMESTAMP, Sort.ASCENDING); + + if (results != null && !results.isEmpty()) { + MessageItem lastMessage = results.last(); + String id = lastMessage.getArchivedId(); + if (id == null) id = lastMessage.getStanzaId(); + chat.setLastMessageId(id); + } + } +} diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index 57d1974d96..07a7810f5f 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -122,6 +122,7 @@ public abstract class AbstractChat extends BaseEntity implements RealmChangeList private RealmResults syncInfo; private MessageItem lastMessage; private RealmResults messages; + private String lastMessageId = null; protected AbstractChat(@NonNull final AccountJid account, @NonNull final UserJid user, boolean isPrivateMucChat) { super(account, isPrivateMucChat ? user : user.getBareUserJid()); @@ -246,7 +247,7 @@ public boolean notifyAboutMessage() { else return false; } - private void enableNotificationsIfNeed() { + public void enableNotificationsIfNeed() { int currentTime = (int) (System.currentTimeMillis() / 1000L); NotificationState.NotificationMode mode = notificationState.getMode(); @@ -942,4 +943,12 @@ public RealmList parseForwardedMessage(boolean ui, Stanza packet, Str } protected abstract String parseInnerMessage(boolean ui, Message message, String parentMessageId); + + public String getLastMessageId() { + return lastMessageId; + } + + public void setLastMessageId(String lastMessageId) { + this.lastMessageId = lastMessageId; + } } \ No newline at end of file diff --git a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java index 4c5774ef8d..c0ac131713 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java +++ b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java @@ -536,7 +536,7 @@ public void removeVisibleChat() { * @param chat * @return Whether specified chat is currently visible. */ - boolean isVisibleChat(AbstractChat chat) { + public boolean isVisibleChat(AbstractChat chat) { return visibleChat == chat; } diff --git a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java index 05b6d9bcb4..297dd89f6b 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java @@ -17,6 +17,7 @@ import android.content.Intent; import android.support.annotation.NonNull; import android.text.TextUtils; +import android.util.Log; import com.xabber.android.data.NetworkException; import com.xabber.android.data.SettingsManager; @@ -43,6 +44,7 @@ import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smackx.delay.packet.DelayInformation; import org.jivesoftware.smackx.muc.packet.MUCUser; +import org.jivesoftware.smackx.offline.OfflineMessageHeader; import org.jxmpp.jid.Jid; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.jid.parts.Domainpart; @@ -178,6 +180,12 @@ protected boolean onPacket(UserJid bareAddress, Stanza packet, boolean isCarbons if (text == null) return true; + DelayInformation delayInformation = message.getExtension(DelayInformation.ELEMENT, DelayInformation.NAMESPACE); + if (delayInformation != null && "Offline Storage".equals(delayInformation.getReason())) { + Log.d("VALERA_TEST", "message from offline storage should be ignored"); + return true; + } + // Xabber service message received if (message.getType() == Type.headline) { if (XMPPAuthManager.getInstance().isXabberServiceMessage(message.getStanzaId())) diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java index 27f3ed01e8..3f88051c2a 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java @@ -61,6 +61,7 @@ import com.xabber.android.data.extension.mam.LastHistoryLoadStartedEvent; import com.xabber.android.data.extension.mam.LoadHistorySettings; import com.xabber.android.data.extension.mam.MamManager; +import com.xabber.android.data.extension.mam.NextMamManager; import com.xabber.android.data.extension.mam.PreviousHistoryLoadFinishedEvent; import com.xabber.android.data.extension.mam.PreviousHistoryLoadStartedEvent; import com.xabber.android.data.extension.muc.MUCManager; @@ -421,7 +422,8 @@ public void onStart() { if (loadHistorySettings == LoadHistorySettings.all || loadHistorySettings == LoadHistorySettings.current) { if (!isRemoteHistoryRequested) { - MamManager.getInstance().requestLastHistoryByUser(getChat()); + //MamManager.getInstance().requestLastHistoryByUser(getChat()); + NextMamManager.getInstance().onChatOpen(getChat()); } } } @@ -684,7 +686,7 @@ private void requestRemoteHistoryLoad() { if (!isRemoteHistoryRequested) { AbstractChat chat = getChat(); if (chat != null) { - MamManager.getInstance().requestPreviousHistory(chat); + //MamManager.getInstance().requestPreviousHistory(chat); } } From c87ebb79ef75dc287fe3cebfe873328ba86a3a6d Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 23 Apr 2019 17:22:22 +0500 Subject: [PATCH 049/237] Added loading history by scroll --- .../data/extension/mam/NextMamManager.java | 118 ++++++++++++++---- .../android/data/message/AbstractChat.java | 1 + .../ui/adapter/chat/MessagesAdapter.java | 15 +++ .../android/ui/fragment/ChatFragment.java | 13 +- 4 files changed, 118 insertions(+), 29 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index 8b5b17750e..3dcb14ed2a 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -27,10 +27,10 @@ import net.java.otr4j.io.SerializationUtils; import net.java.otr4j.io.messages.PlainTextMessage; +import org.greenrobot.eventbus.EventBus; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Message; -import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.tcp.XMPPTCPConnection; import org.jivesoftware.smack.util.PacketParserUtils; import org.jivesoftware.smackx.delay.packet.DelayInformation; @@ -65,6 +65,8 @@ public class NextMamManager implements OnRosterReceivedListener { * позднее - непрочитанными. * */ private long startHistoryTimestamp; + private boolean isRequested = false; + private final Object lock = new Object(); public static NextMamManager getInstance() { if (instance == null) @@ -105,15 +107,6 @@ public void onAccountConnected(AccountItem accountItem) { realm.close(); } -// public void onAccountDisconnected(AccountItem accountItem) { -// /** -// * Проставляем для всех чатов lastMessageArchiveID = null -// */ -// -// // для всех чатов -// // chat.setLastMessageArchiveID(null) -// } - /** * Проверяем наличие дыр в истории: * - Берем все сообщения с previousID = null @@ -138,9 +131,26 @@ public void run() { }); } -// public void onScrollInChat(AbstractChat chat) { -// loadNextHistory(chat); -// } + public void onScrollInChat(final AbstractChat chat) { + Application.getInstance().runInBackgroundUserRequest(new Runnable() { + @Override + public void run() { + synchronized (lock) { + if (isRequested) return; + else isRequested = true; + } + EventBus.getDefault().post(new PreviousHistoryLoadStartedEvent(chat)); + Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); + AccountItem accountItem = AccountManager.getInstance().getAccount(chat.getAccount()); + loadNextHistory(realm, accountItem, chat); + realm.close(); + EventBus.getDefault().post(new PreviousHistoryLoadFinishedEvent(chat)); + synchronized (lock) { + isRequested = false; + } + } + }); + } /** MAIN */ @@ -165,8 +175,8 @@ private void loadLastMessage(Realm realm, AccountItem accountItem, AbstractChat if (queryResult != null) { List messages = new ArrayList<>(queryResult.forwardedMessages); saveOrUpdateMessages(realm, chat, parseMessage(chat.getAccount(), chat.getUser(), messages, null)); - updateLastMessageId(chat, realm); } + updateLastMessageId(chat, realm); } private void loadAllNewMessages(Realm realm, AccountItem accountItem) { @@ -205,21 +215,43 @@ private void loadNewMessages(Realm realm, AccountItem accountItem, AbstractChat if (!messages.isEmpty()) { saveOrUpdateMessages(realm, chat, parseMessage(chat.getAccount(), chat.getUser(), messages, chat.getLastMessageId())); - updateLastMessageId(chat, realm); } + updateLastMessageId(chat, realm); } } -// private void loadNextHistory(AbstractChat chat) { -// /** -// * Запросить страницу истории до самого первого сообщения в чате. -// * previousID сообщения на котором начиналась история = archivedID последнего полученного сообщения. -// * previousID первого полученного сообщения = null -// * -// * Если при запросе истории вернулась пустая страница, то -// * previousID сообщения на котором начиналась история = archivedID этого сообщения -// */ -// } + /** + * Запросить страницу истории до самого первого сообщения в чате. + * previousID сообщения на котором начиналась история = archivedID последнего полученного сообщения. + * previousID первого полученного сообщения = null + * + * Если при запросе истории вернулась пустая страница, то + * previousID сообщения на котором начиналась история = archivedID этого сообщения + */ + private void loadNextHistory(Realm realm, AccountItem accountItem, AbstractChat chat) { + MessageItem firstMessage = getFirstMessage(chat, realm); + if (firstMessage != null) { + MamManager.MamQueryResult queryResult = requestMessagesBeforeId(accountItem, chat, firstMessage.getArchivedId()); + if (queryResult != null) { + List messages = new ArrayList<>(queryResult.forwardedMessages); + if (!messages.isEmpty()) { + List savedMessages = saveOrUpdateMessages(realm, chat, + parseMessage(chat.getAccount(), chat.getUser(), messages, null)); + + if (savedMessages != null && !savedMessages.isEmpty()) { + realm.beginTransaction(); + firstMessage.setPreviousId(savedMessages.get(savedMessages.size() - 1).getArchivedId()); + realm.commitTransaction(); + } + } else if (queryResult.mamFin.isComplete()) { + realm.beginTransaction(); + firstMessage.setPreviousId(firstMessage.getArchivedId()); + realm.commitTransaction(); + } + } + } + + } /** * Находим M2 - первое сообщение перед M1 с archivedID != null и previousID != null @@ -256,8 +288,6 @@ private void loadMissedMessages(Realm realm, AccountItem accountItem, AbstractCh m1.setPreviousId(savedMessages.get(savedMessages.size() - 1).getArchivedId()); realm.commitTransaction(); } - - updateLastMessageId(chat, realm); } } } @@ -323,6 +353,27 @@ private void initializeStartTimestamp(@Nonnull AccountItem accountItem) { return queryResult; } + /** Request messages before with archivedID from chat history */ + private @Nullable MamManager.MamQueryResult requestMessagesBeforeId( + @Nonnull AccountItem accountItem, @Nonnull AbstractChat chat, String archivedId) { + + MamManager.MamQueryResult queryResult = null; + XMPPTCPConnection connection = accountItem.getConnection(); + + if (connection.isAuthenticated()) { + MamManager mamManager = MamManager.getInstanceFor(connection); + try { + queryResult = mamManager.pageBefore(chat.getUser().getJid(), archivedId, 50); + } catch (SmackException.NotLoggedInException | InterruptedException + | SmackException.NotConnectedException | SmackException.NoResponseException + | XMPPException.XMPPErrorException e) { + LogManager.exception(this, e); + } + } + + return queryResult; + } + /** Request messages started with startID and ending with endID from chat history */ private @Nullable MamManager.MamQueryResult requestMissedMessages( @Nonnull AccountItem accountItem, @Nonnull AbstractChat chat, Date startDate, Date endDate) { @@ -579,6 +630,19 @@ private String getLastMessageArchivedId(AbstractChat chat, Realm realm) { } else return null; } + private MessageItem getFirstMessage(AbstractChat chat, Realm realm) { + RealmResults results = realm.where(MessageItem.class) + .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) + .equalTo(MessageItem.Fields.USER, chat.getUser().toString()) + .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) + .isNotNull(MessageItem.Fields.ARCHIVED_ID) + .findAllSorted(MessageItem.Fields.TIMESTAMP, Sort.ASCENDING); + + if (results != null && !results.isEmpty()) { + return results.first(); + } else return null; + } + private long getLastMessageTimestamp(AccountItem account, Realm realm) { RealmResults results = realm.where(MessageItem.class) .equalTo(MessageItem.Fields.ACCOUNT, account.getAccount().toString()) diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index 07a7810f5f..ac26673c92 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -787,6 +787,7 @@ protected void onComplete() { * Disconnection occured. */ protected void onDisconnect() { + setLastMessageId(null); } public void setIsPrivateMucChatAccepted(boolean isPrivateMucChatAccepted) { diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessagesAdapter.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessagesAdapter.java index 19c875d5ce..ec42c6b2dc 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessagesAdapter.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessagesAdapter.java @@ -59,6 +59,7 @@ public class MessagesAdapter extends RealmRecyclerViewAdapter 0) + return realmResults.first().getUniqueId(); + else return null; + } + @Override public int getItemViewType(int position) { MessageItem messageItem = getMessageItem(position); @@ -230,13 +240,18 @@ public void onBindViewHolder(final BasicMessageVH holder, int position) { @Override public void onChange() { + int lastPosition = listener.getLastVisiblePosition(); + String firstMessageId = getFirstMessageId(); notifyDataSetChanged(); listener.onMessagesUpdated(); int itemCount = getItemCount(); if (prevItemCount != itemCount) { + if (firstMessageId != null && !firstMessageId.equals(prevFirstItemId)) + listener.scrollTo(lastPosition + (itemCount - prevItemCount)); listener.onMessageNumberChanged(prevItemCount); prevItemCount = itemCount; + prevFirstItemId = firstMessageId; } } diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java index 3f88051c2a..72117b21ce 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java @@ -60,7 +60,6 @@ import com.xabber.android.data.extension.mam.LastHistoryLoadFinishedEvent; import com.xabber.android.data.extension.mam.LastHistoryLoadStartedEvent; import com.xabber.android.data.extension.mam.LoadHistorySettings; -import com.xabber.android.data.extension.mam.MamManager; import com.xabber.android.data.extension.mam.NextMamManager; import com.xabber.android.data.extension.mam.PreviousHistoryLoadFinishedEvent; import com.xabber.android.data.extension.mam.PreviousHistoryLoadStartedEvent; @@ -686,7 +685,7 @@ private void requestRemoteHistoryLoad() { if (!isRemoteHistoryRequested) { AbstractChat chat = getChat(); if (chat != null) { - //MamManager.getInstance().requestPreviousHistory(chat); + NextMamManager.getInstance().onScrollInChat(getChat()); } } @@ -1311,6 +1310,16 @@ public void onMessageNumberChanged(int prevItemCount) { } } + @Override + public int getLastVisiblePosition() { + return layoutManager.findLastVisibleItemPosition(); + } + + @Override + public void scrollTo(int position) { + layoutManager.scrollToPosition(position); + } + public void saveScrollState() { int position = layoutManager.findLastCompletelyVisibleItemPosition(); AbstractChat chat = getChat(); From b316e4a4e8aa89b26fd7c342dbd14905d597f862 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 23 Apr 2019 18:26:57 +0500 Subject: [PATCH 050/237] Added endOfHistory flag in abstract chat to prevent endless loading --- .../android/data/extension/mam/NextMamManager.java | 9 ++++++++- .../com/xabber/android/data/message/AbstractChat.java | 9 +++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index 3dcb14ed2a..8b07f88fe8 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -132,6 +132,7 @@ public void run() { } public void onScrollInChat(final AbstractChat chat) { + if (chat.historyIsFull()) return; Application.getInstance().runInBackgroundUserRequest(new Runnable() { @Override public void run() { @@ -231,6 +232,11 @@ private void loadNewMessages(Realm realm, AccountItem accountItem, AbstractChat private void loadNextHistory(Realm realm, AccountItem accountItem, AbstractChat chat) { MessageItem firstMessage = getFirstMessage(chat, realm); if (firstMessage != null) { + if (firstMessage.getArchivedId().equals(firstMessage.getPreviousId())) { + chat.setHistoryIsFull(); + return; + } + MamManager.MamQueryResult queryResult = requestMessagesBeforeId(accountItem, chat, firstMessage.getArchivedId()); if (queryResult != null) { List messages = new ArrayList<>(queryResult.forwardedMessages); @@ -532,7 +538,8 @@ private MessageItem determineSaveOrUpdate(Realm realm, AbstractChat chat, final // notify about new message chat.enableNotificationsIfNeed(); - boolean notify = !message.getText().trim().isEmpty() && message.isIncoming() && chat.notifyAboutMessage(); + boolean notify = (message.getText() != null && !message.getText().trim().isEmpty()) + && message.isIncoming() && chat.notifyAboutMessage(); boolean visible = MessageManager.getInstance().isVisibleChat(chat); if (notify && !visible) NotificationManager.getInstance().onMessageNotification(message); diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index ac26673c92..609c4ccdb5 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -123,6 +123,7 @@ public abstract class AbstractChat extends BaseEntity implements RealmChangeList private MessageItem lastMessage; private RealmResults messages; private String lastMessageId = null; + private boolean historyIsFull = false; protected AbstractChat(@NonNull final AccountJid account, @NonNull final UserJid user, boolean isPrivateMucChat) { super(account, isPrivateMucChat ? user : user.getBareUserJid()); @@ -952,4 +953,12 @@ public String getLastMessageId() { public void setLastMessageId(String lastMessageId) { this.lastMessageId = lastMessageId; } + + public boolean historyIsFull() { + return historyIsFull; + } + + public void setHistoryIsFull() { + this.historyIsFull = true; + } } \ No newline at end of file From f20c6545b92047a9e530adfdfa3921c60826fae6 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 23 Apr 2019 18:30:53 +0500 Subject: [PATCH 051/237] Up version to 607 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 15a3a13088..ed7667f283 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 606 - versionName '2.6.4(606)' + versionCode 607 + versionName '2.6.4(607)' } lintOptions { From e6bfe0dfed8fad676df93465049eea3cb307883a Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 24 Apr 2019 11:49:35 +0500 Subject: [PATCH 052/237] Remove refresh layout from chat screen --- .../android/ui/fragment/ChatFragment.java | 19 ------------------- xabber/src/main/res/layout/fragment_chat.xml | 13 ++----------- 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java index 72117b21ce..19e3440ce2 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java @@ -13,7 +13,6 @@ import android.support.annotation.Nullable; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; -import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.AlertDialog; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; @@ -148,7 +147,6 @@ public class ChatFragment extends FileInteractionFragment implements PopupMenu.O private RecyclerView realmRecyclerView; private MessagesAdapter chatMessageAdapter; private LinearLayoutManager layoutManager; - private SwipeRefreshLayout swipeContainer; private View placeholder; private LinearLayout inputLayout; private ViewStub stubJoin; @@ -350,21 +348,6 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { } }); - swipeContainer = (SwipeRefreshLayout) view.findViewById(R.id.swipeContainer); - swipeContainer.setColorSchemeColors(ColorManager.getInstance().getAccountPainter().getAccountMainColor(account)); - swipeContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { - @Override - public void onRefresh() { - swipeContainer.setRefreshing(false); - AbstractChat chat = getChat(); - if (chat != null) { - if (chat.isRemotePreviousHistoryCompletelyLoaded()) - Toast.makeText(getActivity(), R.string.toast_no_history, Toast.LENGTH_SHORT).show(); - else requestRemoteHistoryLoad(); - } - } - }); - stubNotify = (ViewStub) view.findViewById(R.id.stubNotify); stubJoin = (ViewStub) view.findViewById(R.id.stubJoin); @@ -719,7 +702,6 @@ public void onEvent(PreviousHistoryLoadStartedEvent event) { LogManager.i(this, "PreviousHistoryLoadStartedEvent"); previousHistoryProgressBar.setVisibility(View.VISIBLE); isRemoteHistoryRequested = true; - swipeContainer.setRefreshing(true); } } @@ -729,7 +711,6 @@ public void onEvent(PreviousHistoryLoadFinishedEvent event) { LogManager.i(this, "PreviousHistoryLoadFinishedEvent"); isRemoteHistoryRequested = false; previousHistoryProgressBar.setVisibility(View.GONE); - swipeContainer.setRefreshing(false); } } diff --git a/xabber/src/main/res/layout/fragment_chat.xml b/xabber/src/main/res/layout/fragment_chat.xml index 4291ebf474..ecf2499dfd 100644 --- a/xabber/src/main/res/layout/fragment_chat.xml +++ b/xabber/src/main/res/layout/fragment_chat.xml @@ -21,15 +21,6 @@ android:id="@+id/root_view" android:elevation="24dp"> - - - - Date: Wed, 24 Apr 2019 12:14:19 +0500 Subject: [PATCH 053/237] Change event type on load previous history --- .../com/xabber/android/data/extension/mam/NextMamManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index 8b07f88fe8..c485168080 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -140,12 +140,12 @@ public void run() { if (isRequested) return; else isRequested = true; } - EventBus.getDefault().post(new PreviousHistoryLoadStartedEvent(chat)); + EventBus.getDefault().post(new LastHistoryLoadStartedEvent(chat)); Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); AccountItem accountItem = AccountManager.getInstance().getAccount(chat.getAccount()); loadNextHistory(realm, accountItem, chat); realm.close(); - EventBus.getDefault().post(new PreviousHistoryLoadFinishedEvent(chat)); + EventBus.getDefault().post(new LastHistoryLoadFinishedEvent(chat)); synchronized (lock) { isRequested = false; } From 6842da7ca24476494e61546b94d0209959ef56d2 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 24 Apr 2019 13:55:59 +0500 Subject: [PATCH 054/237] Added loading previous history on chat open if history not enough --- .../data/extension/mam/NextMamManager.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index c485168080..b669b0d50d 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -120,6 +120,22 @@ public void onChatOpen(final AbstractChat chat) { public void run() { Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); AccountItem accountItem = AccountManager.getInstance().getAccount(chat.getAccount()); + + // load prev page if history is not enough + if (historyIsNotEnough(realm, chat) && !chat.historyIsFull()) { + synchronized (lock) { + if (isRequested) return; + else isRequested = true; + } + EventBus.getDefault().post(new LastHistoryLoadStartedEvent(chat)); + loadNextHistory(realm, accountItem, chat); + EventBus.getDefault().post(new LastHistoryLoadFinishedEvent(chat)); + synchronized (lock) { + isRequested = false; + } + } + + // load missed messages if need List messages = findMissedMessages(realm, chat); if (messages != null && !messages.isEmpty() && accountItem != null) { for (MessageItem message : messages) { @@ -623,6 +639,15 @@ private boolean historyIsEmpty(AccountItem account) { return messageItem == null; } + private boolean historyIsNotEnough(Realm realm, AbstractChat chat) { + RealmResults results = realm.where(MessageItem.class) + .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) + .equalTo(MessageItem.Fields.USER, chat.getUser().toString()) + .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) + .findAll(); + return results.size() < 30; + } + private String getLastMessageArchivedId(AbstractChat chat, Realm realm) { RealmResults results = realm.where(MessageItem.class) .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) From ebd723a739b1fced7b789a5df2aa4e2d16ba1aae Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 24 Apr 2019 14:41:12 +0500 Subject: [PATCH 055/237] Fixed notifications for messages from archive --- .../com/xabber/android/data/extension/mam/NextMamManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index b669b0d50d..fec6544200 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -489,7 +489,7 @@ private List parseMessage(AccountJid account, UserJid user, messageItem.setIncoming(incoming); messageItem.setStanzaId(message.getStanzaId()); messageItem.setReceivedFromMessageArchive(true); - messageItem.setRead(timestamp < startHistoryTimestamp); + messageItem.setRead(timestamp <= startHistoryTimestamp); messageItem.setSent(true); messageItem.setEncrypted(encrypted); @@ -554,7 +554,7 @@ private MessageItem determineSaveOrUpdate(Realm realm, AbstractChat chat, final // notify about new message chat.enableNotificationsIfNeed(); - boolean notify = (message.getText() != null && !message.getText().trim().isEmpty()) + boolean notify = !message.isRead() && (message.getText() != null && !message.getText().trim().isEmpty()) && message.isIncoming() && chat.notifyAboutMessage(); boolean visible = MessageManager.getInstance().isVisibleChat(chat); if (notify && !visible) From e9d0524a45537e768da24c8110bd7678bf3e8e9a Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 24 Apr 2019 16:34:03 +0500 Subject: [PATCH 056/237] Changed determine stanza id for message Changes in archive synchronization --- .../data/extension/mam/NextMamManager.java | 2 +- .../android/data/extension/muc/RoomChat.java | 19 +++++------------- .../android/data/message/AbstractChat.java | 20 +++++++++++++++++++ .../android/data/message/MessageManager.java | 2 +- .../android/data/message/ReceiptManager.java | 4 ++-- .../android/data/message/RegularChat.java | 8 ++++---- .../com/xabber/xmpp/sid/UniqStanzaHelper.java | 7 +++++++ 7 files changed, 40 insertions(+), 22 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index fec6544200..e65bb41a01 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -487,7 +487,7 @@ private List parseMessage(AccountJid account, UserJid user, messageItem.setDelayTimestamp(messageDelay.getStamp().getTime()); } messageItem.setIncoming(incoming); - messageItem.setStanzaId(message.getStanzaId()); + messageItem.setStanzaId(AbstractChat.getStanzaId(message)); messageItem.setReceivedFromMessageArchive(true); messageItem.setRead(timestamp <= startHistoryTimestamp); messageItem.setSent(true); diff --git a/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java b/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java index 4ecf78e22a..27cf483acf 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java @@ -259,10 +259,6 @@ protected boolean onPacket(UserJid bareAddress, Stanza stanza, boolean isCarbons newAction(resource, subject, ChatAction.subject, true); } else { boolean notify = true; - String stanzaId = message.getStanzaId(); - - // Use stanza id from XEP-0359 if common stanza id is null - if (stanzaId == null) stanzaId = UniqStanzaHelper.getStanzaId(message); DelayInformation delayInformation = DelayInformation.from(message); Date delay = null; @@ -280,7 +276,7 @@ protected boolean onPacket(UserJid bareAddress, Stanza stanza, boolean isCarbons String originalFrom = stanza.getFrom().toString(); - String messageUId = getMessageIdIfInHistory(stanzaId, text); + String messageUId = getMessageIdIfInHistory(getStanzaId(message), text); if (messageUId != null) { if (isSelf(resource)) { markMessageAsDelivered(messageUId, originalFrom); @@ -303,12 +299,12 @@ protected boolean onPacket(UserJid bareAddress, Stanza stanza, boolean isCarbons // create message with file-attachments if (attachments.size() > 0) createAndSaveFileMessage(true, uid, resource, text, null, delay, true, notify, - false, false, stanzaId, attachments, + false, false, getStanzaId(message), attachments, originalStanza, null, originalFrom, true, false); // create message without attachments else createAndSaveNewMessage(true, uid, resource, text, null, delay, true, notify, - false, false, stanzaId, + false, false, getStanzaId(message), originalStanza, null, originalFrom, forwardIds, true, false); EventBus.getDefault().post(new NewIncomingMessageEvent(account, user)); @@ -382,11 +378,6 @@ protected String parseInnerMessage(boolean ui, Message message, String parentMes if (text == null) return null; if (subject != null) return null; - String stanzaId = message.getStanzaId(); - - // Use stanza id from XEP-0359 if common stanza id is null - if (stanzaId == null) stanzaId = UniqStanzaHelper.getStanzaId(message); - RealmList attachments = HttpFileUploadManager.parseFileMessage(message); String uid = UUID.randomUUID().toString(); @@ -400,12 +391,12 @@ protected String parseInnerMessage(boolean ui, Message message, String parentMes // create message with file-attachments if (attachments.size() > 0) createAndSaveFileMessage(ui, uid, resource, text, null, null, - true, false, false, false, stanzaId, attachments, + true, false, false, false, getStanzaId(message), attachments, originalStanza, parentMessageId, originalFrom, fromMUC, true); // create message without attachments else createAndSaveNewMessage(ui, uid, resource, text, null, null, - true, false, false, false, stanzaId, + true, false, false, false, getStanzaId(message), originalStanza, parentMessageId, originalFrom, forwardIds, fromMUC, true); return uid; diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index 609c4ccdb5..5681d05734 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -46,6 +46,7 @@ import com.xabber.android.data.message.chat.ChatManager; import com.xabber.android.data.notification.MessageNotificationManager; import com.xabber.android.data.notification.NotificationManager; +import com.xabber.xmpp.sid.UniqStanzaHelper; import org.greenrobot.eventbus.EventBus; import org.jivesoftware.smack.SmackException; @@ -436,6 +437,12 @@ protected MessageItem createMessageItem(String uid, Resourcepart resource, Strin if (this.notifyAboutMessage()) this.archived = false; + // update last id in chat + messageItem.setPreviousId(getLastMessageId()); + String id = messageItem.getArchivedId(); + if (id == null) id = messageItem.getStanzaId(); + setLastMessageId(id); + return messageItem; } @@ -961,4 +968,17 @@ public boolean historyIsFull() { public void setHistoryIsFull() { this.historyIsFull = true; } + + public static String getStanzaId(Message message) { + String stanzaId = null; + + stanzaId = UniqStanzaHelper.getOriginId(message); + if (stanzaId != null && !stanzaId.isEmpty()) return stanzaId; + + stanzaId = UniqStanzaHelper.getStanzaId(message); + if (stanzaId != null && !stanzaId.isEmpty()) return stanzaId; + + stanzaId = message.getStanzaId(); + return stanzaId; + } } \ No newline at end of file diff --git a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java index c0ac131713..8327cb804a 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java +++ b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java @@ -783,7 +783,7 @@ public void processCarbonsMessage(AccountJid account, final Message message, Car if (forwardComment != null) text = forwardComment; MessageItem newMessageItem = finalChat.createNewMessageItem(text); - newMessageItem.setStanzaId(message.getStanzaId()); + newMessageItem.setStanzaId(AbstractChat.getStanzaId(message)); newMessageItem.setSent(true); newMessageItem.setForwarded(true); diff --git a/xabber/src/main/java/com/xabber/android/data/message/ReceiptManager.java b/xabber/src/main/java/com/xabber/android/data/message/ReceiptManager.java index fe2601f2a9..33d7d2fb48 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/ReceiptManager.java +++ b/xabber/src/main/java/com/xabber/android/data/message/ReceiptManager.java @@ -100,7 +100,7 @@ public void run() { // TODO setDefaultAutoReceiptMode should be used for (ExtensionElement packetExtension : message.getExtensions()) { if (packetExtension instanceof DeliveryReceiptRequest) { - String id = message.getStanzaId(); + String id = AbstractChat.getStanzaId(message); if (id == null) { continue; } @@ -124,7 +124,7 @@ private void markAsError(final AccountJid account, final Message message) { realm.beginTransaction(); MessageItem first = realm.where(MessageItem.class) .equalTo(MessageItem.Fields.ACCOUNT, account.toString()) - .equalTo(MessageItem.Fields.STANZA_ID, message.getStanzaId()).findFirst(); + .equalTo(MessageItem.Fields.STANZA_ID, AbstractChat.getStanzaId(message)).findFirst(); if (first != null) { first.setError(true); XMPPError error = message.getError(); diff --git a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java index 297dd89f6b..3a7f565ec1 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java @@ -234,14 +234,14 @@ protected boolean onPacket(UserJid bareAddress, Stanza packet, boolean isCarbons createAndSaveFileMessage(true, uid, resource, text, null, getDelayStamp(message), true, true, encrypted, isOfflineMessage(account.getFullJid().getDomain(), packet), - packet.getStanzaId(), attachments, originalStanza, null, + getStanzaId(message), attachments, originalStanza, null, originalFrom, false, false); // create message without attachments else createAndSaveNewMessage(true, uid, resource, text, null, getDelayStamp(message), true, true, encrypted, isOfflineMessage(account.getFullJid().getDomain(), packet), - packet.getStanzaId(), originalStanza, null, + getStanzaId(message), originalStanza, null, originalFrom, forwardIds,false, false); EventBus.getDefault().post(new NewIncomingMessageEvent(account, user)); @@ -279,12 +279,12 @@ protected String parseInnerMessage(boolean ui, Message message, String parentMes // create message with file-attachments if (attachments.size() > 0) createAndSaveFileMessage(ui, uid, resource, text, null, null, true, - false, encrypted, false, message.getStanzaId(), attachments, + false, encrypted, false, getStanzaId(message), attachments, originalStanza, parentMessageId, originalFrom, fromMuc, true); // create message without attachments else createAndSaveNewMessage(ui, uid, resource, text, null, null, true, - false, encrypted, false, message.getStanzaId(), originalStanza, + false, encrypted, false, getStanzaId(message), originalStanza, parentMessageId, originalFrom, forwardIds, fromMuc, true); return uid; diff --git a/xabber/src/main/java/com/xabber/xmpp/sid/UniqStanzaHelper.java b/xabber/src/main/java/com/xabber/xmpp/sid/UniqStanzaHelper.java index a8de2864cc..52e8f9cc8e 100644 --- a/xabber/src/main/java/com/xabber/xmpp/sid/UniqStanzaHelper.java +++ b/xabber/src/main/java/com/xabber/xmpp/sid/UniqStanzaHelper.java @@ -9,6 +9,7 @@ public class UniqStanzaHelper { + private final static String ELEMENT_NAME_ORIGIN = "origin-id"; private final static String ELEMENT_NAME = "stanza-id"; private final static String NAMESPACE = "urn:xmpp:sid:0"; private final static String ATTRIBUTE_ID = "id"; @@ -19,4 +20,10 @@ public static String getStanzaId(Message message) { else return null; } + public static String getOriginId(Message message) { + StandardExtensionElement sidElement = message.getExtension(ELEMENT_NAME_ORIGIN, NAMESPACE); + if (sidElement != null) return sidElement.getAttributeValue(ATTRIBUTE_ID); + else return null; + } + } From a09fc84c3d61fa1d1fc64c34be5e6cbdd9093c3c Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 24 Apr 2019 17:50:46 +0500 Subject: [PATCH 057/237] Start history timestamp now stored in account item. Separate for each account. Added check for MAM settings. --- .../android/data/account/AccountItem.java | 14 ++++++ .../data/extension/mam/NextMamManager.java | 45 +++++++++++-------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java b/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java index 23cf60994e..fa17aaf900 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java @@ -121,6 +121,12 @@ public class AccountItem extends ConnectionItem implements Comparable contacts = RosterManager.getInstance() .getAccountRosterContacts(accountItem.getAccount()); @@ -191,12 +195,14 @@ private void loadLastMessage(Realm realm, AccountItem accountItem, AbstractChat MamManager.MamQueryResult queryResult = requestLastMessage(accountItem, chat); if (queryResult != null) { List messages = new ArrayList<>(queryResult.forwardedMessages); - saveOrUpdateMessages(realm, chat, parseMessage(chat.getAccount(), chat.getUser(), messages, null)); + saveOrUpdateMessages(realm, chat, parseMessage(accountItem, chat.getAccount(), chat.getUser(), messages, null)); } updateLastMessageId(chat, realm); } private void loadAllNewMessages(Realm realm, AccountItem accountItem) { + if (accountItem.getLoadHistorySettings() != LoadHistorySettings.all) return; + Collection contacts = RosterManager.getInstance() .getAccountRosterContacts(accountItem.getAccount()); @@ -231,7 +237,7 @@ private void loadNewMessages(Realm realm, AccountItem accountItem, AbstractChat if (!messages.isEmpty()) { saveOrUpdateMessages(realm, chat, - parseMessage(chat.getAccount(), chat.getUser(), messages, chat.getLastMessageId())); + parseMessage(accountItem, chat.getAccount(), chat.getUser(), messages, chat.getLastMessageId())); } updateLastMessageId(chat, realm); } @@ -258,7 +264,7 @@ private void loadNextHistory(Realm realm, AccountItem accountItem, AbstractChat List messages = new ArrayList<>(queryResult.forwardedMessages); if (!messages.isEmpty()) { List savedMessages = saveOrUpdateMessages(realm, chat, - parseMessage(chat.getAccount(), chat.getUser(), messages, null)); + parseMessage(accountItem, chat.getAccount(), chat.getUser(), messages, null)); if (savedMessages != null && !savedMessages.isEmpty()) { realm.beginTransaction(); @@ -303,7 +309,7 @@ private void loadMissedMessages(Realm realm, AccountItem accountItem, AbstractCh if (!messages.isEmpty()) { List savedMessages = saveOrUpdateMessages(realm, chat, - parseMessage(chat.getAccount(), chat.getUser(), messages, m2.getArchivedId())); + parseMessage(accountItem, chat.getAccount(), chat.getUser(), messages, m2.getArchivedId())); if (savedMessages != null && !savedMessages.isEmpty()) { realm.beginTransaction(); @@ -317,13 +323,14 @@ private void loadMissedMessages(Realm realm, AccountItem accountItem, AbstractCh /** Request most recent message from all history and save it timestamp to startHistoryTimestamp * If message is null save current time to startHistoryTimestamp */ private void initializeStartTimestamp(@Nonnull AccountItem accountItem) { - startHistoryTimestamp = System.currentTimeMillis(); + long startHistoryTimestamp = System.currentTimeMillis(); MamManager.MamQueryResult queryResult = requestLastMessage(accountItem); if (queryResult != null && !queryResult.forwardedMessages.isEmpty()) { Forwarded forwarded = queryResult.forwardedMessages.get(0); startHistoryTimestamp = forwarded.getDelayInformation().getStamp().getTime(); } + accountItem.setStartHistoryTimestamp(startHistoryTimestamp); } /** REQUESTS */ @@ -419,11 +426,11 @@ private void initializeStartTimestamp(@Nonnull AccountItem accountItem) { /** PARSING */ - private List parseMessage(AccountJid account, UserJid user, + private List parseMessage(AccountItem accountItem, AccountJid account, UserJid user, List forwardedMessages, String prevID) { List messageItems = new ArrayList<>(); for (Forwarded forwarded : forwardedMessages) { - MessageItem message = parseMessage(account, user, forwarded, prevID); + MessageItem message = parseMessage(accountItem, account, user, forwarded, prevID); if (message != null) { messageItems.add(message); prevID = message.getArchivedId(); @@ -432,7 +439,7 @@ private List parseMessage(AccountJid account, UserJid user, return messageItems; } - private @Nullable MessageItem parseMessage(AccountJid account, UserJid user, Forwarded forwarded, String prevID) { + private @Nullable MessageItem parseMessage(AccountItem accountItem, AccountJid account, UserJid user, Forwarded forwarded, String prevID) { if (!(forwarded.getForwardedStanza() instanceof Message)) { return null; } @@ -489,7 +496,7 @@ private List parseMessage(AccountJid account, UserJid user, messageItem.setIncoming(incoming); messageItem.setStanzaId(AbstractChat.getStanzaId(message)); messageItem.setReceivedFromMessageArchive(true); - messageItem.setRead(timestamp <= startHistoryTimestamp); + messageItem.setRead(timestamp <= accountItem.getStartHistoryTimestamp()); messageItem.setSent(true); messageItem.setEncrypted(encrypted); From 62dd93cd539d36618d4e2e4c717adc9a00c2a240 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 24 Apr 2019 18:09:55 +0500 Subject: [PATCH 058/237] Up version to 608 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index ed7667f283..f1157d00bb 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 607 - versionName '2.6.4(607)' + versionCode 608 + versionName '2.6.4(608)' } lintOptions { From 549d26d8492fb7794b2cb44f9ea558840380136e Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 25 Apr 2019 11:12:14 +0500 Subject: [PATCH 059/237] Added checking for MAM support to NextMamManager --- .../data/connection/ConnectionListener.java | 3 +- .../data/extension/mam/NextMamManager.java | 40 +++++++++++++++++-- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/connection/ConnectionListener.java b/xabber/src/main/java/com/xabber/android/data/connection/ConnectionListener.java index d7da287fbf..5a84ad5a5f 100644 --- a/xabber/src/main/java/com/xabber/android/data/connection/ConnectionListener.java +++ b/xabber/src/main/java/com/xabber/android/data/connection/ConnectionListener.java @@ -9,6 +9,7 @@ import com.xabber.android.data.extension.carbons.CarbonManager; import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager; import com.xabber.android.data.extension.mam.MamManager; +import com.xabber.android.data.extension.mam.NextMamManager; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.message.MessageManager; import com.xabber.android.data.roster.PresenceManager; @@ -63,7 +64,7 @@ public void authenticated(XMPPConnection connection, final boolean resumed) { // just to see the order of call CarbonManager.getInstance().onAuthorized(connectionItem); - MamManager.getInstance().onAuthorized(connectionItem); + NextMamManager.getInstance().onAuthorized(connectionItem); BlockingManager.getInstance().onAuthorized(connectionItem); HttpFileUploadManager.getInstance().onAuthorized(connectionItem); diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index 9b613f3949..231e718c8d 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -5,6 +5,7 @@ import com.xabber.android.data.Application; import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.account.AccountManager; +import com.xabber.android.data.connection.ConnectionItem; import com.xabber.android.data.database.MessageDatabaseManager; import com.xabber.android.data.database.messagerealm.Attachment; import com.xabber.android.data.database.messagerealm.ForwardId; @@ -44,7 +45,9 @@ import java.util.Date; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -60,6 +63,7 @@ public class NextMamManager implements OnRosterReceivedListener { private static NextMamManager instance; + private Map supportedByAccount = new ConcurrentHashMap<>(); private boolean isRequested = false; private final Object lock = new Object(); @@ -69,6 +73,10 @@ public static NextMamManager getInstance() { return instance; } + public void onAuthorized(ConnectionItem connectionItem) { + updateIsSupported((AccountItem) connectionItem); + } + @Override public void onRosterReceived(AccountItem accountItem) { onAccountConnected(accountItem); @@ -110,7 +118,8 @@ public void onAccountConnected(AccountItem accountItem) { */ public void onChatOpen(final AbstractChat chat) { final AccountItem accountItem = AccountManager.getInstance().getAccount(chat.getAccount()); - if (accountItem == null || accountItem.getLoadHistorySettings() == LoadHistorySettings.none) return; + if (accountItem == null || accountItem.getLoadHistorySettings() == LoadHistorySettings.none + || !isSupported(accountItem.getAccount())) return; Application.getInstance().runInBackground(new Runnable() { @Override @@ -149,7 +158,8 @@ public void run() { public void onScrollInChat(final AbstractChat chat) { final AccountItem accountItem = AccountManager.getInstance().getAccount(chat.getAccount()); - if (accountItem == null || accountItem.getLoadHistorySettings() == LoadHistorySettings.none) return; + if (accountItem == null || accountItem.getLoadHistorySettings() == LoadHistorySettings.none + || !isSupported(accountItem.getAccount())) return; if (chat.historyIsFull()) return; Application.getInstance().runInBackgroundUserRequest(new Runnable() { @@ -171,10 +181,17 @@ public void run() { }); } + public boolean isSupported(AccountJid accountJid) { + Boolean isSupported = supportedByAccount.get(accountJid); + if (isSupported != null) return isSupported; + else return false; + } + /** MAIN */ private void loadLastMessages(Realm realm, AccountItem accountItem) { - if (accountItem.getLoadHistorySettings() != LoadHistorySettings.all) return; + if (accountItem.getLoadHistorySettings() != LoadHistorySettings.all + || !isSupported(accountItem.getAccount())) return; Collection contacts = RosterManager.getInstance() .getAccountRosterContacts(accountItem.getAccount()); @@ -201,7 +218,8 @@ private void loadLastMessage(Realm realm, AccountItem accountItem, AbstractChat } private void loadAllNewMessages(Realm realm, AccountItem accountItem) { - if (accountItem.getLoadHistorySettings() != LoadHistorySettings.all) return; + if (accountItem.getLoadHistorySettings() != LoadHistorySettings.all + || !isSupported(accountItem.getAccount())) return; Collection contacts = RosterManager.getInstance() .getAccountRosterContacts(accountItem.getAccount()); @@ -333,6 +351,20 @@ private void initializeStartTimestamp(@Nonnull AccountItem accountItem) { accountItem.setStartHistoryTimestamp(startHistoryTimestamp); } + private void updateIsSupported(AccountItem accountItem) { + MamManager mamManager = MamManager.getInstanceFor(accountItem.getConnection()); + boolean isSupported; + try { + isSupported = mamManager.isSupportedByServer(); + } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException + | InterruptedException | SmackException.NotConnectedException | ClassCastException e) { + LogManager.exception(this, e); + isSupported = false; + } + supportedByAccount.put(accountItem.getAccount(), isSupported); + AccountManager.getInstance().onAccountChanged(accountItem.getAccount()); + } + /** REQUESTS */ /** Request most recent message from all history */ From bc51b43c729c42be75d8d89fcc395bdaf8ee2f6f Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 25 Apr 2019 12:25:43 +0500 Subject: [PATCH 060/237] Added request to update MAM preferences on server --- .../android/data/account/AccountManager.java | 4 +-- .../data/extension/mam/NextMamManager.java | 30 +++++++++++++++++++ .../AccountHistorySettingsFragment.java | 4 +-- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java index 3a08cb816c..80b2f9d772 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java @@ -46,7 +46,7 @@ import com.xabber.android.data.database.sqlite.StatusTable; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.extension.mam.LoadHistorySettings; -import com.xabber.android.data.extension.mam.MamManager; +import com.xabber.android.data.extension.mam.NextMamManager; import com.xabber.android.data.extension.vcard.VCardManager; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.notification.BaseAccountNotificationProvider; @@ -977,7 +977,7 @@ public void setMamDefaultBehaviour(AccountJid accountJid, MamPrefsIQ.DefaultBeha if (!accountItem.getMamDefaultBehaviour().equals(mamDefaultBehavior)) { accountItem.setMamDefaultBehaviour(mamDefaultBehavior); requestToWriteAccount(accountItem); - MamManager.getInstance().requestUpdatePreferences(accountJid); + NextMamManager.getInstance().onRequestUpdatePreferences(accountJid); } } diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index 231e718c8d..8fcc471737 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -181,6 +181,18 @@ public void run() { }); } + public void onRequestUpdatePreferences(AccountJid accountJid) { + final AccountItem accountItem = AccountManager.getInstance().getAccount(accountJid); + if (accountItem == null || !isSupported(accountJid)) return; + + Application.getInstance().runInBackgroundUserRequest(new Runnable() { + @Override + public void run() { + requestUpdatePreferences(accountItem); + } + }); + } + public boolean isSupported(AccountJid accountJid) { Boolean isSupported = supportedByAccount.get(accountJid); if (isSupported != null) return isSupported; @@ -456,6 +468,24 @@ private void updateIsSupported(AccountItem accountItem) { return queryResult; } + private @Nullable MamManager.MamPrefsResult requestUpdatePreferences(@Nonnull AccountItem accountItem) { + MamManager.MamPrefsResult prefsResult = null; + XMPPTCPConnection connection = accountItem.getConnection(); + + if (connection.isAuthenticated()) { + MamManager mamManager = MamManager.getInstanceFor(connection); + try { + prefsResult = mamManager.updateArchivingPreferences(null, null, accountItem.getMamDefaultBehaviour()); + } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException + | InterruptedException | SmackException.NotConnectedException + | SmackException.NotLoggedInException e) { + LogManager.exception(NextMamManager.class, e); + } + } + + return prefsResult; + } + /** PARSING */ private List parseMessage(AccountItem accountItem, AccountJid account, UserJid user, diff --git a/xabber/src/main/java/com/xabber/android/ui/preferences/AccountHistorySettingsFragment.java b/xabber/src/main/java/com/xabber/android/ui/preferences/AccountHistorySettingsFragment.java index 5fe4043211..870038cb61 100644 --- a/xabber/src/main/java/com/xabber/android/ui/preferences/AccountHistorySettingsFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/preferences/AccountHistorySettingsFragment.java @@ -13,7 +13,7 @@ import com.xabber.android.data.account.listeners.OnAccountChangedListener; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.extension.mam.LoadHistorySettings; -import com.xabber.android.data.extension.mam.MamManager; +import com.xabber.android.data.extension.mam.NextMamManager; import org.jivesoftware.smackx.mam.element.MamPrefsIQ; @@ -53,7 +53,7 @@ protected void onInflate(Bundle savedInstanceState) { } private void setUpMamPreference(Preference mamPreference, @Nullable String newSummary) { - Boolean supported = MamManager.getInstance().isSupported(account); + Boolean supported = NextMamManager.getInstance().isSupported(account); if (supported == null) { mamPreference.setEnabled(false); mamPreference.setSummary(getString(R.string.account_chat_history_unknown)); From f88b183b0cf5dd5d426d28db381fcfc39ea4e96f Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 25 Apr 2019 14:11:20 +0500 Subject: [PATCH 061/237] Removed MamManager --- .../com/xabber/android/data/Application.java | 2 - .../data/connection/ConnectionListener.java | 2 - .../data/extension/mam/MamManager.java | 660 ------------------ .../data/extension/mam/NextMamManager.java | 61 ++ .../android/ui/fragment/ChatFragment.java | 1 - .../ui/preferences/DebugSettingsFragment.java | 3 +- 6 files changed, 62 insertions(+), 667 deletions(-) delete mode 100644 xabber/src/main/java/com/xabber/android/data/extension/mam/MamManager.java diff --git a/xabber/src/main/java/com/xabber/android/data/Application.java b/xabber/src/main/java/com/xabber/android/data/Application.java index 9ff1e5a7d8..a0f8745e60 100644 --- a/xabber/src/main/java/com/xabber/android/data/Application.java +++ b/xabber/src/main/java/com/xabber/android/data/Application.java @@ -44,7 +44,6 @@ import com.xabber.android.data.extension.chat_markers.ChatMarkerManager; import com.xabber.android.data.extension.cs.ChatStateManager; import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager; -import com.xabber.android.data.extension.mam.MamManager; import com.xabber.android.data.extension.mam.NextMamManager; import com.xabber.android.data.extension.muc.MUCManager; import com.xabber.android.data.extension.otr.OTRManager; @@ -388,7 +387,6 @@ private void addManagers() { addManager(CarbonManager.getInstance()); addManager(HttpFileUploadManager.getInstance()); addManager(BlockingManager.getInstance()); - //addManager(MamManager.getInstance()); addManager(NextMamManager.getInstance()); addManager(CertificateManager.getInstance()); addManager(XMPPAuthManager.getInstance()); diff --git a/xabber/src/main/java/com/xabber/android/data/connection/ConnectionListener.java b/xabber/src/main/java/com/xabber/android/data/connection/ConnectionListener.java index 5a84ad5a5f..98f63b704f 100644 --- a/xabber/src/main/java/com/xabber/android/data/connection/ConnectionListener.java +++ b/xabber/src/main/java/com/xabber/android/data/connection/ConnectionListener.java @@ -8,7 +8,6 @@ import com.xabber.android.data.extension.bookmarks.BookmarksManager; import com.xabber.android.data.extension.carbons.CarbonManager; import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager; -import com.xabber.android.data.extension.mam.MamManager; import com.xabber.android.data.extension.mam.NextMamManager; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.message.MessageManager; @@ -16,7 +15,6 @@ import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.packet.StreamError; import org.jivesoftware.smack.sasl.SASLErrorException; class ConnectionListener implements org.jivesoftware.smack.ConnectionListener { diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/MamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/MamManager.java deleted file mode 100644 index f3dd41fe05..0000000000 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/MamManager.java +++ /dev/null @@ -1,660 +0,0 @@ -package com.xabber.android.data.extension.mam; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.util.Log; - -import com.xabber.android.data.Application; -import com.xabber.android.data.account.AccountItem; -import com.xabber.android.data.account.AccountManager; -import com.xabber.android.data.connection.ConnectionItem; -import com.xabber.android.data.database.MessageDatabaseManager; -import com.xabber.android.data.database.messagerealm.Attachment; -import com.xabber.android.data.database.messagerealm.ForwardId; -import com.xabber.android.data.database.messagerealm.MessageItem; -import com.xabber.android.data.database.messagerealm.SyncInfo; -import com.xabber.android.data.entity.AccountJid; -import com.xabber.android.data.entity.BaseEntity; -import com.xabber.android.data.entity.UserJid; -import com.xabber.android.data.extension.file.FileManager; -import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager; -import com.xabber.android.data.extension.otr.OTRManager; -import com.xabber.android.data.log.LogManager; -import com.xabber.android.data.message.AbstractChat; -import com.xabber.android.data.message.ForwardManager; -import com.xabber.android.data.message.MessageManager; -import com.xabber.android.data.roster.OnRosterReceivedListener; -import com.xabber.android.data.roster.RosterContact; -import com.xabber.android.data.roster.RosterManager; - -import net.java.otr4j.io.SerializationUtils; -import net.java.otr4j.io.messages.PlainTextMessage; - -import org.greenrobot.eventbus.EventBus; -import org.jivesoftware.smack.SmackException; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.packet.Message; -import org.jivesoftware.smack.tcp.XMPPTCPConnection; -import org.jivesoftware.smack.util.PacketParserUtils; -import org.jivesoftware.smackx.delay.packet.DelayInformation; -import org.jivesoftware.smackx.forward.packet.Forwarded; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; - -import io.realm.Realm; -import io.realm.RealmList; -import io.realm.RealmResults; - -public class MamManager implements OnRosterReceivedListener { - static final String LOG_TAG = MamManager.class.getSimpleName(); - private static MamManager instance; - public static final int SYNC_INTERVAL_MINUTES = 5; - - public static int PAGE_SIZE = AbstractChat.PRELOADED_MESSAGES; - - private Map supportedByAccount; - - private boolean isRequested = false; - private final Object lock = new Object(); - - public static MamManager getInstance() { - if (instance == null) { - instance = new MamManager(); - } - - return instance; - } - - public MamManager() { - supportedByAccount = new ConcurrentHashMap<>(); - } - - public void onAuthorized(ConnectionItem connectionItem) { - updateIsSupported((AccountItem) connectionItem); - } - - - @Override - public void onRosterReceived(final AccountItem accountItem) { - LogManager.i(this, "onRosterReceived " + accountItem.getAccount()); - Application.getInstance().runOnUiThread(new Runnable() { - @Override - public void run() { - if (accountItem.getLoadHistorySettings() != LoadHistorySettings.all) { - return; - } - - Collection contacts = RosterManager.getInstance() - .getAccountRosterContacts(accountItem.getAccount()); - for (RosterContact contact : contacts) { - requestLastHistory(MessageManager.getInstance() - .getOrCreateChat(contact.getAccount(), contact.getUser())); - } - } - }); - } - - @Nullable - public Boolean isSupported(AccountJid accountJid) { - return supportedByAccount.get(accountJid); - } - - private boolean checkSupport(AccountItem accountItem) { - Boolean isSupported = supportedByAccount.get(accountItem.getAccount()); - - if (isSupported != null) { - return isSupported; - } - - return updateIsSupported(accountItem); - } - - private boolean updateIsSupported(AccountItem accountItem) { - org.jivesoftware.smackx.mam.MamManager mamManager = org.jivesoftware.smackx.mam.MamManager - .getInstanceFor(accountItem.getConnection()); - - boolean isSupported; - try { - isSupported = mamManager.isSupportedByServer(); - - if (isSupported) { - org.jivesoftware.smackx.mam.MamManager.MamPrefsResult archivingPreferences = mamManager.retrieveArchivingPreferences(); - LogManager.i(this, "archivingPreferences default behaviour " + archivingPreferences.mamPrefs.getDefault()); - org.jivesoftware.smackx.mam.MamManager.MamPrefsResult result - = mamManager.updateArchivingPreferences(null, null, accountItem.getMamDefaultBehaviour()); - LogManager.i(this, "updateArchivingPreferences result " + result.toString()); - } - - } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException - | InterruptedException | SmackException.NotConnectedException | SmackException.NotLoggedInException - | ClassCastException e) { - LogManager.exception(this, e); - return false; - } - - LogManager.i(this, "MAM support for account " + accountItem.getAccount() + " " + isSupported); - supportedByAccount.put(accountItem.getAccount(), isSupported); - - AccountManager.getInstance().onAccountChanged(accountItem.getAccount()); - return isSupported; - } - - public void requestUpdatePreferences(final AccountJid accountJid) { - Application.getInstance().runInBackgroundUserRequest(new Runnable() { - @Override - public void run() { - AccountItem accountItem = AccountManager.getInstance().getAccount(accountJid); - if (accountItem == null) { - return; - } - org.jivesoftware.smackx.mam.MamManager mamManager = org.jivesoftware.smackx.mam.MamManager - .getInstanceFor(accountItem.getConnection()); - - try { - org.jivesoftware.smackx.mam.MamManager.MamPrefsResult result - = mamManager.updateArchivingPreferences(null, null, accountItem.getMamDefaultBehaviour()); - LogManager.i(LOG_TAG, "MAM default behavior updated to " + result.mamPrefs.getDefault()); - } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException - | InterruptedException | SmackException.NotConnectedException - | SmackException.NotLoggedInException e) { - LogManager.exception(LOG_TAG, e); - } - - } - }); - } - - public void requestLastHistoryByUser(final AbstractChat chat) { - Application.getInstance().runInBackgroundUserRequest(new Runnable() { - @Override - public void run() { - getLastHistory(chat, false); - } - }); - } - - private void requestLastHistory(final AbstractChat chat) { - Application.getInstance().runInBackground(new Runnable() { - @Override - public void run() { - getLastHistory(chat, true); - } - }); - } - - private boolean isTimeToRefreshHistory(AbstractChat chat) { - return chat.getLastSyncedTime() != null - && TimeUnit.MILLISECONDS.toMinutes(System.currentTimeMillis() - chat.getLastSyncedTime().getTime()) - < SYNC_INTERVAL_MINUTES; - } - - @SuppressWarnings("WeakerAccess") - void getLastHistory(AbstractChat chat, boolean ignoreTime) { - if (chat == null) { - return; - } - - if (!ignoreTime) { - if (isTimeToRefreshHistory(chat)) { - return; - } - } - - final AccountItem accountItem = AccountManager.getInstance().getAccount(chat.getAccount()); - if (accountItem == null) { - return; - } - - XMPPTCPConnection connection = accountItem.getConnection(); - if (!connection.isAuthenticated()) { - return; - } - - if (!checkSupport(accountItem)) { - return; - } - - EventBus.getDefault().post(new LastHistoryLoadStartedEvent(chat)); - - org.jivesoftware.smackx.mam.MamManager mamManager - = org.jivesoftware.smackx.mam.MamManager.getInstanceFor(connection); - - String lastMessageMamId; - int receivedMessagesCount; - do { - Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); - lastMessageMamId = getSyncInfo(realm, chat.getAccount(), chat.getUser()).getLastMessageMamId(); - realm.close(); - - receivedMessagesCount = requestLastHistoryPage(mamManager, chat, lastMessageMamId); - - // if it was NOT the first time, and we got exactly one page, - // it means that there should be more unloaded recent history - } while (lastMessageMamId != null && receivedMessagesCount == PAGE_SIZE); - - // if it was first time receiving history, and we got less than a page - // it mean that all previous history loaded - if (lastMessageMamId == null - && receivedMessagesCount >= 0 && receivedMessagesCount < PAGE_SIZE) { - setRemoteHistoryCompletelyLoaded(chat); - } - - EventBus.getDefault().post(new LastHistoryLoadFinishedEvent(chat)); - } - - public void setRemoteHistoryCompletelyLoaded(AbstractChat chat) { - LogManager.i(this, "setRemoteHistoryCompletelyLoaded " + chat.getUser()); - - Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); - SyncInfo syncInfo = getSyncInfo(realm, chat.getAccount(), chat.getUser()); - realm.beginTransaction(); - syncInfo.setRemoteHistoryCompletelyLoaded(true); - realm.commitTransaction(); - realm.close(); - } - - private int requestLastHistoryPage(org.jivesoftware.smackx.mam.MamManager mamManager, - AbstractChat chat, String lastMessageMamId) { - final org.jivesoftware.smackx.mam.MamManager.MamQueryResult mamQueryResult; - try { - if (lastMessageMamId == null) { - mamQueryResult = mamManager.pageBefore(chat.getUser().getJid(), "", PAGE_SIZE); - } else { - mamQueryResult = mamManager.pageAfter(chat.getUser().getJid(), lastMessageMamId, PAGE_SIZE); - } - } catch (SmackException.NotLoggedInException | InterruptedException - | SmackException.NotConnectedException | SmackException.NoResponseException | XMPPException.XMPPErrorException e) { - LogManager.exception(this, e); - return -1; - } - - int receivedMessagesCount = mamQueryResult.forwardedMessages.size(); - - LogManager.i(this, "receivedMessagesCount " + receivedMessagesCount); - - chat.setLastSyncedTime(new Date(System.currentTimeMillis())); - - Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); - updateLastHistorySyncInfo(realm, chat, mamQueryResult); - syncMessages(realm, chat, getMessageItems(mamQueryResult, chat)); - realm.close(); - - return receivedMessagesCount; - } - - private void syncMessages(Realm realm, AbstractChat chat, final Collection messagesFromServer) { - - if (messagesFromServer == null || messagesFromServer.isEmpty()) { - return; - } - - LogManager.i(this, "syncMessages: " + messagesFromServer.size()); - - RealmResults localMessages = realm.where(MessageItem.class) - .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) - .equalTo(MessageItem.Fields.USER, chat.getUser().toString()) - .findAll(); - - Iterator iterator = messagesFromServer.iterator(); - while (iterator.hasNext()) { - MessageItem remoteMessage = iterator.next(); - - // set text from comment to text in message for prevent doubling messages from MAM - Message originalMessage = null; - try { - originalMessage = (Message) PacketParserUtils.parseStanza(remoteMessage.getOriginalStanza()); - String comment = ForwardManager.parseForwardComment(originalMessage); - if (comment != null) remoteMessage.setText(comment); - } catch (Exception e) { - e.printStackTrace(); - } - - // assume that Stanza ID could be not unique - if (localMessages.where() - .equalTo(MessageItem.Fields.STANZA_ID, remoteMessage.getStanzaId()) - .equalTo(MessageItem.Fields.TEXT, remoteMessage.getText()) - .count() > 0) { - LogManager.i(this, "Sync. Removing message with same Stanza ID and text. Remote message:" - + " Text: " + remoteMessage.getText() - + " Timestamp: " + remoteMessage.getTimestamp() - + " Delay Timestamp: " + remoteMessage.getDelayTimestamp() - + " StanzaId: " + remoteMessage.getStanzaId()); - iterator.remove(); - continue; - } - - Long remoteMessageDelayTimestamp = remoteMessage.getDelayTimestamp(); - Long remoteMessageTimestamp = remoteMessage.getTimestamp(); - - RealmResults sameTextMessages = localMessages.where() - .equalTo(MessageItem.Fields.TEXT, remoteMessage.getText()).findAll(); - - if (isTimeStampSimilar(sameTextMessages, remoteMessageTimestamp)) { - LogManager.i(this, "Sync. Found messages with same text and similar remote timestamp. Removing. Remote message:" - + " Text: " + remoteMessage.getText() - + " Timestamp: " + remoteMessage.getTimestamp() - + " Delay Timestamp: " + remoteMessage.getDelayTimestamp() - + " StanzaId: " + remoteMessage.getStanzaId()); - iterator.remove(); - continue; - } - - if (remoteMessageDelayTimestamp != null - && isTimeStampSimilar(sameTextMessages, remoteMessageDelayTimestamp)) { - LogManager.i(this, "Sync. Found messages with same text and similar remote delay timestamp. Removing. Remote message:" - + " Text: " + remoteMessage.getText() - + " Timestamp: " + remoteMessage.getTimestamp() - + " Delay Timestamp: " + remoteMessage.getDelayTimestamp() - + " StanzaId: " + remoteMessage.getStanzaId()); - iterator.remove(); - continue; - } - - // forwarded - if (originalMessage != null) { - RealmList forwardIds = chat.parseForwardedMessage(false, originalMessage, remoteMessage.getUniqueId()); - if (forwardIds != null && !forwardIds.isEmpty()) - remoteMessage.setForwardedIds(forwardIds); - } - } - - realm.beginTransaction(); - realm.copyToRealm(messagesFromServer); - realm.commitTransaction(); - } - - private static boolean isTimeStampSimilar(RealmResults sameTextMessages, long remoteMessageTimestamp) { - long start = remoteMessageTimestamp - (1000 * 5); - long end = remoteMessageTimestamp + (1000 * 5); - - if (sameTextMessages.where() - .between(MessageItem.Fields.TIMESTAMP, start, end) - .count() > 0) { - LogManager.i(MamManager.class.getSimpleName(), "Sync. Found messages with similar local timestamp"); - return true; - } - - if (sameTextMessages.where() - .between(MessageItem.Fields.DELAY_TIMESTAMP, start, end) - .count() > 0) { - LogManager.i(MamManager.class.getSimpleName(), "Sync. Found messages with similar local delay timestamp."); - return true; - } - return false; - } - - @NonNull - private SyncInfo getSyncInfo(Realm realm, AccountJid account, UserJid user) { - SyncInfo syncInfo = realm.where(SyncInfo.class) - .equalTo(SyncInfo.FIELD_ACCOUNT, account.toString()) - .equalTo(SyncInfo.FIELD_USER, user.toString()).findFirst(); - - if (syncInfo == null) { - realm.beginTransaction(); - syncInfo = realm.createObject(SyncInfo.class); - syncInfo.setAccount(account); - syncInfo.setUser(user); - realm.commitTransaction(); - } - return syncInfo; - } - - private void updateLastHistorySyncInfo(Realm realm, BaseEntity chat, org.jivesoftware.smackx.mam.MamManager.MamQueryResult mamQueryResult) { - SyncInfo syncInfo = getSyncInfo(realm, chat.getAccount(), chat.getUser()); - - realm.beginTransaction(); - - if (mamQueryResult.mamFin.getRSMSet() != null) { - - if (syncInfo.getFirstMamMessageMamId() == null) { - syncInfo.setFirstMamMessageMamId(mamQueryResult.mamFin.getRSMSet().getFirst()); - if (!mamQueryResult.forwardedMessages.isEmpty()) { - syncInfo.setFirstMamMessageStanzaId(mamQueryResult.forwardedMessages.get(0).getForwardedStanza().getStanzaId()); - } - } - if (mamQueryResult.mamFin.getRSMSet().getLast() != null) { - syncInfo.setLastMessageMamId(mamQueryResult.mamFin.getRSMSet().getLast()); - } - - } - - realm.commitTransaction(); - } - - public void requestPreviousHistory(final AbstractChat chat) { - if (chat == null || chat.isRemotePreviousHistoryCompletelyLoaded()) { - return; - } - - final AccountItem accountItem = AccountManager.getInstance().getAccount(chat.getAccount()); - if (accountItem == null || !accountItem.getFactualStatusMode().isOnline()) { - return; - } - - Application.getInstance().runInBackgroundUserRequest(new Runnable() { - @Override - public void run() { - if (!checkSupport(accountItem)) { - return; - } - - synchronized (lock) { - if (isRequested) return; - else isRequested = true; - } - - String firstMamMessageMamId; - boolean remoteHistoryCompletelyLoaded; - { - Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); - SyncInfo syncInfo = getSyncInfo(realm, chat.getAccount(), chat.getUser()); - firstMamMessageMamId = syncInfo.getFirstMamMessageMamId(); - remoteHistoryCompletelyLoaded = syncInfo.isRemoteHistoryCompletelyLoaded(); - realm.close(); - } - - if (remoteHistoryCompletelyLoaded) { - chat.setRemotePreviousHistoryCompletelyLoaded(true); - } - - if (firstMamMessageMamId == null || remoteHistoryCompletelyLoaded) { - disableLock(); - return; - } - - org.jivesoftware.smackx.mam.MamManager mamManager = org.jivesoftware.smackx.mam.MamManager.getInstanceFor(accountItem.getConnection()); - - final org.jivesoftware.smackx.mam.MamManager.MamQueryResult mamQueryResult; - try { - EventBus.getDefault().post(new PreviousHistoryLoadStartedEvent(chat)); - LogManager.i("MAM", "Loading previous history"); - mamQueryResult = mamManager.pageBefore(chat.getUser().getJid(), firstMamMessageMamId, PAGE_SIZE); - } catch (SmackException.NotLoggedInException | SmackException.NoResponseException | XMPPException.XMPPErrorException | InterruptedException | SmackException.NotConnectedException e) { - LogManager.exception(this, e); - EventBus.getDefault().post(new PreviousHistoryLoadFinishedEvent(chat)); - disableLock(); - return; - } - - LogManager.i("MAM", "queryArchive finished. fin count expected: " + mamQueryResult.mamFin.getRSMSet().getCount() + " real: " + mamQueryResult.forwardedMessages.size()); - - Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); - updatePreviousHistorySyncInfo(realm, chat, mamQueryResult); - List messageItems = getMessageItems(mamQueryResult, chat); - syncMessages(realm, chat, messageItems); - realm.close(); - - EventBus.getDefault().post(new PreviousHistoryLoadFinishedEvent(chat)); - disableLock(); - } - - }); - - } - - private void disableLock() { - synchronized (lock) { - isRequested = false; - } - } - - private void updatePreviousHistorySyncInfo(Realm realm, BaseEntity chat, - org.jivesoftware.smackx.mam.MamManager.MamQueryResult mamQueryResult) { - SyncInfo syncInfo = getSyncInfo(realm, chat.getAccount(), chat.getUser()); - - realm.beginTransaction(); - if (mamQueryResult.forwardedMessages.size() < PAGE_SIZE) { - syncInfo.setRemoteHistoryCompletelyLoaded(true); - } - - syncInfo.setFirstMamMessageMamId(mamQueryResult.mamFin.getRSMSet().getFirst()); - if (!mamQueryResult.forwardedMessages.isEmpty()) { - syncInfo.setFirstMamMessageStanzaId(mamQueryResult.forwardedMessages.get(0).getForwardedStanza().getStanzaId()); - } - realm.commitTransaction(); - } - - private List getMessageItems(org.jivesoftware.smackx.mam.MamManager.MamQueryResult mamQueryResult, AbstractChat chat) { - List messageItems = new ArrayList<>(); - - for (Forwarded forwarded : mamQueryResult.forwardedMessages) { - if (!(forwarded.getForwardedStanza() instanceof Message)) { - continue; - } - - Message message = (Message) forwarded.getForwardedStanza(); - - DelayInformation delayInformation = forwarded.getDelayInformation(); - - DelayInformation messageDelay = DelayInformation.from(message); - - String body = message.getBody(); - net.java.otr4j.io.messages.AbstractMessage otrMessage; - try { - otrMessage = SerializationUtils.toMessage(body); - } catch (IOException e) { - continue; - } - boolean encrypted = false; - if (otrMessage != null) { - if (otrMessage.messageType != net.java.otr4j.io.messages.AbstractMessage.MESSAGE_PLAINTEXT) { - encrypted = true; - try { - // this transforming just decrypt message if have keys. No action as injectMessage or something else - body = OTRManager.getInstance().transformReceivingIfSessionExist(chat.getAccount(), chat.getUser(), body); - if (OTRManager.getInstance().isEncrypted(body)) { - continue; - } - } catch (Exception e) { - continue; - } - } - else body = ((PlainTextMessage) otrMessage).cleanText; - } - - boolean incoming = message.getFrom().asBareJid().equals(chat.getUser().getJid().asBareJid()); - - String uid = UUID.randomUUID().toString(); - MessageItem messageItem = new MessageItem(uid); - - messageItem.setAccount(chat.getAccount()); - messageItem.setUser(chat.getUser()); - messageItem.setResource(chat.getUser().getJid().getResourceOrNull()); - messageItem.setText(body); - messageItem.setTimestamp(delayInformation.getStamp().getTime()); - if (messageDelay != null) { - messageItem.setDelayTimestamp(messageDelay.getStamp().getTime()); - } - messageItem.setIncoming(incoming); - messageItem.setStanzaId(message.getStanzaId()); - messageItem.setReceivedFromMessageArchive(true); - messageItem.setRead(true); - messageItem.setSent(true); - messageItem.setEncrypted(encrypted); - - // attachments - FileManager.processFileMessage(messageItem); - - RealmList attachments = HttpFileUploadManager.parseFileMessage(message); - if (attachments.size() > 0) - messageItem.setAttachments(attachments); - - // forwarded - messageItem.setOriginalStanza(message.toXML().toString()); - messageItem.setOriginalFrom(message.getFrom().toString()); - - messageItems.add(messageItem); - } - return messageItems; - } - - /** - * Only for debugging - * Call only from background thread - * @param chat - */ - public void requestFullChatHistory(final AbstractChat chat) { - if (chat == null || chat.isRemotePreviousHistoryCompletelyLoaded()) { - return; - } - - final AccountItem accountItem = AccountManager.getInstance().getAccount(chat.getAccount()); - if (accountItem == null || !accountItem.getFactualStatusMode().isOnline()) { - return; - } - - if (!checkSupport(accountItem)) { - return; - } - - String firstMamMessageMamId; - boolean remoteHistoryCompletelyLoaded; - { - Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); - SyncInfo syncInfo = getSyncInfo(realm, chat.getAccount(), chat.getUser()); - firstMamMessageMamId = syncInfo.getFirstMamMessageMamId(); - remoteHistoryCompletelyLoaded = syncInfo.isRemoteHistoryCompletelyLoaded(); - realm.close(); - } - - if (remoteHistoryCompletelyLoaded) { - chat.setRemotePreviousHistoryCompletelyLoaded(true); - } - - if (firstMamMessageMamId == null || remoteHistoryCompletelyLoaded) { - return; - } - - org.jivesoftware.smackx.mam.MamManager mamManager = - org.jivesoftware.smackx.mam.MamManager.getInstanceFor(accountItem.getConnection()); - - final org.jivesoftware.smackx.mam.MamManager.MamQueryResult mamQueryResult; - try { - LogManager.i("MAM", "Loading previous history"); - mamQueryResult = mamManager.queryArchive(chat.getUser().getJid()); - } catch (SmackException.NotLoggedInException | SmackException.NoResponseException - | XMPPException.XMPPErrorException | InterruptedException - | SmackException.NotConnectedException e) { - LogManager.exception(this, e); - return; - } - LogManager.i("MAM", "queryArchive finished. fin count expected: " - + mamQueryResult.mamFin.getRSMSet().getCount() + " real: " - + mamQueryResult.forwardedMessages.size()); - - Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); - List messageItems = getMessageItems(mamQueryResult, chat); - syncMessages(realm, chat, messageItems); - updatePreviousHistorySyncInfo(realm, chat, mamQueryResult); - realm.close(); - } -} diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index 8fcc471737..f9f623ed9c 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -770,4 +770,65 @@ private void updateLastMessageId(AbstractChat chat, Realm realm) { chat.setLastMessageId(id); } } + + /** + * Only for debugging + * Call only from background thread + * @param chat + */ +// public void requestFullChatHistory(final AbstractChat chat) { +// if (chat == null || chat.isRemotePreviousHistoryCompletelyLoaded()) { +// return; +// } +// +// final AccountItem accountItem = AccountManager.getInstance().getAccount(chat.getAccount()); +// if (accountItem == null || !accountItem.getFactualStatusMode().isOnline()) { +// return; +// } +// +// if (!checkSupport(accountItem)) { +// return; +// } +// +// String firstMamMessageMamId; +// boolean remoteHistoryCompletelyLoaded; +// { +// Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); +// SyncInfo syncInfo = getSyncInfo(realm, chat.getAccount(), chat.getUser()); +// firstMamMessageMamId = syncInfo.getFirstMamMessageMamId(); +// remoteHistoryCompletelyLoaded = syncInfo.isRemoteHistoryCompletelyLoaded(); +// realm.close(); +// } +// +// if (remoteHistoryCompletelyLoaded) { +// chat.setRemotePreviousHistoryCompletelyLoaded(true); +// } +// +// if (firstMamMessageMamId == null || remoteHistoryCompletelyLoaded) { +// return; +// } +// +// org.jivesoftware.smackx.mam.MamManager mamManager = +// org.jivesoftware.smackx.mam.MamManager.getInstanceFor(accountItem.getConnection()); +// +// final org.jivesoftware.smackx.mam.MamManager.MamQueryResult mamQueryResult; +// try { +// LogManager.i("MAM", "Loading previous history"); +// mamQueryResult = mamManager.queryArchive(chat.getUser().getJid()); +// } catch (SmackException.NotLoggedInException | SmackException.NoResponseException +// | XMPPException.XMPPErrorException | InterruptedException +// | SmackException.NotConnectedException e) { +// LogManager.exception(this, e); +// return; +// } +// LogManager.i("MAM", "queryArchive finished. fin count expected: " +// + mamQueryResult.mamFin.getRSMSet().getCount() + " real: " +// + mamQueryResult.forwardedMessages.size()); +// +// Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); +// List messageItems = getMessageItems(mamQueryResult, chat); +// syncMessages(realm, chat, messageItems); +// updatePreviousHistorySyncInfo(realm, chat, mamQueryResult); +// realm.close(); +// } } diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java index 19e3440ce2..fa34ea0869 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java @@ -404,7 +404,6 @@ public void onStart() { if (loadHistorySettings == LoadHistorySettings.all || loadHistorySettings == LoadHistorySettings.current) { if (!isRemoteHistoryRequested) { - //MamManager.getInstance().requestLastHistoryByUser(getChat()); NextMamManager.getInstance().onChatOpen(getChat()); } } diff --git a/xabber/src/main/java/com/xabber/android/ui/preferences/DebugSettingsFragment.java b/xabber/src/main/java/com/xabber/android/ui/preferences/DebugSettingsFragment.java index 96b6327676..37b04e3888 100644 --- a/xabber/src/main/java/com/xabber/android/ui/preferences/DebugSettingsFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/preferences/DebugSettingsFragment.java @@ -10,7 +10,6 @@ import com.xabber.android.R; import com.xabber.android.data.Application; import com.xabber.android.data.SettingsManager; -import com.xabber.android.data.extension.mam.MamManager; import com.xabber.android.data.http.CrowdfundingManager; import com.xabber.android.data.message.AbstractChat; import com.xabber.android.data.message.MessageManager; @@ -112,7 +111,7 @@ public void run() { for (AbstractChat chat : chats) { setDownloadProgress(totalArchives, downloadedArchives); - MamManager.getInstance().requestFullChatHistory(chat); + //MamManager.getInstance().requestFullChatHistory(chat); downloadedArchives++; } closeDownloadArchiveDialog(); From 9414b8ab5db0fb7f9440115998eb1c039ed0ddd9 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 25 Apr 2019 15:38:59 +0500 Subject: [PATCH 062/237] Removed unused code --- .../android/data/message/AbstractChat.java | 14 --- .../android/ui/fragment/ChatFragment.java | 112 +++--------------- 2 files changed, 14 insertions(+), 112 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index 5681d05734..964e6464b1 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -28,7 +28,6 @@ import com.xabber.android.data.database.messagerealm.Attachment; import com.xabber.android.data.database.messagerealm.ForwardId; import com.xabber.android.data.database.messagerealm.MessageItem; -import com.xabber.android.data.database.messagerealm.SyncInfo; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.entity.BaseEntity; import com.xabber.android.data.entity.UserJid; @@ -120,7 +119,6 @@ public abstract class AbstractChat extends BaseEntity implements RealmChangeList private boolean isRemotePreviousHistoryCompletelyLoaded = false; private Date lastSyncedTime; - private RealmResults syncInfo; private MessageItem lastMessage; private RealmResults messages; private String lastMessageId = null; @@ -201,18 +199,6 @@ public RealmResults getMessages() { return messages; } - public RealmResults getSyncInfo() { - if (syncInfo == null) { - syncInfo = MessageDatabaseManager.getInstance() - .getRealmUiThread().where(SyncInfo.class) - .equalTo(SyncInfo.FIELD_ACCOUNT, getAccountString()) - .equalTo(SyncInfo.FIELD_USER, getUserString()) - .findAllAsync(); - } - - return syncInfo; - } - boolean isStatusTrackingEnabled() { return trackStatus; } diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java index fa34ea0869..867ad75d51 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java @@ -43,11 +43,8 @@ import com.xabber.android.data.Application; import com.xabber.android.data.NetworkException; import com.xabber.android.data.SettingsManager; -import com.xabber.android.data.account.AccountItem; -import com.xabber.android.data.account.AccountManager; import com.xabber.android.data.account.listeners.OnAccountChangedListener; import com.xabber.android.data.database.messagerealm.MessageItem; -import com.xabber.android.data.database.messagerealm.SyncInfo; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.entity.BaseEntity; import com.xabber.android.data.entity.UserJid; @@ -58,7 +55,6 @@ import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager; import com.xabber.android.data.extension.mam.LastHistoryLoadFinishedEvent; import com.xabber.android.data.extension.mam.LastHistoryLoadStartedEvent; -import com.xabber.android.data.extension.mam.LoadHistorySettings; import com.xabber.android.data.extension.mam.NextMamManager; import com.xabber.android.data.extension.mam.PreviousHistoryLoadFinishedEvent; import com.xabber.android.data.extension.mam.PreviousHistoryLoadStartedEvent; @@ -118,7 +114,6 @@ import github.ankushsachdeva.emojicon.EmojiconsPopup; import github.ankushsachdeva.emojicon.emoji.Emojicon; import io.realm.RealmResults; -import io.realm.Sort; public class ChatFragment extends FileInteractionFragment implements PopupMenu.OnMenuItemClickListener, View.OnClickListener, Toolbar.OnMenuItemClickListener, MessageVH.MessageClickListener, @@ -173,9 +168,7 @@ public class ChatFragment extends FileInteractionFragment implements PopupMenu.O private Timer stopTypingTimer = new Timer(); - private boolean isRemoteHistoryRequested = false; - private int firstRemoteSyncedItemPosition = RecyclerView.NO_POSITION; - private RealmResults syncInfoResults; + private boolean historyIsLoading = false; private RealmResults messageItems; private boolean toBeScrolled; @@ -332,7 +325,7 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (dy < 0) { - loadHistoryIfNeeded(); + loadHistoryIfNeed(); } if (dy >= 0) { @@ -380,7 +373,6 @@ public void setChat(AccountJid accountJid, UserJid userJid) { if (abstractChat != null) { messageItems = abstractChat.getMessages(); - syncInfoResults = abstractChat.getSyncInfo(); } chatMessageAdapter = new MessagesAdapter(getActivity(), messageItems, abstractChat, @@ -397,17 +389,7 @@ public void setChat(AccountJid accountJid, UserJid userJid) { public void onStart() { super.onStart(); EventBus.getDefault().register(this); - - AccountItem accountItem = AccountManager.getInstance().getAccount(this.account); - if (accountItem != null) { - LoadHistorySettings loadHistorySettings = accountItem.getLoadHistorySettings(); - - if (loadHistorySettings == LoadHistorySettings.all || loadHistorySettings == LoadHistorySettings.current) { - if (!isRemoteHistoryRequested) { - NextMamManager.getInstance().onChatOpen(getChat()); - } - } - } + NextMamManager.getInstance().onChatOpen(getChat()); } @Override @@ -622,54 +604,13 @@ public void onClick(View v) { }); } - private void loadHistoryIfNeeded() { - AccountItem accountItem = AccountManager.getInstance().getAccount(this.account); - if (accountItem == null) { - return; - } - - LoadHistorySettings loadHistorySettings = accountItem.getLoadHistorySettings(); - - if (loadHistorySettings != LoadHistorySettings.current - && loadHistorySettings != LoadHistorySettings.all) { - return; - } - - if (isRemoteHistoryRequested) { - return; - } - - int visibleItemCount = layoutManager.getChildCount(); - - if (visibleItemCount == 0) { - return; - } - - int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition(); - - if (firstVisibleItemPosition / visibleItemCount <= 2) { - requestRemoteHistoryLoad(); - return; - } - - if (firstVisibleItemPosition < firstRemoteSyncedItemPosition) { - requestRemoteHistoryLoad(); - return; - } - - if (firstVisibleItemPosition - firstRemoteSyncedItemPosition < visibleItemCount * 2) { - requestRemoteHistoryLoad(); - return; - } - } - - private void requestRemoteHistoryLoad() { - if (!isRemoteHistoryRequested) { - AbstractChat chat = getChat(); - if (chat != null) { - NextMamManager.getInstance().onScrollInChat(getChat()); + private void loadHistoryIfNeed() { + if (!historyIsLoading) { + int invisibleMessagesCount = layoutManager.findFirstVisibleItemPosition(); + if (invisibleMessagesCount <= 15) { + AbstractChat chat = getChat(); + if (chat != null) NextMamManager.getInstance().onScrollInChat(chat); } - } } @@ -683,7 +624,7 @@ private AbstractChat getChat() { public void onEvent(LastHistoryLoadStartedEvent event) { if (event.getAccount().equals(account) && event.getUser().equals(user)) { lastHistoryProgressBar.setVisibility(View.VISIBLE); - isRemoteHistoryRequested = true; + historyIsLoading = true; } } @@ -691,7 +632,7 @@ public void onEvent(LastHistoryLoadStartedEvent event) { public void onEvent(LastHistoryLoadFinishedEvent event) { if (event.getAccount().equals(account) && event.getUser().equals(user)) { lastHistoryProgressBar.setVisibility(View.GONE); - isRemoteHistoryRequested = false; + historyIsLoading = false; } } @@ -700,7 +641,7 @@ public void onEvent(PreviousHistoryLoadStartedEvent event) { if (event.getAccount().equals(account) && event.getUser().equals(user)) { LogManager.i(this, "PreviousHistoryLoadStartedEvent"); previousHistoryProgressBar.setVisibility(View.VISIBLE); - isRemoteHistoryRequested = true; + historyIsLoading = true; } } @@ -708,7 +649,7 @@ public void onEvent(PreviousHistoryLoadStartedEvent event) { public void onEvent(PreviousHistoryLoadFinishedEvent event) { if (event.getAccount().equals(account) && event.getUser().equals(user)) { LogManager.i(this, "PreviousHistoryLoadFinishedEvent"); - isRemoteHistoryRequested = false; + historyIsLoading = false; previousHistoryProgressBar.setVisibility(View.GONE); } } @@ -1325,32 +1266,7 @@ else if (position > 0) @Override public void onMessagesUpdated() { - updateFirstRemoteSyncedItemPosition(); - loadHistoryIfNeeded(); - } - - private void updateFirstRemoteSyncedItemPosition() { - if (!syncInfoResults.isLoaded() || !messageItems.isLoaded() || syncInfoResults.isEmpty()) { - return; - } - - SyncInfo syncInfo = syncInfoResults.first(); - - String firstMamMessageStanzaId = syncInfo.getFirstMamMessageStanzaId(); - if (firstMamMessageStanzaId == null) { - return; - } - - RealmResults allSorted = messageItems.where() - .equalTo(MessageItem.Fields.STANZA_ID, firstMamMessageStanzaId) - .findAllSorted(MessageItem.Fields.TIMESTAMP, Sort.ASCENDING); - if (allSorted.isEmpty()) { - return; - } - - String firstRemotelySyncedMessageUniqueId = allSorted.last().getUniqueId(); - - firstRemoteSyncedItemPosition = chatMessageAdapter.findMessagePosition(firstRemotelySyncedMessageUniqueId); + loadHistoryIfNeed(); } public interface ChatViewerFragmentListener { From 68fd348521a6193340151f103e9d89b6dbb0f7e6 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 25 Apr 2019 15:49:15 +0500 Subject: [PATCH 063/237] Removed unused code --- .../ui/adapter/chat/MessagesAdapter.java | 2 -- .../android/ui/fragment/ChatFragment.java | 20 +------------------ 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessagesAdapter.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessagesAdapter.java index ec42c6b2dc..4b6db940f0 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessagesAdapter.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessagesAdapter.java @@ -67,7 +67,6 @@ public class MessagesAdapter extends RealmRecyclerViewAdapter checkedItemIds = new ArrayList<>(); public interface Listener { - void onMessageNumberChanged(int prevItemCount); void onMessagesUpdated(); void onChangeCheckedItems(int checkedItems); int getLastVisiblePosition(); @@ -249,7 +248,6 @@ public void onChange() { if (prevItemCount != itemCount) { if (firstMessageId != null && !firstMessageId.equals(prevFirstItemId)) listener.scrollTo(lastPosition + (itemCount - prevItemCount)); - listener.onMessageNumberChanged(prevItemCount); prevItemCount = itemCount; prevFirstItemId = firstMessageId; } diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java index 867ad75d51..583e1d625e 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java @@ -170,7 +170,6 @@ public class ChatFragment extends FileInteractionFragment implements PopupMenu.O private boolean historyIsLoading = false; private RealmResults messageItems; - private boolean toBeScrolled; private List> menuItems = null; @@ -324,14 +323,7 @@ public void onClick(View v) { public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); - if (dy < 0) { - loadHistoryIfNeed(); - } - - if (dy >= 0) { - toBeScrolled = false; - } - + if (dy < 0) loadHistoryIfNeed(); showScrollDownButtonIfNeed(); /** Necessary for @@ -1221,16 +1213,6 @@ public void onCompletion(MediaPlayer mediaPlayer) { } } - @Override - public void onMessageNumberChanged(int prevItemCount) { - int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition(); - - if (toBeScrolled || lastVisibleItemPosition == -1 || lastVisibleItemPosition == (prevItemCount - 1)) { - toBeScrolled = true; - scrollDown(); - } - } - @Override public int getLastVisiblePosition() { return layoutManager.findLastVisibleItemPosition(); From 1b6075bb631f4dda184de6577b48eb5c2fd8e4e7 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 25 Apr 2019 16:34:07 +0500 Subject: [PATCH 064/237] Fixed loadFullChatHistory method --- .../data/extension/mam/NextMamManager.java | 91 ++++++------------- .../ui/preferences/DebugSettingsFragment.java | 3 +- 2 files changed, 29 insertions(+), 65 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index f9f623ed9c..19d97f33cd 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -181,6 +181,29 @@ public void run() { }); } + /** + * Only for debugging + * This method ignores MAM settings. + * Call only from background thread + */ + public void loadFullChatHistory(AbstractChat chat) { + final AccountItem accountItem = AccountManager.getInstance().getAccount(chat.getAccount()); + if (accountItem == null || !isSupported(accountItem.getAccount()) || chat.historyIsFull()) return; + + Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); + + // if history is empty - load last message + MessageItem firstMessage = getFirstMessage(chat, realm); + if (firstMessage == null) loadLastMessage(realm, accountItem, chat); + + boolean complete = false; + while (!complete) { + complete = loadNextHistory(realm, accountItem, chat); + } + + realm.close(); + } + public void onRequestUpdatePreferences(AccountJid accountJid) { final AccountItem accountItem = AccountManager.getInstance().getAccount(accountJid); if (accountItem == null || !isSupported(accountJid)) return; @@ -281,12 +304,12 @@ private void loadNewMessages(Realm realm, AccountItem accountItem, AbstractChat * Если при запросе истории вернулась пустая страница, то * previousID сообщения на котором начиналась история = archivedID этого сообщения */ - private void loadNextHistory(Realm realm, AccountItem accountItem, AbstractChat chat) { + private boolean loadNextHistory(Realm realm, AccountItem accountItem, AbstractChat chat) { MessageItem firstMessage = getFirstMessage(chat, realm); if (firstMessage != null) { if (firstMessage.getArchivedId().equals(firstMessage.getPreviousId())) { chat.setHistoryIsFull(); - return; + return true; } MamManager.MamQueryResult queryResult = requestMessagesBeforeId(accountItem, chat, firstMessage.getArchivedId()); @@ -300,6 +323,7 @@ private void loadNextHistory(Realm realm, AccountItem accountItem, AbstractChat realm.beginTransaction(); firstMessage.setPreviousId(savedMessages.get(savedMessages.size() - 1).getArchivedId()); realm.commitTransaction(); + return false; } } else if (queryResult.mamFin.isComplete()) { realm.beginTransaction(); @@ -308,7 +332,7 @@ private void loadNextHistory(Realm realm, AccountItem accountItem, AbstractChat } } } - + return true; } /** @@ -770,65 +794,4 @@ private void updateLastMessageId(AbstractChat chat, Realm realm) { chat.setLastMessageId(id); } } - - /** - * Only for debugging - * Call only from background thread - * @param chat - */ -// public void requestFullChatHistory(final AbstractChat chat) { -// if (chat == null || chat.isRemotePreviousHistoryCompletelyLoaded()) { -// return; -// } -// -// final AccountItem accountItem = AccountManager.getInstance().getAccount(chat.getAccount()); -// if (accountItem == null || !accountItem.getFactualStatusMode().isOnline()) { -// return; -// } -// -// if (!checkSupport(accountItem)) { -// return; -// } -// -// String firstMamMessageMamId; -// boolean remoteHistoryCompletelyLoaded; -// { -// Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); -// SyncInfo syncInfo = getSyncInfo(realm, chat.getAccount(), chat.getUser()); -// firstMamMessageMamId = syncInfo.getFirstMamMessageMamId(); -// remoteHistoryCompletelyLoaded = syncInfo.isRemoteHistoryCompletelyLoaded(); -// realm.close(); -// } -// -// if (remoteHistoryCompletelyLoaded) { -// chat.setRemotePreviousHistoryCompletelyLoaded(true); -// } -// -// if (firstMamMessageMamId == null || remoteHistoryCompletelyLoaded) { -// return; -// } -// -// org.jivesoftware.smackx.mam.MamManager mamManager = -// org.jivesoftware.smackx.mam.MamManager.getInstanceFor(accountItem.getConnection()); -// -// final org.jivesoftware.smackx.mam.MamManager.MamQueryResult mamQueryResult; -// try { -// LogManager.i("MAM", "Loading previous history"); -// mamQueryResult = mamManager.queryArchive(chat.getUser().getJid()); -// } catch (SmackException.NotLoggedInException | SmackException.NoResponseException -// | XMPPException.XMPPErrorException | InterruptedException -// | SmackException.NotConnectedException e) { -// LogManager.exception(this, e); -// return; -// } -// LogManager.i("MAM", "queryArchive finished. fin count expected: " -// + mamQueryResult.mamFin.getRSMSet().getCount() + " real: " -// + mamQueryResult.forwardedMessages.size()); -// -// Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); -// List messageItems = getMessageItems(mamQueryResult, chat); -// syncMessages(realm, chat, messageItems); -// updatePreviousHistorySyncInfo(realm, chat, mamQueryResult); -// realm.close(); -// } } diff --git a/xabber/src/main/java/com/xabber/android/ui/preferences/DebugSettingsFragment.java b/xabber/src/main/java/com/xabber/android/ui/preferences/DebugSettingsFragment.java index 37b04e3888..5beb15ef14 100644 --- a/xabber/src/main/java/com/xabber/android/ui/preferences/DebugSettingsFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/preferences/DebugSettingsFragment.java @@ -10,6 +10,7 @@ import com.xabber.android.R; import com.xabber.android.data.Application; import com.xabber.android.data.SettingsManager; +import com.xabber.android.data.extension.mam.NextMamManager; import com.xabber.android.data.http.CrowdfundingManager; import com.xabber.android.data.message.AbstractChat; import com.xabber.android.data.message.MessageManager; @@ -111,7 +112,7 @@ public void run() { for (AbstractChat chat : chats) { setDownloadProgress(totalArchives, downloadedArchives); - //MamManager.getInstance().requestFullChatHistory(chat); + NextMamManager.getInstance().loadFullChatHistory(chat); downloadedArchives++; } closeDownloadArchiveDialog(); From 305c5227d13de628b3320a297587a6687df72a37 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 25 Apr 2019 16:48:08 +0500 Subject: [PATCH 065/237] Fixed updating support information --- .../xabber/android/data/extension/mam/NextMamManager.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index 19d97f33cd..446092c658 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -5,7 +5,6 @@ import com.xabber.android.data.Application; import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.account.AccountManager; -import com.xabber.android.data.connection.ConnectionItem; import com.xabber.android.data.database.MessageDatabaseManager; import com.xabber.android.data.database.messagerealm.Attachment; import com.xabber.android.data.database.messagerealm.ForwardId; @@ -73,10 +72,6 @@ public static NextMamManager getInstance() { return instance; } - public void onAuthorized(ConnectionItem connectionItem) { - updateIsSupported((AccountItem) connectionItem); - } - @Override public void onRosterReceived(AccountItem accountItem) { onAccountConnected(accountItem); @@ -96,6 +91,7 @@ public void onRosterReceived(AccountItem accountItem) { * - - Запрашиваем все новые сообщения в каждом чате. */ public void onAccountConnected(AccountItem accountItem) { + updateIsSupported(accountItem); Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); accountItem.setStartHistoryTimestamp(getLastMessageTimestamp(accountItem, realm)); if (accountItem.getStartHistoryTimestamp() == 0) { From 4f38aa48e274d4dcdbebe1f06557fe4415a78a12 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 25 Apr 2019 17:34:45 +0500 Subject: [PATCH 066/237] Refactoring --- .../data/connection/ConnectionListener.java | 2 - .../data/extension/mam/NextMamManager.java | 138 +++++++----------- .../android/data/message/RegularChat.java | 4 - 3 files changed, 49 insertions(+), 95 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/connection/ConnectionListener.java b/xabber/src/main/java/com/xabber/android/data/connection/ConnectionListener.java index 98f63b704f..1704cd236f 100644 --- a/xabber/src/main/java/com/xabber/android/data/connection/ConnectionListener.java +++ b/xabber/src/main/java/com/xabber/android/data/connection/ConnectionListener.java @@ -8,7 +8,6 @@ import com.xabber.android.data.extension.bookmarks.BookmarksManager; import com.xabber.android.data.extension.carbons.CarbonManager; import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager; -import com.xabber.android.data.extension.mam.NextMamManager; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.message.MessageManager; import com.xabber.android.data.roster.PresenceManager; @@ -62,7 +61,6 @@ public void authenticated(XMPPConnection connection, final boolean resumed) { // just to see the order of call CarbonManager.getInstance().onAuthorized(connectionItem); - NextMamManager.getInstance().onAuthorized(connectionItem); BlockingManager.getInstance().onAuthorized(connectionItem); HttpFileUploadManager.getInstance().onAuthorized(connectionItem); diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index 446092c658..da9472871a 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -1,7 +1,5 @@ package com.xabber.android.data.extension.mam; -import android.util.Log; - import com.xabber.android.data.Application; import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.account.AccountManager; @@ -36,7 +34,6 @@ import org.jivesoftware.smackx.delay.packet.DelayInformation; import org.jivesoftware.smackx.forward.packet.Forwarded; import org.jivesoftware.smackx.mam.MamManager; -import org.jxmpp.jid.Jid; import java.io.IOException; import java.util.ArrayList; @@ -340,8 +337,6 @@ private void loadMissedMessages(Realm realm, AccountItem accountItem, AbstractCh MessageItem m2 = getMessageForCloseMissedMessages(realm, m1); if (m2 != null && !m2.getUniqueId().equals(m1.getUniqueId())) { - Log.d("VALERA_TEST", "m1 archived id: " + m1.getArchivedId() + " text: " + m1.getText()); - Log.d("VALERA_TEST", "m2 archived id: " + m2.getArchivedId() + " text: " + m2.getText()); Date startDate = new Date(m2.getTimestamp()); Date endDate = new Date(m1.getTimestamp()); @@ -375,7 +370,7 @@ private void loadMissedMessages(Realm realm, AccountItem accountItem, AbstractCh private void initializeStartTimestamp(@Nonnull AccountItem accountItem) { long startHistoryTimestamp = System.currentTimeMillis(); - MamManager.MamQueryResult queryResult = requestLastMessage(accountItem); + MamManager.MamQueryResult queryResult = requestLastMessage(accountItem, null); if (queryResult != null && !queryResult.forwardedMessages.isEmpty()) { Forwarded forwarded = queryResult.forwardedMessages.get(0); startHistoryTimestamp = forwarded.getDelayInformation().getStamp().getTime(); @@ -399,111 +394,85 @@ private void updateIsSupported(AccountItem accountItem) { /** REQUESTS */ - /** Request most recent message from all history */ - private @Nullable MamManager.MamQueryResult requestLastMessage(@Nonnull AccountItem accountItem) { - return requestLastMessage(accountItem, null); + abstract class MamRequest { + abstract MamManager.MamQueryResult execute(MamManager manager) throws Exception; } - /** Request recent message from chat history */ - private @Nullable MamManager.MamQueryResult requestLastMessage(@Nonnull AccountItem accountItem, AbstractChat chat) { + private MamManager.MamQueryResult requestToMessageArchive(AccountItem accountItem, MamRequest request) { MamManager.MamQueryResult queryResult = null; XMPPTCPConnection connection = accountItem.getConnection(); - Jid chatJid = null; - if (chat != null) chatJid = chat.getUser().getJid(); if (connection.isAuthenticated()) { MamManager mamManager = MamManager.getInstanceFor(connection); try { - queryResult = mamManager.mostRecentPage(chatJid, 1); - } catch (SmackException.NotLoggedInException | InterruptedException - | SmackException.NotConnectedException | SmackException.NoResponseException - | XMPPException.XMPPErrorException e) { + queryResult = request.execute(mamManager); + } catch (Exception e) { LogManager.exception(this, e); } } - return queryResult; } - /** Request messages started with archivedID from chat history */ - private @Nullable MamManager.MamQueryResult requestMessagesFromId( - @Nonnull AccountItem accountItem, @Nonnull AbstractChat chat, String archivedId) { - - MamManager.MamQueryResult queryResult = null; - XMPPTCPConnection connection = accountItem.getConnection(); + /** Request recent message from chat history if chat not null + * Else request most recent message from all history*/ + private @Nullable MamManager.MamQueryResult requestLastMessage( + @Nonnull AccountItem accountItem, @Nullable final AbstractChat chat) { - if (connection.isAuthenticated()) { - MamManager mamManager = MamManager.getInstanceFor(connection); - try { - queryResult = mamManager.pageAfter(chat.getUser().getJid(), archivedId, 50); - } catch (SmackException.NotLoggedInException | InterruptedException - | SmackException.NotConnectedException | SmackException.NoResponseException - | XMPPException.XMPPErrorException e) { - LogManager.exception(this, e); + return requestToMessageArchive(accountItem, new MamRequest() { + @Override + MamManager.MamQueryResult execute(MamManager manager) throws Exception { + if (chat != null) return manager.mostRecentPage(chat.getUser().getJid(), 1); + else return manager.mostRecentPage(null, 1); } - } + }); + } - return queryResult; + /** Request messages after archivedID from chat history */ + private @Nullable MamManager.MamQueryResult requestMessagesFromId( + @Nonnull AccountItem accountItem, @Nonnull final AbstractChat chat, final String archivedId) { + + return requestToMessageArchive(accountItem, new MamRequest() { + @Override + MamManager.MamQueryResult execute(MamManager manager) throws Exception { + return manager.pageAfter(chat.getUser().getJid(), archivedId, 50); + } + }); } - /** Request messages before with archivedID from chat history */ + /** Request messages before archivedID from chat history */ private @Nullable MamManager.MamQueryResult requestMessagesBeforeId( - @Nonnull AccountItem accountItem, @Nonnull AbstractChat chat, String archivedId) { - - MamManager.MamQueryResult queryResult = null; - XMPPTCPConnection connection = accountItem.getConnection(); + @Nonnull AccountItem accountItem, @Nonnull final AbstractChat chat, final String archivedId) { - if (connection.isAuthenticated()) { - MamManager mamManager = MamManager.getInstanceFor(connection); - try { - queryResult = mamManager.pageBefore(chat.getUser().getJid(), archivedId, 50); - } catch (SmackException.NotLoggedInException | InterruptedException - | SmackException.NotConnectedException | SmackException.NoResponseException - | XMPPException.XMPPErrorException e) { - LogManager.exception(this, e); + return requestToMessageArchive(accountItem, new MamRequest() { + @Override + MamManager.MamQueryResult execute(MamManager manager) throws Exception { + return manager.pageBefore(chat.getUser().getJid(), archivedId, 50); } - } - - return queryResult; + }); } /** Request messages started with startID and ending with endID from chat history */ private @Nullable MamManager.MamQueryResult requestMissedMessages( - @Nonnull AccountItem accountItem, @Nonnull AbstractChat chat, Date startDate, Date endDate) { - - MamManager.MamQueryResult queryResult = null; - XMPPTCPConnection connection = accountItem.getConnection(); + @Nonnull AccountItem accountItem, @Nonnull final AbstractChat chat, + final Date startDate, final Date endDate) { - if (connection.isAuthenticated()) { - MamManager mamManager = MamManager.getInstanceFor(connection); - try { - queryResult = mamManager.queryArchive(50, startDate, endDate, chat.getUser().getJid(), null); - } catch (SmackException.NotLoggedInException | InterruptedException - | SmackException.NotConnectedException | SmackException.NoResponseException - | XMPPException.XMPPErrorException e) { - LogManager.exception(this, e); + return requestToMessageArchive(accountItem, new MamRequest() { + @Override + MamManager.MamQueryResult execute(MamManager manager) throws Exception { + return manager.queryArchive(50, startDate, endDate, chat.getUser().getJid(), null); } - } - - return queryResult; + }); } - private @Nullable MamManager.MamPrefsResult requestUpdatePreferences(@Nonnull AccountItem accountItem) { - MamManager.MamPrefsResult prefsResult = null; - XMPPTCPConnection connection = accountItem.getConnection(); - - if (connection.isAuthenticated()) { - MamManager mamManager = MamManager.getInstanceFor(connection); - try { - prefsResult = mamManager.updateArchivingPreferences(null, null, accountItem.getMamDefaultBehaviour()); - } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException - | InterruptedException | SmackException.NotConnectedException - | SmackException.NotLoggedInException e) { - LogManager.exception(NextMamManager.class, e); + /** Request update archiving preferences on server */ + private void requestUpdatePreferences(@Nonnull final AccountItem accountItem) { + requestToMessageArchive(accountItem, new MamRequest() { + @Override + MamManager.MamQueryResult execute(MamManager manager) throws Exception { + manager.updateArchivingPreferences(null, null, accountItem.getMamDefaultBehaviour()); + return null; } - } - - return prefsResult; + }); } /** PARSING */ @@ -719,15 +688,6 @@ private boolean isTimeToLoadAllNewMessages(AccountItem account, Realm realm) { } else return false; } - private boolean historyIsEmpty(AccountItem account) { - Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); - MessageItem messageItem = realm.where(MessageItem.class) - .equalTo(MessageItem.Fields.ACCOUNT, account.getAccount().toString()) - .findFirst(); - realm.close(); - return messageItem == null; - } - private boolean historyIsNotEnough(Realm realm, AbstractChat chat) { RealmResults results = realm.where(MessageItem.class) .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) diff --git a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java index 3a7f565ec1..57d2264137 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java @@ -17,7 +17,6 @@ import android.content.Intent; import android.support.annotation.NonNull; import android.text.TextUtils; -import android.util.Log; import com.xabber.android.data.NetworkException; import com.xabber.android.data.SettingsManager; @@ -26,7 +25,6 @@ import com.xabber.android.data.database.messagerealm.MessageItem; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.entity.UserJid; -import com.xabber.android.data.extension.chat_markers.ChatMarkerManager; import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager; import com.xabber.android.data.extension.muc.MUCManager; import com.xabber.android.data.extension.otr.OTRManager; @@ -44,7 +42,6 @@ import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smackx.delay.packet.DelayInformation; import org.jivesoftware.smackx.muc.packet.MUCUser; -import org.jivesoftware.smackx.offline.OfflineMessageHeader; import org.jxmpp.jid.Jid; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.jid.parts.Domainpart; @@ -182,7 +179,6 @@ protected boolean onPacket(UserJid bareAddress, Stanza packet, boolean isCarbons DelayInformation delayInformation = message.getExtension(DelayInformation.ELEMENT, DelayInformation.NAMESPACE); if (delayInformation != null && "Offline Storage".equals(delayInformation.getReason())) { - Log.d("VALERA_TEST", "message from offline storage should be ignored"); return true; } From c659f6ebbf428bf8e6cf848a48a09f2b0876e81c Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 25 Apr 2019 17:38:48 +0500 Subject: [PATCH 067/237] Up version to 609 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index f1157d00bb..3168d43eeb 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 608 - versionName '2.6.4(608)' + versionCode 609 + versionName '2.6.4(609)' } lintOptions { From 113734e71fa9d9d8df7bc12111835e0993c6ab06 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 26 Apr 2019 11:23:16 +0500 Subject: [PATCH 068/237] Refactoring --- .../com/xabber/android/data/Application.java | 8 ++-- .../data/extension/mam/NextMamManager.java | 48 ------------------- 2 files changed, 4 insertions(+), 52 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/Application.java b/xabber/src/main/java/com/xabber/android/data/Application.java index a0f8745e60..2b96b08c2e 100644 --- a/xabber/src/main/java/com/xabber/android/data/Application.java +++ b/xabber/src/main/java/com/xabber/android/data/Application.java @@ -333,10 +333,10 @@ public void onCreate() { AndroidDevMetrics.initWith(this); /** Strict Mode */ -// StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() -// .detectAll() -// .penaltyLog() -// .build()); + StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() + .detectAll() + .penaltyLog() + .build()); } /** Crashlytics */ diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index da9472871a..d60d8dfc31 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -74,19 +74,6 @@ public void onRosterReceived(AccountItem accountItem) { onAccountConnected(accountItem); } - /** - * Thread: Smack-Cached Executor - * - * Если локальной истории еще нет: - * - Запрашиваем одно самое последнее сообщение из истории. - * Это сообщение считается прочитанным, а все сообщения полученные после него считать непрочитанными. - * - Запрашиваем 1 последнее сообщение в каждом чате. - * Иначе: - * - Если с момента получения последнего сообщения прошло больше 30 минут: - * - - Запрашиваем 1 последнее сообщение в каждом чате. - * - Иначе: - * - - Запрашиваем все новые сообщения в каждом чате. - */ public void onAccountConnected(AccountItem accountItem) { updateIsSupported(accountItem); Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); @@ -102,13 +89,6 @@ public void onAccountConnected(AccountItem accountItem) { realm.close(); } - /** - * Проверяем наличие дыр в истории: - * - Берем все сообщения с previousID = null - * - Если сообщение M1 - не является самым первым в истории, то - * - - Выполняем заполнение истории для всех найденных дыр: - * - - requestMissedMessages(message) - */ public void onChatOpen(final AbstractChat chat) { final AccountItem accountItem = AccountManager.getInstance().getAccount(chat.getAccount()); if (accountItem == null || accountItem.getLoadHistorySettings() == LoadHistorySettings.none @@ -174,11 +154,6 @@ public void run() { }); } - /** - * Only for debugging - * This method ignores MAM settings. - * Call only from background thread - */ public void loadFullChatHistory(AbstractChat chat) { final AccountItem accountItem = AccountManager.getInstance().getAccount(chat.getAccount()); if (accountItem == null || !isSupported(accountItem.getAccount()) || chat.historyIsFull()) return; @@ -231,11 +206,6 @@ private void loadLastMessages(Realm realm, AccountItem accountItem) { } } - /** - * Запросить последнее сообщение в этом чате - * previousID = null - * setChatLastId(archivedID последнего сообщения в этом чате) - */ private void loadLastMessage(Realm realm, AccountItem accountItem, AbstractChat chat) { MamManager.MamQueryResult queryResult = requestLastMessage(accountItem, chat); if (queryResult != null) { @@ -259,11 +229,6 @@ private void loadAllNewMessages(Realm realm, AccountItem accountItem) { } } - /** - * Запросить все сообщения начиная со времени получения последнего сообщения. - * previousID первого нового сообщения = archivedID последнего сообщения. - * setChatLastId(archivedID последнего сообщения в этом чате) - */ private void loadNewMessages(Realm realm, AccountItem accountItem, AbstractChat chat) { String lastArchivedId = getLastMessageArchivedId(chat, realm); if (lastArchivedId != null) { @@ -289,14 +254,6 @@ private void loadNewMessages(Realm realm, AccountItem accountItem, AbstractChat } } - /** - * Запросить страницу истории до самого первого сообщения в чате. - * previousID сообщения на котором начиналась история = archivedID последнего полученного сообщения. - * previousID первого полученного сообщения = null - * - * Если при запросе истории вернулась пустая страница, то - * previousID сообщения на котором начиналась история = archivedID этого сообщения - */ private boolean loadNextHistory(Realm realm, AccountItem accountItem, AbstractChat chat) { MessageItem firstMessage = getFirstMessage(chat, realm); if (firstMessage != null) { @@ -328,11 +285,6 @@ private boolean loadNextHistory(Realm realm, AccountItem accountItem, AbstractCh return true; } - /** - * Находим M2 - первое сообщение перед M1 с archivedID != null и previousID != null - * Выполняем запрос истории начиная от archivedID M2 и заканчивая archivedID M1 - * Используя полученные сообщения проставляем previousID для сообщений. - */ private void loadMissedMessages(Realm realm, AccountItem accountItem, AbstractChat chat, MessageItem m1) { MessageItem m2 = getMessageForCloseMissedMessages(realm, m1); From 419a101f64828edbc9dc15f98ad616d2f4b299b8 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 26 Apr 2019 13:40:58 +0500 Subject: [PATCH 069/237] Fixed bug with scroll in chat --- .../com/xabber/android/ui/adapter/chat/MessagesAdapter.java | 3 +++ .../main/java/com/xabber/android/ui/fragment/ChatFragment.java | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessagesAdapter.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessagesAdapter.java index 4b6db940f0..ee07266826 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessagesAdapter.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessagesAdapter.java @@ -248,6 +248,9 @@ public void onChange() { if (prevItemCount != itemCount) { if (firstMessageId != null && !firstMessageId.equals(prevFirstItemId)) listener.scrollTo(lastPosition + (itemCount - prevItemCount)); + else if (lastPosition == prevItemCount - 1) + listener.scrollTo(itemCount - 1); + prevItemCount = itemCount; prevFirstItemId = firstMessageId; } diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java index 583e1d625e..c91038dc78 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java @@ -782,7 +782,6 @@ private void sendMessage() { private void sendMessage(String text) { MessageManager.getInstance().sendMessage(account, user, text); setFirstUnreadMessageId(null); - scrollDown(); } @@ -1418,7 +1417,6 @@ private void sendForwardMessage(List messages, String text) { ForwardManager.forwardMessage(messages, account, user, text); hideForwardPanel(); setFirstUnreadMessageId(null); - scrollDown(); } private void openChooserForForward(ArrayList forwardIds) { From 8711f246222dc673bdef49ce3e9af161ece58c55 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 26 Apr 2019 14:52:56 +0500 Subject: [PATCH 070/237] Added origin id to message packet --- .../android/data/message/AbstractChat.java | 2 ++ .../com/xabber/xmpp/sid/OriginIdElement.java | 30 +++++++++++++++++++ .../com/xabber/xmpp/sid/UniqStanzaHelper.java | 8 ++--- 3 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 xabber/src/main/java/com/xabber/xmpp/sid/OriginIdElement.java diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index 964e6464b1..aa9cddb221 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -45,6 +45,7 @@ import com.xabber.android.data.message.chat.ChatManager; import com.xabber.android.data.notification.MessageNotificationManager; import com.xabber.android.data.notification.NotificationManager; +import com.xabber.xmpp.sid.OriginIdElement; import com.xabber.xmpp.sid.UniqStanzaHelper; import org.greenrobot.eventbus.EventBus; @@ -695,6 +696,7 @@ boolean sendMessage(MessageItem messageItem) { if (message != null) { ChatStateManager.getInstance().updateOutgoingMessage(AbstractChat.this, message); CarbonManager.getInstance().updateOutgoingMessage(AbstractChat.this, message); + message.addExtension(new OriginIdElement(messageItem.getStanzaId())); if (delayTimestamp != null) { message.addExtension(new DelayInformation(delayTimestamp)); } diff --git a/xabber/src/main/java/com/xabber/xmpp/sid/OriginIdElement.java b/xabber/src/main/java/com/xabber/xmpp/sid/OriginIdElement.java new file mode 100644 index 0000000000..6c02903a58 --- /dev/null +++ b/xabber/src/main/java/com/xabber/xmpp/sid/OriginIdElement.java @@ -0,0 +1,30 @@ +package com.xabber.xmpp.sid; + +import org.jivesoftware.smack.packet.ExtensionElement; +import org.jivesoftware.smack.util.XmlStringBuilder; + +public class OriginIdElement implements ExtensionElement { + + private String id; + + public OriginIdElement(String id) { + this.id = id; + } + + @Override + public String getNamespace() { + return UniqStanzaHelper.NAMESPACE; + } + + @Override + public String getElementName() { + return UniqStanzaHelper.ELEMENT_NAME_ORIGIN; + } + + @Override + public CharSequence toXML() { + return new XmlStringBuilder(OriginIdElement.this) + .attribute(UniqStanzaHelper.ATTRIBUTE_ID, id) + .closeEmptyElement(); + } +} \ No newline at end of file diff --git a/xabber/src/main/java/com/xabber/xmpp/sid/UniqStanzaHelper.java b/xabber/src/main/java/com/xabber/xmpp/sid/UniqStanzaHelper.java index 52e8f9cc8e..cea488bc1e 100644 --- a/xabber/src/main/java/com/xabber/xmpp/sid/UniqStanzaHelper.java +++ b/xabber/src/main/java/com/xabber/xmpp/sid/UniqStanzaHelper.java @@ -9,10 +9,10 @@ public class UniqStanzaHelper { - private final static String ELEMENT_NAME_ORIGIN = "origin-id"; - private final static String ELEMENT_NAME = "stanza-id"; - private final static String NAMESPACE = "urn:xmpp:sid:0"; - private final static String ATTRIBUTE_ID = "id"; + final static String ELEMENT_NAME_ORIGIN = "origin-id"; + final static String ELEMENT_NAME = "stanza-id"; + final static String NAMESPACE = "urn:xmpp:sid:0"; + final static String ATTRIBUTE_ID = "id"; public static String getStanzaId(Message message) { StandardExtensionElement sidElement = message.getExtension(ELEMENT_NAME, NAMESPACE); From 2f86f4dcf7833d9a11d6ad03a90abf8e90557cf5 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 26 Apr 2019 16:07:09 +0500 Subject: [PATCH 071/237] Fixed parsing packet extension --- .../android/data/connection/ConnectionThread.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/connection/ConnectionThread.java b/xabber/src/main/java/com/xabber/android/data/connection/ConnectionThread.java index f6cb85568c..ecdcfa0d28 100644 --- a/xabber/src/main/java/com/xabber/android/data/connection/ConnectionThread.java +++ b/xabber/src/main/java/com/xabber/android/data/connection/ConnectionThread.java @@ -126,6 +126,12 @@ void connectAndLogin() { LogManager.i(this, "Use DNS Java resolver"); ExtDNSJavaResolver.setup(); + ProviderManager.addExtensionProvider(DataForm.ELEMENT, + DataForm.NAMESPACE, new CustomDataProvider()); + + ProviderManager.addExtensionProvider(ForwardComment.ELEMENT, + ForwardComment.NAMESPACE, new ForwardCommentProvider()); + try { LogManager.i(this, "Trying to connect and login..."); if (!connection.isConnected()) { @@ -141,13 +147,6 @@ void connectAndLogin() { connection.login(); - // can be a cause of strange Smack behavior - // not authorization or not receiving a iq's - ProviderManager.addExtensionProvider(DataForm.ELEMENT, - DataForm.NAMESPACE, new CustomDataProvider()); - - ProviderManager.addExtensionProvider(ForwardComment.ELEMENT, - ForwardComment.NAMESPACE, new ForwardCommentProvider()); } else { LogManager.i(this, "Already authenticated"); } From 21bce57697af60f913fc20317ea3850417a8cce6 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 26 Apr 2019 18:04:58 +0500 Subject: [PATCH 072/237] Added receiving default mam settings from server on connection --- .../data/extension/mam/NextMamManager.java | 49 +++++++++++++------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index d60d8dfc31..b0859277ea 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -34,6 +34,7 @@ import org.jivesoftware.smackx.delay.packet.DelayInformation; import org.jivesoftware.smackx.forward.packet.Forwarded; import org.jivesoftware.smackx.mam.MamManager; +import org.jivesoftware.smackx.mam.element.MamPrefsIQ; import java.io.IOException; import java.util.ArrayList; @@ -76,6 +77,7 @@ public void onRosterReceived(AccountItem accountItem) { public void onAccountConnected(AccountItem accountItem) { updateIsSupported(accountItem); + updatePreferencesFromServer(accountItem); Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); accountItem.setStartHistoryTimestamp(getLastMessageTimestamp(accountItem, realm)); if (accountItem.getStartHistoryTimestamp() == 0) { @@ -344,25 +346,35 @@ private void updateIsSupported(AccountItem accountItem) { AccountManager.getInstance().onAccountChanged(accountItem.getAccount()); } + private void updatePreferencesFromServer(@Nonnull AccountItem accountItem) { + MamManager.MamPrefsResult prefsResult = requestPreferencesFromServer(accountItem); + if (prefsResult != null) { + MamPrefsIQ.DefaultBehavior behavior = prefsResult.mamPrefs.getDefault(); + AccountManager.getInstance().setMamDefaultBehaviour(accountItem.getAccount(), behavior); + } + } + /** REQUESTS */ - abstract class MamRequest { - abstract MamManager.MamQueryResult execute(MamManager manager) throws Exception; + /** T extends MamManager.MamQueryResult or T extends MamManager.MamPrefsResult */ + abstract class MamRequest { + abstract T execute(MamManager manager) throws Exception; } - private MamManager.MamQueryResult requestToMessageArchive(AccountItem accountItem, MamRequest request) { - MamManager.MamQueryResult queryResult = null; + /** T extends MamManager.MamQueryResult or T extends MamManager.MamPrefsResult */ + private T requestToMessageArchive(AccountItem accountItem, MamRequest request) { + T result = null; XMPPTCPConnection connection = accountItem.getConnection(); if (connection.isAuthenticated()) { MamManager mamManager = MamManager.getInstanceFor(connection); try { - queryResult = request.execute(mamManager); + result = request.execute(mamManager); } catch (Exception e) { LogManager.exception(this, e); } } - return queryResult; + return result; } /** Request recent message from chat history if chat not null @@ -370,7 +382,7 @@ private MamManager.MamQueryResult requestToMessageArchive(AccountItem accountIte private @Nullable MamManager.MamQueryResult requestLastMessage( @Nonnull AccountItem accountItem, @Nullable final AbstractChat chat) { - return requestToMessageArchive(accountItem, new MamRequest() { + return requestToMessageArchive(accountItem, new MamRequest() { @Override MamManager.MamQueryResult execute(MamManager manager) throws Exception { if (chat != null) return manager.mostRecentPage(chat.getUser().getJid(), 1); @@ -383,7 +395,7 @@ MamManager.MamQueryResult execute(MamManager manager) throws Exception { private @Nullable MamManager.MamQueryResult requestMessagesFromId( @Nonnull AccountItem accountItem, @Nonnull final AbstractChat chat, final String archivedId) { - return requestToMessageArchive(accountItem, new MamRequest() { + return requestToMessageArchive(accountItem, new MamRequest() { @Override MamManager.MamQueryResult execute(MamManager manager) throws Exception { return manager.pageAfter(chat.getUser().getJid(), archivedId, 50); @@ -395,7 +407,7 @@ MamManager.MamQueryResult execute(MamManager manager) throws Exception { private @Nullable MamManager.MamQueryResult requestMessagesBeforeId( @Nonnull AccountItem accountItem, @Nonnull final AbstractChat chat, final String archivedId) { - return requestToMessageArchive(accountItem, new MamRequest() { + return requestToMessageArchive(accountItem, new MamRequest() { @Override MamManager.MamQueryResult execute(MamManager manager) throws Exception { return manager.pageBefore(chat.getUser().getJid(), archivedId, 50); @@ -408,7 +420,7 @@ MamManager.MamQueryResult execute(MamManager manager) throws Exception { @Nonnull AccountItem accountItem, @Nonnull final AbstractChat chat, final Date startDate, final Date endDate) { - return requestToMessageArchive(accountItem, new MamRequest() { + return requestToMessageArchive(accountItem, new MamRequest() { @Override MamManager.MamQueryResult execute(MamManager manager) throws Exception { return manager.queryArchive(50, startDate, endDate, chat.getUser().getJid(), null); @@ -418,11 +430,20 @@ MamManager.MamQueryResult execute(MamManager manager) throws Exception { /** Request update archiving preferences on server */ private void requestUpdatePreferences(@Nonnull final AccountItem accountItem) { - requestToMessageArchive(accountItem, new MamRequest() { + requestToMessageArchive(accountItem, new MamRequest() { @Override - MamManager.MamQueryResult execute(MamManager manager) throws Exception { - manager.updateArchivingPreferences(null, null, accountItem.getMamDefaultBehaviour()); - return null; + MamManager.MamPrefsResult execute(MamManager manager) throws Exception { + return manager.updateArchivingPreferences(null, null, accountItem.getMamDefaultBehaviour()); + } + }); + } + + /** Request archiving preferences from server */ + private @Nullable MamManager.MamPrefsResult requestPreferencesFromServer(@Nonnull final AccountItem accountItem) { + return requestToMessageArchive(accountItem, new MamRequest() { + @Override + MamManager.MamPrefsResult execute(MamManager manager) throws Exception { + return manager.retrieveArchivingPreferences(); } }); } From 1d155395e9ad1cb81ed08da9f4a59bf39466c324 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 26 Apr 2019 18:10:14 +0500 Subject: [PATCH 073/237] Up version to 610 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 3168d43eeb..7c1d5e822b 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 609 - versionName '2.6.4(609)' + versionCode 610 + versionName '2.6.4(610)' } lintOptions { From 4bc32d938b08864d9379cd75ce7b4fc86deef445 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 29 Apr 2019 17:05:51 +0500 Subject: [PATCH 074/237] Try to fixed error with migration from old message-ids to new --- .../data/database/messagerealm/MessageItem.java | 11 +++++++++++ .../android/data/extension/mam/NextMamManager.java | 5 ++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/data/database/messagerealm/MessageItem.java b/xabber/src/main/java/com/xabber/android/data/database/messagerealm/MessageItem.java index 816a064958..3fd22489ed 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/messagerealm/MessageItem.java +++ b/xabber/src/main/java/com/xabber/android/data/database/messagerealm/MessageItem.java @@ -32,6 +32,7 @@ import io.realm.RealmList; import io.realm.RealmObject; +import io.realm.annotations.Ignore; import io.realm.annotations.Index; import io.realm.annotations.PrimaryKey; import io.realm.annotations.Required; @@ -213,6 +214,8 @@ public static class Fields { private String parentMessageId; private String previousId; private String archivedId; + @Ignore + private String packetId; private RealmList forwardedIds; @@ -575,6 +578,14 @@ public void setArchivedId(String archivedId) { this.archivedId = archivedId; } + public String getPacketId() { + return packetId; + } + + public void setPacketId(String packetId) { + this.packetId = packetId; + } + public boolean isFromMUC() { return fromMUC; } diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index b0859277ea..b42dffed54 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -519,6 +519,7 @@ private List parseMessage(AccountItem accountItem, AccountJid accou } messageItem.setIncoming(incoming); messageItem.setStanzaId(AbstractChat.getStanzaId(message)); + messageItem.setPacketId(message.getStanzaId()); messageItem.setReceivedFromMessageArchive(true); messageItem.setRead(timestamp <= accountItem.getStartHistoryTimestamp()); messageItem.setSent(true); @@ -570,9 +571,11 @@ private MessageItem determineSaveOrUpdate(Realm realm, AbstractChat chat, final MessageItem localMessage = realm.where(MessageItem.class) .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) .equalTo(MessageItem.Fields.USER, chat.getUser().toString()) - .equalTo(MessageItem.Fields.STANZA_ID, message.getStanzaId()) .equalTo(MessageItem.Fields.TEXT, message.getText()) .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) + .equalTo(MessageItem.Fields.STANZA_ID, message.getStanzaId()) + .or().equalTo(MessageItem.Fields.STANZA_ID, message.getPacketId()) + .or().equalTo(MessageItem.Fields.STANZA_ID, message.getArchivedId()) .findFirst(); if (localMessage == null) { From ded4b27e84a08a238766cbe3e926d5e5ee21e6f2 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 29 Apr 2019 17:31:51 +0500 Subject: [PATCH 075/237] Changes in Realm migration. Push enabled now is true by default. --- .../com/xabber/android/data/database/RealmManager.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java b/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java index 36a0f519c0..b31bc55206 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java +++ b/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java @@ -24,6 +24,7 @@ import com.xabber.android.data.notification.custom_notification.NotifyPrefsRealm; import io.realm.DynamicRealm; +import io.realm.DynamicRealmObject; import io.realm.FieldAttribute; import io.realm.Realm; import io.realm.RealmConfiguration; @@ -322,6 +323,12 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { if (oldVersion == 22) { schema.get(AccountRealm.class.getSimpleName()) .addField(AccountRealm.Fields.PUSH_ENABLED, boolean.class) + .transform(new RealmObjectSchema.Function() { + @Override + public void apply(DynamicRealmObject obj) { + obj.setBoolean(AccountRealm.Fields.PUSH_ENABLED, true); + } + }) .addField(AccountRealm.Fields.PUSH_WAS_ENABLED, boolean.class); oldVersion++; From 94f50502891bb61dad617efb792f3d4b89594077 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 29 Apr 2019 17:37:18 +0500 Subject: [PATCH 076/237] Up version to 611 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 7c1d5e822b..bcef6700d3 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 610 - versionName '2.6.4(610)' + versionCode 611 + versionName '2.6.4(611)' } lintOptions { From 7b1404b295a8ad3ae2c677fb8dbd980299e58774 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 30 Apr 2019 17:23:15 +0500 Subject: [PATCH 077/237] Updated Arabic translation --- .../main/res/values-ar-rSA/account_list.xml | 5 +- .../main/res/values-ar-rSA/chat_viewer.xml | 68 +++++++++++--- .../main/res/values-ar-rSA/contact_editor.xml | 9 +- .../main/res/values-ar-rSA/contact_list.xml | 50 +++++++++++ .../main/res/values-ar-rSA/contact_viewer.xml | 16 +++- .../res/values-ar-rSA/notification_bar.xml | 23 ++++- .../res/values-ar-rSA/preference_editor.xml | 90 +++++++++++++++++++ xabber/src/main/res/values-ar-rSA/words.xml | 15 +++- 8 files changed, 258 insertions(+), 18 deletions(-) diff --git a/xabber/src/main/res/values-ar-rSA/account_list.xml b/xabber/src/main/res/values-ar-rSA/account_list.xml index 4824468302..9efc93bf66 100644 --- a/xabber/src/main/res/values-ar-rSA/account_list.xml +++ b/xabber/src/main/res/values-ar-rSA/account_list.xml @@ -3,10 +3,11 @@ هل حقاً تريد حذف الحساب %s؟\n(لن يتم حذفه من الخادم، فقط من Xabber) أضف حساب - سجل حساب جديد + تسجيل حساب جديد حذف الحساب + إعدادات الحساب جارِ التسجيل - جارِ التخويل + جارِ الاتصال متصل جارِ الاتصال جارِ قطع الاتصال diff --git a/xabber/src/main/res/values-ar-rSA/chat_viewer.xml b/xabber/src/main/res/values-ar-rSA/chat_viewer.xml index 59dcedd44a..7100675e99 100644 --- a/xabber/src/main/res/values-ar-rSA/chat_viewer.xml +++ b/xabber/src/main/res/values-ar-rSA/chat_viewer.xml @@ -2,11 +2,11 @@ %1$s غير حالته: %2$s - %1$s مسح نص الحالة - %1$s انضم للاجتماع - %1$s تم طرده - أنت حالياً غير متصل. سيتم تسليم الرسائل التي ترسلها عندما تتصل مرة أخرى. - أرسل في %s + %1$s تم حذف الرسائل + %1$s انضم + %1$s تعرض للطرد + أنت غير متصل حاليًا. سيتم تسليم الرسائل التي ترسلها في المرة القادمة التي تتصل فيها. + ارسل في %s أكتب رسالتك هنا أرسل مسح سجل الرسائل @@ -16,9 +16,11 @@ طرف الاتصال غير متاح ملف غير موجود نسخ + إشارة اقتباس احذف من سجل الرسائل أعد محاولة الإرسال + عرض الرسالة حفظ السجل محلياً\nتخزين سجل الرسائل محلياً تم إرسال طلب انتباه تم طلب انتباهك @@ -49,13 +51,14 @@ %1$s يطلب عدم الإزعاج %1$s غير متاح %1$s متغيب لفترة طويلة - %1$s غير الموضوع إلى: %2$s - طرف الاتصال لا يدعم أو عطل خاصية طلب الانتباه - طلب انتباه - خيارات المحادثة - يقوم بالكتابة… - كتب نصاً… - كُتبت في %s + %1$s غير الموضوع الى: %2$s + جهة الاتصال لا تدعم أو تم تعطيل الاهتمام + تنبيه المكالمة + خيارات المحادثه + يكتب… + ادخل نصاً… + كتبت في %s + تاريخ التصدير تم تصدير سجل المحادثة لبطاقة الذاكرة SD %2$s إلى %1$s.html أرسل بعد التصدير @@ -69,10 +72,20 @@ تم طلب تشفير المحادثة باستخدام OTR لكن ليس لديك أداة تدعمها. استخدم Pidgin أو Gajim أو Adium لأنظمة الحاسوب، أو Xabber أو ChatSecure لأنظمة Android.\nتصفح http://otr.cypherpunks.ca/ لمزيد من المعلومات. ابدأ التشفير الرسالة المشفرة التي أرسلتها ليست مقروؤة لدى الطرف الآخر + لا يمكن فك تشفير الرسالة + رسالة معاد توجيهها %d تحقق OTR تحقق بالبصمة تحقق بالسؤال السري تحقق بكلمة سر + حدد الجهاز لتأسيس جلسة OTR: + جلسة OTR لم تبدأ. + جلسة OTR لم تبدأ. الاتصال غير متصل. + طلب التحقق من OTR + تحقق OTR في تقدم + افتح + اغلاق + رسالة مخفية استخدم الإعدادات العامة إظهار نص الرسالة إخفاء نص الرسالة @@ -81,4 +94,35 @@ فتح محادثة خاصة لا يوجد إذن لقراءة الملفات لا يوجد إذن لكتابة الملفات + لا إذن للكاميرا + وصف خاطئ: + ارسلت + تم التوصيل + وردت من التاريخ + خطأ + المرسلة من جهاز آخر + إرسال + لا يمكنك إرسال أكثر من 10 عناصر في وقت واحد + لا يوجد المزيد من الرسائل في التاريخ + وسيط + مشارك + زائر + الدردشات الأرشيف هو مبين + الدردشات الأرشيف مخفية + إشعار لهذه الدردشة + الخادم الذي تستخدمه لا يدعم نقل الملفات. يمكنك تجربة خادم xabber.org. + الانضمام إلى المؤتمر + اسحب لليمين لفتح الدردشات الحديثة + اسحب لليسار لفتح معلومات الاتصال + انسخ الرابط + تحميل + تم حفظ الصورة + تم نسخ الرابط إلى الحافظة + لا يمكن فتح الملف + جاري التحميل.. %s + رسائل غير مقروءة + مسؤول Xabber + تغذية الأخبار + دعم Xabber + جهة اتصال جديدة diff --git a/xabber/src/main/res/values-ar-rSA/contact_editor.xml b/xabber/src/main/res/values-ar-rSA/contact_editor.xml index 47e49edffa..e6c54a8054 100644 --- a/xabber/src/main/res/values-ar-rSA/contact_editor.xml +++ b/xabber/src/main/res/values-ar-rSA/contact_editor.xml @@ -5,7 +5,7 @@ اختر المجموعات المعرف (اختياري) مشاركة حالة الحساب %1$s مع طرف الاتصال؟ - معرف طرف الاتصال + اسم طرف الاتصال لم يتم العثور على طرف الاتصال حدد اسم المجموعة اسم المجموعة @@ -14,4 +14,11 @@ أضف مجموعة جديدة… تصريح إلغاء + جار معالجة الصورة... + خطأ أثناء قص الصورة + خطأ أثناء معالجة الصور + معلومات الخادم + قائمة قدرات الخادم + %1$s من %2$s يريد لبدء محادثة خاصة معك + قبول diff --git a/xabber/src/main/res/values-ar-rSA/contact_list.xml b/xabber/src/main/res/values-ar-rSA/contact_list.xml index 216961ba02..9407b40a8c 100644 --- a/xabber/src/main/res/values-ar-rSA/contact_list.xml +++ b/xabber/src/main/res/values-ar-rSA/contact_list.xml @@ -14,6 +14,7 @@ ليس لديك أي حسابات ليس لديك أطراف اتصال لا أحد متاح + لم يتم العثور على جهات اتصال لا حساب متصل متصل. جارِ تشغيل التطبيق… @@ -25,15 +26,27 @@ حظر جهة الاتصال هل حقاً تريد أن تحذف طرف الاتصال %1$s من حساب %2$s؟ رفض الاتصال + الارشيف + إلغاء الأرشفة + كتم إلى الأبد + كتم ل ١٥ دقيقة + كتم لساعه + كتم لساعتين + كتم ليوم واحد + كتم الصوت + الغاء كتم الصوت + عرض الارشيف خروج محادثات دائرة لا توجد مجموعات حذف مجموعة هل حقاً تريد حذف المجموعة %s؟ الأعضاء في تلك المجموعة سيظلون في قائمة الاتصال. أعد تسمية المجموعة + اعدادات الاشعارات حساب غير موجود لم يتم الاتصال طلب الاشتراك + إرسال جهة الاتصال خطأ في تدفق البيانات حفظ التغييرات…\nسيتم إغلاق التطبيق قريباً. اجتماعات @@ -54,4 +67,41 @@ تم إلغاء حظر جهات الاتصال بنجاح خطأ في إلغاء حظر جهات الاتصال هل حقاً تريد أن تحظر طرف الاتصال %1$s من حساب %2$s؟ + هل تريد حقًا إلغاء حظر جميع جهات الاتصال من الحساب %1$s؟ + إلغاء حظر الجميع + إلغاء حظر المحددين + اختار + سمة مظلمة جديدة متاحة الآن لـ Xabber. الانضمام إلى الجانب المظلم أو البقاء على الجانب ضوء؟ + مظلم + فاتح + عمل البطارية + يقوم جهازك ببعض عمليات تحسين البطارية الثقيلة على Xabber والتي قد تؤدي إلى تأخير الإخطارات أو حتى فقدان الرسائل. n/n/ سيُطلب منك الآن تعطيلها. + حذف الملفات القديمة + افتح + ارسل + مزامنة الإشارات المرجعية + حذف الكل + إزالة المحدد + هل تريد حقًا إلغاء حظر جميع جهات الاتصال من الحساب %1$s؟ + هل تريد حقا إزالة جميع الاجتماعات من الحساب؟ %1$s + لا يوجد محادثات في الارشيف + لايوجد دردشات غير مقروئه + تم أرشفة الدردشة + الحذف من الأرشيف + تراجع + المحادثات الأخيرة + دردشات غير مقروءة + دردشات المؤرشفة + كل المحادثات + لايوجد رسائل + اظهر كل الدردشات + جهات الاتصال + اسحب الدردشة إلى اليسار أو اليمين لأرشفتها + آخر ظهور منذ قليل + اخر ظهور منذ %1$s دقائق + اخر ظهور قبل ساعة + اخر ظهور %1$s + اخر ظهور ليلة امس %1$s + اخر ظهور %1$s في %2$s + اخر ظهور %1$s diff --git a/xabber/src/main/res/values-ar-rSA/contact_viewer.xml b/xabber/src/main/res/values-ar-rSA/contact_viewer.xml index 4ad03472f1..b5b4df9612 100644 --- a/xabber/src/main/res/values-ar-rSA/contact_viewer.xml +++ b/xabber/src/main/res/values-ar-rSA/contact_viewer.xml @@ -4,7 +4,7 @@ بيانات طرف الاتصال عميل هذا الجهاز - كنية + الاسم المستعار الاسم الكامل بادئة الاسم @@ -48,6 +48,20 @@ تعديل المعرِّف تعديل المجموعات حذف جهة اتصال + تعديل معلومات المستخدم تعديل تم حفظ معلومات الحساب بنجاح + لا يمكن حفظ معلومات مستخدم الحساب + حفظ... + اختيار من المعرض + اختيار صورة + ازالة الصوره + تغيير + لا يمكن الحصول على معلومات المؤتمر + الاسم + وصف + الموضوع + الركاب %d + الأجهزة المتصلة + البروفايل diff --git a/xabber/src/main/res/values-ar-rSA/notification_bar.xml b/xabber/src/main/res/values-ar-rSA/notification_bar.xml index 3c664b3b00..b5c9fdf441 100644 --- a/xabber/src/main/res/values-ar-rSA/notification_bar.xml +++ b/xabber/src/main/res/values-ar-rSA/notification_bar.xml @@ -1,7 +1,7 @@ - حساب + الحساب حسابات - @@ -20,6 +20,8 @@ - %1$d %2$s من %3$d %4$s %1$d %2$s من %3$s + %1$d جديد %2$s + %1$d جديد %2$s من %3$s %1$s: %2$s %1$d من %2$d %3$s متصل %1$d من %2$d %3$s متصلة @@ -39,4 +41,23 @@ مطلوب كلمة المرور انتبه طلب تصريح + محادثة خاصة المؤتمر + الردّ + غفوة + تاشير كمقروء + عرض الإشعارات المخصصة + قناة إعلام مخصصة للمحادثة: + قناة إعلام مخصصة للمجموعة: + قناة إعلام مخصصة للحساب: + قناة إعلام مخصصة للمحادثة: + مكالمات الاهتمام + إعلامات المكالمات الاهتمام + دردشة خاصة + إعلامات حول رسائل في الأحاديث الخاصة + مجموعة الدردشة + إعلامات حول الرسائل في دردشات المجموعة + استخدام الاتصال المستمر + الإخطار المستمرة لتأسيس اتصال لتلقي الرسائل + الأحداث + إخطارات للأحداث مثل: المحادثة المجموعة تدعو، طلبات الاشتراك، وطلبات OTR diff --git a/xabber/src/main/res/values-ar-rSA/preference_editor.xml b/xabber/src/main/res/values-ar-rSA/preference_editor.xml index 8f6b29458f..f22bd86064 100644 --- a/xabber/src/main/res/values-ar-rSA/preference_editor.xml +++ b/xabber/src/main/res/values-ar-rSA/preference_editor.xml @@ -1,25 +1,49 @@ + عمل البطارية + تحسين البطاريه معطل. لتمكينه انتقل إلى إعدادات الجهاز + تم تشغيل تحسينات البطارية مسح البيانات\nمسح كل البيانات المخزنة على الجهاز. هذا قد يحرر بعض المساحة. هل حقاً تريد حذف سجل المحادثات وكافة البيانات المحلية؟\nلن يتأثر الحساب ولا بيانات قائمة الاتصال. سيتم غلق التطبيق. أرسل بزر الإدخال\nيمكن إرسال الرسائل عند الضغط على مفتاح الإدخال تغييب ذاتي\nتعيين حالة الغياب ذاتياً عند قفل الشاشة + فرز جهات الاتصال أبجدي بالحالة جمِّع حسب الحساب\nجمِّع الأطراف في قائمة الاتصال حسب الحساب إظهار الصور الرمزية\nإظهار الصور الرمزية للأطراف في قائمة الاتصال + إظهار رسائل\nيظهر المستخدمين في قائمة جهات الاتصال أظهر المجموعات الخالية\nأظهر المجموعات التي ليس بها أطراف متاحة إظهار المجموعات\nإظهار المجموعات في قائمة الاتصال إظهار الأطراف الغير المتاحة سجل التصحيح\nكتابة الرسائل لسجل التصحيح (برجاء إعادة تشغيل البرنامج لتطبيق التغيير) كتابة ملف سجل التصحيح \nكتابة سجل التصحيح إلى ملف محلي (يمكنك مشاركته). ملفات السجل\nقائمة ملفات السجل المكتوبة. + تحميل كافة الرسائل من أرشيف\nوظيفة التصحيح. أيار/مايو ويعمل مع الأخطاء ملفات السجل إظهار أخطاء الاتصال\nإظهار اطارات منبثقة ﻷخطاء الاتصال + حصة تحطم وتشخيص البيانات\nمساعدة مطوري التطبيق تحسين شبير بالسماح بتبادل البيانات تحطم وتشخيص معهم (الرجاء إعادة تشغيل التطبيق لتطبيق التغييرات). + سيتم تطبيق التغييرات API شبير\nبعد إعادة التشغيل + إحضار علاوة تغذية الآن + بيانات الأعطال والتشخيص + Xabber يجمع تقارير الأخطاء المجهولة. يمكنك تعطيل فإنه في إعدادات التصحيح، ولكن سوف تعوق قدرتنا على توفير تجربة مراسلة موثوق بها للمستخدمين شبير. + إعدادات + إشارة الضوء + وميض LED على الإخطار + إشارة الضوء + وميض LED على الإشعار من المؤتمرات أيقونة شريط المهام\nاظهار مستمر للإخطار. هذا الخيار يمنع نظام Android من إزالة التطبيق من الذاكرة + الصوت + اختيار صوت التنبيهات + إهتزاز + تحديث إشعار التفضيلات + تفضيلات الإعلام مخصص تجاهل كافة الإعدادات الأخرى في الإشعار + يجب عليك أولاً حفظ عبارة + مظهر داكن فاتح + رموز المشاعر تعبيرات Android لا تعبيرات رسومية إعدادات الاتصال\nإعدادات الاتصال @@ -28,13 +52,25 @@ الإعدادات إشعارات\nضبط الإشعارات ضبط المظهر\nإعدادات المظهر + ضبط فلتر السبام + \nوجود وجود إعدادات + إعدادات خصوصية الخصوصية\n + بلا امان + قبول الرسائل من جهاة الاتصال فقط + قبول الرسائل من جهات الاتصال مع تحقق كابتشا + رسائل فقط من جهات الاتصال، بلا تحقق حول أظهر صورة الخلفية\nتعطيلها قد يحسن الأداء + حجم الخط كبير طبيعي صغير كبير جداً + إخفاء لوحة المفاتيح في الوضع العرضي + الصور الرمزية في الدردشة\nإظهار الصور الرمزية في كل رسالة داخل الدردشة + الصور الرمزية في الدردشة\nإظهار الصور الرمزية في كل رسالة داخل الدردشة + إظهار تغيير الحالات في الاجتماعات إرسال إخطار الكتابة\nإخطار الطرف الآخر أنك تكتب له رسالة تعديل الأولوية\nضبط الأولوية حسب الحالة المحددة. أولوية الحساب سيتم تجاوزها. @@ -46,14 +82,68 @@ أبقٍ اتصال WiFi نشطاً\nأبقٍ اتصال WiFi نشط في وضع السكون. سينقص عمر البطارية إعادة تعيين إعدادات الأطراف الغير متاحة\nمسح الإعدادات الفردية للمجموعات وأطراف الاتصال هل ترغب حقاً في مسح الإعدادات الفردية للمجموعات وأطراف الاتصال؟ + تنبيه على الرسالة الأولى + إعلام فقط في أول رسالة في المحادثة + معاينة الرسالة + إظهار نص رسالة من الأحاديث في منطقة الإعلام + معاينة الرسالة + إظهار نص رسالة من الأحاديث في منطقة الإعلام حظر بعض رسائل الحالة\nحظر رسائل \'الهويات في هذه الغرفة ليست مجهولة\' ‎%s‎ (لن تتلقَ رسائل من أي محادثة) حسابات XMPP\nإدارة الحسابات الأمان\nإعدادات الأمان تحقق من شهادة الخادم\nإخطار بمشاكل الشهادة على الاتصالات المشفرة وضع OTR + انتباه + الرد على طلبات الاهتمام الواردة + صوت الاشعار الاهتمام + إختر نغمة الرنين حمّل بطاقة vCard\nحمّل وحدّث البيانات الشخصية وصورة طرف الاتصال. عطّلها لتقليل استخدام بيانات الشبكة. تحميل صور\nتحميل الصور من رابط الملف تلقائياً. تعطيل للحد من استخدام بيانات الهاتف. وضع النسخة الكربونية\nقد تكون غير مستقرة!سوف تشارك المحادثات لنفس الحساب على هذا العميل. عطّلها لتقليل استخدام بيانات الشبكة. + Resolver + MiniDNSResolver (تجريبية) + عبارات مفتاحية + عبارات مفتاحية + إنشاء إعلامات مخصصة للرسائل المستلمة التي تحتوي على عبارات محددة + يجب اختيار تصفية واحدة على الأقل إعدادات + واجهة المستخدم + إعدادات + حول + المظهر العام + السلوك + قائمة جهات الاتصال + الجهات الغير متصلة + إعادة تعيين نغمة الاشعارات + إعدادات الاتصال + إعدادات متقدمة + التوافر: + إشعارات الرسائل + إشعارات المجموعات + الاشعارات داخل التطبيق + عبارات مفتاحية + إشعار مخصص + تنبية + تنبيه عن رسائل جديدة في الأحاديث + تنبية + تنبيه عن رسائل جديدة في الأحاديث + الافتراضي + اهتزاز قصيرة + الإهتزاز طويل + فقط في الوضع الصامت + أصوات في التطبيق + قراءة الأصوات في الرسالة في آخر محادثة + يهتز في التطبيق + قراءة الأصوات في الرسالة في آخر محادثة + معاينة داخل التطبيق + قراءة الأصوات في الرسالة في آخر محادثة + أصوات في المحادثه + قراءة الأصوات في الرسالة في آخر محادثة + إعادة تعيين + أن تعيين كافة الإخطار الإعدادات إلى الاعدادات القديمه + اعادة تعيين إعدادات الإشعارات + تم إعادة تعيين الإعدادات + إزالة كافة التخصيصات؟ + أن إزالة كافة إعدادات إعلام مخصصة (للاتصالات، قائمة بأسماء المجموعات والحسابات) diff --git a/xabber/src/main/res/values-ar-rSA/words.xml b/xabber/src/main/res/values-ar-rSA/words.xml index a8731cd86a..75748dd7b3 100644 --- a/xabber/src/main/res/values-ar-rSA/words.xml +++ b/xabber/src/main/res/values-ar-rSA/words.xml @@ -1,7 +1,7 @@ - بعد 10 دقائف + بعد 10 دقائق بعد 15 دقيقة بعد ساعة بعد دقيقة @@ -15,4 +15,17 @@ مطلوب آلياً حفظ + إلغاء + إزالة + تخطي + تخطي على أي حال + تحذير! + إعدادات + حسناً + تسجيل الدخول + مشاركة + الإرسال إلى + احصل عليه + بحث + مجاني From 77a67030c008100e2a70185274b58be45f1a00fd Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 13 May 2019 16:38:13 +0500 Subject: [PATCH 078/237] Added migration for messages to new archive system --- .../data/database/MessageDatabaseManager.java | 8 ++- .../data/extension/mam/NextMamManager.java | 53 ++++++++++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java b/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java index 5dd4c32166..3fa0a716ea 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java +++ b/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java @@ -323,7 +323,13 @@ public void apply(DynamicRealmObject obj) { if (oldVersion == 19) { schema.get(MessageItem.class.getSimpleName()) .addField(MessageItem.Fields.PREVIOUS_ID, String.class) - .addField(MessageItem.Fields.ARCHIVED_ID, String.class); + .addField(MessageItem.Fields.ARCHIVED_ID, String.class) + .transform(new RealmObjectSchema.Function() { + @Override + public void apply(DynamicRealmObject obj) { + obj.setString(MessageItem.Fields.PREVIOUS_ID, "legacy"); + } + }); oldVersion++; } diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index b42dffed54..c7634a4402 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -7,6 +7,7 @@ import com.xabber.android.data.database.messagerealm.Attachment; import com.xabber.android.data.database.messagerealm.ForwardId; import com.xabber.android.data.database.messagerealm.MessageItem; +import com.xabber.android.data.database.messagerealm.SyncInfo; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.entity.UserJid; import com.xabber.android.data.extension.file.FileManager; @@ -56,6 +57,7 @@ public class NextMamManager implements OnRosterReceivedListener { + private static final String LOG_TAG = NextMamManager.class.getSimpleName(); private static final long ALL_MESSAGE_LOAD_INTERVAL = 1800000; private static NextMamManager instance; @@ -84,6 +86,9 @@ public void onAccountConnected(AccountItem accountItem) { initializeStartTimestamp(accountItem); loadLastMessages(realm, accountItem); } else { + if (isNeedMigration(accountItem, realm)) { + runMigrationToNewArchive(accountItem, realm); + } if (isTimeToLoadAllNewMessages(accountItem, realm)) { loadAllNewMessages(realm, accountItem); } else loadLastMessages(realm, accountItem); @@ -209,6 +214,7 @@ private void loadLastMessages(Realm realm, AccountItem accountItem) { } private void loadLastMessage(Realm realm, AccountItem accountItem, AbstractChat chat) { + LogManager.d(LOG_TAG, "load last messages in chat: " + chat.getUser()); MamManager.MamQueryResult queryResult = requestLastMessage(accountItem, chat); if (queryResult != null) { List messages = new ArrayList<>(queryResult.forwardedMessages); @@ -232,6 +238,7 @@ private void loadAllNewMessages(Realm realm, AccountItem accountItem) { } private void loadNewMessages(Realm realm, AccountItem accountItem, AbstractChat chat) { + LogManager.d(LOG_TAG, "load new messages in chat: " + chat.getUser()); String lastArchivedId = getLastMessageArchivedId(chat, realm); if (lastArchivedId != null) { @@ -257,6 +264,7 @@ private void loadNewMessages(Realm realm, AccountItem accountItem, AbstractChat } private boolean loadNextHistory(Realm realm, AccountItem accountItem, AbstractChat chat) { + LogManager.d(LOG_TAG, "load next history in chat: " + chat.getUser()); MessageItem firstMessage = getFirstMessage(chat, realm); if (firstMessage != null) { if (firstMessage.getArchivedId().equals(firstMessage.getPreviousId())) { @@ -288,7 +296,7 @@ private boolean loadNextHistory(Realm realm, AccountItem accountItem, AbstractCh } private void loadMissedMessages(Realm realm, AccountItem accountItem, AbstractChat chat, MessageItem m1) { - + LogManager.d(LOG_TAG, "load missed messages in chat: " + chat.getUser()); MessageItem m2 = getMessageForCloseMissedMessages(realm, m1); if (m2 != null && !m2.getUniqueId().equals(m1.getUniqueId())) { Date startDate = new Date(m2.getTimestamp()); @@ -664,6 +672,14 @@ private boolean isTimeToLoadAllNewMessages(AccountItem account, Realm realm) { } else return false; } + private boolean isNeedMigration(AccountItem account, Realm realm) { + MessageItem result = realm.where(MessageItem.class) + .equalTo(MessageItem.Fields.ACCOUNT, account.getAccount().toString()) + .notEqualTo(MessageItem.Fields.PREVIOUS_ID, "legacy") + .findFirst(); + return result == null; + } + private boolean historyIsNotEnough(Realm realm, AbstractChat chat) { RealmResults results = realm.where(MessageItem.class) .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) @@ -700,6 +716,18 @@ private MessageItem getFirstMessage(AbstractChat chat, Realm realm) { } else return null; } + private MessageItem getFirstMessageForMigration(AbstractChat chat, Realm realm) { + RealmResults results = realm.where(MessageItem.class) + .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) + .equalTo(MessageItem.Fields.USER, chat.getUser().toString()) + .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) + .findAllSorted(MessageItem.Fields.TIMESTAMP, Sort.ASCENDING); + + if (results != null && !results.isEmpty()) { + return results.first(); + } else return null; + } + private long getLastMessageTimestamp(AccountItem account, Realm realm) { RealmResults results = realm.where(MessageItem.class) .equalTo(MessageItem.Fields.ACCOUNT, account.getAccount().toString()) @@ -726,4 +754,27 @@ private void updateLastMessageId(AbstractChat chat, Realm realm) { chat.setLastMessageId(id); } } + + private void runMigrationToNewArchive(AccountItem accountItem, Realm realm) { + LogManager.d(LOG_TAG, "run migration for account: " + accountItem.getAccount().toString()); + Collection contacts = RosterManager.getInstance() + .getAccountRosterContacts(accountItem.getAccount()); + + for (RosterContact contact : contacts) { + AbstractChat chat = MessageManager.getInstance() + .getOrCreateChat(contact.getAccount(), contact.getUser()); + + MessageItem firstMessage = getFirstMessageForMigration(chat, realm); + SyncInfo syncInfo = realm.where(SyncInfo.class) + .equalTo(SyncInfo.FIELD_ACCOUNT, accountItem.getAccount().toString()) + .equalTo(SyncInfo.FIELD_USER, chat.getUser().toString()).findFirst(); + + if (firstMessage != null && syncInfo != null) { + realm.beginTransaction(); + firstMessage.setArchivedId(syncInfo.getFirstMamMessageMamId()); + firstMessage.setPreviousId(null); + realm.commitTransaction(); + } + } + } } From 6bb3dabb8ce49403b30a433ea37d15efd9a150e8 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 13 May 2019 16:42:47 +0500 Subject: [PATCH 079/237] Removed disabling push on xmpp-server --- .../xabber/android/data/push/PushManager.java | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index ec46200746..0c6a1c2fa3 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -23,7 +23,6 @@ import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.tcp.XMPPTCPConnection; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; -import org.jivesoftware.smackx.push_notifications.element.DisablePushNotificationsIQ; import org.jivesoftware.smackx.push_notifications.element.EnablePushNotificationsIQ; import org.jivesoftware.smackx.push_notifications.element.PushNotificationsElements; import org.jxmpp.jid.EntityBareJid; @@ -140,9 +139,6 @@ public void enablePushNotificationsIfNeed(AccountItem accountItem) { public void disablePushNotification(AccountItem accountItem, boolean needConfirm) { if (accountItem != null) { deleteEndpoint(accountItem); - - if (accountItem.getConnection().isConnected()) - sendDisablePushIQ(accountItem, needConfirm); AccountManager.getInstance().setPushWasEnabled(accountItem, false); } } @@ -227,18 +223,4 @@ private void sendEnablePushIQ(final AccountItem accountItem, final String pushSe } } - private void sendDisablePushIQ(final AccountItem accountItem, boolean needConfirm) { - String stanzaID = null; - try { - DisablePushNotificationsIQ disableIQ = new DisablePushNotificationsIQ( - UserJid.from(accountItem.getPushServiceJid()).getJid(), accountItem.getPushNode()); - stanzaID = disableIQ.getStanzaId(); - if (needConfirm) waitingIQs.put(stanzaID, false); - accountItem.getConnection().sendStanza(disableIQ); - } catch (SmackException.NotConnectedException | InterruptedException | UserJid.UserJidCreateException e) { - Log.d(LOG_TAG, "Push notification enabling failed: " + e.toString()); - waitingIQs.remove(stanzaID); - } - } - } From d36d7b64cfe69b4aecd3f15ccb79bdf704872788 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 13 May 2019 17:39:20 +0500 Subject: [PATCH 080/237] Up version to 612 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index bcef6700d3..3c6ab4f0a2 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 611 - versionName '2.6.4(611)' + versionCode 612 + versionName '2.6.4(612)' } lintOptions { From 755daf69e30ac0e0e7575c8889e9b0c50f96b0a9 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 16 May 2019 15:38:02 +0500 Subject: [PATCH 081/237] Loading all new message from archive changed: Some request for each chat in loop replaced with one summary request --- .../data/extension/mam/NextMamManager.java | 116 +++++++++++++----- 1 file changed, 85 insertions(+), 31 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index c7634a4402..80b02bffa0 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -30,17 +30,22 @@ import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.tcp.XMPPTCPConnection; import org.jivesoftware.smack.util.PacketParserUtils; import org.jivesoftware.smackx.delay.packet.DelayInformation; import org.jivesoftware.smackx.forward.packet.Forwarded; import org.jivesoftware.smackx.mam.MamManager; import org.jivesoftware.smackx.mam.element.MamPrefsIQ; +import org.jxmpp.jid.Jid; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.Date; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -58,7 +63,7 @@ public class NextMamManager implements OnRosterReceivedListener { private static final String LOG_TAG = NextMamManager.class.getSimpleName(); - private static final long ALL_MESSAGE_LOAD_INTERVAL = 1800000; + private static final long ALL_MESSAGE_LOAD_INTERVAL = 24 * 60 * 60 * 1000; private static NextMamManager instance; @@ -218,7 +223,7 @@ private void loadLastMessage(Realm realm, AccountItem accountItem, AbstractChat MamManager.MamQueryResult queryResult = requestLastMessage(accountItem, chat); if (queryResult != null) { List messages = new ArrayList<>(queryResult.forwardedMessages); - saveOrUpdateMessages(realm, chat, parseMessage(accountItem, chat.getAccount(), chat.getUser(), messages, null)); + saveOrUpdateMessages(realm, parseMessage(accountItem, chat.getAccount(), chat.getUser(), messages, null)); } updateLastMessageId(chat, realm); } @@ -227,27 +232,17 @@ private void loadAllNewMessages(Realm realm, AccountItem accountItem) { if (accountItem.getLoadHistorySettings() != LoadHistorySettings.all || !isSupported(accountItem.getAccount())) return; - Collection contacts = RosterManager.getInstance() - .getAccountRosterContacts(accountItem.getAccount()); - - for (RosterContact contact : contacts) { - AbstractChat chat = MessageManager.getInstance() - .getOrCreateChat(contact.getAccount(), contact.getUser()); - loadNewMessages(realm, accountItem, chat); - } - } + LogManager.d(LOG_TAG, "load new messages"); + String lastArchivedId = getLastMessageArchivedId(accountItem, realm); - private void loadNewMessages(Realm realm, AccountItem accountItem, AbstractChat chat) { - LogManager.d(LOG_TAG, "load new messages in chat: " + chat.getUser()); - String lastArchivedId = getLastMessageArchivedId(chat, realm); if (lastArchivedId != null) { - List messages = new ArrayList<>(); boolean complete = false; - String id = lastArchivedId; + + // Request all new messages after last archived id while (!complete && id != null) { - MamManager.MamQueryResult queryResult = requestMessagesFromId(accountItem, chat, id); + MamManager.MamQueryResult queryResult = requestMessagesFromId(accountItem, null, id); if (queryResult != null) { messages.addAll(queryResult.forwardedMessages); complete = queryResult.mamFin.isComplete(); @@ -256,10 +251,65 @@ private void loadNewMessages(Realm realm, AccountItem accountItem, AbstractChat } if (!messages.isEmpty()) { - saveOrUpdateMessages(realm, chat, - parseMessage(accountItem, chat.getAccount(), chat.getUser(), messages, chat.getLastMessageId())); + HashMap> messagesByChat = new HashMap<>(); + List parsedMessages = new ArrayList<>(); + List chatsNeedUpdateLastMessageId = new ArrayList<>(); + + // Sort messages by chat to separate lists + for (Forwarded forwarded : messages) { + Stanza stanza = forwarded.getForwardedStanza(); + Jid user = stanza.getFrom().asBareJid(); + if (user.equals(accountItem.getAccount().getFullJid().asBareJid())) + user = stanza.getTo().asBareJid(); + + if (!messagesByChat.containsKey(user.toString())) { + messagesByChat.put(user.toString(), new ArrayList()); + } + ArrayList list = messagesByChat.get(user.toString()); + if (list != null) list.add(forwarded); + } + + // parse message lists + for (Map.Entry> entry : messagesByChat.entrySet()) { + ArrayList list = entry.getValue(); + if (list != null) { + try { + AbstractChat chat = MessageManager.getInstance() + .getOrCreateChat(accountItem.getAccount(), UserJid.from(entry.getKey())); + + // sort messages in list by timestamp + Collections.sort(list, new Comparator() { + @Override + public int compare(Forwarded o1, Forwarded o2) { + DelayInformation delayInformation1 = o1.getDelayInformation(); + long time1 = delayInformation1.getStamp().getTime(); + + DelayInformation delayInformation2 = o2.getDelayInformation(); + long time2 = delayInformation2.getStamp().getTime(); + + return Long.valueOf(time1).compareTo(time2); + } + }); + + // parse messages and set previous id + parsedMessages.addAll( + parseMessage(accountItem, accountItem.getAccount(), + chat.getUser(), list, chat.getLastMessageId())); + chatsNeedUpdateLastMessageId.add(chat); + + } catch (UserJid.UserJidCreateException e) { + LogManager.d(LOG_TAG, e.toString()); + continue; + } + } + } + + // save messages to Realm + saveOrUpdateMessages(realm, parsedMessages); + for (AbstractChat chat : chatsNeedUpdateLastMessageId) { + updateLastMessageId(chat, realm); + } } - updateLastMessageId(chat, realm); } } @@ -276,7 +326,7 @@ private boolean loadNextHistory(Realm realm, AccountItem accountItem, AbstractCh if (queryResult != null) { List messages = new ArrayList<>(queryResult.forwardedMessages); if (!messages.isEmpty()) { - List savedMessages = saveOrUpdateMessages(realm, chat, + List savedMessages = saveOrUpdateMessages(realm, parseMessage(accountItem, chat.getAccount(), chat.getUser(), messages, null)); if (savedMessages != null && !savedMessages.isEmpty()) { @@ -315,7 +365,7 @@ private void loadMissedMessages(Realm realm, AccountItem accountItem, AbstractCh } if (!messages.isEmpty()) { - List savedMessages = saveOrUpdateMessages(realm, chat, + List savedMessages = saveOrUpdateMessages(realm, parseMessage(accountItem, chat.getAccount(), chat.getUser(), messages, m2.getArchivedId())); if (savedMessages != null && !savedMessages.isEmpty()) { @@ -399,14 +449,16 @@ MamManager.MamQueryResult execute(MamManager manager) throws Exception { }); } - /** Request messages after archivedID from chat history */ + /** Request messages after archivedID from chat history + * Else request messages after archivedID from all history */ private @Nullable MamManager.MamQueryResult requestMessagesFromId( - @Nonnull AccountItem accountItem, @Nonnull final AbstractChat chat, final String archivedId) { + @Nonnull AccountItem accountItem, @Nullable final AbstractChat chat, final String archivedId) { return requestToMessageArchive(accountItem, new MamRequest() { @Override MamManager.MamQueryResult execute(MamManager manager) throws Exception { - return manager.pageAfter(chat.getUser().getJid(), archivedId, 50); + if (chat != null) return manager.pageAfter(chat.getUser().getJid(), archivedId, 50); + else return manager.pageAfter(null, archivedId, 50); } }); } @@ -549,12 +601,12 @@ private List parseMessage(AccountItem accountItem, AccountJid accou /** SAVING */ - private List saveOrUpdateMessages(Realm realm, AbstractChat chat, final Collection messages) { + private List saveOrUpdateMessages(Realm realm, final Collection messages) { List messagesToSave = new ArrayList<>(); if (messages != null && !messages.isEmpty()) { Iterator iterator = messages.iterator(); while (iterator.hasNext()) { - MessageItem newMessage = determineSaveOrUpdate(realm, chat, iterator.next()); + MessageItem newMessage = determineSaveOrUpdate(realm, iterator.next()); if (newMessage != null) messagesToSave.add(newMessage); } } @@ -565,7 +617,7 @@ private List saveOrUpdateMessages(Realm realm, AbstractChat chat, f return messagesToSave; } - private MessageItem determineSaveOrUpdate(Realm realm, AbstractChat chat, final MessageItem message) { + private MessageItem determineSaveOrUpdate(Realm realm, final MessageItem message) { // set text from comment to text in message for prevent doubling messages from MAM Message originalMessage = null; try { @@ -576,6 +628,9 @@ private MessageItem determineSaveOrUpdate(Realm realm, AbstractChat chat, final e.printStackTrace(); } + AbstractChat chat = MessageManager.getInstance().getOrCreateChat(message.getAccount(), message.getUser()); + if (chat == null) return null; + MessageItem localMessage = realm.where(MessageItem.class) .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) .equalTo(MessageItem.Fields.USER, chat.getUser().toString()) @@ -689,10 +744,9 @@ private boolean historyIsNotEnough(Realm realm, AbstractChat chat) { return results.size() < 30; } - private String getLastMessageArchivedId(AbstractChat chat, Realm realm) { + private String getLastMessageArchivedId(AccountItem account, Realm realm) { RealmResults results = realm.where(MessageItem.class) - .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) - .equalTo(MessageItem.Fields.USER, chat.getUser().toString()) + .equalTo(MessageItem.Fields.ACCOUNT, account.getAccount().toString()) .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) .isNotNull(MessageItem.Fields.ARCHIVED_ID) .findAllSorted(MessageItem.Fields.TIMESTAMP, Sort.ASCENDING); From 9a787b402c9fe97d6252a944132bf0fa9fa449bf Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 16 May 2019 16:48:27 +0500 Subject: [PATCH 082/237] Changes in push enabling --- .../com/xabber/android/data/push/PushManager.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index 0c6a1c2fa3..5fdc33ffc5 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -1,6 +1,8 @@ package com.xabber.android.data.push; +import android.annotation.SuppressLint; import android.content.Context; +import android.provider.Settings; import android.util.Log; import com.google.firebase.iid.FirebaseInstanceId; @@ -76,7 +78,7 @@ public void onEndpointRegistered(String jid, String pushServiceJid, String node) AccountJid accountJid = null; Collection accounts = AccountManager.getInstance().getEnabledAccounts(); for (AccountJid account : accounts) { - if (account.getFullJid().asBareJid().equals(jid)) { + if ((account.getFullJid().asBareJid() + getAndroidId()).equals(jid)) { accountJid = account; break; } @@ -173,7 +175,8 @@ public boolean isSupport(XMPPTCPConnection connection) { private void registerEndpoint(AccountJid accountJid) { compositeSubscription.add( PushApiClient.registerEndpoint( - FirebaseInstanceId.getInstance().getToken(), accountJid.toString()) + FirebaseInstanceId.getInstance().getToken(), + accountJid.getFullJid().asBareJid().toString() + getAndroidId()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1() { @@ -223,4 +226,10 @@ private void sendEnablePushIQ(final AccountItem accountItem, final String pushSe } } + @SuppressLint("HardwareIds") + private static String getAndroidId() { + return "/" + Settings.Secure.getString(Application.getInstance().getContentResolver(), + Settings.Secure.ANDROID_ID); + } + } From f91e46cf3d6cd39ecd580450fd51492610d4051a Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 16 May 2019 18:54:34 +0500 Subject: [PATCH 083/237] Changed algorithm of loading messages at start --- .../data/extension/mam/NextMamManager.java | 156 ++++++++---------- 1 file changed, 72 insertions(+), 84 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index 80b02bffa0..dc668b2578 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -63,7 +63,6 @@ public class NextMamManager implements OnRosterReceivedListener { private static final String LOG_TAG = NextMamManager.class.getSimpleName(); - private static final long ALL_MESSAGE_LOAD_INTERVAL = 24 * 60 * 60 * 1000; private static NextMamManager instance; @@ -94,8 +93,10 @@ public void onAccountConnected(AccountItem accountItem) { if (isNeedMigration(accountItem, realm)) { runMigrationToNewArchive(accountItem, realm); } - if (isTimeToLoadAllNewMessages(accountItem, realm)) { - loadAllNewMessages(realm, accountItem); + String lastArchivedId = getLastMessageArchivedId(accountItem, realm); + if (lastArchivedId != null) { + boolean historyCompleted = loadAllNewMessages(realm, accountItem, lastArchivedId); + if (!historyCompleted) loadLastMessages(realm, accountItem); } else loadLastMessages(realm, accountItem); } realm.close(); @@ -228,89 +229,87 @@ private void loadLastMessage(Realm realm, AccountItem accountItem, AbstractChat updateLastMessageId(chat, realm); } - private void loadAllNewMessages(Realm realm, AccountItem accountItem) { + private boolean loadAllNewMessages(Realm realm, AccountItem accountItem, String lastArchivedId) { if (accountItem.getLoadHistorySettings() != LoadHistorySettings.all - || !isSupported(accountItem.getAccount())) return; + || !isSupported(accountItem.getAccount())) return true; LogManager.d(LOG_TAG, "load new messages"); - String lastArchivedId = getLastMessageArchivedId(accountItem, realm); + List messages = new ArrayList<>(); + boolean complete = false; + String id = lastArchivedId; + int pageLoaded = 0; + // Request all new messages after last archived id + while (!complete && id != null && pageLoaded < 2) { + MamManager.MamQueryResult queryResult = requestMessagesFromId(accountItem, null, id); + if (queryResult != null) { + messages.addAll(queryResult.forwardedMessages); + complete = queryResult.mamFin.isComplete(); + id = getNextId(queryResult); + pageLoaded++; + } else complete = true; + } - if (lastArchivedId != null) { - List messages = new ArrayList<>(); - boolean complete = false; - String id = lastArchivedId; + if (!messages.isEmpty()) { + HashMap> messagesByChat = new HashMap<>(); + List parsedMessages = new ArrayList<>(); + List chatsNeedUpdateLastMessageId = new ArrayList<>(); - // Request all new messages after last archived id - while (!complete && id != null) { - MamManager.MamQueryResult queryResult = requestMessagesFromId(accountItem, null, id); - if (queryResult != null) { - messages.addAll(queryResult.forwardedMessages); - complete = queryResult.mamFin.isComplete(); - id = getNextId(queryResult); - } else complete = true; - } + // Sort messages by chat to separate lists + for (Forwarded forwarded : messages) { + Stanza stanza = forwarded.getForwardedStanza(); + Jid user = stanza.getFrom().asBareJid(); + if (user.equals(accountItem.getAccount().getFullJid().asBareJid())) + user = stanza.getTo().asBareJid(); - if (!messages.isEmpty()) { - HashMap> messagesByChat = new HashMap<>(); - List parsedMessages = new ArrayList<>(); - List chatsNeedUpdateLastMessageId = new ArrayList<>(); - - // Sort messages by chat to separate lists - for (Forwarded forwarded : messages) { - Stanza stanza = forwarded.getForwardedStanza(); - Jid user = stanza.getFrom().asBareJid(); - if (user.equals(accountItem.getAccount().getFullJid().asBareJid())) - user = stanza.getTo().asBareJid(); - - if (!messagesByChat.containsKey(user.toString())) { - messagesByChat.put(user.toString(), new ArrayList()); - } - ArrayList list = messagesByChat.get(user.toString()); - if (list != null) list.add(forwarded); + if (!messagesByChat.containsKey(user.toString())) { + messagesByChat.put(user.toString(), new ArrayList()); } + ArrayList list = messagesByChat.get(user.toString()); + if (list != null) list.add(forwarded); + } - // parse message lists - for (Map.Entry> entry : messagesByChat.entrySet()) { - ArrayList list = entry.getValue(); - if (list != null) { - try { - AbstractChat chat = MessageManager.getInstance() - .getOrCreateChat(accountItem.getAccount(), UserJid.from(entry.getKey())); - - // sort messages in list by timestamp - Collections.sort(list, new Comparator() { - @Override - public int compare(Forwarded o1, Forwarded o2) { - DelayInformation delayInformation1 = o1.getDelayInformation(); - long time1 = delayInformation1.getStamp().getTime(); - - DelayInformation delayInformation2 = o2.getDelayInformation(); - long time2 = delayInformation2.getStamp().getTime(); - - return Long.valueOf(time1).compareTo(time2); - } - }); - - // parse messages and set previous id - parsedMessages.addAll( - parseMessage(accountItem, accountItem.getAccount(), - chat.getUser(), list, chat.getLastMessageId())); - chatsNeedUpdateLastMessageId.add(chat); - - } catch (UserJid.UserJidCreateException e) { - LogManager.d(LOG_TAG, e.toString()); - continue; - } + // parse message lists + for (Map.Entry> entry : messagesByChat.entrySet()) { + ArrayList list = entry.getValue(); + if (list != null) { + try { + AbstractChat chat = MessageManager.getInstance() + .getOrCreateChat(accountItem.getAccount(), UserJid.from(entry.getKey())); + + // sort messages in list by timestamp + Collections.sort(list, new Comparator() { + @Override + public int compare(Forwarded o1, Forwarded o2) { + DelayInformation delayInformation1 = o1.getDelayInformation(); + long time1 = delayInformation1.getStamp().getTime(); + + DelayInformation delayInformation2 = o2.getDelayInformation(); + long time2 = delayInformation2.getStamp().getTime(); + + return Long.valueOf(time1).compareTo(time2); + } + }); + + // parse messages and set previous id + parsedMessages.addAll( + parseMessage(accountItem, accountItem.getAccount(), + chat.getUser(), list, chat.getLastMessageId())); + chatsNeedUpdateLastMessageId.add(chat); + + } catch (UserJid.UserJidCreateException e) { + LogManager.d(LOG_TAG, e.toString()); + continue; } } + } - // save messages to Realm - saveOrUpdateMessages(realm, parsedMessages); - for (AbstractChat chat : chatsNeedUpdateLastMessageId) { - updateLastMessageId(chat, realm); - } + // save messages to Realm + saveOrUpdateMessages(realm, parsedMessages); + for (AbstractChat chat : chatsNeedUpdateLastMessageId) { + updateLastMessageId(chat, realm); } } + return complete; } private boolean loadNextHistory(Realm realm, AccountItem accountItem, AbstractChat chat) { @@ -716,17 +715,6 @@ private MessageItem getMessageForCloseMissedMessages(Realm realm, MessageItem me } else return null; } - private boolean isTimeToLoadAllNewMessages(AccountItem account, Realm realm) { - RealmResults results = realm.where(MessageItem.class) - .equalTo(MessageItem.Fields.ACCOUNT, account.getAccount().toString()) - .findAllSorted(MessageItem.Fields.TIMESTAMP, Sort.ASCENDING); - - if (results != null && !results.isEmpty()) { - MessageItem lastMessage = results.last(); - return System.currentTimeMillis() < lastMessage.getTimestamp() + ALL_MESSAGE_LOAD_INTERVAL; - } else return false; - } - private boolean isNeedMigration(AccountItem account, Realm realm) { MessageItem result = realm.where(MessageItem.class) .equalTo(MessageItem.Fields.ACCOUNT, account.getAccount().toString()) From 135fe897a2f50cd06f793e4078bab84804d47a80 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 16 May 2019 19:21:12 +0500 Subject: [PATCH 084/237] Up version to 613 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 3c6ab4f0a2..1f6fe3386d 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 612 - versionName '2.6.4(612)' + versionCode 613 + versionName '2.6.4(613)' } lintOptions { From da642e0b6e271f92a838460dc150831af87aa51b Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 17 May 2019 14:26:42 +0500 Subject: [PATCH 085/237] Added async request for recent messages in chat --- .../data/extension/mam/NextMamManager.java | 112 ++++++++++++++++-- 1 file changed, 103 insertions(+), 9 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index dc668b2578..1b41ece63e 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -3,6 +3,8 @@ import com.xabber.android.data.Application; import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.account.AccountManager; +import com.xabber.android.data.connection.ConnectionItem; +import com.xabber.android.data.connection.listeners.OnPacketListener; import com.xabber.android.data.database.MessageDatabaseManager; import com.xabber.android.data.database.messagerealm.Attachment; import com.xabber.android.data.database.messagerealm.ForwardId; @@ -29,6 +31,8 @@ import org.greenrobot.eventbus.EventBus; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.packet.ExtensionElement; +import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.tcp.XMPPTCPConnection; @@ -36,7 +40,12 @@ import org.jivesoftware.smackx.delay.packet.DelayInformation; import org.jivesoftware.smackx.forward.packet.Forwarded; import org.jivesoftware.smackx.mam.MamManager; +import org.jivesoftware.smackx.mam.element.MamElements; import org.jivesoftware.smackx.mam.element.MamPrefsIQ; +import org.jivesoftware.smackx.mam.element.MamQueryIQ; +import org.jivesoftware.smackx.rsm.packet.RSMSet; +import org.jivesoftware.smackx.xdata.FormField; +import org.jivesoftware.smackx.xdata.packet.DataForm; import org.jxmpp.jid.Jid; import java.io.IOException; @@ -46,9 +55,11 @@ import java.util.Comparator; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -60,7 +71,7 @@ import io.realm.RealmResults; import io.realm.Sort; -public class NextMamManager implements OnRosterReceivedListener { +public class NextMamManager implements OnRosterReceivedListener, OnPacketListener { private static final String LOG_TAG = NextMamManager.class.getSimpleName(); @@ -69,6 +80,7 @@ public class NextMamManager implements OnRosterReceivedListener { private Map supportedByAccount = new ConcurrentHashMap<>(); private boolean isRequested = false; private final Object lock = new Object(); + private Set waitingRequests = new HashSet<>(); public static NextMamManager getInstance() { if (instance == null) @@ -88,7 +100,7 @@ public void onAccountConnected(AccountItem accountItem) { accountItem.setStartHistoryTimestamp(getLastMessageTimestamp(accountItem, realm)); if (accountItem.getStartHistoryTimestamp() == 0) { initializeStartTimestamp(accountItem); - loadLastMessages(realm, accountItem); + loadLastMessagesAsync(accountItem); } else { if (isNeedMigration(accountItem, realm)) { runMigrationToNewArchive(accountItem, realm); @@ -96,8 +108,8 @@ public void onAccountConnected(AccountItem accountItem) { String lastArchivedId = getLastMessageArchivedId(accountItem, realm); if (lastArchivedId != null) { boolean historyCompleted = loadAllNewMessages(realm, accountItem, lastArchivedId); - if (!historyCompleted) loadLastMessages(realm, accountItem); - } else loadLastMessages(realm, accountItem); + if (!historyCompleted) loadLastMessagesAsync(accountItem); + } else loadLastMessagesAsync(accountItem); } realm.close(); } @@ -197,6 +209,23 @@ public void run() { }); } + @Override + public void onStanza(ConnectionItem connection, Stanza packet) { + if (packet instanceof Message) { + for (ExtensionElement packetExtension : packet.getExtensions()) { + if (packetExtension instanceof MamElements.MamResultExtension) { + MamElements.MamResultExtension resultExtension = + (MamElements.MamResultExtension) packetExtension; + String resultID = resultExtension.getQueryId(); + if (waitingRequests.contains(resultID)) { + parseAndSaveMessageFromMamResult(connection.getAccount(), resultExtension); + waitingRequests.remove(resultID); + } + } + } + } + } + public boolean isSupported(AccountJid accountJid) { Boolean isSupported = supportedByAccount.get(accountJid); if (isSupported != null) return isSupported; @@ -205,17 +234,18 @@ public boolean isSupported(AccountJid accountJid) { /** MAIN */ - private void loadLastMessages(Realm realm, AccountItem accountItem) { + private void loadLastMessagesAsync(AccountItem accountItem) { if (accountItem.getLoadHistorySettings() != LoadHistorySettings.all || !isSupported(accountItem.getAccount())) return; + LogManager.d(LOG_TAG, "load last messages in each chat"); Collection contacts = RosterManager.getInstance() .getAccountRosterContacts(accountItem.getAccount()); for (RosterContact contact : contacts) { AbstractChat chat = MessageManager.getInstance() .getOrCreateChat(contact.getAccount(), contact.getUser()); - loadLastMessage(realm, accountItem, chat); + requestLastMessageAsync(accountItem, chat); } } @@ -448,6 +478,29 @@ MamManager.MamQueryResult execute(MamManager manager) throws Exception { }); } + /** Send async request for recent message from chat history */ + private void requestLastMessageAsync(@Nonnull final AccountItem accountItem, @Nonnull final AbstractChat chat) { + requestToMessageArchive(accountItem, new MamRequest() { + @Override + MamManager.MamQueryResult execute(MamManager manager) throws Exception { + // add request id to waiting list + String queryID = UUID.randomUUID().toString(); + waitingRequests.add(queryID); + + // send request stanza + RSMSet rsmSet = new RSMSet(null, "", -1, -1, null, 1, null, -1); + DataForm dataForm = getNewMamForm(); + addWithJid(chat.getUser().getJid(), dataForm); + MamQueryIQ mamQueryIQ = new MamQueryIQ(queryID, null, dataForm); + mamQueryIQ.setType(IQ.Type.set); + mamQueryIQ.setTo((Jid) null); + mamQueryIQ.addExtension(rsmSet); + accountItem.getConnection().sendStanza(mamQueryIQ); + return null; + } + }); + } + /** Request messages after archivedID from chat history * Else request messages after archivedID from all history */ private @Nullable MamManager.MamQueryResult requestMessagesFromId( @@ -509,6 +562,27 @@ MamManager.MamPrefsResult execute(MamManager manager) throws Exception { /** PARSING */ + private void parseAndSaveMessageFromMamResult(AccountJid account, MamElements.MamResultExtension resultExtension) { + Forwarded forwarded = resultExtension.getForwarded(); + Stanza stanza = forwarded.getForwardedStanza(); + AccountItem accountItem = AccountManager.getInstance().getAccount(account); + Jid user = stanza.getFrom().asBareJid(); + if (user.equals(account.getFullJid().asBareJid())) + user = stanza.getTo().asBareJid(); + + try { + AbstractChat chat = MessageManager.getInstance().getOrCreateChat(account, UserJid.from(user)); + MessageItem messageItem = parseMessage(accountItem, account, chat.getUser(), forwarded, null); + if (messageItem != null) { + Realm realm = MessageDatabaseManager.getInstance().getRealmUiThread(); + saveOrUpdateMessages(realm, Collections.singletonList(messageItem), true); + updateLastMessageId(chat, realm); + } + } catch (UserJid.UserJidCreateException e) { + LogManager.d(LOG_TAG, e.toString()); + } + } + private List parseMessage(AccountItem accountItem, AccountJid account, UserJid user, List forwardedMessages, String prevID) { List messageItems = new ArrayList<>(); @@ -601,11 +675,15 @@ private List parseMessage(AccountItem accountItem, AccountJid accou /** SAVING */ private List saveOrUpdateMessages(Realm realm, final Collection messages) { + return saveOrUpdateMessages(realm, messages, false); + } + + private List saveOrUpdateMessages(Realm realm, final Collection messages, boolean ui) { List messagesToSave = new ArrayList<>(); if (messages != null && !messages.isEmpty()) { Iterator iterator = messages.iterator(); while (iterator.hasNext()) { - MessageItem newMessage = determineSaveOrUpdate(realm, iterator.next()); + MessageItem newMessage = determineSaveOrUpdate(realm, iterator.next(), ui); if (newMessage != null) messagesToSave.add(newMessage); } } @@ -616,7 +694,7 @@ private List saveOrUpdateMessages(Realm realm, final Collection forwardIds = chat.parseForwardedMessage(false, originalMessage, message.getUniqueId()); + RealmList forwardIds = chat.parseForwardedMessage(ui, originalMessage, message.getUniqueId()); if (forwardIds != null && !forwardIds.isEmpty()) message.setForwardedIds(forwardIds); } @@ -668,6 +746,22 @@ private MessageItem determineSaveOrUpdate(Realm realm, final MessageItem message /** UTILS */ + private static DataForm getNewMamForm() { + FormField field = new FormField(FormField.FORM_TYPE); + field.setType(FormField.Type.hidden); + field.addValue(MamElements.NAMESPACE); + DataForm form = new DataForm(DataForm.Type.submit); + form.addField(field); + return form; + } + + private static void addWithJid(Jid withJid, DataForm dataForm) { + if (withJid == null) return; + FormField formField = new FormField("with"); + formField.addValue(withJid.toString()); + dataForm.addField(formField); + } + private String getNextId(MamManager.MamQueryResult queryResult) { String archivedId = null; if (queryResult.forwardedMessages != null && !queryResult.forwardedMessages.isEmpty()) { From ce6370330a76abcf5096ee58770dbb212e2bfd80 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 21 May 2019 14:28:22 +0500 Subject: [PATCH 086/237] Fixed delayed notification action from push --- .../data/notification/MessageNotificationManager.java | 2 -- .../com/xabber/android/data/push/SyncManager.java | 11 +++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java index 95e7dd7752..0c3fbdca99 100644 --- a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java +++ b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java @@ -20,7 +20,6 @@ import com.xabber.android.data.message.AbstractChat; import com.xabber.android.data.message.MessageManager; import com.xabber.android.data.message.NotificationState; -import com.xabber.android.data.push.SyncManager; import com.xabber.android.data.roster.OnContactChangedListener; import com.xabber.android.data.roster.RosterContact; import com.xabber.android.data.roster.RosterManager; @@ -219,7 +218,6 @@ public void performAction(FullAction action) { case reply: MessageManager.getInstance().sendMessage(accountJid, userJid, action.getReplyText().toString()); } - SyncManager.getInstance().onDelayedNotificationActionDone(); } private void onLoaded(List loadedChats) { diff --git a/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java b/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java index b8d89ae07b..1188acec62 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/SyncManager.java @@ -23,6 +23,7 @@ public class SyncManager implements OnTimerListener { private boolean syncMode; private boolean syncPeriod; private boolean syncActionDone; + private boolean syncNotifActionDone; private long timestamp; private List pushNodes = new ArrayList<>(); @@ -46,10 +47,6 @@ public void onMessageSaved() { this.syncActionDone = true; } - public void onDelayedNotificationActionDone() { - this.syncActionDone = true; - } - public void onServiceStarted(Intent intent) { if (intent != null && intent.getBooleanExtra(SYNC_MODE, false)) { if (intent.hasExtra(PUSH_NODE)) startSyncMode(intent.getStringExtra(PUSH_NODE)); @@ -110,6 +107,7 @@ private void startSyncMode(String pushNode) { this.pushNodes.add(pushNode); this.syncPeriod = true; this.syncActionDone = false; + this.syncNotifActionDone = true; } private void startSyncMode(AccountJid accountJid) { @@ -118,7 +116,8 @@ private void startSyncMode(AccountJid accountJid) { if (this.accountJids != null && !this.accountJids.contains(accountJid)) this.accountJids.add(accountJid); this.syncPeriod = true; - this.syncActionDone = false; + this.syncActionDone = true; + this.syncNotifActionDone = false; } private void stopSyncMode() { @@ -133,6 +132,6 @@ private void stopSyncPeriod() { } private boolean isTimeToStopSyncPeriod() { - return syncActionDone || System.currentTimeMillis() > timestamp + SYNC_TIME; + return (syncActionDone && syncNotifActionDone) || System.currentTimeMillis() > timestamp + SYNC_TIME; } } From 0dbe4e684782e6584b20d80ee7107b9a231d0cac Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 21 May 2019 15:12:06 +0500 Subject: [PATCH 087/237] Fixed synchronization message archive --- .../android/data/extension/mam/NextMamManager.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index 1b41ece63e..cd199dadb5 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -586,13 +586,26 @@ private void parseAndSaveMessageFromMamResult(AccountJid account, MamElements.Ma private List parseMessage(AccountItem accountItem, AccountJid account, UserJid user, List forwardedMessages, String prevID) { List messageItems = new ArrayList<>(); + String lastOutgoingId = null; for (Forwarded forwarded : forwardedMessages) { MessageItem message = parseMessage(accountItem, account, user, forwarded, prevID); if (message != null) { messageItems.add(message); prevID = message.getArchivedId(); + if (!message.isIncoming()) lastOutgoingId = message.getUniqueId(); } } + + // mark messages before outgoing as read + if (lastOutgoingId != null) { + for (MessageItem message : messageItems) { + if (lastOutgoingId.equals(message.getUniqueId())) { + break; + } + message.setRead(true); + } + } + return messageItems; } From 981c2fc098e558a293dc14cce5fca0926d4497a0 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 22 May 2019 14:08:48 +0500 Subject: [PATCH 088/237] Changed app start process --- .../main/java/com/xabber/android/data/ActivityManager.java | 5 +++-- .../com/xabber/android/data/account/AccountManager.java | 6 ++++++ .../com/xabber/android/ui/activity/ContactListActivity.java | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/ActivityManager.java b/xabber/src/main/java/com/xabber/android/data/ActivityManager.java index 915f1d61e3..cc3f20e48f 100644 --- a/xabber/src/main/java/com/xabber/android/data/ActivityManager.java +++ b/xabber/src/main/java/com/xabber/android/data/ActivityManager.java @@ -25,6 +25,7 @@ import com.xabber.android.data.connection.CertificateManager; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.push.SyncManager; +import com.xabber.android.service.XabberService; import com.xabber.android.ui.activity.AboutActivity; import com.xabber.android.ui.activity.ContactListActivity; import com.xabber.android.ui.activity.LoadActivity; @@ -202,11 +203,11 @@ public void onResume(final Activity activity) { if (LOG) { LogManager.i(activity, "onResume"); } - if (!application.isInitialized() && !(activity instanceof LoadActivity)) { + if (!application.isInitialized() && !Application.getInstance().isClosing()) { if (LOG) { LogManager.i(this, "Wait for loading"); } - activity.startActivity(LoadActivity.createIntent(activity)); + activity.startService(XabberService.createIntent(activity)); } if (onErrorListener != null) { application.removeUIListener(OnErrorListener.class, onErrorListener); diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java index 80b2f9d772..d0bda16e65 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java @@ -718,6 +718,12 @@ public boolean hasAccounts() { return !accountItems.isEmpty(); } + public boolean checkAccounts() { + Realm realm = RealmManager.getInstance().getRealmUiThread(); + RealmResults accountRealms = realm.where(AccountRealm.class).findAll(); + return !accountRealms.isEmpty(); + } + /** * @return List of all accounts including disabled. */ diff --git a/xabber/src/main/java/com/xabber/android/ui/activity/ContactListActivity.java b/xabber/src/main/java/com/xabber/android/ui/activity/ContactListActivity.java index f3e5ed6700..829077cfb4 100644 --- a/xabber/src/main/java/com/xabber/android/ui/activity/ContactListActivity.java +++ b/xabber/src/main/java/com/xabber/android/ui/activity/ContactListActivity.java @@ -329,7 +329,7 @@ private void openChat(BaseEntity entity, String text) { protected void onResume() { super.onResume(); - if (!AccountManager.getInstance().hasAccounts() && XabberAccountManager.getInstance().getAccount() == null) { + if (!AccountManager.getInstance().checkAccounts() && XabberAccountManager.getInstance().getAccount() == null) { startActivity(TutorialActivity.createIntent(this)); finish(); return; From 9c00838d87bb79867db5aaff7240244bdabc8b33 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 27 May 2019 16:49:10 +0500 Subject: [PATCH 089/237] Changed refresh interval in contact list update backpressure --- .../presentation/mvp/contactlist/UpdateBackpressure.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/presentation/mvp/contactlist/UpdateBackpressure.java b/xabber/src/main/java/com/xabber/android/presentation/mvp/contactlist/UpdateBackpressure.java index 3615b2f6ab..96ad6e433e 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/mvp/contactlist/UpdateBackpressure.java +++ b/xabber/src/main/java/com/xabber/android/presentation/mvp/contactlist/UpdateBackpressure.java @@ -10,7 +10,7 @@ public class UpdateBackpressure implements Runnable { - private static final long REFRESH_INTERVAL = 1000; + private static final long REFRESH_INTERVAL = 50; public interface UpdatableObject { void update(); From 681fec4ded818de7044d8a67298a5ebf0bc180ad Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 27 May 2019 16:49:48 +0500 Subject: [PATCH 090/237] Some changes in contact list presenter --- .../mvp/contactlist/ContactListPresenter.java | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/presentation/mvp/contactlist/ContactListPresenter.java b/xabber/src/main/java/com/xabber/android/presentation/mvp/contactlist/ContactListPresenter.java index c2dfe3e619..14adf027e9 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/mvp/contactlist/ContactListPresenter.java +++ b/xabber/src/main/java/com/xabber/android/presentation/mvp/contactlist/ContactListPresenter.java @@ -6,7 +6,6 @@ import com.xabber.android.R; import com.xabber.android.data.Application; import com.xabber.android.data.SettingsManager; -import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.account.AccountManager; import com.xabber.android.data.account.CommonState; import com.xabber.android.data.account.listeners.OnAccountChangedListener; @@ -235,7 +234,7 @@ public void update() { if (!blockedUsers.contains(contact.getUser())) rosterContacts.add(contact); } else rosterContacts.add(contact); - } + } else rosterContacts.add(contact); } final boolean showOffline = SettingsManager.contactsShowOffline(); @@ -323,6 +322,7 @@ public void update() { // chats on top Collection chats = MessageManager.getInstance().getChatsOfEnabledAccount(); chatsGroup = getChatsGroup(chats, currentChatsState); + if (!chatsGroup.isEmpty()) hasVisibleContacts = true; // Build structure. for (RosterContact rosterContact : rosterContacts) { @@ -473,24 +473,19 @@ private GroupConfiguration getChatsGroup(Collection chats, ChatLis for (AbstractChat abstractChat : chats) { MessageItem lastMessage = abstractChat.getLastMessage(); - if (lastMessage != null) { - AccountItem accountItem = AccountManager.getInstance().getAccount(abstractChat.getAccount()); - if (accountItem != null && accountItem.isEnabled()) { - - switch (state) { - case unread: - if (!abstractChat.isArchived() && abstractChat.getUnreadMessageCount() > 0) - newChats.add(abstractChat); - break; - case archived: - if (abstractChat.isArchived()) newChats.add(abstractChat); - break; - default: - // recent - if (!abstractChat.isArchived()) newChats.add(abstractChat); - break; - } + switch (state) { + case unread: + if (!abstractChat.isArchived() && abstractChat.getUnreadMessageCount() > 0) + newChats.add(abstractChat); + break; + case archived: + if (abstractChat.isArchived()) newChats.add(abstractChat); + break; + default: + // recent + if (!abstractChat.isArchived()) newChats.add(abstractChat); + break; } } } From 2747842c04f96c308a3e5167d2333d9bc6894dbd Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 27 May 2019 16:51:53 +0500 Subject: [PATCH 091/237] Added cached enabled account jids --- .../android/data/account/AccountManager.java | 44 +++++++++++++++++++ .../android/data/message/AbstractChat.java | 24 ++++------ .../android/data/message/MessageManager.java | 14 +++++- 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java index d0bda16e65..046756d32d 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java @@ -107,6 +107,7 @@ public class AccountManager implements OnLoadListener, OnUnloadListener, OnWipeL * List of accounts. */ private final Map accountItems; + private final List cachedEnabledAccounts; private final BaseAccountNotificationProvider accountErrorProvider; private final Application application; @@ -131,6 +132,7 @@ private AccountManager() { this.application = Application.getInstance(); accountItems = new HashMap<>(); savedStatuses = new ArrayList<>(); + cachedEnabledAccounts = new ArrayList<>(); accountErrorProvider = new BaseAccountNotificationProvider<>(R.drawable.ic_stat_error); colors = application.getResources().getIntArray(R.array.account_color_names).length; @@ -139,6 +141,44 @@ private AccountManager() { xa = false; } + public void onPreInitialize() { + Realm realm = RealmManager.getInstance().getRealmUiThread(); + RealmResults accountRealms = realm.where(AccountRealm.class).findAll(); + + for (AccountRealm accountRealm : accountRealms) { + DomainBareJid serverName = null; + try { + serverName = JidCreate.domainBareFrom(accountRealm.getServerName()); + } catch (XmppStringprepException e) { + LogManager.exception(this, e); + } + + Localpart userName = null; + try { + userName = Localpart.from(accountRealm.getUserName()); + } catch (XmppStringprepException e) { + LogManager.exception(this, e); + } + + Resourcepart resource = null; + try { + resource = Resourcepart.from(accountRealm.getResource()); + } catch (XmppStringprepException e) { + LogManager.exception(this, e); + } + + if (serverName == null || userName == null || resource == null) { + LogManager.e(LOG_TAG, "could not create account. username " + userName + + ", server name " + serverName + + ", resource " + resource); + continue; + } + + if (accountRealm.isEnabled()) + cachedEnabledAccounts.add(AccountJid.from(userName, serverName, resource)); + } + } + @Override public void onLoad() { final Collection savedStatuses = loadSavedStatuses(); @@ -714,6 +754,10 @@ public Collection getEnabledAccounts() { return Collections.unmodifiableCollection(enabledAccounts); } + public Collection getCachedEnabledAccounts() { + return Collections.unmodifiableCollection(cachedEnabledAccounts); + } + public boolean hasAccounts() { return !accountItems.isEmpty(); } diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index aa9cddb221..818f5ae68f 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -510,22 +510,16 @@ public synchronized MessageItem getLastMessage() { return lastMessage; } + public void setLastMessage(MessageItem lastMessage) { + this.lastMessage = lastMessage; + } + private void updateLastMessage() { - if (messages.isValid() && messages.isLoaded() && !messages.isEmpty()) { - List textMessages = MessageDatabaseManager.getInstance() - .getRealmUiThread() - .copyFromRealm(messages.where().isNull(MessageItem.Fields.ACTION) - .or().equalTo(MessageItem.Fields.ACTION, ChatAction.available.toString()).findAll()); - - if (!textMessages.isEmpty()) - lastMessage = textMessages.get(textMessages.size() - 1); - else - lastMessage = MessageDatabaseManager.getInstance() - .getRealmUiThread() - .copyFromRealm(messages.last()); - } else { - lastMessage = null; - } + lastMessage = MessageDatabaseManager.getChatMessagesQuery( + MessageDatabaseManager.getInstance().getRealmUiThread(), account, user) + .isNull(MessageItem.Fields.ACTION) + .or().equalTo(MessageItem.Fields.ACTION, ChatAction.available.toString()) + .findAllSorted(MessageItem.Fields.TIMESTAMP, Sort.ASCENDING).last(null); } /** diff --git a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java index 8327cb804a..8ea4a8a230 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java +++ b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java @@ -77,6 +77,7 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.UUID; @@ -170,7 +171,12 @@ public AbstractChat getChat(AccountJid account, UserJid user) { public Collection getChatsOfEnabledAccount() { List chats = new ArrayList<>(); - for (AccountJid accountJid : AccountManager.getInstance().getEnabledAccounts()) { + + HashSet enabledAccounts = new HashSet<>(); + enabledAccounts.addAll(AccountManager.getInstance().getEnabledAccounts()); + enabledAccounts.addAll(AccountManager.getInstance().getCachedEnabledAccounts()); + + for (AccountJid accountJid : enabledAccounts) { chats.addAll(this.chats.getNested(accountJid.toString()).values()); } return chats; @@ -458,6 +464,12 @@ public Collection getActiveChats() { return Collections.unmodifiableCollection(collection); } + public AbstractChat getOrCreateChat(AccountJid account, UserJid user, MessageItem lastMessage) { + AbstractChat chat = getOrCreateChat(account, user); + chat.setLastMessage(lastMessage); + return chat; + } + /** * Returns existed chat or create new one. * From 218a1d04eebdef99e80cda3f85e02c951658585e Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 27 May 2019 16:52:28 +0500 Subject: [PATCH 092/237] Added ContactRealm --- .../data/database/MessageDatabaseManager.java | 17 +++- .../data/database/realm/ContactRealm.java | 83 +++++++++++++++++++ 2 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 xabber/src/main/java/com/xabber/android/data/database/realm/ContactRealm.java diff --git a/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java b/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java index 3fa0a716ea..65ada882cd 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java +++ b/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java @@ -9,6 +9,7 @@ import com.xabber.android.data.database.messagerealm.ForwardId; import com.xabber.android.data.database.messagerealm.MessageItem; import com.xabber.android.data.database.messagerealm.SyncInfo; +import com.xabber.android.data.database.realm.ContactRealm; import com.xabber.android.data.database.sqlite.MessageTable; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.entity.UserJid; @@ -33,7 +34,7 @@ public class MessageDatabaseManager { private static final String REALM_MESSAGE_DATABASE_NAME = "xabber.realm"; - static final int REALM_MESSAGE_DATABASE_VERSION = 20; + static final int REALM_MESSAGE_DATABASE_VERSION = 21; private final RealmConfiguration realmConfiguration; private static MessageDatabaseManager instance; @@ -137,7 +138,7 @@ public void execute(Realm realm) { } - @RealmModule(classes = {MessageItem.class, SyncInfo.class, Attachment.class, ForwardId.class}) + @RealmModule(classes = {MessageItem.class, SyncInfo.class, Attachment.class, ForwardId.class, ContactRealm.class}) static class MessageRealmDatabaseModule { } @@ -333,6 +334,18 @@ public void apply(DynamicRealmObject obj) { oldVersion++; } + if (oldVersion == 20) { + schema.create(ContactRealm.class.getSimpleName()) + .addField(ContactRealm.Fields.ID, String.class, FieldAttribute.PRIMARY_KEY, FieldAttribute.REQUIRED) + .addField(ContactRealm.Fields.ACCOUNT, String.class) + .addField(ContactRealm.Fields.USER, String.class) + .addField(ContactRealm.Fields.NAME, String.class) + .addField(ContactRealm.Fields.ACCOUNT_RESOURCE, String.class) + .addRealmObjectField(ContactRealm.Fields.LAST_MESSAGE, schema.get(MessageItem.class.getSimpleName())); + + oldVersion++; + } + } }) .build(); diff --git a/xabber/src/main/java/com/xabber/android/data/database/realm/ContactRealm.java b/xabber/src/main/java/com/xabber/android/data/database/realm/ContactRealm.java new file mode 100644 index 0000000000..6a1f473c0d --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/database/realm/ContactRealm.java @@ -0,0 +1,83 @@ +package com.xabber.android.data.database.realm; + +import com.xabber.android.data.database.messagerealm.MessageItem; + +import java.util.UUID; + +import io.realm.RealmObject; +import io.realm.annotations.PrimaryKey; +import io.realm.annotations.Required; + +public class ContactRealm extends RealmObject { + + public static class Fields { + public static final String ID = "id"; + public static final String ACCOUNT = "account"; + public static final String USER = "user"; + public static final String NAME = "name"; + public static final String ACCOUNT_RESOURCE = "accountResource"; + public static final String LAST_MESSAGE = "lastMessage"; + } + + @PrimaryKey + @Required + private String id; + + private String account; + private String user; + private String accountResource; + private String name; + private MessageItem lastMessage; + + public ContactRealm() { + this.id = UUID.randomUUID().toString(); + } + + public ContactRealm(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + public String getAccount() { + return account; + } + + public void setAccount(String account) { + this.account = account; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAccountResource() { + return accountResource; + } + + public void setAccountResource(String accountResource) { + this.accountResource = accountResource; + } + + public MessageItem getLastMessage() { + return lastMessage; + } + + public void setLastMessage(MessageItem lastMessage) { + this.lastMessage = lastMessage; + } +} From d2f6a1dd06752f0375a7e853af45bd14e5c6eec7 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 27 May 2019 17:35:49 +0500 Subject: [PATCH 093/237] Added roster cache and last message cache Added delay for start service --- .../xabber/android/data/ActivityManager.java | 21 +++++++- .../data/extension/mam/NextMamManager.java | 2 + .../android/data/message/AbstractChat.java | 2 + .../data/roster/RosterCacheManager.java | 50 +++++++++++++++++++ .../android/data/roster/RosterManager.java | 37 ++++++++++++-- 5 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java diff --git a/xabber/src/main/java/com/xabber/android/data/ActivityManager.java b/xabber/src/main/java/com/xabber/android/data/ActivityManager.java index cc3f20e48f..03d65a9a52 100644 --- a/xabber/src/main/java/com/xabber/android/data/ActivityManager.java +++ b/xabber/src/main/java/com/xabber/android/data/ActivityManager.java @@ -25,6 +25,7 @@ import com.xabber.android.data.connection.CertificateManager; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.push.SyncManager; +import com.xabber.android.data.roster.RosterManager; import com.xabber.android.service.XabberService; import com.xabber.android.ui.activity.AboutActivity; import com.xabber.android.ui.activity.ContactListActivity; @@ -44,6 +45,7 @@ public class ActivityManager implements OnUnloadListener { private static final String EXTRA_TASK_INDEX = "com.xabber.android.data.ActivityManager.EXTRA_TASK_INDEX"; + private static final long START_SERVICE_DELAY = 1000; private static final boolean LOG = true; private static ActivityManager instance; @@ -207,7 +209,24 @@ public void onResume(final Activity activity) { if (LOG) { LogManager.i(this, "Wait for loading"); } - activity.startService(XabberService.createIntent(activity)); + AccountManager.getInstance().onPreInitialize(); + RosterManager.getInstance().onPreInitialize(); + Application.getInstance().runInBackground(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(START_SERVICE_DELAY); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Application.getInstance().runOnUiThread(new Runnable() { + @Override + public void run() { + activity.startService(XabberService.createIntent(activity)); + } + }); + } + }); } if (onErrorListener != null) { application.removeUIListener(OnErrorListener.class, onErrorListener); diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index cd199dadb5..777617c1f0 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -22,6 +22,7 @@ import com.xabber.android.data.notification.NotificationManager; import com.xabber.android.data.push.SyncManager; import com.xabber.android.data.roster.OnRosterReceivedListener; +import com.xabber.android.data.roster.RosterCacheManager; import com.xabber.android.data.roster.RosterContact; import com.xabber.android.data.roster.RosterManager; @@ -901,6 +902,7 @@ private void updateLastMessageId(AbstractChat chat, Realm realm) { String id = lastMessage.getArchivedId(); if (id == null) id = lastMessage.getStanzaId(); chat.setLastMessageId(id); + RosterCacheManager.saveLastMessageToContact(MessageDatabaseManager.getInstance().getRealmUiThread(), lastMessage); } } diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index 818f5ae68f..5ffba6fbe7 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -45,6 +45,7 @@ import com.xabber.android.data.message.chat.ChatManager; import com.xabber.android.data.notification.MessageNotificationManager; import com.xabber.android.data.notification.NotificationManager; +import com.xabber.android.data.roster.RosterCacheManager; import com.xabber.xmpp.sid.OriginIdElement; import com.xabber.xmpp.sid.UniqStanzaHelper; @@ -429,6 +430,7 @@ protected MessageItem createMessageItem(String uid, Resourcepart resource, Strin String id = messageItem.getArchivedId(); if (id == null) id = messageItem.getStanzaId(); setLastMessageId(id); + RosterCacheManager.saveLastMessageToContact(MessageDatabaseManager.getInstance().getRealmUiThread(), messageItem); return messageItem; } diff --git a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java new file mode 100644 index 0000000000..6317f56393 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java @@ -0,0 +1,50 @@ +package com.xabber.android.data.roster; + +import com.xabber.android.data.database.MessageDatabaseManager; +import com.xabber.android.data.database.messagerealm.MessageItem; +import com.xabber.android.data.database.realm.ContactRealm; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import io.realm.Realm; + +public class RosterCacheManager { + + public static List loadContacts() { + Realm realm = MessageDatabaseManager.getInstance().getRealmUiThread(); + return realm.where(ContactRealm.class).findAll(); + } + + public static void saveContact(Collection contacts) { + Realm realm = MessageDatabaseManager.getInstance().getRealmUiThread(); + List newContacts = new ArrayList<>(); + for (RosterContact contact : contacts) { + String account = contact.getAccount().getFullJid().asBareJid().toString(); + String user = contact.getUser().getBareJid().toString(); + + ContactRealm contactRealm = new ContactRealm(account + "/" + user); + contactRealm.setAccount(account); + contactRealm.setUser(user); + contactRealm.setName(contact.getName()); + contactRealm.setAccountResource(contact.getAccount().getFullJid().getResourcepart().toString()); + newContacts.add(contactRealm); + } + realm.beginTransaction(); + realm.copyToRealmOrUpdate(newContacts); + realm.commitTransaction(); + } + + public static void saveLastMessageToContact(Realm realm, MessageItem messageItem) { + String account = messageItem.getAccount().getFullJid().asBareJid().toString(); + String user = messageItem.getUser().getBareJid().toString(); + ContactRealm contactRealm = realm.where(ContactRealm.class).equalTo(ContactRealm.Fields.ID, account + "/" + user).findFirst(); + realm.beginTransaction(); + if (contactRealm != null) { + contactRealm.setLastMessage(messageItem); + realm.copyToRealmOrUpdate(contactRealm); + } + realm.commitTransaction(); + } +} diff --git a/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java b/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java index 4793441dc5..df0bb209dd 100644 --- a/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java +++ b/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java @@ -29,6 +29,7 @@ import com.xabber.android.data.connection.StanzaSender; import com.xabber.android.data.connection.listeners.OnDisconnectListener; import com.xabber.android.data.database.messagerealm.MessageItem; +import com.xabber.android.data.database.realm.ContactRealm; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.entity.NestedMap; import com.xabber.android.data.entity.UserJid; @@ -51,6 +52,7 @@ import org.jxmpp.jid.BareJid; import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.Jid; +import org.jxmpp.stringprep.XmppStringprepException; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -88,6 +90,30 @@ public static RosterManager getInstance() { return instance; } + public void onPreInitialize() { + List contacts = RosterCacheManager.loadContacts(); + for (ContactRealm contactRealm : contacts) { + try { + AccountJid account = AccountJid.from(contactRealm.getAccount() + "/" + contactRealm.getAccountResource()); + UserJid userJid = UserJid.from(contactRealm.getUser()); + RosterContact contact = RosterContact.getRosterContact(account, userJid, contactRealm.getName()); + rosterContacts.put(contact.getAccount().toString(), + contact.getUser().getBareJid().toString(), contact); + + MessageItem lastMessage = contactRealm.getLastMessage(); + if (lastMessage != null) { + MessageManager.getInstance().getOrCreateChat(contact.getAccount(), contact.getUser(), lastMessage); + } else MessageManager.getInstance().getOrCreateChat(contact.getAccount(), contact.getUser()); + + } catch (UserJid.UserJidCreateException e) { + e.printStackTrace(); + } catch (XmppStringprepException e) { + e.printStackTrace(); + } + } + onContactsChanged(Collections.emptyList()); + } + @Nullable private Roster getRoster(AccountJid account) { final AccountItem accountItem = AccountManager.getInstance().getAccount(account); @@ -137,10 +163,7 @@ public Collection getAllContacts() { void onContactsAdded(AccountJid account, Collection addresses) { final Roster roster = RosterManager.getInstance().getRoster(account); - - Collection newContacts = new ArrayList<>(addresses.size()); - - + final Collection newContacts = new ArrayList<>(addresses.size()); for (Jid jid : addresses) { RosterEntry entry = roster.getEntry(jid.asBareJid()); try { @@ -155,6 +178,12 @@ void onContactsAdded(AccountJid account, Collection addresses) { } } + Application.getInstance().runOnUiThread(new Runnable() { + @Override + public void run() { + RosterCacheManager.saveContact(newContacts); + } + }); onContactsChanged(newContacts); } From 6f2a8ce083e897da80513da96a84915c0647cd27 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 27 May 2019 18:06:54 +0500 Subject: [PATCH 094/237] Fixed saving contact to cache --- .../android/data/roster/RosterCacheManager.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java index 6317f56393..951526d53f 100644 --- a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java +++ b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java @@ -19,24 +19,31 @@ public static List loadContacts() { public static void saveContact(Collection contacts) { Realm realm = MessageDatabaseManager.getInstance().getRealmUiThread(); + + realm.beginTransaction(); List newContacts = new ArrayList<>(); for (RosterContact contact : contacts) { String account = contact.getAccount().getFullJid().asBareJid().toString(); String user = contact.getUser().getBareJid().toString(); - ContactRealm contactRealm = new ContactRealm(account + "/" + user); + ContactRealm contactRealm = realm.where(ContactRealm.class).equalTo(ContactRealm.Fields.ID, + account + "/" + user).findFirst(); + if (contactRealm == null) { + contactRealm = new ContactRealm(account + "/" + user); + } + contactRealm.setAccount(account); contactRealm.setUser(user); contactRealm.setName(contact.getName()); contactRealm.setAccountResource(contact.getAccount().getFullJid().getResourcepart().toString()); newContacts.add(contactRealm); } - realm.beginTransaction(); realm.copyToRealmOrUpdate(newContacts); realm.commitTransaction(); } public static void saveLastMessageToContact(Realm realm, MessageItem messageItem) { + if (messageItem == null) return; String account = messageItem.getAccount().getFullJid().asBareJid().toString(); String user = messageItem.getUser().getBareJid().toString(); ContactRealm contactRealm = realm.where(ContactRealm.class).equalTo(ContactRealm.Fields.ID, account + "/" + user).findFirst(); From 6fa68ee1124202048f46a2d32118ec5e83455fec Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 27 May 2019 18:17:52 +0500 Subject: [PATCH 095/237] Fixed saving last message to cache --- .../java/com/xabber/android/data/roster/RosterCacheManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java index 951526d53f..354cd2a56f 100644 --- a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java +++ b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java @@ -48,7 +48,7 @@ public static void saveLastMessageToContact(Realm realm, MessageItem messageItem String user = messageItem.getUser().getBareJid().toString(); ContactRealm contactRealm = realm.where(ContactRealm.class).equalTo(ContactRealm.Fields.ID, account + "/" + user).findFirst(); realm.beginTransaction(); - if (contactRealm != null) { + if (contactRealm != null && messageItem.isValid() && messageItem.isManaged()) { contactRealm.setLastMessage(messageItem); realm.copyToRealmOrUpdate(contactRealm); } From afc0a772c1626ca4c17c1e87e66d3d5a8f55dacc Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 27 May 2019 18:28:48 +0500 Subject: [PATCH 096/237] Added new message event to mam manager --- .../com/xabber/android/data/extension/mam/NextMamManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index 777617c1f0..73e84a5b8c 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -19,6 +19,7 @@ import com.xabber.android.data.message.AbstractChat; import com.xabber.android.data.message.ForwardManager; import com.xabber.android.data.message.MessageManager; +import com.xabber.android.data.message.NewMessageEvent; import com.xabber.android.data.notification.NotificationManager; import com.xabber.android.data.push.SyncManager; import com.xabber.android.data.roster.OnRosterReceivedListener; @@ -705,6 +706,7 @@ private List saveOrUpdateMessages(Realm realm, final Collection Date: Mon, 27 May 2019 18:35:46 +0500 Subject: [PATCH 097/237] Changes in contact list fragment - info view is gone by default --- xabber/src/main/res/layout/fragment_contact_list_new.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xabber/src/main/res/layout/fragment_contact_list_new.xml b/xabber/src/main/res/layout/fragment_contact_list_new.xml index 366f711404..ce2d62ae8d 100644 --- a/xabber/src/main/res/layout/fragment_contact_list_new.xml +++ b/xabber/src/main/res/layout/fragment_contact_list_new.xml @@ -20,7 +20,8 @@ android:id="@+id/info" android:layout_width="match_parent" android:layout_height="match_parent" - android:gravity="center_vertical" > + android:gravity="center_vertical" + android:visibility="gone"> Date: Mon, 27 May 2019 18:36:44 +0500 Subject: [PATCH 098/237] Up version to 614 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 1f6fe3386d..611b5a4bf7 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 613 - versionName '2.6.4(613)' + versionCode 614 + versionName '2.6.4(614)' } lintOptions { From a2607975bf80d782243ab0475a1783148fb41bd7 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 27 May 2019 19:18:20 +0500 Subject: [PATCH 099/237] Fixed NPE in ContactVO.convert --- .../presentation/ui/contactlist/viewobjects/ContactVO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java index 9867a8b8d9..f8c85424fc 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java +++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java @@ -166,7 +166,7 @@ public static ContactVO convert(AbstractContact contact, ContactClickListener li AbstractChat chat = messageManager.getOrCreateChat(contact.getAccount(), contact.getUser()); MessageItem lastMessage = chat.getLastMessage(); - if (lastMessage == null) { + if (lastMessage == null || lastMessage.getText() == null) { messageText = statusText; } else { if (lastMessage.haveAttachments() && lastMessage.getAttachments().size() > 0) { From aa67d9a4dab70c8668b6d993518068e08438fc3a Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 28 May 2019 15:51:56 +0500 Subject: [PATCH 100/237] Added groups to roster cache --- .../data/database/MessageDatabaseManager.java | 12 ++++++-- .../data/database/realm/ContactGroup.java | 30 +++++++++++++++++++ .../data/database/realm/ContactRealm.java | 11 +++++++ .../data/roster/RosterCacheManager.java | 10 +++++++ .../android/data/roster/RosterManager.java | 7 +++++ 5 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 xabber/src/main/java/com/xabber/android/data/database/realm/ContactGroup.java diff --git a/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java b/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java index 65ada882cd..98792e59a3 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java +++ b/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java @@ -9,6 +9,7 @@ import com.xabber.android.data.database.messagerealm.ForwardId; import com.xabber.android.data.database.messagerealm.MessageItem; import com.xabber.android.data.database.messagerealm.SyncInfo; +import com.xabber.android.data.database.realm.ContactGroup; import com.xabber.android.data.database.realm.ContactRealm; import com.xabber.android.data.database.sqlite.MessageTable; import com.xabber.android.data.entity.AccountJid; @@ -17,6 +18,7 @@ import org.jxmpp.stringprep.XmppStringprepException; +import java.lang.reflect.Field; import java.util.Date; import io.realm.DynamicRealm; @@ -138,7 +140,8 @@ public void execute(Realm realm) { } - @RealmModule(classes = {MessageItem.class, SyncInfo.class, Attachment.class, ForwardId.class, ContactRealm.class}) + @RealmModule(classes = {MessageItem.class, SyncInfo.class, Attachment.class, ForwardId.class, + ContactRealm.class, ContactGroup.class}) static class MessageRealmDatabaseModule { } @@ -335,13 +338,18 @@ public void apply(DynamicRealmObject obj) { } if (oldVersion == 20) { + schema.create(ContactGroup.class.getSimpleName()) + .addField(ContactGroup.Fields.GROUP_NAME, String.class, + FieldAttribute.PRIMARY_KEY, FieldAttribute.REQUIRED); + schema.create(ContactRealm.class.getSimpleName()) .addField(ContactRealm.Fields.ID, String.class, FieldAttribute.PRIMARY_KEY, FieldAttribute.REQUIRED) .addField(ContactRealm.Fields.ACCOUNT, String.class) .addField(ContactRealm.Fields.USER, String.class) .addField(ContactRealm.Fields.NAME, String.class) .addField(ContactRealm.Fields.ACCOUNT_RESOURCE, String.class) - .addRealmObjectField(ContactRealm.Fields.LAST_MESSAGE, schema.get(MessageItem.class.getSimpleName())); + .addRealmObjectField(ContactRealm.Fields.LAST_MESSAGE, schema.get(MessageItem.class.getSimpleName())) + .addRealmListField(ContactRealm.Fields.GROUPS, schema.get(ContactGroup.class.getSimpleName())); oldVersion++; } diff --git a/xabber/src/main/java/com/xabber/android/data/database/realm/ContactGroup.java b/xabber/src/main/java/com/xabber/android/data/database/realm/ContactGroup.java new file mode 100644 index 0000000000..0441126796 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/database/realm/ContactGroup.java @@ -0,0 +1,30 @@ +package com.xabber.android.data.database.realm; + +import java.util.UUID; + +import io.realm.RealmObject; +import io.realm.annotations.PrimaryKey; +import io.realm.annotations.Required; + +public class ContactGroup extends RealmObject { + + public static class Fields { + public static final String GROUP_NAME = "groupName"; + } + + @PrimaryKey + @Required + private String groupName; + + public ContactGroup() { + this.groupName = UUID.randomUUID().toString(); + } + + public ContactGroup(String groupName) { + this.groupName = groupName; + } + + public String getGroupName() { + return groupName; + } +} diff --git a/xabber/src/main/java/com/xabber/android/data/database/realm/ContactRealm.java b/xabber/src/main/java/com/xabber/android/data/database/realm/ContactRealm.java index 6a1f473c0d..3f353dff72 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/realm/ContactRealm.java +++ b/xabber/src/main/java/com/xabber/android/data/database/realm/ContactRealm.java @@ -4,6 +4,7 @@ import java.util.UUID; +import io.realm.RealmList; import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; import io.realm.annotations.Required; @@ -17,6 +18,7 @@ public static class Fields { public static final String NAME = "name"; public static final String ACCOUNT_RESOURCE = "accountResource"; public static final String LAST_MESSAGE = "lastMessage"; + public static final String GROUPS = "groups"; } @PrimaryKey @@ -28,6 +30,7 @@ public static class Fields { private String accountResource; private String name; private MessageItem lastMessage; + private RealmList groups; public ContactRealm() { this.id = UUID.randomUUID().toString(); @@ -80,4 +83,12 @@ public MessageItem getLastMessage() { public void setLastMessage(MessageItem lastMessage) { this.lastMessage = lastMessage; } + + public RealmList getGroups() { + return groups; + } + + public void setGroups(RealmList groups) { + this.groups = groups; + } } diff --git a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java index 354cd2a56f..bb73f5725f 100644 --- a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java +++ b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java @@ -2,6 +2,7 @@ import com.xabber.android.data.database.MessageDatabaseManager; import com.xabber.android.data.database.messagerealm.MessageItem; +import com.xabber.android.data.database.realm.ContactGroup; import com.xabber.android.data.database.realm.ContactRealm; import java.util.ArrayList; @@ -9,6 +10,7 @@ import java.util.List; import io.realm.Realm; +import io.realm.RealmList; public class RosterCacheManager { @@ -32,6 +34,14 @@ public static void saveContact(Collection contacts) { contactRealm = new ContactRealm(account + "/" + user); } + RealmList groups = new RealmList<>(); + for (String groupName : contact.getGroupNames()) { + ContactGroup group = realm.copyToRealmOrUpdate(new ContactGroup(groupName)); + if (group.isManaged() && group.isValid()) + groups.add(group); + } + + contactRealm.setGroups(groups); contactRealm.setAccount(account); contactRealm.setUser(user); contactRealm.setName(contact.getName()); diff --git a/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java b/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java index df0bb209dd..504c4e3b50 100644 --- a/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java +++ b/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java @@ -17,6 +17,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; +import android.util.Log; import com.xabber.android.R; import com.xabber.android.data.Application; @@ -29,6 +30,7 @@ import com.xabber.android.data.connection.StanzaSender; import com.xabber.android.data.connection.listeners.OnDisconnectListener; import com.xabber.android.data.database.messagerealm.MessageItem; +import com.xabber.android.data.database.realm.ContactGroup; import com.xabber.android.data.database.realm.ContactRealm; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.entity.NestedMap; @@ -97,6 +99,11 @@ public void onPreInitialize() { AccountJid account = AccountJid.from(contactRealm.getAccount() + "/" + contactRealm.getAccountResource()); UserJid userJid = UserJid.from(contactRealm.getUser()); RosterContact contact = RosterContact.getRosterContact(account, userJid, contactRealm.getName()); + + for (ContactGroup group : contactRealm.getGroups()) { + contact.addGroupReference(new RosterGroupReference(new RosterGroup(account, group.getGroupName()))); + } + rosterContacts.put(contact.getAccount().toString(), contact.getUser().getBareJid().toString(), contact); From 2371a8d98fd32479f8cb4152e7138e10f1448f38 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 28 May 2019 16:16:02 +0500 Subject: [PATCH 101/237] Added removing contacts from cache on deleting contacts from roster --- .../android/data/roster/RosterCacheManager.java | 15 +++++++++++++++ .../xabber/android/data/roster/RosterManager.java | 8 +++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java index bb73f5725f..3b65d1726c 100644 --- a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java +++ b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java @@ -52,6 +52,21 @@ public static void saveContact(Collection contacts) { realm.commitTransaction(); } + public static void removeContact(Collection contacts) { + Realm realm = MessageDatabaseManager.getInstance().getRealmUiThread(); + realm.beginTransaction(); + for (RosterContact contact : contacts) { + String account = contact.getAccount().getFullJid().asBareJid().toString(); + String user = contact.getUser().getBareJid().toString(); + + ContactRealm contactRealm = realm.where(ContactRealm.class).equalTo(ContactRealm.Fields.ID, + account + "/" + user).findFirst(); + if (contactRealm != null) + contactRealm.deleteFromRealm(); + } + realm.commitTransaction(); + } + public static void saveLastMessageToContact(Realm realm, MessageItem messageItem) { if (messageItem == null) return; String account = messageItem.getAccount().getFullJid().asBareJid().toString(); diff --git a/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java b/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java index 504c4e3b50..abdd53b54f 100644 --- a/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java +++ b/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java @@ -199,7 +199,7 @@ void onContactsUpdated(AccountJid account, Collection addresses) { } void onContactsDeleted(AccountJid account, Collection addresses) { - Collection removedContacts = new ArrayList<>(addresses.size()); + final Collection removedContacts = new ArrayList<>(addresses.size()); for (Jid jid : addresses) { RosterContact contact = rosterContacts.remove(account.toString(), jid.asBareJid().toString()); @@ -207,6 +207,12 @@ void onContactsDeleted(AccountJid account, Collection addresses) { removedContacts.add(contact); } } + Application.getInstance().runOnUiThread(new Runnable() { + @Override + public void run() { + RosterCacheManager.removeContact(removedContacts); + } + }); onContactsChanged(removedContacts); } From 2be1b7ca914d7c77a5436341345ecfa0c49cffd8 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 28 May 2019 16:56:00 +0500 Subject: [PATCH 102/237] Fixed crash --- .../com/xabber/android/data/extension/mam/NextMamManager.java | 2 +- .../main/java/com/xabber/android/data/message/AbstractChat.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index 73e84a5b8c..c66eb1d460 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -904,7 +904,7 @@ private void updateLastMessageId(AbstractChat chat, Realm realm) { String id = lastMessage.getArchivedId(); if (id == null) id = lastMessage.getStanzaId(); chat.setLastMessageId(id); - RosterCacheManager.saveLastMessageToContact(MessageDatabaseManager.getInstance().getRealmUiThread(), lastMessage); + RosterCacheManager.saveLastMessageToContact(realm, lastMessage); } } diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index 5ffba6fbe7..4892126c4c 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -430,7 +430,6 @@ protected MessageItem createMessageItem(String uid, Resourcepart resource, Strin String id = messageItem.getArchivedId(); if (id == null) id = messageItem.getStanzaId(); setLastMessageId(id); - RosterCacheManager.saveLastMessageToContact(MessageDatabaseManager.getInstance().getRealmUiThread(), messageItem); return messageItem; } @@ -522,6 +521,7 @@ private void updateLastMessage() { .isNull(MessageItem.Fields.ACTION) .or().equalTo(MessageItem.Fields.ACTION, ChatAction.available.toString()) .findAllSorted(MessageItem.Fields.TIMESTAMP, Sort.ASCENDING).last(null); + RosterCacheManager.saveLastMessageToContact(MessageDatabaseManager.getInstance().getRealmUiThread(), lastMessage); } /** From 0d993b269b208fe115a8d030c3fb9cd0815e9147 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 28 May 2019 17:54:27 +0500 Subject: [PATCH 103/237] Fixed avatars in cache --- .../com/xabber/android/data/ActivityManager.java | 2 ++ .../data/extension/avatar/AvatarManager.java | 14 ++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/ActivityManager.java b/xabber/src/main/java/com/xabber/android/data/ActivityManager.java index 03d65a9a52..f8dd34b3cf 100644 --- a/xabber/src/main/java/com/xabber/android/data/ActivityManager.java +++ b/xabber/src/main/java/com/xabber/android/data/ActivityManager.java @@ -23,6 +23,7 @@ import com.xabber.android.R; import com.xabber.android.data.account.AccountManager; import com.xabber.android.data.connection.CertificateManager; +import com.xabber.android.data.extension.avatar.AvatarManager; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.push.SyncManager; import com.xabber.android.data.roster.RosterManager; @@ -214,6 +215,7 @@ public void onResume(final Activity activity) { Application.getInstance().runInBackground(new Runnable() { @Override public void run() { + AvatarManager.getInstance().onPreInitialize(); try { Thread.sleep(START_SERVICE_DELAY); } catch (InterruptedException e) { diff --git a/xabber/src/main/java/com/xabber/android/data/extension/avatar/AvatarManager.java b/xabber/src/main/java/com/xabber/android/data/extension/avatar/AvatarManager.java index 66543a933e..66acd99867 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/avatar/AvatarManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/avatar/AvatarManager.java @@ -35,7 +35,6 @@ import com.amulyakhare.textdrawable.util.ColorGenerator; import com.xabber.android.R; import com.xabber.android.data.Application; -import com.xabber.android.data.OnLoadListener; import com.xabber.android.data.OnLowMemoryListener; import com.xabber.android.data.SettingsManager; import com.xabber.android.data.account.AccountItem; @@ -47,6 +46,8 @@ import com.xabber.android.data.entity.UserJid; import com.xabber.android.data.extension.vcard.VCardManager; import com.xabber.android.data.log.LogManager; +import com.xabber.android.data.roster.OnContactChangedListener; +import com.xabber.android.data.roster.RosterContact; import com.xabber.android.ui.color.ColorManager; import com.xabber.xmpp.vcardupdate.VCardUpdate; @@ -57,6 +58,7 @@ import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.stringprep.XmppStringprepException; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -77,7 +79,7 @@ * * @author alexander.ivanov */ -public class AvatarManager implements OnLoadListener, OnLowMemoryListener, OnPacketListener { +public class AvatarManager implements OnLowMemoryListener, OnPacketListener { /** * Maximum image width / height to be loaded. @@ -204,8 +206,7 @@ public static Bitmap getCircleBitmap(Bitmap bitmap) { return output; } - @Override - public void onLoad() { + public void onPreInitialize() { final Map hashes = new HashMap<>(); final Map bitmaps = new HashMap<>(); Cursor cursor = AvatarTable.getInstance().list(); @@ -241,6 +242,11 @@ public void run() { private void onLoaded(Map hashes, Map bitmaps) { this.hashes.putAll(hashes); this.bitmaps.putAll(bitmaps); + this.contactListDrawables.clear(); + for (OnContactChangedListener onContactChangedListener : Application + .getInstance().getUIListeners(OnContactChangedListener.class)) { + onContactChangedListener.onContactsChanged(Collections.emptyList()); + } } /** From 4ff8b1a5a34a69906d702ff033023c4b2b572d42 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 28 May 2019 18:52:52 +0500 Subject: [PATCH 104/237] Add debug push log --- .../xabber/android/data/SettingsManager.java | 24 +++++++++++++++++++ .../xabber/android/data/push/PushManager.java | 18 +++++++++++--- xabber/src/main/res/values/preferences.xml | 2 ++ 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/SettingsManager.java b/xabber/src/main/java/com/xabber/android/data/SettingsManager.java index b7c22db2d4..75ac1bc830 100644 --- a/xabber/src/main/java/com/xabber/android/data/SettingsManager.java +++ b/xabber/src/main/java/com/xabber/android/data/SettingsManager.java @@ -46,7 +46,9 @@ import java.util.Collections; import java.util.Comparator; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; /** @@ -142,6 +144,17 @@ private static void setString(int key, String value) { editor.commit(); } + private static Set getStringSet(int key) { + return getSharedPreferences().getStringSet( + Application.getInstance().getString(key), null); + } + + private static void setStringSet(int key, Set set) { + Editor editor = getSharedPreferences().edit(); + editor.putStringSet(Application.getInstance().getString(key), set); + editor.commit(); + } + private static String getNotifString(int key, String def) { return getNotificationSharedPreferences().getString( Application.getInstance().getString(key), def); @@ -862,6 +875,17 @@ public static String getEnabledPushNodes() { return getString(R.string.enabled_push_nodes, ""); } + public static Set getPushLog() { + return getStringSet(R.string.push_log); + } + + public static void addToPushLog(String event) { + Set log = getPushLog(); + if (log == null) log = new HashSet<>(); + log.add(event); + setStringSet(R.string.push_log, log); + } + public static void resetPreferences(Context context, String preferencesName) { context.getSharedPreferences(preferencesName, Context.MODE_PRIVATE).edit().clear().apply(); } diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index 5fdc33ffc5..1115d9c951 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -29,9 +29,13 @@ import org.jivesoftware.smackx.push_notifications.element.PushNotificationsElements; import org.jxmpp.jid.EntityBareJid; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.HashMap; +import java.util.Locale; import okhttp3.ResponseBody; import rx.android.schedulers.AndroidSchedulers; @@ -101,15 +105,23 @@ public void onEndpointRegistered(String jid, String pushServiceJid, String node) } public void onNewMessagePush(Context context, String node) { + String log = new SimpleDateFormat("yyyy.MM.dd - HH:mm:ss", Locale.getDefault()).format(new Date()); + String message = ""; if (!Application.getInstance().isServiceStarted() && SettingsManager.getEnabledPushNodes().contains(node)) { Utils.startXabberServiceCompatWithSyncMode(context, node); - LogManager.d(LOG_TAG, "Received message push. Starting service."); + message = "Received message push. Starting service."; + LogManager.d(LOG_TAG, message); } else if (SyncManager.getInstance().isSyncMode()) { - LogManager.d(LOG_TAG, "Received message push. Service also started. Add account to allowed accounts."); + message = "Received message push. Service also started. Add account to allowed accounts."; + LogManager.d(LOG_TAG, message); SyncManager.getInstance().addAllowedAccount(node); + } else { + message = "Received message push. Service also started. Not a sync mode - account maybe connected."; + LogManager.d(LOG_TAG, message); } - LogManager.d(LOG_TAG, "Received message push. Service also started. Not a sync mode - account maybe connected."); + LogManager.d("VALERA_TEST", log + ": " + message); + SettingsManager.addToPushLog(log + ": " + message); } @Override diff --git a/xabber/src/main/res/values/preferences.xml b/xabber/src/main/res/values/preferences.xml index b45277f52c..b62c0c988e 100644 --- a/xabber/src/main/res/values/preferences.xml +++ b/xabber/src/main/res/values/preferences.xml @@ -538,6 +538,8 @@ chat_events_suppress_100 false + push_log + From b6a72b92cb70721964ff2ac6985d8befe065aff9 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 28 May 2019 19:19:34 +0500 Subject: [PATCH 105/237] Up version to 615 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 611b5a4bf7..c781970865 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 614 - versionName '2.6.4(614)' + versionCode 615 + versionName '2.6.4(615)' } lintOptions { From c3de417727744319aa3d9a8d3fb387b62839f6cb Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 29 May 2019 11:53:36 +0500 Subject: [PATCH 106/237] Added push log activity --- xabber/src/dev/res/xml/preference_debug.xml | 8 ++++ xabber/src/main/AndroidManifest.xml | 5 +++ .../android/ui/activity/PushLogActivity.java | 41 +++++++++++++++++++ .../src/main/res/values/preference_editor.xml | 1 + xabber/src/main/res/values/preferences.xml | 1 + 5 files changed, 56 insertions(+) create mode 100644 xabber/src/main/java/com/xabber/android/ui/activity/PushLogActivity.java diff --git a/xabber/src/dev/res/xml/preference_debug.xml b/xabber/src/dev/res/xml/preference_debug.xml index 983205d8b4..41e4b0b1ef 100644 --- a/xabber/src/dev/res/xml/preference_debug.xml +++ b/xabber/src/dev/res/xml/preference_debug.xml @@ -53,4 +53,12 @@ android:title="@string/debug_fetch_crowdfunding_feed_title"> + + + + \ No newline at end of file diff --git a/xabber/src/main/AndroidManifest.xml b/xabber/src/main/AndroidManifest.xml index 594d2d58ae..4ccee7f9c4 100644 --- a/xabber/src/main/AndroidManifest.xml +++ b/xabber/src/main/AndroidManifest.xml @@ -572,6 +572,11 @@ android:value="com.xabber.android.ui.activity.ChatActivity" /> + + + \ No newline at end of file diff --git a/xabber/src/main/java/com/xabber/android/ui/activity/PushLogActivity.java b/xabber/src/main/java/com/xabber/android/ui/activity/PushLogActivity.java new file mode 100644 index 0000000000..220b579099 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/ui/activity/PushLogActivity.java @@ -0,0 +1,41 @@ +package com.xabber.android.ui.activity; + +import android.os.Bundle; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.view.View; +import android.widget.ProgressBar; + +import com.xabber.android.R; +import com.xabber.android.data.SettingsManager; +import com.xabber.android.ui.adapter.ServerInfoAdapter; +import com.xabber.android.ui.color.BarPainter; +import com.xabber.android.ui.helper.ToolbarHelper; + +import java.util.ArrayList; +import java.util.Set; + +public class PushLogActivity extends ManagedActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_server_info); + + Toolbar toolbar = ToolbarHelper.setUpDefaultToolbar(this, getString(R.string.push_log_title)); + BarPainter barPainter = new BarPainter(this, toolbar); + barPainter.setDefaultColor(); + + RecyclerView recyclerView = (RecyclerView) findViewById(R.id.server_info_recycler_view); + ServerInfoAdapter serverInfoAdapter = new ServerInfoAdapter(); + Set log = SettingsManager.getPushLog(); + if (log != null) + serverInfoAdapter.setServerInfoList(new ArrayList<>(log)); + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + recyclerView.setAdapter(serverInfoAdapter); + + ProgressBar progressBar = findViewById(R.id.server_info_progress_bar); + progressBar.setVisibility(View.GONE); + } +} diff --git a/xabber/src/main/res/values/preference_editor.xml b/xabber/src/main/res/values/preference_editor.xml index 61c4304065..ba41955e68 100644 --- a/xabber/src/main/res/values/preference_editor.xml +++ b/xabber/src/main/res/values/preference_editor.xml @@ -22,6 +22,7 @@ Debug log\nWrite messages to debug log (please restart application to apply changes) Write file log\nWrite debug log to local file (you can share it). Log files\nList of written log files. + Push-notification log Download all messages from archive\nDebug function. May works with errors Log files Show connection errors\nDisplay connection exceptions pop-ups diff --git a/xabber/src/main/res/values/preferences.xml b/xabber/src/main/res/values/preferences.xml index b62c0c988e..7076778217 100644 --- a/xabber/src/main/res/values/preferences.xml +++ b/xabber/src/main/res/values/preferences.xml @@ -376,6 +376,7 @@ false debug_log_activity + push_log_activity_key debug_crash_reports true From 022a53d928500ac2d1542d2e75bacb696faa93ff Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 29 May 2019 14:32:18 +0500 Subject: [PATCH 107/237] Added pushLogRecord realm model Changes in push logs --- .../android/data/database/RealmManager.java | 14 ++++- .../data/database/realm/PushLogRecord.java | 48 +++++++++++++++ .../xabber/android/data/push/PushManager.java | 59 +++++++++++++++---- .../android/ui/activity/PushLogActivity.java | 44 +++++++++++--- 4 files changed, 141 insertions(+), 24 deletions(-) create mode 100644 xabber/src/main/java/com/xabber/android/data/database/realm/PushLogRecord.java diff --git a/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java b/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java index b31bc55206..d9400834e7 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java +++ b/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java @@ -14,6 +14,7 @@ import com.xabber.android.data.database.realm.NotificationStateRealm; import com.xabber.android.data.database.realm.PatreonGoalRealm; import com.xabber.android.data.database.realm.PatreonRealm; +import com.xabber.android.data.database.realm.PushLogRecord; import com.xabber.android.data.database.realm.SocialBindingRealm; import com.xabber.android.data.database.realm.SyncStateRealm; import com.xabber.android.data.database.realm.XMPPUserRealm; @@ -35,7 +36,7 @@ public class RealmManager { private static final String REALM_DATABASE_NAME = "realm_database.realm"; - private static final int REALM_DATABASE_VERSION = 24; + private static final int REALM_DATABASE_VERSION = 25; private static final String LOG_TAG = RealmManager.class.getSimpleName(); private final RealmConfiguration realmConfiguration; @@ -70,7 +71,7 @@ void deleteRealm() { XMPPUserRealm.class, EmailRealm.class, SocialBindingRealm.class, SyncStateRealm.class, PatreonGoalRealm.class, PatreonRealm.class, ChatDataRealm.class, NotificationStateRealm.class, CrowdfundingMessage.class, NotifChatRealm.class, NotifMessageRealm.class, NotifyPrefsRealm.class, - UploadServer.class}) + UploadServer.class, PushLogRecord.class}) static class RealmDatabaseModule { } @@ -340,6 +341,15 @@ public void apply(DynamicRealmObject obj) { oldVersion++; } + + if (oldVersion == 24) { + schema.create(PushLogRecord.class.getSimpleName()) + .addField(UploadServer.Fields.ID, String.class, FieldAttribute.PRIMARY_KEY, FieldAttribute.REQUIRED) + .addField(PushLogRecord.Fields.TIME, long.class) + .addField(PushLogRecord.Fields.MESSAGE, String.class); + + oldVersion++; + } } }) .modules(new RealmDatabaseModule()) diff --git a/xabber/src/main/java/com/xabber/android/data/database/realm/PushLogRecord.java b/xabber/src/main/java/com/xabber/android/data/database/realm/PushLogRecord.java new file mode 100644 index 0000000000..e2ded51021 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/database/realm/PushLogRecord.java @@ -0,0 +1,48 @@ +package com.xabber.android.data.database.realm; + +import java.util.UUID; + +import io.realm.RealmObject; +import io.realm.annotations.PrimaryKey; +import io.realm.annotations.Required; + +public class PushLogRecord extends RealmObject { + + public static class Fields { + public static final String ID = "id"; + public static final String TIME = "time"; + public static final String MESSAGE = "message"; + } + + @PrimaryKey + @Required + private String id; + private long time; + private String message; + + public PushLogRecord(long time, String message) { + this.id = UUID.randomUUID().toString(); + this.time = time; + this.message = message; + } + + public PushLogRecord() { + this.id = UUID.randomUUID().toString(); + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public long getTime() { + return time; + } + + public void setTime(long time) { + this.time = time; + } +} diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index 1115d9c951..baf4135a8f 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -13,6 +13,8 @@ import com.xabber.android.data.connection.ConnectionItem; import com.xabber.android.data.connection.listeners.OnConnectedListener; import com.xabber.android.data.connection.listeners.OnPacketListener; +import com.xabber.android.data.database.RealmManager; +import com.xabber.android.data.database.realm.PushLogRecord; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.entity.UserJid; import com.xabber.android.data.http.PushApiClient; @@ -29,14 +31,18 @@ import org.jivesoftware.smackx.push_notifications.element.PushNotificationsElements; import org.jxmpp.jid.EntityBareJid; -import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.List; import java.util.Locale; +import io.realm.Realm; +import io.realm.RealmResults; +import io.realm.Sort; import okhttp3.ResponseBody; import rx.android.schedulers.AndroidSchedulers; import rx.functions.Action1; @@ -105,23 +111,18 @@ public void onEndpointRegistered(String jid, String pushServiceJid, String node) } public void onNewMessagePush(Context context, String node) { - String log = new SimpleDateFormat("yyyy.MM.dd - HH:mm:ss", Locale.getDefault()).format(new Date()); - String message = ""; + String message; if (!Application.getInstance().isServiceStarted() && SettingsManager.getEnabledPushNodes().contains(node)) { Utils.startXabberServiceCompatWithSyncMode(context, node); - message = "Received message push. Starting service."; - LogManager.d(LOG_TAG, message); + message = "Starting service"; } else if (SyncManager.getInstance().isSyncMode()) { - message = "Received message push. Service also started. Add account to allowed accounts."; - LogManager.d(LOG_TAG, message); + message = "Service also started. Add account to allowed accounts"; SyncManager.getInstance().addAllowedAccount(node); - } else { - message = "Received message push. Service also started. Not a sync mode - account maybe connected."; - LogManager.d(LOG_TAG, message); - } - LogManager.d("VALERA_TEST", log + ": " + message); - SettingsManager.addToPushLog(log + ": " + message); + } else message = "Service also started. Not a sync mode - account maybe connected"; + + LogManager.d(LOG_TAG, "Received message push. " + message); + addToPushLog(message); } @Override @@ -182,6 +183,38 @@ public boolean isSupport(XMPPTCPConnection connection) { } } + /** Log */ + + private void addToPushLog(String message) { + Realm realm = RealmManager.getInstance().getNewBackgroundRealm(); + PushLogRecord pushLogRecord = new PushLogRecord(System.currentTimeMillis(), message); + realm.beginTransaction(); + realm.copyToRealm(pushLogRecord); + realm.commitTransaction(); + realm.close(); + } + + public static List getPushLogs() { + Realm realm = RealmManager.getInstance().getRealmUiThread(); + List logs = new ArrayList<>(); + RealmResults records = realm.where(PushLogRecord.class) + .findAllSorted(PushLogRecord.Fields.TIME, Sort.DESCENDING); + for (PushLogRecord record : records) { + String time = new SimpleDateFormat("yyyy.MM.dd - HH:mm:ss", + Locale.getDefault()).format(new Date(record.getTime())); + logs.add(time + ": " + record.getMessage()); + } + return logs; + } + + public static void clearPushLog() { + Realm realm = RealmManager.getInstance().getRealmUiThread(); + RealmResults records = realm.where(PushLogRecord.class).findAll(); + realm.beginTransaction(); + records.deleteAllFromRealm(); + realm.commitTransaction(); + } + /** Private */ private void registerEndpoint(AccountJid accountJid) { diff --git a/xabber/src/main/java/com/xabber/android/ui/activity/PushLogActivity.java b/xabber/src/main/java/com/xabber/android/ui/activity/PushLogActivity.java index 220b579099..7d041e8274 100644 --- a/xabber/src/main/java/com/xabber/android/ui/activity/PushLogActivity.java +++ b/xabber/src/main/java/com/xabber/android/ui/activity/PushLogActivity.java @@ -4,19 +4,21 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; +import android.view.MenuItem; import android.view.View; import android.widget.ProgressBar; import com.xabber.android.R; -import com.xabber.android.data.SettingsManager; +import com.xabber.android.data.push.PushManager; import com.xabber.android.ui.adapter.ServerInfoAdapter; import com.xabber.android.ui.color.BarPainter; import com.xabber.android.ui.helper.ToolbarHelper; -import java.util.ArrayList; -import java.util.Set; +import java.util.List; -public class PushLogActivity extends ManagedActivity { +public class PushLogActivity extends ManagedActivity implements Toolbar.OnMenuItemClickListener { + + private ServerInfoAdapter serverInfoAdapter; @Override protected void onCreate(Bundle savedInstanceState) { @@ -27,15 +29,39 @@ protected void onCreate(Bundle savedInstanceState) { BarPainter barPainter = new BarPainter(this, toolbar); barPainter.setDefaultColor(); - RecyclerView recyclerView = (RecyclerView) findViewById(R.id.server_info_recycler_view); - ServerInfoAdapter serverInfoAdapter = new ServerInfoAdapter(); - Set log = SettingsManager.getPushLog(); - if (log != null) - serverInfoAdapter.setServerInfoList(new ArrayList<>(log)); + toolbar.inflateMenu(R.menu.toolbar_log); + toolbar.setOnMenuItemClickListener(this); + + RecyclerView recyclerView = findViewById(R.id.server_info_recycler_view); + serverInfoAdapter = new ServerInfoAdapter(); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(serverInfoAdapter); ProgressBar progressBar = findViewById(R.id.server_info_progress_bar); progressBar.setVisibility(View.GONE); } + + @Override + protected void onResume() { + super.onResume(); + updateList(); + } + + @Override + public boolean onMenuItemClick(MenuItem menuItem) { + if (menuItem.getItemId() == R.id.action_clear_log) { + PushManager.clearPushLog(); + updateList(); + return true; + } + return false; + } + + private void updateList() { + List log = PushManager.getPushLogs(); + if (log != null) { + serverInfoAdapter.setServerInfoList(log); + serverInfoAdapter.notifyDataSetChanged(); + } + } } From 0263568d1ae2f8f306cce9cee0c35a5b1b8bc503 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 29 May 2019 14:34:05 +0500 Subject: [PATCH 108/237] Removed unused code --- .../xabber/android/data/SettingsManager.java | 24 ------------------- xabber/src/main/res/values/preferences.xml | 2 -- 2 files changed, 26 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/SettingsManager.java b/xabber/src/main/java/com/xabber/android/data/SettingsManager.java index 75ac1bc830..b7c22db2d4 100644 --- a/xabber/src/main/java/com/xabber/android/data/SettingsManager.java +++ b/xabber/src/main/java/com/xabber/android/data/SettingsManager.java @@ -46,9 +46,7 @@ import java.util.Collections; import java.util.Comparator; -import java.util.HashSet; import java.util.Map; -import java.util.Set; import java.util.regex.Pattern; /** @@ -144,17 +142,6 @@ private static void setString(int key, String value) { editor.commit(); } - private static Set getStringSet(int key) { - return getSharedPreferences().getStringSet( - Application.getInstance().getString(key), null); - } - - private static void setStringSet(int key, Set set) { - Editor editor = getSharedPreferences().edit(); - editor.putStringSet(Application.getInstance().getString(key), set); - editor.commit(); - } - private static String getNotifString(int key, String def) { return getNotificationSharedPreferences().getString( Application.getInstance().getString(key), def); @@ -875,17 +862,6 @@ public static String getEnabledPushNodes() { return getString(R.string.enabled_push_nodes, ""); } - public static Set getPushLog() { - return getStringSet(R.string.push_log); - } - - public static void addToPushLog(String event) { - Set log = getPushLog(); - if (log == null) log = new HashSet<>(); - log.add(event); - setStringSet(R.string.push_log, log); - } - public static void resetPreferences(Context context, String preferencesName) { context.getSharedPreferences(preferencesName, Context.MODE_PRIVATE).edit().clear().apply(); } diff --git a/xabber/src/main/res/values/preferences.xml b/xabber/src/main/res/values/preferences.xml index 7076778217..ecb1e15211 100644 --- a/xabber/src/main/res/values/preferences.xml +++ b/xabber/src/main/res/values/preferences.xml @@ -539,8 +539,6 @@ chat_events_suppress_100 false - push_log - From 58ecd0222820cc2c8f4e34f211fab9dd502e984a Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 29 May 2019 14:48:53 +0500 Subject: [PATCH 109/237] Push logs stored only in dev flavour --- .../main/java/com/xabber/android/data/push/PushManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java index baf4135a8f..253e2a1326 100644 --- a/xabber/src/main/java/com/xabber/android/data/push/PushManager.java +++ b/xabber/src/main/java/com/xabber/android/data/push/PushManager.java @@ -6,6 +6,7 @@ import android.util.Log; import com.google.firebase.iid.FirebaseInstanceId; +import com.xabber.android.BuildConfig; import com.xabber.android.data.Application; import com.xabber.android.data.SettingsManager; import com.xabber.android.data.account.AccountItem; @@ -122,7 +123,7 @@ public void onNewMessagePush(Context context, String node) { } else message = "Service also started. Not a sync mode - account maybe connected"; LogManager.d(LOG_TAG, "Received message push. " + message); - addToPushLog(message); + if (BuildConfig.FLAVOR.equals("dev")) addToPushLog(message); } @Override From f3e2ac3717202adac9c5e842aeab1fdcb1442a65 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 29 May 2019 17:18:35 +0500 Subject: [PATCH 110/237] Some optimizations of contact list update --- .../data/roster/RosterCacheManager.java | 19 ++++ .../mvp/contactlist/UpdateBackpressure.java | 2 +- .../com/xabber/android/utils/StringUtils.java | 104 +++++++++--------- 3 files changed, 74 insertions(+), 51 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java index 3b65d1726c..d8062fbc2d 100644 --- a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java +++ b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java @@ -7,13 +7,24 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import io.realm.Realm; import io.realm.RealmList; public class RosterCacheManager { + private static RosterCacheManager instance; + private Map lastActivityCache = new HashMap<>(); + + public static RosterCacheManager getInstance() { + if (instance == null) + instance = new RosterCacheManager(); + return instance; + } + public static List loadContacts() { Realm realm = MessageDatabaseManager.getInstance().getRealmUiThread(); return realm.where(ContactRealm.class).findAll(); @@ -79,4 +90,12 @@ public static void saveLastMessageToContact(Realm realm, MessageItem messageItem } realm.commitTransaction(); } + + public String getCachedLastActivityString(long lastActivityTime) { + return lastActivityCache.get(lastActivityTime); + } + + public void putLastActivityStringToCache(long lastActivityTime, String string) { + lastActivityCache.put(lastActivityTime, string); + } } diff --git a/xabber/src/main/java/com/xabber/android/presentation/mvp/contactlist/UpdateBackpressure.java b/xabber/src/main/java/com/xabber/android/presentation/mvp/contactlist/UpdateBackpressure.java index 96ad6e433e..e7fa2959b5 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/mvp/contactlist/UpdateBackpressure.java +++ b/xabber/src/main/java/com/xabber/android/presentation/mvp/contactlist/UpdateBackpressure.java @@ -10,7 +10,7 @@ public class UpdateBackpressure implements Runnable { - private static final long REFRESH_INTERVAL = 50; + private static final long REFRESH_INTERVAL = 500; public interface UpdatableObject { void update(); diff --git a/xabber/src/main/java/com/xabber/android/utils/StringUtils.java b/xabber/src/main/java/com/xabber/android/utils/StringUtils.java index 10d8ef41bc..ffb667f189 100644 --- a/xabber/src/main/java/com/xabber/android/utils/StringUtils.java +++ b/xabber/src/main/java/com/xabber/android/utils/StringUtils.java @@ -19,6 +19,7 @@ import com.xabber.android.R; import com.xabber.android.data.Application; +import com.xabber.android.data.roster.RosterCacheManager; import java.text.DateFormat; import java.text.DateFormatSymbols; @@ -195,58 +196,61 @@ public static SimpleDateFormat getLogDateTimeFormat() { } public static String getLastActivityString(long lastActivityTime) { - if (lastActivityTime > 0) { - long timeAgo = System.currentTimeMillis()/1000 - lastActivityTime; - long time; - - if (timeAgo < 60) return Application.getInstance().getString(R.string.last_seen_now); - if (timeAgo < 3600) { - time = TimeUnit.SECONDS.toMinutes(timeAgo); - return Application.getInstance().getString(R.string.last_seen_minutes, String.valueOf(time)); + String result = RosterCacheManager.getInstance().getCachedLastActivityString(lastActivityTime); + + if (result == null || result.isEmpty()) { + result = ""; + if (lastActivityTime > 0) { + long timeAgo = System.currentTimeMillis()/1000 - lastActivityTime; + long time; + String sTime; + Date date = new Date(lastActivityTime * 1000); + Date today = new Date(); + Locale locale = Application.getInstance().getResources().getConfiguration().locale; + + if (timeAgo < 60) { + result = Application.getInstance().getString(R.string.last_seen_now); + + } else if (timeAgo < 3600) { + time = TimeUnit.SECONDS.toMinutes(timeAgo); + result = Application.getInstance().getString(R.string.last_seen_minutes, String.valueOf(time)); + + } else if (timeAgo < 7200) { + result = Application.getInstance().getString(R.string.last_seen_hours); + + } else if (isToday(date)) { + SimpleDateFormat pattern = new SimpleDateFormat("HH:mm", locale); + sTime = pattern.format(date); + result = Application.getInstance().getString(R.string.last_seen_today, sTime); + + } else if (isYesterday(date)) { + SimpleDateFormat pattern = new SimpleDateFormat("HH:mm", locale); + sTime = pattern.format(date); + result = Application.getInstance().getString(R.string.last_seen_yesterday, sTime); + + } else if (timeAgo < TimeUnit.DAYS.toSeconds(7)) { + SimpleDateFormat pattern = new SimpleDateFormat("HH:mm", locale); + sTime = pattern.format(date); + result = Application.getInstance().getString(R.string.last_seen_on_week, + getDayOfWeek(date, locale), sTime); + + } else if (date.getYear() == today.getYear()) { + SimpleDateFormat pattern = new SimpleDateFormat("d MMMM", locale); + sTime = pattern.format(date); + result = Application.getInstance().getString(R.string.last_seen_date, sTime); + + } else if (date.getYear() < today.getYear()) { + SimpleDateFormat pattern = new SimpleDateFormat("d MMMM yyyy", locale); + sTime = pattern.format(date); + result = Application.getInstance().getString(R.string.last_seen_date, sTime); + } + + if (!result.isEmpty()) + RosterCacheManager.getInstance().putLastActivityStringToCache(lastActivityTime, result); } - if (timeAgo < 7200) { - time = TimeUnit.SECONDS.toHours(timeAgo); - return Application.getInstance().getString(R.string.last_seen_hours); - } - - String sTime; - Date date = new Date(lastActivityTime * 1000); - Date today = new Date(); - Locale locale = Application.getInstance().getResources().getConfiguration().locale; - - if (isToday(date)) { - SimpleDateFormat pattern = new SimpleDateFormat("HH:mm", locale); - sTime = pattern.format(date); - return Application.getInstance().getString(R.string.last_seen_today, sTime); - } - - if (isYesterday(date)) { - SimpleDateFormat pattern = new SimpleDateFormat("HH:mm", locale); - sTime = pattern.format(date); - return Application.getInstance().getString(R.string.last_seen_yesterday, sTime); - } - - if (timeAgo < TimeUnit.DAYS.toSeconds(7)) { - SimpleDateFormat pattern = new SimpleDateFormat("HH:mm", locale); - sTime = pattern.format(date); - return Application.getInstance().getString(R.string.last_seen_on_week, - getDayOfWeek(date, locale), sTime); - } - - if (date.getYear() == today.getYear()) { - SimpleDateFormat pattern = new SimpleDateFormat("d MMMM", locale); - sTime = pattern.format(date); - return Application.getInstance().getString(R.string.last_seen_date, sTime); - } - - if (date.getYear() < today.getYear()) { - SimpleDateFormat pattern = new SimpleDateFormat("d MMMM yyyy", locale); - sTime = pattern.format(date); - return Application.getInstance().getString(R.string.last_seen_date, sTime); - } - return ""; } - else return ""; + + return result; } public static boolean isToday(Date date) { From a6d86dc84877c76e7db50215ccb499c79ff80e4c Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 29 May 2019 17:40:26 +0500 Subject: [PATCH 111/237] Added preference of sync bookmarks on app start --- xabber/src/dev/res/values/preferences.xml | 1 + xabber/src/dev/res/xml/preference_debug.xml | 6 ++++++ .../main/java/com/xabber/android/data/SettingsManager.java | 4 ++++ .../android/data/extension/bookmarks/BookmarksManager.java | 6 +++--- xabber/src/main/res/values/preference_editor.xml | 1 + xabber/src/main/res/values/preferences.xml | 1 + 6 files changed, 16 insertions(+), 3 deletions(-) diff --git a/xabber/src/dev/res/values/preferences.xml b/xabber/src/dev/res/values/preferences.xml index 224b22e6ad..eb82acccb9 100644 --- a/xabber/src/dev/res/values/preferences.xml +++ b/xabber/src/dev/res/values/preferences.xml @@ -17,5 +17,6 @@ true true + false diff --git a/xabber/src/dev/res/xml/preference_debug.xml b/xabber/src/dev/res/xml/preference_debug.xml index 41e4b0b1ef..db03248080 100644 --- a/xabber/src/dev/res/xml/preference_debug.xml +++ b/xabber/src/dev/res/xml/preference_debug.xml @@ -61,4 +61,10 @@ android:targetPackage="@string/application_package" /> + + \ No newline at end of file diff --git a/xabber/src/main/java/com/xabber/android/data/SettingsManager.java b/xabber/src/main/java/com/xabber/android/data/SettingsManager.java index b7c22db2d4..082c6838dc 100644 --- a/xabber/src/main/java/com/xabber/android/data/SettingsManager.java +++ b/xabber/src/main/java/com/xabber/android/data/SettingsManager.java @@ -600,6 +600,10 @@ public static boolean useDevelopAPI() { return getBoolean(R.string.debug_use_develop_api_key, R.bool.debug_use_develop_api_default); } + public static boolean syncBookmarksOnStart() { + return getBoolean(R.string.debug_sync_bookmarks_on_start_key, R.bool.debug_sync_bookmarks_on_start_default); + } + public static boolean isCrashReportsSupported() { return BuildConfig.FLAVOR.equals("beta") || BuildConfig.FLAVOR.equals("vip") diff --git a/xabber/src/main/java/com/xabber/android/data/extension/bookmarks/BookmarksManager.java b/xabber/src/main/java/com/xabber/android/data/extension/bookmarks/BookmarksManager.java index cd4517dd41..ee7ee45398 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/bookmarks/BookmarksManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/bookmarks/BookmarksManager.java @@ -3,6 +3,7 @@ import android.support.annotation.NonNull; import com.xabber.android.data.Application; +import com.xabber.android.data.SettingsManager; import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.account.AccountManager; import com.xabber.android.data.entity.AccountJid; @@ -19,9 +20,7 @@ import org.jivesoftware.smackx.bookmarks.BookmarkManager; import org.jivesoftware.smackx.bookmarks.BookmarkedConference; import org.jivesoftware.smackx.bookmarks.BookmarkedURL; -import org.jxmpp.jid.BareJid; import org.jxmpp.jid.EntityBareJid; -import org.jxmpp.jid.Jid; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.jid.parts.Resourcepart; import org.jxmpp.stringprep.XmppStringprepException; @@ -31,7 +30,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Set; /** * Manage bookmarks and there requests. @@ -184,6 +182,8 @@ public void cleanCache(AccountJid accountJid) { } public void onAuthorized(AccountJid account) { + if (!SettingsManager.syncBookmarksOnStart()) return; + cleanCache(account); List conferences; diff --git a/xabber/src/main/res/values/preference_editor.xml b/xabber/src/main/res/values/preference_editor.xml index ba41955e68..9a60e17c18 100644 --- a/xabber/src/main/res/values/preference_editor.xml +++ b/xabber/src/main/res/values/preference_editor.xml @@ -28,6 +28,7 @@ Show connection errors\nDisplay connection exceptions pop-ups Share crash and diagnostics data\nHelp app developers improve Xabber by allowing to share crash and diagnostics data with them (please restart application to apply changes). Use development Xabber API\nChanges will be applied after restart + Sync bookmarks on start Fetch crowdfunding feed now Crash and diagnostics data diff --git a/xabber/src/main/res/values/preferences.xml b/xabber/src/main/res/values/preferences.xml index ecb1e15211..7ba23046c7 100644 --- a/xabber/src/main/res/values/preferences.xml +++ b/xabber/src/main/res/values/preferences.xml @@ -386,6 +386,7 @@ debug_develop_xabber_api_key false debug_fetch_crowdfunding_feed_key + debug_sync_bookmarks_on_start_key @string/about_viewer From ec54254beb46c2a6661b3a73273005e3e4b51257 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 29 May 2019 17:56:22 +0500 Subject: [PATCH 112/237] Up version to 616 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index c781970865..50d0ce2340 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 615 - versionName '2.6.4(615)' + versionCode 616 + versionName '2.6.4(616)' } lintOptions { From d45f77af756441443ac64af5272b1e2dad94e7f1 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 30 May 2019 11:56:03 +0500 Subject: [PATCH 113/237] In all branches except dev by default bookmarks sync is enabled --- xabber/src/main/res/values/preferences.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/xabber/src/main/res/values/preferences.xml b/xabber/src/main/res/values/preferences.xml index 7ba23046c7..b2b2460ac2 100644 --- a/xabber/src/main/res/values/preferences.xml +++ b/xabber/src/main/res/values/preferences.xml @@ -385,6 +385,7 @@ debug_download_all_messages_key debug_develop_xabber_api_key false + true debug_fetch_crowdfunding_feed_key debug_sync_bookmarks_on_start_key From bf315aa846724e41bf4817d6cdd3afa2f701c30b Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 30 May 2019 12:20:28 +0500 Subject: [PATCH 114/237] Added removing account from cached on disabling --- .../java/com/xabber/android/data/account/AccountManager.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java index 046756d32d..036739851e 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java @@ -733,6 +733,9 @@ public void setEnabled(AccountJid account, boolean enabled) { // disable push if (!enabled) PushManager.getInstance().disablePushNotification(getAccount(account), false); + // remove from cached if disabled + if (!enabled) cachedEnabledAccounts.remove(account); + accountItem.setEnabled(enabled); requestToWriteAccount(accountItem); PushManager.getInstance().updateEnabledPushNodes(); From 1cef09fe5d40a7d80c47d40540310cd96698cf52 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 30 May 2019 14:33:46 +0500 Subject: [PATCH 115/237] Added removing contacts from cache on account deleting --- .../xabber/android/data/account/AccountManager.java | 5 +++++ .../android/data/roster/RosterCacheManager.java | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java index 036739851e..be7a0ea71c 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java @@ -53,6 +53,7 @@ import com.xabber.android.data.notification.NotificationManager; import com.xabber.android.data.push.PushManager; import com.xabber.android.data.roster.PresenceManager; +import com.xabber.android.data.roster.RosterCacheManager; import com.xabber.android.data.roster.RosterManager; import com.xabber.android.data.xaccount.XabberAccountManager; @@ -507,6 +508,10 @@ private void removeAccountWithoutCallback(final AccountJid account) { // disable push PushManager.getInstance().disablePushNotification(getAccount(account), false); + // remove contacts and account from cache + RosterCacheManager.removeContacts(account); + cachedEnabledAccounts.remove(account); + boolean wasEnabled = accountItem.isEnabled(); accountItem.setEnabled(false); accountItem.disconnect(); diff --git a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java index d8062fbc2d..dab65102ac 100644 --- a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java +++ b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java @@ -4,6 +4,7 @@ import com.xabber.android.data.database.messagerealm.MessageItem; import com.xabber.android.data.database.realm.ContactGroup; import com.xabber.android.data.database.realm.ContactRealm; +import com.xabber.android.data.entity.AccountJid; import java.util.ArrayList; import java.util.Collection; @@ -13,6 +14,7 @@ import io.realm.Realm; import io.realm.RealmList; +import io.realm.RealmResults; public class RosterCacheManager { @@ -78,6 +80,16 @@ public static void removeContact(Collection contacts) { realm.commitTransaction(); } + public static void removeContacts(AccountJid account) { + String accountJid = account.getFullJid().asBareJid().toString(); + Realm realm = MessageDatabaseManager.getInstance().getRealmUiThread(); + RealmResults results = realm.where(ContactRealm.class) + .equalTo(ContactRealm.Fields.ACCOUNT, accountJid).findAll(); + realm.beginTransaction(); + results.deleteAllFromRealm(); + realm.commitTransaction(); + } + public static void saveLastMessageToContact(Realm realm, MessageItem messageItem) { if (messageItem == null) return; String account = messageItem.getAccount().getFullJid().asBareJid().toString(); From 9a4d860baddd7f33f159a1a0c29aa9d73cc5b821 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 30 May 2019 15:18:06 +0500 Subject: [PATCH 116/237] Changes in pre-initialize process --- .../main/java/com/xabber/android/data/ActivityManager.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/ActivityManager.java b/xabber/src/main/java/com/xabber/android/data/ActivityManager.java index f8dd34b3cf..a61b40c33d 100644 --- a/xabber/src/main/java/com/xabber/android/data/ActivityManager.java +++ b/xabber/src/main/java/com/xabber/android/data/ActivityManager.java @@ -206,16 +206,18 @@ public void onResume(final Activity activity) { if (LOG) { LogManager.i(activity, "onResume"); } - if (!application.isInitialized() && !Application.getInstance().isClosing()) { + if((!application.isInitialized() || SyncManager.getInstance().isSyncMode()) + && !Application.getInstance().isClosing()) { + if (LOG) { LogManager.i(this, "Wait for loading"); } AccountManager.getInstance().onPreInitialize(); RosterManager.getInstance().onPreInitialize(); + AvatarManager.getInstance().onPreInitialize(); Application.getInstance().runInBackground(new Runnable() { @Override public void run() { - AvatarManager.getInstance().onPreInitialize(); try { Thread.sleep(START_SERVICE_DELAY); } catch (InterruptedException e) { From 6a99aefe7482250890bd266946613730c4315f04 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 30 May 2019 15:52:30 +0500 Subject: [PATCH 117/237] Added limit of notification frequency --- .../data/notification/MessageNotificationCreator.java | 2 ++ .../data/notification/MessageNotificationManager.java | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationCreator.java b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationCreator.java index 8c9a9e5677..65b38b2d3d 100644 --- a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationCreator.java +++ b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationCreator.java @@ -152,6 +152,7 @@ private String getChannelID(MessageNotificationManager.Chat chat) { } private void sendNotification(NotificationCompat.Builder builder, int notificationId) { + MessageNotificationManager.getInstance().setLastNotificationTime(); try { notificationManager.notify(notificationId, builder.build()); } catch (SecurityException e) { @@ -164,6 +165,7 @@ private void sendNotification(NotificationCompat.Builder builder, int notificati /** UTILS */ private static boolean inGracePeriod(MessageNotificationManager.Chat chat) { + if (!MessageNotificationManager.getInstance().isTimeToNewFullNotification()) return true; if (chat == null) return false; AccountItem accountItem = AccountManager.getInstance().getAccount(chat.getAccountJid()); if (accountItem != null) return accountItem.inGracePeriod(); diff --git a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java index 0c3fbdca99..59fdec7807 100644 --- a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java +++ b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java @@ -44,6 +44,7 @@ public class MessageNotificationManager implements OnLoadListener { private List chats = new ArrayList<>(); private Message lastMessage = null; private HashMap delayedActions = new HashMap<>(); + private long lastNotificationTime = 0; private MessageNotificationManager() { context = Application.getInstance(); @@ -71,6 +72,14 @@ public static MessageNotificationManager getInstance() { return instance; } + public boolean isTimeToNewFullNotification() { + return System.currentTimeMillis() > (lastNotificationTime + 1000); + } + + public void setLastNotificationTime() { + this.lastNotificationTime = System.currentTimeMillis(); + } + /** LISTENER */ public void onNotificationAction(Action action) { From c31b97d16eb65a5e059796e2e194e761ff9e5db3 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 30 May 2019 16:35:32 +0500 Subject: [PATCH 118/237] Fixed bottom view layout --- xabber/src/main/res/layout-v22/view_bottom_navigation.xml | 2 +- xabber/src/main/res/layout/view_bottom_navigation.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/res/layout-v22/view_bottom_navigation.xml b/xabber/src/main/res/layout-v22/view_bottom_navigation.xml index 88f1cdb747..363af5c35e 100644 --- a/xabber/src/main/res/layout-v22/view_bottom_navigation.xml +++ b/xabber/src/main/res/layout-v22/view_bottom_navigation.xml @@ -12,7 +12,7 @@ Date: Thu, 30 May 2019 17:46:17 +0500 Subject: [PATCH 119/237] Changed algorithm of updating roster cache --- .../xabber/android/data/roster/RosterCacheManager.java | 9 ++++++++- .../com/xabber/android/data/roster/RosterManager.java | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java index dab65102ac..1a8dde85a6 100644 --- a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java +++ b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java @@ -32,10 +32,17 @@ public static List loadContacts() { return realm.where(ContactRealm.class).findAll(); } - public static void saveContact(Collection contacts) { + public static void saveContact(AccountJid accountJid, Collection contacts) { Realm realm = MessageDatabaseManager.getInstance().getRealmUiThread(); realm.beginTransaction(); + if (contacts.size() > 1) { + RealmResults results = realm.where(ContactRealm.class) + .equalTo(ContactRealm.Fields.ACCOUNT, + accountJid.getFullJid().asBareJid().toString()).findAll(); + results.deleteAllFromRealm(); + } + List newContacts = new ArrayList<>(); for (RosterContact contact : contacts) { String account = contact.getAccount().getFullJid().asBareJid().toString(); diff --git a/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java b/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java index abdd53b54f..b4368f4207 100644 --- a/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java +++ b/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java @@ -168,7 +168,7 @@ public Collection getAllContacts() { return Collections.unmodifiableCollection(rosterContacts.values()); } - void onContactsAdded(AccountJid account, Collection addresses) { + void onContactsAdded(final AccountJid account, Collection addresses) { final Roster roster = RosterManager.getInstance().getRoster(account); final Collection newContacts = new ArrayList<>(addresses.size()); for (Jid jid : addresses) { @@ -188,7 +188,7 @@ void onContactsAdded(AccountJid account, Collection addresses) { Application.getInstance().runOnUiThread(new Runnable() { @Override public void run() { - RosterCacheManager.saveContact(newContacts); + RosterCacheManager.saveContact(account, newContacts); } }); onContactsChanged(newContacts); From 5847b20346d2f203b19cb490cc64723fe969afb9 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 30 May 2019 18:28:54 +0500 Subject: [PATCH 120/237] Fixed crash in RosterCacheManager --- .../data/roster/RosterCacheManager.java | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java index 1a8dde85a6..33fb35e207 100644 --- a/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java +++ b/xabber/src/main/java/com/xabber/android/data/roster/RosterCacheManager.java @@ -99,15 +99,20 @@ public static void removeContacts(AccountJid account) { public static void saveLastMessageToContact(Realm realm, MessageItem messageItem) { if (messageItem == null) return; - String account = messageItem.getAccount().getFullJid().asBareJid().toString(); - String user = messageItem.getUser().getBareJid().toString(); - ContactRealm contactRealm = realm.where(ContactRealm.class).equalTo(ContactRealm.Fields.ID, account + "/" + user).findFirst(); - realm.beginTransaction(); - if (contactRealm != null && messageItem.isValid() && messageItem.isManaged()) { - contactRealm.setLastMessage(messageItem); - realm.copyToRealmOrUpdate(contactRealm); - } - realm.commitTransaction(); + final String account = messageItem.getAccount().getFullJid().asBareJid().toString(); + final String user = messageItem.getUser().getBareJid().toString(); + final String messageID = messageItem.getUniqueId(); + realm.executeTransactionAsync(new Realm.Transaction() { + @Override + public void execute(Realm realm) { + ContactRealm contactRealm = realm.where(ContactRealm.class).equalTo(ContactRealm.Fields.ID, account + "/" + user).findFirst(); + MessageItem message = realm.where(MessageItem.class).equalTo(MessageItem.Fields.UNIQUE_ID, messageID).findFirst(); + if (contactRealm != null && message.isValid() && message.isManaged()) { + contactRealm.setLastMessage(message); + realm.copyToRealmOrUpdate(contactRealm); + } + } + }); } public String getCachedLastActivityString(long lastActivityTime) { From 7ed773db5fbfaccc4c442dc6394f5f74b182e2b7 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 30 May 2019 18:38:52 +0500 Subject: [PATCH 121/237] Changes in message status view --- .../xabber/android/ui/adapter/chat/OutgoingMessageVH.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/OutgoingMessageVH.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/OutgoingMessageVH.java index 12dcdde180..cbc3976ebf 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/OutgoingMessageVH.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/OutgoingMessageVH.java @@ -105,12 +105,11 @@ private void setStatusIcon(MessageItem messageItem) { if (isFileUploadInProgress) progressBar.setVisibility(View.VISIBLE); - int messageIcon = 0; + int messageIcon = R.drawable.ic_message_not_sent_14dp; if (messageItem.isError()) { messageIcon = R.drawable.ic_message_has_error_14dp; - } else if (!isFileUploadInProgress && !messageItem.isSent() - && System.currentTimeMillis() - messageItem.getTimestamp() > 1000) { + } else if (!isFileUploadInProgress && !messageItem.isSent()) { messageIcon = R.drawable.ic_message_not_sent_14dp; } else if (messageItem.isDisplayed() || messageItem.isReceivedFromMessageArchive()) { messageIcon = R.drawable.ic_message_displayed; From 08cb07b2d1bccb1687fa4b591be6fd4e25803d0d Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 30 May 2019 18:40:14 +0500 Subject: [PATCH 122/237] Up version to 617 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 50d0ce2340..834d7439f2 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 616 - versionName '2.6.4(616)' + versionCode 617 + versionName '2.6.4(617)' } lintOptions { From 2a2783ff9f7df0dafd247df8b065075be613a4d1 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 31 May 2019 12:17:03 +0500 Subject: [PATCH 123/237] Request for last activity changed to async --- .../com/xabber/android/data/Application.java | 2 + .../iqlast/LastActivityInteractor.java | 62 ++++++++++--------- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/Application.java b/xabber/src/main/java/com/xabber/android/data/Application.java index 2b96b08c2e..cf991341c2 100644 --- a/xabber/src/main/java/com/xabber/android/data/Application.java +++ b/xabber/src/main/java/com/xabber/android/data/Application.java @@ -44,6 +44,7 @@ import com.xabber.android.data.extension.chat_markers.ChatMarkerManager; import com.xabber.android.data.extension.cs.ChatStateManager; import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager; +import com.xabber.android.data.extension.iqlast.LastActivityInteractor; import com.xabber.android.data.extension.mam.NextMamManager; import com.xabber.android.data.extension.muc.MUCManager; import com.xabber.android.data.extension.otr.OTRManager; @@ -392,6 +393,7 @@ private void addManagers() { addManager(XMPPAuthManager.getInstance()); addManager(PushManager.getInstance()); addManager(DelayedNotificationActionManager.getInstance()); + addManager(LastActivityInteractor.getInstance()); } /** diff --git a/xabber/src/main/java/com/xabber/android/data/extension/iqlast/LastActivityInteractor.java b/xabber/src/main/java/com/xabber/android/data/extension/iqlast/LastActivityInteractor.java index 90b6cf6c83..a6d7098602 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/iqlast/LastActivityInteractor.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/iqlast/LastActivityInteractor.java @@ -3,20 +3,22 @@ import com.xabber.android.data.Application; import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.account.AccountManager; +import com.xabber.android.data.connection.ConnectionItem; +import com.xabber.android.data.connection.listeners.OnPacketListener; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.entity.UserJid; +import com.xabber.android.data.log.LogManager; import com.xabber.android.data.roster.RosterManager; import org.jivesoftware.smack.SmackException; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.tcp.XMPPTCPConnection; -import org.jivesoftware.smackx.iqlast.LastActivityManager; +import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smackx.iqlast.packet.LastActivity; +import org.jxmpp.jid.Jid; import java.util.HashMap; import java.util.LinkedList; -public class LastActivityInteractor { +public class LastActivityInteractor implements OnPacketListener { private static LastActivityInteractor instance; private HashMap lastActivities = new HashMap<>(); @@ -28,6 +30,22 @@ public static LastActivityInteractor getInstance() { return instance; } + @Override + public void onStanza(ConnectionItem connection, Stanza packet) { + if (packet instanceof LastActivity) { + try { + Jid jid = packet.getFrom(); + long result = ((LastActivity) packet).lastActivity; + if (result > 0) { + result = System.currentTimeMillis() / 1000 - result; + setLastActivity(connection.getAccount(), UserJid.from(jid), result); + } + } catch (UserJid.UserJidCreateException e) { + e.printStackTrace(); + } + } + } + public void addJidToLastActivityQuery(AccountJid account, UserJid user) { queryForLastActivityUpdate.addLast(new JidPair(account, user)); if (!this.isRun) @@ -59,37 +77,21 @@ private synchronized void runGettingLastActivity() { this.isRun = true; while (!queryForLastActivityUpdate.isEmpty()) { JidPair item = queryForLastActivityUpdate.removeFirst(); - long lastActivity = requestLastActivity(item.account, item.user); - setLastActivity(item.account, item.user, lastActivity); + requestLastActivityAsync(item.account, item.user); } this.isRun = false; } - private long requestLastActivity(AccountJid account, UserJid user) { - long lastActivitySeconds = 0; - - AccountItem accountItem = AccountManager - .getInstance().getAccount(account); - - if (accountItem == null) return lastActivitySeconds; - - XMPPTCPConnection xmppConnection = accountItem.getConnection(); - - LastActivityManager lastActivityManager = LastActivityManager.getInstanceFor(xmppConnection); - LastActivity lastActivity = null; - - try { - lastActivity = lastActivityManager.getLastActivity(user.getJid()); - } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException - | SmackException.NotConnectedException | InterruptedException e) { - e.printStackTrace(); + private void requestLastActivityAsync(AccountJid account, UserJid user) { + AccountItem accountItem = AccountManager.getInstance().getAccount(account); + if (accountItem != null) { + LastActivity activity = new LastActivity(user.getJid()); + try { + accountItem.getConnection().sendStanza(activity); + } catch (SmackException.NotConnectedException | InterruptedException e) { + LogManager.d(LastActivityInteractor.class, e.toString()); + } } - - if (lastActivity != null) lastActivitySeconds = lastActivity.lastActivity; - - if (lastActivitySeconds > 0) - lastActivitySeconds = System.currentTimeMillis()/1000 - lastActivitySeconds; - return lastActivitySeconds; } private class JidPair { From ad515d3caa98879d621c498fde69361ae6173263 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 31 May 2019 12:28:01 +0500 Subject: [PATCH 124/237] Refactoring in last activity interactor --- .../iqlast/LastActivityInteractor.java | 43 ++----------------- .../android/data/roster/RosterManager.java | 2 +- 2 files changed, 5 insertions(+), 40 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/iqlast/LastActivityInteractor.java b/xabber/src/main/java/com/xabber/android/data/extension/iqlast/LastActivityInteractor.java index a6d7098602..bc61c67583 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/iqlast/LastActivityInteractor.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/iqlast/LastActivityInteractor.java @@ -1,6 +1,5 @@ package com.xabber.android.data.extension.iqlast; -import com.xabber.android.data.Application; import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.account.AccountManager; import com.xabber.android.data.connection.ConnectionItem; @@ -16,14 +15,11 @@ import org.jxmpp.jid.Jid; import java.util.HashMap; -import java.util.LinkedList; public class LastActivityInteractor implements OnPacketListener { private static LastActivityInteractor instance; private HashMap lastActivities = new HashMap<>(); - private LinkedList queryForLastActivityUpdate = new LinkedList<>(); - private boolean isRun; public static LastActivityInteractor getInstance() { if (instance == null) instance = new LastActivityInteractor(); @@ -46,17 +42,6 @@ public void onStanza(ConnectionItem connection, Stanza packet) { } } - public void addJidToLastActivityQuery(AccountJid account, UserJid user) { - queryForLastActivityUpdate.addLast(new JidPair(account, user)); - if (!this.isRun) - Application.getInstance().runInBackground(new Runnable() { - @Override - public void run() { - runGettingLastActivity(); - } - }); - } - public void setLastActivityTimeNow(AccountJid account, UserJid user) { long time = System.currentTimeMillis()/1000; setLastActivity(account, user, time); @@ -68,21 +53,7 @@ public long getLastActivity(UserJid user) { else return 0; } - private void setLastActivity(AccountJid account, UserJid user, long time) { - lastActivities.put(user, time); - RosterManager.onContactChanged(account, user); - } - - private synchronized void runGettingLastActivity() { - this.isRun = true; - while (!queryForLastActivityUpdate.isEmpty()) { - JidPair item = queryForLastActivityUpdate.removeFirst(); - requestLastActivityAsync(item.account, item.user); - } - this.isRun = false; - } - - private void requestLastActivityAsync(AccountJid account, UserJid user) { + public void requestLastActivityAsync(AccountJid account, UserJid user) { AccountItem accountItem = AccountManager.getInstance().getAccount(account); if (accountItem != null) { LastActivity activity = new LastActivity(user.getJid()); @@ -94,15 +65,9 @@ private void requestLastActivityAsync(AccountJid account, UserJid user) { } } - private class JidPair { - AccountJid account; - UserJid user; - - public JidPair(AccountJid account, UserJid user) { - this.account = account; - this.user = user; - } - + private void setLastActivity(AccountJid account, UserJid user, long time) { + lastActivities.put(user, time); + RosterManager.onContactChanged(account, user); } } diff --git a/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java b/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java index b4368f4207..673a06d2b4 100644 --- a/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java +++ b/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java @@ -179,7 +179,7 @@ void onContactsAdded(final AccountJid account, Collection addresses) { contact.getUser().getBareJid().toString(), contact); newContacts.add(contact); - LastActivityInteractor.getInstance().addJidToLastActivityQuery(account, UserJid.from(jid)); + LastActivityInteractor.getInstance().requestLastActivityAsync(account, UserJid.from(jid)); } catch (UserJid.UserJidCreateException e) { LogManager.exception(LOG_TAG, e); } From cd78e694719f6f6824232a59ab12f388cedc5fb5 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 31 May 2019 14:47:16 +0500 Subject: [PATCH 125/237] Fixed bug with duplicate messages --- .../data/extension/mam/NextMamManager.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index c66eb1d460..ffb60fa318 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -130,18 +130,16 @@ public void run() { MessageItem firstMessage = getFirstMessage(chat, realm); if (firstMessage == null) loadLastMessage(realm, accountItem, chat); + synchronized (lock) { + if (isRequested) return; + else isRequested = true; + } + // load prev page if history is not enough if (historyIsNotEnough(realm, chat) && !chat.historyIsFull()) { - synchronized (lock) { - if (isRequested) return; - else isRequested = true; - } EventBus.getDefault().post(new LastHistoryLoadStartedEvent(chat)); loadNextHistory(realm, accountItem, chat); EventBus.getDefault().post(new LastHistoryLoadFinishedEvent(chat)); - synchronized (lock) { - isRequested = false; - } } // load missed messages if need @@ -151,6 +149,10 @@ public void run() { loadMissedMessages(realm, accountItem, chat, message); } } + + synchronized (lock) { + isRequested = false; + } realm.close(); } }); From 9f718a54eca91c9569f444997d14f9ac9975af8e Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 31 May 2019 16:21:40 +0500 Subject: [PATCH 126/237] Fixed bug with duplicate messages --- .../com/xabber/android/data/extension/mam/NextMamManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index ffb60fa318..8715506502 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -164,7 +164,7 @@ public void onScrollInChat(final AbstractChat chat) { || !isSupported(accountItem.getAccount())) return; if (chat.historyIsFull()) return; - Application.getInstance().runInBackgroundUserRequest(new Runnable() { + Application.getInstance().runInBackground(new Runnable() { @Override public void run() { synchronized (lock) { @@ -733,7 +733,7 @@ private MessageItem determineSaveOrUpdate(Realm realm, final MessageItem message .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) .equalTo(MessageItem.Fields.STANZA_ID, message.getStanzaId()) .or().equalTo(MessageItem.Fields.STANZA_ID, message.getPacketId()) - .or().equalTo(MessageItem.Fields.STANZA_ID, message.getArchivedId()) + .or().equalTo(MessageItem.Fields.ARCHIVED_ID, message.getArchivedId()) .findFirst(); if (localMessage == null) { From 10aee6d1152d49a87b7467b97e0ab09682164350 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 31 May 2019 16:22:48 +0500 Subject: [PATCH 127/237] Fixed concurrentModificationException --- .../java/com/xabber/android/data/account/AccountManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java index be7a0ea71c..5d5ce0bf21 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java @@ -750,8 +750,9 @@ public void setEnabled(AccountJid account, boolean enabled) { * @return List of enabled accounts. */ public Collection getEnabledAccounts() { + Collection accounts = Collections.unmodifiableCollection(accountItems.values()); List enabledAccounts = new ArrayList<>(); - for (AccountItem accountItem : accountItems.values()) { + for (AccountItem accountItem : accounts) { if (accountItem.isEnabled()) { AccountJid accountJid = accountItem.getAccount(); accountJid.setOrder(accountItem.getOrder()); From 526dc8bfcd8f31f8c66c107f422c8718bfc76034 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 31 May 2019 19:23:23 +0500 Subject: [PATCH 128/237] Up version to 618 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 834d7439f2..61ee330ee7 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 617 - versionName '2.6.4(617)' + versionCode 618 + versionName '2.6.4(618)' } lintOptions { From ef4a7cbd6601bd4ff50e6a74746ca9d04e5ad279 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 3 Jun 2019 11:18:47 +0500 Subject: [PATCH 129/237] Fixed IllegalArgumentException in MessageVH --- .../android/ui/adapter/chat/MessageVH.java | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java index 0a72b205d5..938566ebc6 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java @@ -13,6 +13,7 @@ import android.widget.TextView; import com.amulyakhare.textdrawable.util.ColorGenerator; +import com.google.android.gms.common.util.ArrayUtils; import com.xabber.android.R; import com.xabber.android.data.database.MessageDatabaseManager; import com.xabber.android.data.database.messagerealm.MessageItem; @@ -22,6 +23,7 @@ import com.xabber.android.ui.fragment.ChatFragment; import com.xabber.android.utils.StringUtils; +import java.util.Arrays; import java.util.Date; import io.realm.RealmResults; @@ -146,18 +148,21 @@ public void onGlobalLayout() { } protected void setupForwarded(MessageItem messageItem, MessagesAdapter.MessageExtraData extraData) { - RealmResults forwardedMessages = - MessageDatabaseManager.getInstance().getRealmUiThread().where(MessageItem.class) - .in(MessageItem.Fields.UNIQUE_ID, messageItem.getForwardedIdsAsArray()).findAll(); - - if (forwardedMessages.size() > 0) { - RecyclerView recyclerView = forwardLayout.findViewById(R.id.recyclerView); - ForwardedAdapter adapter = new ForwardedAdapter(forwardedMessages, extraData); - recyclerView.setLayoutManager(new LinearLayoutManager(extraData.getContext())); - recyclerView.setAdapter(adapter); - forwardLayout.setBackgroundColor(ColorManager.getColorWithAlpha(R.color.forwarded_background_color, 0.2f)); - forwardLeftBorder.setBackgroundColor(extraData.getAccountMainColor()); - forwardLayout.setVisibility(View.VISIBLE); + String[] forwardedIDs = messageItem.getForwardedIdsAsArray(); + if (!Arrays.asList(forwardedIDs).contains(null)) { + RealmResults forwardedMessages = + MessageDatabaseManager.getInstance().getRealmUiThread().where(MessageItem.class) + .in(MessageItem.Fields.UNIQUE_ID, forwardedIDs).findAll(); + + if (forwardedMessages.size() > 0) { + RecyclerView recyclerView = forwardLayout.findViewById(R.id.recyclerView); + ForwardedAdapter adapter = new ForwardedAdapter(forwardedMessages, extraData); + recyclerView.setLayoutManager(new LinearLayoutManager(extraData.getContext())); + recyclerView.setAdapter(adapter); + forwardLayout.setBackgroundColor(ColorManager.getColorWithAlpha(R.color.forwarded_background_color, 0.2f)); + forwardLeftBorder.setBackgroundColor(extraData.getAccountMainColor()); + forwardLayout.setVisibility(View.VISIBLE); + } } } From c038cbd6f207fca075129bfe4c73b59e592fc699 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 3 Jun 2019 12:07:54 +0500 Subject: [PATCH 130/237] Update travis.yml --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9900afd6f2..3e9779b92f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,8 @@ android: - '.+' before_install: -- yes | sdkmanager "platforms;android-27" +- yes | sdkmanager "platforms;android-28" +- yes | sdkmanager "build-tools;28.0.3" install: # Check install section: http://docs.travis-ci.com/user/build-configuration/#install From fd73f469054ba5c60a43ed3fad7f51c29fc034ab Mon Sep 17 00:00:00 2001 From: Valeriy Miller Date: Mon, 3 Jun 2019 14:14:49 +0500 Subject: [PATCH 131/237] Try to fix travis.yml --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3e9779b92f..438f681437 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,10 +20,6 @@ android: licenses: - '.+' -before_install: -- yes | sdkmanager "platforms;android-28" -- yes | sdkmanager "build-tools;28.0.3" - install: # Check install section: http://docs.travis-ci.com/user/build-configuration/#install # If you'd like to skip the install stage entirely, set it to true and nothing will be run. From 4959885ee22267ca010932fc01845d4defe96ef4 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 3 Jun 2019 15:51:08 +0500 Subject: [PATCH 132/237] Set push notifications disabled by default --- .../java/com/xabber/android/data/database/RealmManager.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java b/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java index d9400834e7..0e190621bb 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java +++ b/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java @@ -324,12 +324,6 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { if (oldVersion == 22) { schema.get(AccountRealm.class.getSimpleName()) .addField(AccountRealm.Fields.PUSH_ENABLED, boolean.class) - .transform(new RealmObjectSchema.Function() { - @Override - public void apply(DynamicRealmObject obj) { - obj.setBoolean(AccountRealm.Fields.PUSH_ENABLED, true); - } - }) .addField(AccountRealm.Fields.PUSH_WAS_ENABLED, boolean.class); oldVersion++; From 9e03cc097439a572431d4e16482d4721e4574475 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 3 Jun 2019 16:59:41 +0500 Subject: [PATCH 133/237] Push settings available only in dev flavour. --- .../android/ui/activity/AccountActivity.java | 2 +- .../adapter/accountoptions/AccountOption.java | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/activity/AccountActivity.java b/xabber/src/main/java/com/xabber/android/ui/activity/AccountActivity.java index f64d5dc363..e075ab90ed 100644 --- a/xabber/src/main/java/com/xabber/android/ui/activity/AccountActivity.java +++ b/xabber/src/main/java/com/xabber/android/ui/activity/AccountActivity.java @@ -147,7 +147,7 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { RecyclerView recyclerView = (RecyclerView) findViewById(R.id.account_options_recycler_view); - accountOptionsAdapter = new AccountOptionsAdapter(AccountOption.values(), this, accountItem); + accountOptionsAdapter = new AccountOptionsAdapter(AccountOption.getValues(), this, accountItem); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(accountOptionsAdapter); diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/accountoptions/AccountOption.java b/xabber/src/main/java/com/xabber/android/ui/adapter/accountoptions/AccountOption.java index 72bce044e9..993de12b8c 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/accountoptions/AccountOption.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/accountoptions/AccountOption.java @@ -3,6 +3,7 @@ import android.support.annotation.DrawableRes; import android.support.annotation.StringRes; +import com.xabber.android.BuildConfig; import com.xabber.android.R; public enum AccountOption { @@ -43,4 +44,20 @@ int getTitleId() { public String getDescription() { return description; } + + public static AccountOption[] getValues() { + if (BuildConfig.FLAVOR.equals("dev")) { + return AccountOption.values(); + } else { + int i = 0; + AccountOption[] values = new AccountOption[AccountOption.values().length - 1]; + for (AccountOption option : AccountOption.values()) { + if (option != AccountOption.PUSH_NOTIFICATIONS) { + values[i] = option; + i++; + } + } + return values; + } + } } From 6b0ffa8adabab4ed2d8114ef955c764d98b73e98 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 3 Jun 2019 17:15:35 +0500 Subject: [PATCH 134/237] Set push notifications disabled by default --- .../main/java/com/xabber/android/data/account/AccountItem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java b/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java index fa17aaf900..d8aebcb905 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountItem.java @@ -116,7 +116,7 @@ public class AccountItem extends ConnectionItem implements Comparable Date: Mon, 3 Jun 2019 18:44:05 +0500 Subject: [PATCH 135/237] Up version to 619 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 61ee330ee7..ea982d36c4 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 618 - versionName '2.6.4(618)' + versionCode 619 + versionName '2.6.4(619)' } lintOptions { From 44334db14537de7f70a12d5ccd2f9089e3bccedb Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 4 Jun 2019 15:49:34 +0500 Subject: [PATCH 136/237] Fixed realm queries --- .../data/extension/mam/NextMamManager.java | 39 ++++++++++++++----- .../android/data/message/AbstractChat.java | 15 +++++-- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index 8715506502..ca12b5ec23 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -726,16 +726,7 @@ private MessageItem determineSaveOrUpdate(Realm realm, final MessageItem message AbstractChat chat = MessageManager.getInstance().getOrCreateChat(message.getAccount(), message.getUser()); if (chat == null) return null; - MessageItem localMessage = realm.where(MessageItem.class) - .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) - .equalTo(MessageItem.Fields.USER, chat.getUser().toString()) - .equalTo(MessageItem.Fields.TEXT, message.getText()) - .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) - .equalTo(MessageItem.Fields.STANZA_ID, message.getStanzaId()) - .or().equalTo(MessageItem.Fields.STANZA_ID, message.getPacketId()) - .or().equalTo(MessageItem.Fields.ARCHIVED_ID, message.getArchivedId()) - .findFirst(); - + MessageItem localMessage = findSameLocalMessage(realm, chat, message); if (localMessage == null) { // forwarded if (originalMessage != null) { @@ -910,6 +901,34 @@ private void updateLastMessageId(AbstractChat chat, Realm realm) { } } + private MessageItem findSameLocalMessage(Realm realm, AbstractChat chat, MessageItem message) { + return realm.where(MessageItem.class) + .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) + .equalTo(MessageItem.Fields.USER, chat.getUser().toString()) + .equalTo(MessageItem.Fields.TEXT, message.getText()) + .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) + .equalTo(MessageItem.Fields.STANZA_ID, message.getStanzaId()) + .or() + .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) + .equalTo(MessageItem.Fields.USER, chat.getUser().toString()) + .equalTo(MessageItem.Fields.TEXT, message.getText()) + .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) + .equalTo(MessageItem.Fields.STANZA_ID, message.getPacketId()) + .or() + .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) + .equalTo(MessageItem.Fields.USER, chat.getUser().toString()) + .equalTo(MessageItem.Fields.TEXT, message.getText()) + .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) + .equalTo(MessageItem.Fields.STANZA_ID, message.getArchivedId()) + .or() + .equalTo(MessageItem.Fields.ACCOUNT, chat.getAccount().toString()) + .equalTo(MessageItem.Fields.USER, chat.getUser().toString()) + .equalTo(MessageItem.Fields.TEXT, message.getText()) + .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) + .equalTo(MessageItem.Fields.ARCHIVED_ID, message.getArchivedId()) + .findFirst(); + } + private void runMigrationToNewArchive(AccountItem accountItem, Realm realm) { LogManager.d(LOG_TAG, "run migration for account: " + accountItem.getAccount().toString()); Collection contacts = RosterManager.getInstance() diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index 4892126c4c..5723e55e4f 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -516,10 +516,19 @@ public void setLastMessage(MessageItem lastMessage) { } private void updateLastMessage() { - lastMessage = MessageDatabaseManager.getChatMessagesQuery( - MessageDatabaseManager.getInstance().getRealmUiThread(), account, user) + Realm realm = MessageDatabaseManager.getInstance().getRealmUiThread(); + lastMessage = realm.where(MessageItem.class) + .equalTo(MessageItem.Fields.ACCOUNT, account.toString()) + .equalTo(MessageItem.Fields.USER, user.toString()) + .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) + .isNotNull(MessageItem.Fields.TEXT) .isNull(MessageItem.Fields.ACTION) - .or().equalTo(MessageItem.Fields.ACTION, ChatAction.available.toString()) + .or() + .equalTo(MessageItem.Fields.ACCOUNT, account.toString()) + .equalTo(MessageItem.Fields.USER, user.toString()) + .isNull(MessageItem.Fields.PARENT_MESSAGE_ID) + .isNotNull(MessageItem.Fields.TEXT) + .equalTo(MessageItem.Fields.ACTION, ChatAction.available.toString()) .findAllSorted(MessageItem.Fields.TIMESTAMP, Sort.ASCENDING).last(null); RosterCacheManager.saveLastMessageToContact(MessageDatabaseManager.getInstance().getRealmUiThread(), lastMessage); } From ef603c470da551cf04a3091447d79da6546da99a Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 4 Jun 2019 17:27:03 +0500 Subject: [PATCH 137/237] Try to fix RejectedExecutionException in AbstractChat.getMessages --- .../com/xabber/android/data/extension/mam/NextMamManager.java | 1 - .../java/com/xabber/android/data/message/AbstractChat.java | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index ca12b5ec23..ce8c5e854d 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -897,7 +897,6 @@ private void updateLastMessageId(AbstractChat chat, Realm realm) { String id = lastMessage.getArchivedId(); if (id == null) id = lastMessage.getStanzaId(); chat.setLastMessageId(id); - RosterCacheManager.saveLastMessageToContact(realm, lastMessage); } } diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index 5723e55e4f..4bc7346705 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -530,7 +530,6 @@ private void updateLastMessage() { .isNotNull(MessageItem.Fields.TEXT) .equalTo(MessageItem.Fields.ACTION, ChatAction.available.toString()) .findAllSorted(MessageItem.Fields.TIMESTAMP, Sort.ASCENDING).last(null); - RosterCacheManager.saveLastMessageToContact(MessageDatabaseManager.getInstance().getRealmUiThread(), lastMessage); } /** @@ -806,6 +805,8 @@ boolean isPrivateMucChatAccepted() { @Override public void onChange(RealmResults messageItems) { updateLastMessage(); + RosterCacheManager.saveLastMessageToContact( + MessageDatabaseManager.getInstance().getRealmUiThread(), lastMessage); } /** UNREAD MESSAGES */ From 25ff6b1ee9615a3774a9c98af113fbeff943e1d5 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 4 Jun 2019 17:52:24 +0500 Subject: [PATCH 138/237] On receive delivered marker mark all previous messages as delivered --- .../chat_markers/ChatMarkerManager.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/chat_markers/ChatMarkerManager.java b/xabber/src/main/java/com/xabber/android/data/extension/chat_markers/ChatMarkerManager.java index 3f91ce0874..7829c8f253 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/chat_markers/ChatMarkerManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/chat_markers/ChatMarkerManager.java @@ -198,15 +198,26 @@ private void markAsDisplayed(final String messageID) { private void markAsDelivered(final String stanzaID) { Realm realm = MessageDatabaseManager.getInstance().getRealmUiThread(); - MessageItem first = realm.where(MessageItem.class) .equalTo(MessageItem.Fields.STANZA_ID, stanzaID).findFirst(); if (first != null) { - realm.beginTransaction(); - first.setDelivered(true); - realm.commitTransaction(); + RealmResults results = realm.where(MessageItem.class) + .equalTo(MessageItem.Fields.ACCOUNT, first.getAccount().toString()) + .equalTo(MessageItem.Fields.USER, first.getUser().toString()) + .equalTo(MessageItem.Fields.INCOMING, false) + .equalTo(MessageItem.Fields.DELIVERED, false) + .lessThanOrEqualTo(MessageItem.Fields.TIMESTAMP, first.getTimestamp()) + .findAll(); + + if (results != null) { + realm.beginTransaction(); + for (MessageItem item : results) { + item.setDelivered(true); + } + realm.commitTransaction(); + EventBus.getDefault().post(new MessageUpdateEvent()); + } } - EventBus.getDefault().post(new MessageUpdateEvent()); } } From 5e75a72aed1ccf5a304c5fe211519d9eb4d1f457 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 4 Jun 2019 18:22:16 +0500 Subject: [PATCH 139/237] Fixed message statuses in contact list --- .../ui/contactlist/viewobjects/ContactVO.java | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java index f8c85424fc..b02cc6d787 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java +++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java @@ -190,17 +190,19 @@ public static ContactVO convert(AbstractContact contact, ContactClickListener li messageOwner = lastMessage.getResource().toString(); // message status - if (lastMessage.isError()) { - messageStatus = 4; - } else if (!MessageItem.isUploadFileMessage(lastMessage) && !lastMessage.isSent() - && System.currentTimeMillis() - lastMessage.getTimestamp() > 1000) { - messageStatus = 5; - } else if (lastMessage.isDisplayed() || lastMessage.isReceivedFromMessageArchive()) { - messageStatus = 1; - } else if (lastMessage.isDelivered() || lastMessage.isForwarded()) { - messageStatus = 2; - } else if (lastMessage.isAcknowledged()) { - messageStatus = 3; + if (isOutgoing) { + if (lastMessage.isError()) { + messageStatus = 4; + } else if (!MessageItem.isUploadFileMessage(lastMessage) && !lastMessage.isSent() + && System.currentTimeMillis() - lastMessage.getTimestamp() > 1000) { + messageStatus = 5; + } else if (lastMessage.isDisplayed() || lastMessage.isReceivedFromMessageArchive()) { + messageStatus = 1; + } else if (lastMessage.isDelivered() || lastMessage.isForwarded()) { + messageStatus = 2; + } else if (lastMessage.isAcknowledged()) { + messageStatus = 3; + } } // forwarded From adbcfc30573dccaea11d8cdcc4fff31e9f7a5cbf Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 4 Jun 2019 18:27:40 +0500 Subject: [PATCH 140/237] Up version to 620 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index ea982d36c4..83c7bc8c2b 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 619 - versionName '2.6.4(619)' + versionCode 620 + versionName '2.6.4(620)' } lintOptions { From 8831deac9beca3bcd0aabe62c33c1d20bdaf7499 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 5 Jun 2019 12:10:12 +0500 Subject: [PATCH 141/237] Fixed infinite loop of vcard updates --- .../data/extension/vcard/VCardManager.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/vcard/VCardManager.java b/xabber/src/main/java/com/xabber/android/data/extension/vcard/VCardManager.java index 4be1fa6589..769f00e7a8 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/vcard/VCardManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/vcard/VCardManager.java @@ -15,6 +15,7 @@ package com.xabber.android.data.extension.vcard; import android.database.Cursor; +import android.util.Log; import com.xabber.android.data.Application; import com.xabber.android.data.NetworkException; @@ -240,13 +241,13 @@ void onVCardReceived(final AccountJid account, final Jid bareAddress, final VCar name = new StructuredName(vCard.getNickName(), vCard.getField(VCardProperty.FN.name()), vCard.getFirstName(), vCard.getMiddleName(), vCard.getLastName()); - try { - if (account.getFullJid().asBareJid().equals(bareAddress.asBareJid())) { - PresenceManager.getInstance().resendPresence(account); - } - } catch (NetworkException e) { - LogManager.exception(this, e); - } +// try { +// if (account.getFullJid().asBareJid().equals(bareAddress.asBareJid())) { +// PresenceManager.getInstance().resendPresence(account); +// } +// } catch (NetworkException e) { +// LogManager.exception(this, e); +// } } names.put(bareAddress, name); From 0b08409a656b20755780096660dd3187ab89031c Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 6 Jun 2019 19:07:45 +0500 Subject: [PATCH 142/237] Added junit and robolectric --- xabber/build.gradle | 10 + .../xabber/android/data/TestApplication.java | 596 ++++++++++++++++++ 2 files changed, 606 insertions(+) create mode 100644 xabber/src/main/java/com/xabber/android/data/TestApplication.java diff --git a/xabber/build.gradle b/xabber/build.gradle index 83c7bc8c2b..13a96a2668 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -95,6 +95,12 @@ android { universalApk true } } + + testOptions { + unitTests { + includeAndroidResources = true + } + } } def build_param = "${build}"; @@ -180,6 +186,10 @@ dependencies { debugImplementation 'com.github.markzhai:blockcanary-android:1.5.0' releaseImplementation 'com.github.markzhai:blockcanary-no-op:1.5.0' + // test + testImplementation 'junit:junit:4.12' + testImplementation "org.robolectric:robolectric:4.0" + testImplementation "org.robolectric:shadows-multidex:4.0.1" } apply plugin: 'com.google.gms.google-services' diff --git a/xabber/src/main/java/com/xabber/android/data/TestApplication.java b/xabber/src/main/java/com/xabber/android/data/TestApplication.java new file mode 100644 index 0000000000..04e1f4ac30 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/TestApplication.java @@ -0,0 +1,596 @@ +/** + * Copyright (c) 2013, Redsolution LTD. All rights reserved. + * + * This file is part of Xabber project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License, Version 3. + * + * Xabber is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License, + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.xabber.android.data; + +import android.app.Activity; +import android.content.Context; +import android.os.Handler; +import android.os.StrictMode; +import android.support.annotation.NonNull; +import android.support.multidex.MultiDex; + +import com.crashlytics.android.Crashlytics; +import com.crashlytics.android.core.CrashlyticsCore; +import com.frogermcs.androiddevmetrics.AndroidDevMetrics; +import com.github.moduth.blockcanary.BlockCanary; +import com.squareup.leakcanary.LeakCanary; +import com.xabber.android.BuildConfig; +import com.xabber.android.R; +import com.xabber.android.data.account.AccountManager; +import com.xabber.android.data.account.ScreenManager; +import com.xabber.android.data.connection.CertificateManager; +import com.xabber.android.data.connection.ConnectionManager; +import com.xabber.android.data.connection.NetworkManager; +import com.xabber.android.data.connection.ReconnectionManager; +import com.xabber.android.data.database.DatabaseManager; +import com.xabber.android.data.extension.attention.AttentionManager; +import com.xabber.android.data.extension.avatar.AvatarManager; +import com.xabber.android.data.extension.avatar.AvatarStorage; +import com.xabber.android.data.extension.blocking.BlockingManager; +import com.xabber.android.data.extension.capability.CapabilitiesManager; +import com.xabber.android.data.extension.carbons.CarbonManager; +import com.xabber.android.data.extension.chat_markers.ChatMarkerManager; +import com.xabber.android.data.extension.cs.ChatStateManager; +import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager; +import com.xabber.android.data.extension.iqlast.LastActivityInteractor; +import com.xabber.android.data.extension.mam.NextMamManager; +import com.xabber.android.data.extension.muc.MUCManager; +import com.xabber.android.data.extension.otr.OTRManager; +import com.xabber.android.data.extension.ssn.SSNManager; +import com.xabber.android.data.extension.vcard.VCardManager; +import com.xabber.android.data.http.CrowdfundingManager; +import com.xabber.android.data.http.PatreonManager; +import com.xabber.android.data.log.LogManager; +import com.xabber.android.data.message.MessageManager; +import com.xabber.android.data.message.ReceiptManager; +import com.xabber.android.data.message.chat.ChatManager; +import com.xabber.android.data.message.phrase.PhraseManager; +import com.xabber.android.data.notification.DelayedNotificationActionManager; +import com.xabber.android.data.notification.NotificationManager; +import com.xabber.android.data.notification.custom_notification.CustomNotifyPrefsManager; +import com.xabber.android.data.push.PushManager; +import com.xabber.android.data.push.SyncManager; +import com.xabber.android.data.roster.GroupManager; +import com.xabber.android.data.roster.PresenceManager; +import com.xabber.android.data.roster.RosterManager; +import com.xabber.android.data.xaccount.XMPPAuthManager; +import com.xabber.android.data.xaccount.XabberAccountManager; +import com.xabber.android.service.XabberService; +import com.xabber.android.utils.AppBlockCanaryContext; + +import org.jivesoftware.smack.provider.ProviderFileLoader; +import org.jivesoftware.smack.provider.ProviderManager; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadFactory; + +import io.fabric.sdk.android.Fabric; + +/** + * Base entry point. + * + * @author alexander.ivanov + */ +public class TestApplication extends android.app.Application { + + private static final String LOG_TAG = Application.class.getSimpleName(); + private static TestApplication instance; + private final ArrayList registeredManagers; + /** + * Thread to execute tasks in background.. + */ + private final ExecutorService backgroundExecutor; + private final ExecutorService backgroundExecutorForUserActions; + /** + * Handler to execute runnable in UI thread. + */ + private final Handler handler; + /** + * Unmodifiable collections of managers that implement some common + * interface. + */ + private Map, Collection> managerInterfaces; + private Map, Collection> uiListeners; + /** + * Where data load was requested. + */ + private boolean serviceStarted; + /** + * Whether application was initialized. + */ + private boolean initialized; + /** + * Whether user was notified about some action in contact list activity + * after application initialization. + */ + private boolean notified; + /** + * Whether application is to be closed. + */ + private boolean closing; + /** + * Whether {@link #onServiceDestroy()} has been called. + */ + private boolean closed; + + private final Runnable timerRunnable = new Runnable() { + + @Override + public void run() { + for (OnTimerListener listener : getManagers(OnTimerListener.class)) { + listener.onTimer(); + } + if (!closing) { + startTimer(); + } + } + + }; + /** + * Future for loading process. + */ + private Future loadFuture; + + public TestApplication() { + instance = this; + serviceStarted = false; + initialized = false; + notified = false; + closing = false; + closed = false; + uiListeners = new HashMap<>(); + managerInterfaces = new HashMap<>(); + registeredManagers = new ArrayList<>(); + + handler = new Handler(); + backgroundExecutor = createSingleThreadExecutor("Background executor service"); + backgroundExecutorForUserActions = Executors.newFixedThreadPool( + Runtime.getRuntime().availableProcessors(), + new ThreadFactory() { + @Override + public Thread newThread(@NonNull Runnable runnable) { + Thread thread = new Thread(runnable); + thread.setPriority(Thread.MIN_PRIORITY); + thread.setDaemon(true); + return thread; + } + }); + } + + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext(base); + MultiDex.install(this); + } + + @NonNull + private ExecutorService createSingleThreadExecutor(final String threadName) { + return Executors.newSingleThreadExecutor(new ThreadFactory() { + @Override + public Thread newThread(@NonNull Runnable runnable) { + Thread thread = new Thread(runnable, threadName); + thread.setPriority(Thread.MIN_PRIORITY); + thread.setDaemon(true); + return thread; + } + }); + } + + public static TestApplication getInstance() { + if (instance == null) { + throw new IllegalStateException(); + } + return instance; + } + + /** + * Whether application is initialized. + */ + public boolean isInitialized() { + return initialized; + } + + private void onLoad() { + ProviderManager.addLoader(new ProviderFileLoader(getResources().openRawResource(R.raw.smack))); + + for (OnLoadListener listener : getManagers(OnLoadListener.class)) { + LogManager.i(listener, "onLoad"); + listener.onLoad(); + } + } + + private void onInitialized() { + for (OnInitializedListener listener : getManagers(OnInitializedListener.class)) { + LogManager.i(listener, "onInitialized"); + listener.onInitialized(); + } + initialized = true; + XabberService.getInstance().changeForeground(); + startTimer(); + } + + private void onClose() { + LogManager.i(LOG_TAG, "onClose1"); + for (Object manager : registeredManagers) { + if (manager instanceof OnCloseListener) { + ((OnCloseListener) manager).onClose(); + } + } + closed = true; + LogManager.i(LOG_TAG, "onClose2"); + } + + void onUnload() { + LogManager.i(LOG_TAG, "onUnload1"); + for (Object manager : registeredManagers) { + if (manager instanceof OnUnloadListener) { + ((OnUnloadListener) manager).onUnload(); + } + } + LogManager.i(LOG_TAG, "onUnload2"); + android.os.Process.killProcess(android.os.Process.myPid()); + } + + /** + * @return true only once per application life. Subsequent + * calls will always returns false. + */ + public boolean doNotify() { + if (notified) { + return false; + } + notified = true; + return true; + } + + /** + * Starts data loading in background if not started yet. + */ + public void onServiceStarted() { + if (serviceStarted) { + return; + } + serviceStarted = true; + LogManager.i(this, "onStart"); + loadFuture = backgroundExecutor.submit(new Callable() { + @Override + public Void call() throws Exception { + try { + onLoad(); + } finally { + runOnUiThread(new Runnable() { + @Override + public void run() { + // Throw exceptions in UI thread if any. + try { + loadFuture.get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + onInitialized(); + } + }); + } + return null; + } + }); + } + + /** + * Requests to close application in some time in future. + */ + public void requestToClose() { + LogManager.i(LOG_TAG, "requestToClose1"); + closing = true; + stopService(XabberService.createIntent(this)); + LogManager.i(LOG_TAG, "requestToClose2"); + } + + /** + * @return Whether application is to be closed. + */ + public boolean isClosing() { + return closing; + } + + @Override + public void onCreate() { + super.onCreate(); + + /** Crashlytics */ + CrashlyticsCore crashlyticsCore = new CrashlyticsCore.Builder() + .disabled(BuildConfig.DEBUG || BuildConfig.FLAVOR == "open") + .build(); + Fabric.with(this, new Crashlytics.Builder().core(crashlyticsCore).build()); + + Thread.currentThread().setPriority(Thread.MAX_PRIORITY); + //addManagers(); + //DatabaseManager.getInstance().addTables(); + LogManager.i(this, "onCreate finished..."); + } + + private void addManagers() { + addManager(SyncManager.getInstance()); + addManager(SettingsManager.getInstance()); + addManager(LogManager.getInstance()); + addManager(DatabaseManager.getInstance()); + addManager(AvatarStorage.getInstance()); + addManager(OTRManager.getInstance()); + addManager(ConnectionManager.getInstance()); + addManager(ScreenManager.getInstance()); + addManager(AccountManager.getInstance()); + addManager(XabberAccountManager.getInstance()); + addManager(PatreonManager.getInstance()); + addManager(CrowdfundingManager.getInstance()); + addManager(MUCManager.getInstance()); + addManager(MessageManager.getInstance()); + addManager(ChatManager.getInstance()); + addManager(VCardManager.getInstance()); + addManager(AvatarManager.getInstance()); + addManager(PresenceManager.getInstance()); + addManager(RosterManager.getInstance()); + addManager(GroupManager.getInstance()); + addManager(PhraseManager.getInstance()); + addManager(NotificationManager.getInstance()); + addManager(CustomNotifyPrefsManager.getInstance()); + addManager(ActivityManager.getInstance()); + addManager(CapabilitiesManager.getInstance()); + addManager(ChatStateManager.getInstance()); + addManager(NetworkManager.getInstance()); + addManager(ReconnectionManager.getInstance()); + addManager(ReceiptManager.getInstance()); + addManager(ChatMarkerManager.getInstance()); + addManager(SSNManager.getInstance()); + addManager(AttentionManager.getInstance()); + addManager(CarbonManager.getInstance()); + addManager(HttpFileUploadManager.getInstance()); + addManager(BlockingManager.getInstance()); + addManager(NextMamManager.getInstance()); + addManager(CertificateManager.getInstance()); + addManager(XMPPAuthManager.getInstance()); + addManager(PushManager.getInstance()); + addManager(DelayedNotificationActionManager.getInstance()); + addManager(LastActivityInteractor.getInstance()); + } + + /** + * Register new manager. + */ + private void addManager(Object manager) { + registeredManagers.add(manager); + } + + @Override + public void onLowMemory() { + for (OnLowMemoryListener listener : getManagers(OnLowMemoryListener.class)) { + listener.onLowMemory(); + } + super.onLowMemory(); + } + + /** + * Service have been destroyed. + */ + public void onServiceDestroy() { + LogManager.i(LOG_TAG, "onServiceDestroy"); + + if (closed) { + LogManager.i(LOG_TAG, "onServiceDestroy closed"); + return; + } + onClose(); + + // use new thread instead of run in background to exit immediately + // without waiting for possible other threads in executor + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + onUnload(); + } + }); + thread.setPriority(Thread.MIN_PRIORITY); + thread.setDaemon(true); + thread.start(); + } + + @Override + public void onTerminate() { + requestToClose(); + super.onTerminate(); + } + + /** + * Start periodically callbacks. + */ + private void startTimer() { + runOnUiThreadDelay(timerRunnable, OnTimerListener.DELAY); + } + + /** + * @param cls Requested class of managers. + * @return List of registered manager. + */ + @SuppressWarnings("unchecked") + public Collection getManagers(Class cls) { + if (closed) { + return Collections.emptyList(); + } + Collection collection = (Collection) managerInterfaces.get(cls); + if (collection == null) { + collection = new ArrayList<>(); + for (Object manager : registeredManagers) { + if (cls.isInstance(manager)) { + collection.add((T) manager); + } + } + collection = Collections.unmodifiableCollection(collection); + managerInterfaces.put(cls, collection); + } + return collection; + } + + /** + * Request to clear application data. + */ + public void requestToClear() { + runInBackground(new Runnable() { + @Override + public void run() { + clear(); + } + }); + } + + private void clear() { + for (Object manager : registeredManagers) { + if (manager instanceof OnClearListener) { + ((OnClearListener) manager).onClear(); + } + } + } + + /** + * Request to wipe all sensitive application data. + */ + public void requestToWipe() { + runInBackground(new Runnable() { + @Override + public void run() { + clear(); + for (Object manager : registeredManagers) + if (manager instanceof OnWipeListener) + ((OnWipeListener) manager).onWipe(); + } + }); + } + + @SuppressWarnings("unchecked") + private Collection getOrCreateUIListeners(Class cls) { + Collection collection = (Collection) uiListeners.get(cls); + if (collection == null) { + collection = new ArrayList(); + uiListeners.put(cls, collection); + } + return collection; + } + + /** + * @param cls Requested class of listeners. + * @return List of registered UI listeners. + */ + public Collection getUIListeners(Class cls) { + if (closed) { + return Collections.emptyList(); + } + return Collections.unmodifiableCollection(getOrCreateUIListeners(cls)); + } + + /** + * Register new listener. + *

+ * Should be called from {@link Activity#onResume()}. + */ + public void addUIListener(Class cls, T listener) { + getOrCreateUIListeners(cls).add(listener); + } + + /** + * Unregister listener. + *

+ * Should be called from {@link Activity#onPause()}. + */ + public void removeUIListener(Class cls, T listener) { + getOrCreateUIListeners(cls).remove(listener); + } + + /** + * Notify about error. + */ + public void onError(final int resourceId) { + runOnUiThread(new Runnable() { + @Override + public void run() { + for (OnErrorListener onErrorListener : getUIListeners(OnErrorListener.class)) { + onErrorListener.onError(resourceId); + } + } + }); + } + + /** + * Notify about error. + */ + public void onError(NetworkException networkException) { + LogManager.exception(this, networkException); + onError(networkException.getResourceId()); + } + + /** + * Submits request to be executed in background. + */ + public void runInBackground(final Runnable runnable) { + backgroundExecutor.submit(new Runnable() { + @Override + public void run() { + try { + runnable.run(); + } catch (Exception e) { + LogManager.exception(runnable, e); + } + } + }); + } + + public void runInBackgroundUserRequest(final Runnable runnable) { + backgroundExecutorForUserActions.submit(new Runnable() { + @Override + public void run() { + try { + runnable.run(); + } catch (Exception e) { + LogManager.exception(runnable, e); + } + } + }); + } + + /** + * Submits request to be executed in UI thread. + */ + public void runOnUiThread(final Runnable runnable) { + handler.post(runnable); + } + + /** + * Submits request to be executed in UI thread. + */ + public void runOnUiThreadDelay(final Runnable runnable, long delayMillis) { + handler.postDelayed(runnable, delayMillis); + } + + public boolean isServiceStarted() { + return serviceStarted; + } +} + From ab6d405a3543bbc3d787a0a68055f9ca3ddffd5e Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 7 Jun 2019 18:15:55 +0500 Subject: [PATCH 143/237] Added parsing References elements of types data and forward --- .../data/connection/ConnectionThread.java | 5 + .../httpfileupload/HttpFileUploadManager.java | 29 ++++ .../data/extension/mam/NextMamManager.java | 12 +- .../android/data/extension/muc/RoomChat.java | 12 +- .../data/extension/references/RefFile.java | 109 ++++++++++++++ .../data/extension/references/RefMedia.java | 24 ++++ .../references/ReferenceElement.java | 85 +++++++++++ .../references/ReferencesManager.java | 94 ++++++++++++ .../references/ReferencesProvider.java | 136 ++++++++++++++++++ .../android/data/message/AbstractChat.java | 23 ++- .../android/data/message/ForwardManager.java | 19 +++ .../android/data/message/MessageManager.java | 6 + .../android/data/message/RegularChat.java | 14 +- 13 files changed, 548 insertions(+), 20 deletions(-) create mode 100644 xabber/src/main/java/com/xabber/android/data/extension/references/RefFile.java create mode 100644 xabber/src/main/java/com/xabber/android/data/extension/references/RefMedia.java create mode 100644 xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java create mode 100644 xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java create mode 100644 xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java diff --git a/xabber/src/main/java/com/xabber/android/data/connection/ConnectionThread.java b/xabber/src/main/java/com/xabber/android/data/connection/ConnectionThread.java index ecdcfa0d28..afe89e6605 100644 --- a/xabber/src/main/java/com/xabber/android/data/connection/ConnectionThread.java +++ b/xabber/src/main/java/com/xabber/android/data/connection/ConnectionThread.java @@ -22,6 +22,8 @@ import com.xabber.android.data.extension.forward.ForwardComment; import com.xabber.android.data.extension.forward.ForwardCommentProvider; import com.xabber.android.data.extension.httpfileupload.CustomDataProvider; +import com.xabber.android.data.extension.references.ReferenceElement; +import com.xabber.android.data.extension.references.ReferencesProvider; import com.xabber.android.data.log.AndroidLoggingHandler; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.xaccount.HttpConfirmIq; @@ -132,6 +134,9 @@ void connectAndLogin() { ProviderManager.addExtensionProvider(ForwardComment.ELEMENT, ForwardComment.NAMESPACE, new ForwardCommentProvider()); + ProviderManager.addExtensionProvider(ReferenceElement.ELEMENT, + ReferenceElement.NAMESPACE, new ReferencesProvider()); + try { LogManager.i(this, "Trying to connect and login..."); if (!connection.isConnected()) { diff --git a/xabber/src/main/java/com/xabber/android/data/extension/httpfileupload/HttpFileUploadManager.java b/xabber/src/main/java/com/xabber/android/data/extension/httpfileupload/HttpFileUploadManager.java index 4f0a054951..9eb14c80fd 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/httpfileupload/HttpFileUploadManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/httpfileupload/HttpFileUploadManager.java @@ -22,6 +22,9 @@ import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.entity.UserJid; import com.xabber.android.data.extension.file.FileManager; +import com.xabber.android.data.extension.references.RefFile; +import com.xabber.android.data.extension.references.RefMedia; +import com.xabber.android.data.extension.references.ReferencesManager; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.message.MessageManager; import com.xabber.android.service.UploadService; @@ -224,6 +227,15 @@ public static String getMimeType(String path) { public static RealmList parseFileMessage(Stanza packet) { RealmList attachments = new RealmList<>(); + // parsing data references + List refMediaList = ReferencesManager.getMediaFromReferences(packet); + if (!refMediaList.isEmpty()) { + for (RefMedia media : refMediaList) { + attachments.add(refMediaToAttachment(media)); + } + } + + // parsing data forms DataForm dataForm = DataForm.from(packet); if (dataForm != null) { @@ -238,6 +250,23 @@ public static RealmList parseFileMessage(Stanza packet) { return attachments; } + private static Attachment refMediaToAttachment(RefMedia media) { + Attachment attachment = new Attachment(); + attachment.setFileUrl(media.getUri()); + attachment.setIsImage(FileManager.isImageUrl(media.getUri())); + + RefFile file = media.getFile(); + if (file != null) { + attachment.setTitle(file.getName()); + attachment.setMimeType(file.getMediaType()); + attachment.setDuration(file.getDuration()); + attachment.setFileSize(file.getSize()); + if (file.getHeight() > 0) attachment.setImageHeight(file.getHeight()); + if (file.getWidth() > 0) attachment.setImageWidth(file.getWidth()); + } + return attachment; + } + private static Attachment mediaToAttachment(ExtendedFormField.Media media, String title) { Attachment attachment = new Attachment(); attachment.setTitle(title); diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index ce8c5e854d..d01acb9683 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -15,6 +15,7 @@ import com.xabber.android.data.extension.file.FileManager; import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager; import com.xabber.android.data.extension.otr.OTRManager; +import com.xabber.android.data.extension.references.ReferencesManager; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.message.AbstractChat; import com.xabber.android.data.message.ForwardManager; @@ -23,7 +24,6 @@ import com.xabber.android.data.notification.NotificationManager; import com.xabber.android.data.push.SyncManager; import com.xabber.android.data.roster.OnRosterReceivedListener; -import com.xabber.android.data.roster.RosterCacheManager; import com.xabber.android.data.roster.RosterContact; import com.xabber.android.data.roster.RosterManager; @@ -648,6 +648,13 @@ private List parseMessage(AccountItem accountItem, AccountJid accou else body = ((PlainTextMessage) otrMessage).cleanText; } + // forward comment (to support previous forwarded xep) + String forwardComment = ForwardManager.parseForwardComment(message); + if (forwardComment != null) body = forwardComment; + + // modify body with references + body = ReferencesManager.modifyBodyWithReferences(message, body); + boolean incoming = message.getFrom().asBareJid().equals(user.getJid().asBareJid()); String uid = UUID.randomUUID().toString(); @@ -713,12 +720,9 @@ private List saveOrUpdateMessages(Realm realm, final Collection 0) createAndSaveFileMessage(ui, uid, resource, text, null, null, diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/RefFile.java b/xabber/src/main/java/com/xabber/android/data/extension/references/RefFile.java new file mode 100644 index 0000000000..2c3c9a3b88 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/RefFile.java @@ -0,0 +1,109 @@ +package com.xabber.android.data.extension.references; + +public class RefFile { + + public static final String ELEMENT = "file"; + + public static final String ELEMENT_MEDIA_TYPE = "media-type"; + public static final String ELEMENT_NAME = "name"; + public static final String ELEMENT_DESC = "desc"; + public static final String ELEMENT_HEIGHT = "height"; + public static final String ELEMENT_WIDTH = "width"; + public static final String ELEMENT_SIZE = "size"; + public static final String ELEMENT_DURATION = "duration"; + public static final String ELEMENT_VOICE = "voice"; + + private String mediaType; + private String name; + private String desc; + private int height; + private int width; + private long size; + private long duration; + private boolean voice; + + public String getMediaType() { + return mediaType; + } + + public String getName() { + return name; + } + + public String getDesc() { + return desc; + } + + public int getHeight() { + return height; + } + + public int getWidth() { + return width; + } + + public long getSize() { + return size; + } + + public long getDuration() { + return duration; + } + + public boolean isVoice() { + return voice; + } + + public static Builder newBuilder() { + return new RefFile().new Builder(); + } + + public class Builder { + private Builder() {} + + public RefFile build() { + return RefFile.this; + } + + public Builder setMediaType(String mediaType) { + RefFile.this.mediaType = mediaType; + return this; + } + + public Builder setName(String name) { + RefFile.this.name = name; + return this; + } + + public Builder setDesc(String desc) { + RefFile.this.desc = desc; + return this; + } + + public Builder setHeight(int height) { + RefFile.this.height = height; + return this; + } + + public Builder setWidth(int width) { + RefFile.this.width = width; + return this; + } + + public Builder setSize(long size) { + RefFile.this.size = size; + return this; + } + + public Builder setDuration(long duration) { + RefFile.this.duration = duration; + return this; + } + + public Builder setVoice(boolean voice) { + RefFile.this.voice = voice; + return this; + } + } + +} diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/RefMedia.java b/xabber/src/main/java/com/xabber/android/data/extension/references/RefMedia.java new file mode 100644 index 0000000000..923649cd73 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/RefMedia.java @@ -0,0 +1,24 @@ +package com.xabber.android.data.extension.references; + +public class RefMedia { + + public static final String ELEMENT = "media"; + public static final String ELEMENT_URI = "uri"; + + private RefFile file; + private String uri; + + public RefMedia(RefFile file, String uri) { + this.file = file; + this.uri = uri; + } + + public RefFile getFile() { + return file; + } + + public String getUri() { + return uri; + } + +} diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java new file mode 100644 index 0000000000..fbd6c4c8cf --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java @@ -0,0 +1,85 @@ +package com.xabber.android.data.extension.references; + +import org.jivesoftware.smack.packet.ExtensionElement; +import org.jivesoftware.smack.util.XmlStringBuilder; +import org.jivesoftware.smackx.forward.packet.Forwarded; + +import java.util.List; + +public class ReferenceElement implements ExtensionElement { + + public static final String NAMESPACE = "urn:xmpp:reference:0"; + public static final String ELEMENT = "reference"; + + private final Type type; + private final int begin; + private final int end; + private final int del; + + private List forwarded; + private List media; + + public ReferenceElement(Type type, int begin, int end, int del, List forwarded, List media) { + this.type = type; + this.begin = begin; + this.end = end; + this.del = del; + this.forwarded = forwarded; + this.media = media; + } + + @Override + public String getNamespace() { + return NAMESPACE; + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public CharSequence toXML() { + XmlStringBuilder xml = new XmlStringBuilder(this); + xml.attribute("type", type); + xml.attribute("begin", begin); + xml.attribute("end", end); + xml.attribute("del", del); + xml.rightAngleBracket(); + xml.closeElement(this); + return xml; + } + + public Type getType() { + return type; + } + + public int getBegin() { + return begin; + } + + public int getEnd() { + return end; + } + + public int getDel() { + return del; + } + + public List getForwarded() { + return forwarded; + } + + public List getMedia() { + return media; + } + + public enum Type { + data, + forward, + markup, + mention, + quote, + legacy + } +} \ No newline at end of file diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java new file mode 100644 index 0000000000..53436e7d61 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -0,0 +1,94 @@ +package com.xabber.android.data.extension.references; + +import android.text.Html; +import android.text.TextUtils; + +import org.jivesoftware.smack.packet.ExtensionElement; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Stanza; +import org.jivesoftware.smackx.forward.packet.Forwarded; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.annotation.Nonnull; + +public class ReferencesManager { + + @Nonnull + public static List getForwardedFromReferences(Stanza packet) { + List elements = packet.getExtensions(ReferenceElement.ELEMENT, ReferenceElement.NAMESPACE); + if (elements == null || elements.size() == 0) return Collections.emptyList(); + + List forwarded = new ArrayList<>(); + for (ExtensionElement element : elements) { + if (element instanceof ReferenceElement) { + forwarded.addAll(((ReferenceElement) element).getForwarded()); + } + } + return forwarded; + } + + @Nonnull + public static List getMediaFromReferences(Stanza packet) { + List elements = packet.getExtensions(ReferenceElement.ELEMENT, ReferenceElement.NAMESPACE); + if (elements == null || elements.size() == 0) return Collections.emptyList(); + + List media = new ArrayList<>(); + for (ExtensionElement element : elements) { + if (element instanceof ReferenceElement) { + media.addAll(((ReferenceElement) element).getMedia()); + } + } + return media; + } + + public static String modifyBodyWithReferences(Message message, String body) { + if (body == null || body.isEmpty() || body.trim().isEmpty()) return body; + + List elements = message.getExtensions(ReferenceElement.ELEMENT, ReferenceElement.NAMESPACE); + if (elements == null || elements.size() == 0) return body; + + char[] chars = TextUtils.htmlEncode(body).toCharArray(); + for (ExtensionElement element : elements) { + if (element instanceof ReferenceElement) { + chars = modifyBodyWithReferences(chars, (ReferenceElement) element); + } + } + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < chars.length; i++) { + if (chars[i] != Character.MIN_VALUE) + builder.append(chars[i]); + } + return Html.fromHtml(builder.toString()).toString(); + } + + private static char[] modifyBodyWithReferences(char[] chars, ReferenceElement reference) { + int begin = reference.getBegin(); + if (begin < 0) begin = 0; + int end = reference.getEnd(); + if (end >= chars.length) end = chars.length - 1; + + switch (reference.getType()) { + case data: + chars = remove(begin, end, chars); + break; + case forward: + chars = remove(begin, end, chars); + break; + case legacy: + chars = remove(begin, end, chars); + break; + } + return chars; + } + + private static char[] remove(int begin, int end, char[] source) { + for (int i = begin; i <= end; i++) { + source[i] = Character.MIN_VALUE; + } + return source; + } + +} diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java new file mode 100644 index 0000000000..d9f3f425b2 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java @@ -0,0 +1,136 @@ +package com.xabber.android.data.extension.references; + +import org.jivesoftware.smack.provider.ExtensionElementProvider; +import org.jivesoftware.smackx.forward.packet.Forwarded; +import org.jivesoftware.smackx.forward.provider.ForwardedProvider; +import org.xmlpull.v1.XmlPullParser; + +import java.util.ArrayList; +import java.util.List; + +public class ReferencesProvider extends ExtensionElementProvider { + + @Override + public ReferenceElement parse(XmlPullParser parser, int initialDepth) throws Exception { + String type = null, beginS = null, endS = null, delS = null; + List forwardedMessages = new ArrayList<>(); + List mediaElements = new ArrayList<>(); + + outerloop: while (true) { + int eventType = parser.getEventType(); + switch (eventType) { + case XmlPullParser.START_TAG: + if (ReferenceElement.ELEMENT.equals(parser.getName()) + && ReferenceElement.NAMESPACE.equals(parser.getNamespace())) { + type = parser.getAttributeValue("", "type"); + beginS = parser.getAttributeValue("", "begin"); + endS = parser.getAttributeValue("", "end"); + delS = parser.getAttributeValue("", "del"); + } + if (Forwarded.ELEMENT.equals(parser.getName()) + && Forwarded.NAMESPACE.equals(parser.getNamespace())) { + Forwarded forwarded = ForwardedProvider.INSTANCE.parse(parser); + if (forwarded != null) forwardedMessages.add(forwarded); + } + if (RefMedia.ELEMENT.equals(parser.getName())) { + RefMedia media = parseMedia(parser); + if (media != null) mediaElements.add(media); + } + parser.next(); + break; + case XmlPullParser.END_TAG: + if (ReferenceElement.ELEMENT.equals(parser.getName())) { + break outerloop; + } else parser.next(); + break; + default: + parser.next(); + } + } + + int begin = 0, end = 0, del = 0; + if (beginS != null && !beginS.isEmpty()) begin = Integer.valueOf(beginS); + if (endS != null && !endS.isEmpty()) end = Integer.valueOf(endS); + if (delS != null && !delS.isEmpty()) del = Integer.valueOf(delS); + return new ReferenceElement(ReferenceElement.Type.valueOf(type), begin, end, del, forwardedMessages, mediaElements); + } + + private RefMedia parseMedia(XmlPullParser parser) throws Exception { + String uri = null; + RefFile file = null; + + parser.next(); + outerloop: while (true) { + int eventType = parser.getEventType(); + switch (eventType) { + case XmlPullParser.START_TAG: + if (RefFile.ELEMENT.equals(parser.getName())) { + file = parseFile(parser); + parser.next(); + } + if (RefMedia.ELEMENT_URI.equals(parser.getName())) { + uri = parser.nextText(); + } + break; + case XmlPullParser.END_TAG: + if (RefMedia.ELEMENT.equals(parser.getName())) { + break outerloop; + } else parser.next(); + break; + default: + parser.next(); + } + } + if (file != null && uri != null) return new RefMedia(file, uri); + else return null; + } + + private RefFile parseFile(XmlPullParser parser) throws Exception { + RefFile.Builder builder = RefFile.newBuilder(); + + parser.next(); + outerloop: while (true) { + int eventType = parser.getEventType(); + switch (eventType) { + case XmlPullParser.START_TAG: + switch (parser.getName()) { + case RefFile.ELEMENT_MEDIA_TYPE: + builder.setMediaType(parser.nextText()); + break; + case RefFile.ELEMENT_NAME: + builder.setName(parser.nextText()); + break; + case RefFile.ELEMENT_DESC: + builder.setDesc(parser.nextText()); + break; + case RefFile.ELEMENT_HEIGHT: + builder.setHeight(Integer.valueOf(parser.nextText())); + break; + case RefFile.ELEMENT_WIDTH: + builder.setWidth(Integer.valueOf(parser.nextText())); + break; + case RefFile.ELEMENT_SIZE: + builder.setSize(Long.valueOf(parser.nextText())); + break; + case RefFile.ELEMENT_DURATION: + builder.setDuration(Long.valueOf(parser.nextText())); + break; + case RefFile.ELEMENT_VOICE: + builder.setVoice(Boolean.valueOf(parser.nextText())); + break; + default: + parser.next(); + } + break; + case XmlPullParser.END_TAG: + if (RefFile.ELEMENT.equals(parser.getName())) { + break outerloop; + } else parser.next(); + break; + default: + parser.next(); + } + } + return builder.build(); + } +} diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index 4bc7346705..81a574ba1d 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -41,6 +41,7 @@ import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager; import com.xabber.android.data.extension.muc.MUCManager; import com.xabber.android.data.extension.otr.OTRManager; +import com.xabber.android.data.extension.references.ReferencesManager; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.message.chat.ChatManager; import com.xabber.android.data.notification.MessageNotificationManager; @@ -52,7 +53,6 @@ import org.greenrobot.eventbus.EventBus; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.StanzaListener; -import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message.Type; import org.jivesoftware.smack.packet.Stanza; @@ -930,19 +930,18 @@ public void setLastPosition(int lastPosition) { } public RealmList parseForwardedMessage(boolean ui, Stanza packet, String parentMessageId) { - List elements = packet.getExtensions(Forwarded.ELEMENT, Forwarded.NAMESPACE); - if (elements == null || elements.size() == 0) return null; - - RealmList forwarded = new RealmList<>(); - for (ExtensionElement element : elements) { - if (element instanceof Forwarded) { - Stanza stanza = ((Forwarded) element).getForwardedStanza(); - if (stanza instanceof Message) { - forwarded.add(new ForwardId(parseInnerMessage(ui, (Message) stanza, parentMessageId))); - } + List forwarded = ReferencesManager.getForwardedFromReferences(packet); + if (forwarded.isEmpty()) forwarded = ForwardManager.getForwardedFromStanza(packet); + if (forwarded.isEmpty()) return null; + + RealmList forwardedIds = new RealmList<>(); + for (Forwarded forward : forwarded) { + Stanza stanza = forward.getForwardedStanza(); + if (stanza instanceof Message) { + forwardedIds.add(new ForwardId(parseInnerMessage(ui, (Message) stanza, parentMessageId))); } } - return forwarded; + return forwardedIds; } protected abstract String parseInnerMessage(boolean ui, Message message, String parentMessageId); diff --git a/xabber/src/main/java/com/xabber/android/data/message/ForwardManager.java b/xabber/src/main/java/com/xabber/android/data/message/ForwardManager.java index 3b259bd9f9..5f1a06927b 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/ForwardManager.java +++ b/xabber/src/main/java/com/xabber/android/data/message/ForwardManager.java @@ -10,9 +10,14 @@ import org.greenrobot.eventbus.EventBus; import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.Stanza; +import org.jivesoftware.smackx.forward.packet.Forwarded; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import javax.annotation.Nonnull; + import io.realm.Realm; import io.realm.RealmList; @@ -49,4 +54,18 @@ public static String parseForwardComment(Stanza packet) { return null; } + @Nonnull + public static List getForwardedFromStanza(Stanza packet) { + List elements = packet.getExtensions(Forwarded.ELEMENT, Forwarded.NAMESPACE); + if (elements == null || elements.size() == 0) return Collections.emptyList(); + + List forwarded = new ArrayList<>(); + for (ExtensionElement element : elements) { + if (element instanceof Forwarded) { + forwarded.add((Forwarded)element); + } + } + return forwarded; + } + } diff --git a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java index 8ea4a8a230..7a1d57261f 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java +++ b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java @@ -49,6 +49,7 @@ import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager; import com.xabber.android.data.extension.muc.MUCManager; import com.xabber.android.data.extension.muc.RoomChat; +import com.xabber.android.data.extension.references.ReferencesManager; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.message.chat.ChatManager; import com.xabber.android.data.message.chat.MucPrivateChatNotification; @@ -791,9 +792,14 @@ public void processCarbonsMessage(AccountJid account, final Message message, Car RealmList forwardIds = finalChat.parseForwardedMessage(true, message, uid); String originalStanza = message.toXML().toString(); String originalFrom = message.getFrom().toString(); + + // forward comment (to support previous forwarded xep) String forwardComment = ForwardManager.parseForwardComment(message); if (forwardComment != null) text = forwardComment; + // modify body with references + text = ReferencesManager.modifyBodyWithReferences(message, text); + MessageItem newMessageItem = finalChat.createNewMessageItem(text); newMessageItem.setStanzaId(AbstractChat.getStanzaId(message)); newMessageItem.setSent(true); diff --git a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java index 57d2264137..529d79191d 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java @@ -30,6 +30,7 @@ import com.xabber.android.data.extension.otr.OTRManager; import com.xabber.android.data.extension.otr.OTRUnencryptedException; import com.xabber.android.data.extension.otr.SecurityLevel; +import com.xabber.android.data.extension.references.ReferencesManager; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.xaccount.XMPPAuthManager; @@ -218,9 +219,14 @@ protected boolean onPacket(UserJid bareAddress, Stanza packet, boolean isCarbons RealmList forwardIds = parseForwardedMessage(true, packet, uid); String originalStanza = packet.toXML().toString(); String originalFrom = packet.getFrom().toString(); + + // forward comment (to support previous forwarded xep) String forwardComment = ForwardManager.parseForwardComment(packet); if (forwardComment != null) text = forwardComment; + // modify body with references + text = ReferencesManager.modifyBodyWithReferences(message, text); + // System message received. if ((text == null || text.trim().equals("")) && (forwardIds == null || forwardIds.isEmpty())) return true; @@ -268,9 +274,13 @@ protected String parseInnerMessage(boolean ui, Message message, String parentMes String originalFrom = ""; if (fromJid != null) originalFrom = fromJid.toString(); boolean fromMuc = message.getType().equals(Type.groupchat); + + // forward comment (to support previous forwarded xep) String forwardComment = ForwardManager.parseForwardComment(message); - if (forwardComment != null && !forwardComment.isEmpty()) - text = forwardComment; + if (forwardComment != null && !forwardComment.isEmpty()) text = forwardComment; + + // modify body with references + text = ReferencesManager.modifyBodyWithReferences(message, text); // create message with file-attachments if (attachments.size() > 0) From 39c65c8c4aef097591916eca908a38b56836e9e0 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 10 Jun 2019 13:44:28 +0500 Subject: [PATCH 144/237] First implementation of sending references of types data and forward --- .../data/extension/references/RefFile.java | 49 +++++++++++++++ .../data/extension/references/RefMedia.java | 16 +++++ .../references/ReferenceElement.java | 10 +++ .../references/ReferencesManager.java | 46 ++++++++++++++ .../android/data/message/AbstractChat.java | 62 ++++--------------- .../android/data/message/ClipManager.java | 4 ++ 6 files changed, 136 insertions(+), 51 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/RefFile.java b/xabber/src/main/java/com/xabber/android/data/extension/references/RefFile.java index 2c3c9a3b88..5c891396a3 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/RefFile.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/RefFile.java @@ -1,5 +1,7 @@ package com.xabber.android.data.extension.references; +import org.jivesoftware.smack.util.XmlStringBuilder; + public class RefFile { public static final String ELEMENT = "file"; @@ -54,6 +56,53 @@ public boolean isVoice() { return voice; } + public CharSequence toXML() { + XmlStringBuilder xml = new XmlStringBuilder(); + xml.openElement(ELEMENT); + if (getMediaType() != null && !getMediaType().isEmpty()) { + xml.openElement(ELEMENT_MEDIA_TYPE); + xml.append(getMediaType()); + xml.closeElement(ELEMENT_MEDIA_TYPE); + } + if (getName() != null && !getName().isEmpty()) { + xml.openElement(ELEMENT_NAME); + xml.append(getName()); + xml.closeElement(ELEMENT_NAME); + } + if (getHeight() > 0) { + xml.openElement(ELEMENT_HEIGHT); + xml.append(String.valueOf(getHeight())); + xml.closeElement(ELEMENT_HEIGHT); + } + if (getWidth() > 0) { + xml.openElement(ELEMENT_WIDTH); + xml.append(String.valueOf(getWidth())); + xml.closeElement(ELEMENT_WIDTH); + } + if (getSize() > 0) { + xml.openElement(ELEMENT_SIZE); + xml.append(String.valueOf(getSize())); + xml.closeElement(ELEMENT_SIZE); + } + if (getDesc() != null && !getDesc().isEmpty()) { + xml.openElement(ELEMENT_DESC); + xml.append(getDesc()); + xml.closeElement(ELEMENT_DESC); + } + if (getDuration() > 0) { + xml.openElement(ELEMENT_DURATION); + xml.append(String.valueOf(getDuration())); + xml.closeElement(ELEMENT_DURATION); + } + if (isVoice()) { + xml.openElement(ELEMENT_VOICE); + xml.append(String.valueOf(isVoice())); + xml.closeElement(ELEMENT_VOICE); + } + xml.closeElement(ELEMENT); + return xml; + } + public static Builder newBuilder() { return new RefFile().new Builder(); } diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/RefMedia.java b/xabber/src/main/java/com/xabber/android/data/extension/references/RefMedia.java index 923649cd73..ccca515ffb 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/RefMedia.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/RefMedia.java @@ -1,5 +1,7 @@ package com.xabber.android.data.extension.references; +import org.jivesoftware.smack.util.XmlStringBuilder; + public class RefMedia { public static final String ELEMENT = "media"; @@ -21,4 +23,18 @@ public String getUri() { return uri; } + public CharSequence toXML() { + XmlStringBuilder xml = new XmlStringBuilder(); + xml.openElement(ELEMENT); + if (file != null) { + xml.append(file.toXML()); + } + if (uri != null) { + xml.openElement(ELEMENT_URI); + xml.append(uri); + xml.closeElement(ELEMENT_URI); + } + xml.closeElement(ELEMENT); + return xml; + } } diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java index fbd6c4c8cf..6d1f6a983d 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java @@ -46,6 +46,16 @@ public CharSequence toXML() { xml.attribute("end", end); xml.attribute("del", del); xml.rightAngleBracket(); + if (forwarded != null && !forwarded.isEmpty()) { + for (Forwarded forward : forwarded) { + xml.append(forward.toXML()); + } + } + if (media != null && !media.isEmpty()) { + for (RefMedia media1 : media) { + xml.append(media1.toXML()); + } + } xml.closeElement(this); return xml; } diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index 53436e7d61..8588711372 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -3,17 +3,26 @@ import android.text.Html; import android.text.TextUtils; +import com.xabber.android.data.database.messagerealm.Attachment; +import com.xabber.android.data.database.messagerealm.MessageItem; + import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Stanza; +import org.jivesoftware.smack.util.PacketParserUtils; +import org.jivesoftware.smackx.delay.packet.DelayInformation; import org.jivesoftware.smackx.forward.packet.Forwarded; import java.util.ArrayList; import java.util.Collections; +import java.util.Date; import java.util.List; import javax.annotation.Nonnull; +import io.realm.RealmList; +import io.realm.RealmResults; + public class ReferencesManager { @Nonnull @@ -30,6 +39,43 @@ public static List getForwardedFromReferences(Stanza packet) { return forwarded; } + public static ReferenceElement createMediaReferences(RealmList attachments, String legacyBody) { + List mediaList = new ArrayList<>(); + for (Attachment attachment : attachments) { + RefFile.Builder builder = RefFile.newBuilder(); + builder.setName(attachment.getTitle()); + builder.setMediaType(attachment.getMimeType()); + builder.setVoice(false); + builder.setDuration(attachment.getDuration()); + builder.setSize(attachment.getFileSize()); + if (attachment.getImageHeight() != null) + builder.setHeight(attachment.getImageHeight()); + if (attachment.getImageWidth() != null) + builder.setWidth(attachment.getImageWidth()); + RefMedia media = new RefMedia(builder.build(), attachment.getFileUrl()); + mediaList.add(media); + } + + char[] chars = TextUtils.htmlEncode(legacyBody).toCharArray(); + return new ReferenceElement(ReferenceElement.Type.data, 0, chars.length - 1, 0, null, mediaList); + } + + public static ReferenceElement createForwardReference(RealmResults items, String legacyBody) { + List forwardedList = new ArrayList<>(); + for (MessageItem item : items) { + try { + Message forwarded = PacketParserUtils.parseStanza(item.getOriginalStanza()); + forwardedList.add(new Forwarded(new DelayInformation(new Date(item.getTimestamp())), forwarded)); + } catch (Exception e) { + e.printStackTrace(); + } + } + + char[] chars = TextUtils.htmlEncode(legacyBody).toCharArray(); + return new ReferenceElement(ReferenceElement.Type.forward, 0, chars.length - 1, 0, + forwardedList, null); + } + @Nonnull public static List getMediaFromReferences(Stanza packet) { List elements = packet.getExtensions(ReferenceElement.ELEMENT, ReferenceElement.NAMESPACE); diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index 81a574ba1d..f24b22d692 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -19,7 +19,6 @@ import android.support.annotation.Nullable; import android.util.Log; -import com.xabber.android.R; import com.xabber.android.data.Application; import com.xabber.android.data.NetworkException; import com.xabber.android.data.SettingsManager; @@ -36,11 +35,10 @@ import com.xabber.android.data.extension.cs.ChatStateManager; import com.xabber.android.data.extension.file.FileManager; import com.xabber.android.data.extension.file.UriUtils; -import com.xabber.android.data.extension.forward.ForwardComment; -import com.xabber.android.data.extension.httpfileupload.ExtendedFormField; import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager; import com.xabber.android.data.extension.muc.MUCManager; import com.xabber.android.data.extension.otr.OTRManager; +import com.xabber.android.data.extension.references.ReferenceElement; import com.xabber.android.data.extension.references.ReferencesManager; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.message.chat.ChatManager; @@ -56,11 +54,9 @@ import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message.Type; import org.jivesoftware.smack.packet.Stanza; -import org.jivesoftware.smack.util.PacketParserUtils; import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smackx.delay.packet.DelayInformation; import org.jivesoftware.smackx.forward.packet.Forwarded; -import org.jivesoftware.smackx.xdata.packet.DataForm; import org.jxmpp.jid.Jid; import org.jxmpp.jid.parts.Resourcepart; @@ -573,25 +569,8 @@ public Message createFileMessagePacket(String stanzaId, RealmList at message.setThread(threadId); if (stanzaId != null) message.setStanzaId(stanzaId); - DataForm dataForm = new DataForm(DataForm.Type.form); - - int i = 1; - for (Attachment attachment : attachments) { - ExtendedFormField formField = new ExtendedFormField("media" + i); - i++; - formField.setLabel(attachment.getTitle()); - - ExtendedFormField.Uri uri = new ExtendedFormField.Uri(attachment.getMimeType(), attachment.getFileUrl()); - uri.setSize(attachment.getFileSize()); - uri.setDuration(attachment.getDuration()); - - formField.setMedia( - new ExtendedFormField.Media(String.valueOf(attachment.getImageHeight()), - String.valueOf(attachment.getImageWidth()), uri)); - - dataForm.addField(formField); - } - message.addExtension(dataForm); + ReferenceElement reference = ReferencesManager.createMediaReferences(attachments, body); + message.addExtension(reference); message.setBody(body); Log.d("XEP-0221", message.toXML().toString()); @@ -661,36 +640,17 @@ boolean sendMessage(MessageItem messageItem) { messageItem.getAttachments(), text); } else if (messageItem.haveForwardedMessages()) { - - int count = messageItem.getForwardedIds().size(); - String body = String.format(Application.getInstance().getResources() - .getString(R.string.forwarded_support_text), count); - if (text != null && !text.isEmpty()) body += "\n" + text; - - message = createMessagePacket(body, messageItem.getStanzaId()); - Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); + RealmResults items = realm.where(MessageItem.class) + .in(MessageItem.Fields.UNIQUE_ID, messageItem.getForwardedIdsAsArray()).findAll(); - // forwarded - if (messageItem.getForwardedIds() != null && messageItem.getForwardedIds().size() > 0) { - final String[] ids = new String[messageItem.getForwardedIds().size()]; - int i = 0; - for (ForwardId id : messageItem.getForwardedIds()) { - ids[i] = id.getForwardMessageId(); - i++; - } + String modifiedBody = ClipManager.createMessageTree(realm, messageItem.getForwardedIdsAsArray()) + "\n"; + text = modifiedBody + text; + message = createMessagePacket(text, messageItem.getStanzaId()); - RealmResults items = realm.where(MessageItem.class) - .in(MessageItem.Fields.UNIQUE_ID, ids).findAll(); - for (MessageItem item : items) { - try { - Message forwarded = (Message) PacketParserUtils.parseStanza(item.getOriginalStanza()); - message.addExtension(new Forwarded(new DelayInformation(new Date(item.getTimestamp())), forwarded)); - } catch (Exception e) { - e.printStackTrace(); - } - } - message.addExtension(new ForwardComment(text)); + if (items != null && !items.isEmpty()) { + ReferenceElement reference = ReferencesManager.createForwardReference(items, modifiedBody); + message.addExtension(reference); } } else if (text != null) { diff --git a/xabber/src/main/java/com/xabber/android/data/message/ClipManager.java b/xabber/src/main/java/com/xabber/android/data/message/ClipManager.java index 6d619422c3..1533c46801 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/ClipManager.java +++ b/xabber/src/main/java/com/xabber/android/data/message/ClipManager.java @@ -32,6 +32,10 @@ public void run() { }); } + public static String createMessageTree(Realm realm, String[] messagesIDs) { + return messagesToText(realm, messagesIDs, 1); + } + private static void insertDataToClipboard(final String text) { Application.getInstance().runOnUiThread(new Runnable() { @Override From 16ce472a8dc8e4ab6b8d00d686bb078f538d7ff3 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 10 Jun 2019 15:19:14 +0500 Subject: [PATCH 145/237] Work on media references --- .../android/data/message/AbstractChat.java | 16 ++++++++++------ .../android/data/message/MessageManager.java | 9 +-------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index f24b22d692..f20d0149f2 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -17,7 +17,6 @@ import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.util.Log; import com.xabber.android.data.Application; import com.xabber.android.data.NetworkException; @@ -559,7 +558,7 @@ public Message createMessagePacket(String body) { } /** - * Send stanza with XEP-0221 + * Send stanza with data-references. */ public Message createFileMessagePacket(String stanzaId, RealmList attachments, String body) { @@ -569,11 +568,16 @@ public Message createFileMessagePacket(String stanzaId, RealmList at message.setThread(threadId); if (stanzaId != null) message.setStanzaId(stanzaId); - ReferenceElement reference = ReferencesManager.createMediaReferences(attachments, body); - message.addExtension(reference); - message.setBody(body); + StringBuilder builder = new StringBuilder(); + for (Attachment attachment : attachments) { + if (builder.length() > 0) builder.append("\n"); + builder.append(attachment.getFileUrl()); + } + String legacyBody = builder.toString(); - Log.d("XEP-0221", message.toXML().toString()); + ReferenceElement reference = ReferencesManager.createMediaReferences(attachments, legacyBody); + message.addExtension(reference); + message.setBody(body + legacyBody); return message; } diff --git a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java index 7a1d57261f..f349a6dc2c 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java +++ b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java @@ -80,7 +80,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.UUID; import io.realm.Realm; @@ -327,13 +326,7 @@ public void execute(Realm realm) { attachment.setFileUrl(urls.get(attachment.getFilePath())); } - StringBuilder strBuilder = new StringBuilder(); - for (Map.Entry entry : urls.entrySet()) { - if (strBuilder.length() > 0) strBuilder.append("\n"); - strBuilder.append(entry.getValue()); - } - - messageItem.setText(strBuilder.toString()); + messageItem.setText(""); messageItem.setSent(false); messageItem.setInProgress(false); messageItem.setError(false); From 28cdaa0c90807ecac5cf7fa9d9269e9cc8046e0a Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 10 Jun 2019 15:52:46 +0500 Subject: [PATCH 146/237] Fixed messages with attachments --- .../java/com/xabber/android/data/message/RegularChat.java | 6 +++--- .../xabber/android/ui/adapter/chat/IncomingMessageVH.java | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java index 529d79191d..815d1c2ef1 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java @@ -224,13 +224,13 @@ protected boolean onPacket(UserJid bareAddress, Stanza packet, boolean isCarbons String forwardComment = ForwardManager.parseForwardComment(packet); if (forwardComment != null) text = forwardComment; - // modify body with references - text = ReferencesManager.modifyBodyWithReferences(message, text); - // System message received. if ((text == null || text.trim().equals("")) && (forwardIds == null || forwardIds.isEmpty())) return true; + // modify body with references + text = ReferencesManager.modifyBodyWithReferences(message, text); + // create message with file-attachments if (attachments.size() > 0) createAndSaveFileMessage(true, uid, resource, text, null, getDelayStamp(message), diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/IncomingMessageVH.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/IncomingMessageVH.java index cf9724bfce..52411d44e8 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/IncomingMessageVH.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/IncomingMessageVH.java @@ -102,7 +102,9 @@ public void bind(final MessageItem messageItem, MessagesAdapter.MessageExtraData setUpAvatar(messageItem, extraData.isMuc(), extraData.getUsername(), needTail); // hide empty message - if (messageItem.getText().trim().isEmpty() && !messageItem.haveForwardedMessages()) { + if (messageItem.getText().trim().isEmpty() + && !messageItem.haveForwardedMessages() + && !messageItem.haveAttachments()) { messageBalloon.setVisibility(View.GONE); messageTime.setVisibility(View.GONE); avatar.setVisibility(View.GONE); From bd5409bbc8695f7734b1f0987980fee01f461808 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 11 Jun 2019 14:28:39 +0500 Subject: [PATCH 147/237] First implementation of markup references --- .../references/ReferenceElement.java | 58 +++++++++++++ .../references/ReferencesManager.java | 86 ++++++++++++++++--- .../references/ReferencesProvider.java | 16 +++- .../android/ui/adapter/chat/MessageVH.java | 4 +- 4 files changed, 152 insertions(+), 12 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java index 6d1f6a983d..3efb8017b2 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java @@ -10,12 +10,22 @@ public class ReferenceElement implements ExtensionElement { public static final String NAMESPACE = "urn:xmpp:reference:0"; public static final String ELEMENT = "reference"; + public static final String ELEMENT_BOLD = "bold"; + public static final String ELEMENT_ITALIC = "italic"; + public static final String ELEMENT_UNDERLINE = "underline"; + public static final String ELEMENT_STRIKE = "strike"; private final Type type; private final int begin; private final int end; private final int del; + private boolean bold; + private boolean italic; + private boolean underline; + private boolean strike; + private String url; + private List forwarded; private List media; @@ -28,6 +38,34 @@ public ReferenceElement(Type type, int begin, int end, int del, List this.media = media; } + public ReferenceElement(Type type, int begin, int end, int del, boolean bold, boolean italic, + boolean underline, boolean strike, String url) { + this.type = type; + this.begin = begin; + this.end = end; + this.del = del; + this.bold = bold; + this.italic = italic; + this.underline = underline; + this.strike = strike; + this.url = url; + } + + public ReferenceElement(Type type, int begin, int end, int del, boolean bold, boolean italic, + boolean underline, boolean strike, String url, List forwarded, List media) { + this.type = type; + this.begin = begin; + this.end = end; + this.del = del; + this.bold = bold; + this.italic = italic; + this.underline = underline; + this.strike = strike; + this.url = url; + this.forwarded = forwarded; + this.media = media; + } + @Override public String getNamespace() { return NAMESPACE; @@ -76,6 +114,26 @@ public int getDel() { return del; } + public boolean isBold() { + return bold; + } + + public boolean isItalic() { + return italic; + } + + public boolean isUnderline() { + return underline; + } + + public boolean isStrike() { + return strike; + } + + public String getUrl() { + return url; + } + public List getForwarded() { return forwarded; } diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index 8588711372..0bb743fa4b 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -96,21 +96,59 @@ public static String modifyBodyWithReferences(Message message, String body) { List elements = message.getExtensions(ReferenceElement.ELEMENT, ReferenceElement.NAMESPACE); if (elements == null || elements.size() == 0) return body; - char[] chars = TextUtils.htmlEncode(body).toCharArray(); + List references = getReferences(elements); + if (references.isEmpty()) return body; + + // encode HTML and split into chars + String[] chars = stringToChars(TextUtils.htmlEncode(body)); + + // modify chars with references except markup + for (ReferenceElement reference : references) { + if (!reference.getType().equals(ReferenceElement.Type.markup)) + chars = modifyBodyWithReferences(chars, reference); + } + + // chars to string and decode from html + // then split string into chars + chars = stringToChars(Html.fromHtml(charsToString(chars)).toString()); + + // modify chars with markup references + for (ReferenceElement reference : references) { + if (reference.getType().equals(ReferenceElement.Type.markup)) + chars = modifyBodyWithReferences(chars, reference); + } + + // chars to string + return charsToString(chars); + } + + private static List getReferences(List elements) { + List references = new ArrayList<>(); for (ExtensionElement element : elements) { - if (element instanceof ReferenceElement) { - chars = modifyBodyWithReferences(chars, (ReferenceElement) element); - } + if (element instanceof ReferenceElement) references.add((ReferenceElement) element); } + return references; + } + + private static String charsToString(String[] array) { StringBuilder builder = new StringBuilder(); + for (int i = 0; i < array.length; i++) { + if (!array[i].equals(String.valueOf(Character.MIN_VALUE))) + builder.append(array[i]); + } + return builder.toString(); + } + + private static String[] stringToChars(String source) { + char[] chars = source.toCharArray(); + String[] result = new String[chars.length]; for (int i = 0; i < chars.length; i++) { - if (chars[i] != Character.MIN_VALUE) - builder.append(chars[i]); + result[i] = String.valueOf(chars[i]); } - return Html.fromHtml(builder.toString()).toString(); + return result; } - private static char[] modifyBodyWithReferences(char[] chars, ReferenceElement reference) { + private static String[] modifyBodyWithReferences(String[] chars, ReferenceElement reference) { int begin = reference.getBegin(); if (begin < 0) begin = 0; int end = reference.getEnd(); @@ -126,14 +164,42 @@ private static char[] modifyBodyWithReferences(char[] chars, ReferenceElement re case legacy: chars = remove(begin, end, chars); break; + case markup: + chars = markup(begin, end, chars, reference); + break; } return chars; } - private static char[] remove(int begin, int end, char[] source) { + private static String[] remove(int begin, int end, String[] source) { for (int i = begin; i <= end; i++) { - source[i] = Character.MIN_VALUE; + source[i] = String.valueOf(Character.MIN_VALUE); + } + return source; + } + + private static String[] markup(int begin, int end, String[] source, ReferenceElement reference) { + StringBuilder builderOpen = new StringBuilder(); + StringBuilder builderClose = new StringBuilder(); + if (reference.isBold()) { + builderOpen.append(""); + builderClose.append(new StringBuilder("").reverse()); + } + if (reference.isItalic()) { + builderOpen.append(""); + builderClose.append(new StringBuilder("").reverse()); + } + if (reference.isUnderline()) { + builderOpen.append(""); + builderClose.append(new StringBuilder("").reverse()); + } + if (reference.isStrike()) { + builderOpen.append(""); + builderClose.append(new StringBuilder("").reverse()); } + source[begin] = builderOpen.append(source[begin]).toString(); + builderClose.append(new StringBuilder(source[end]).reverse()); + source[end] = builderClose.reverse().toString(); return source; } diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java index d9f3f425b2..2fb31630d9 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java @@ -15,6 +15,7 @@ public ReferenceElement parse(XmlPullParser parser, int initialDepth) throws Exc String type = null, beginS = null, endS = null, delS = null; List forwardedMessages = new ArrayList<>(); List mediaElements = new ArrayList<>(); + boolean bold = false, italic = false, underline = false, strike = false; outerloop: while (true) { int eventType = parser.getEventType(); @@ -36,6 +37,18 @@ public ReferenceElement parse(XmlPullParser parser, int initialDepth) throws Exc RefMedia media = parseMedia(parser); if (media != null) mediaElements.add(media); } + if (ReferenceElement.ELEMENT_BOLD.equals(parser.getName())) { + bold = true; + } + if (ReferenceElement.ELEMENT_ITALIC.equals(parser.getName())) { + italic = true; + } + if (ReferenceElement.ELEMENT_UNDERLINE.equals(parser.getName())) { + underline = true; + } + if (ReferenceElement.ELEMENT_STRIKE.equals(parser.getName())) { + strike = true; + } parser.next(); break; case XmlPullParser.END_TAG: @@ -52,7 +65,8 @@ public ReferenceElement parse(XmlPullParser parser, int initialDepth) throws Exc if (beginS != null && !beginS.isEmpty()) begin = Integer.valueOf(beginS); if (endS != null && !endS.isEmpty()) end = Integer.valueOf(endS); if (delS != null && !delS.isEmpty()) del = Integer.valueOf(delS); - return new ReferenceElement(ReferenceElement.Type.valueOf(type), begin, end, del, forwardedMessages, mediaElements); + return new ReferenceElement(ReferenceElement.Type.valueOf(type), begin, end, del, bold, + italic, underline, strike, null, forwardedMessages, mediaElements); } private RefMedia parseMedia(XmlPullParser parser) throws Exception { diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java index 938566ebc6..c1b176eb72 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java @@ -7,6 +7,8 @@ import android.support.v4.graphics.drawable.DrawableCompat; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; +import android.text.Html; +import android.text.method.LinkMovementMethod; import android.view.View; import android.view.ViewTreeObserver; import android.widget.ImageView; @@ -93,7 +95,7 @@ public void bind(MessageItem messageItem, MessagesAdapter.MessageExtraData extra ivEncrypted.setVisibility(View.GONE); } - messageText.setText(messageItem.getText()); + messageText.setText(Html.fromHtml(messageItem.getText())); if (OTRManager.getInstance().isEncrypted(messageItem.getText())) { if (extraData.isShowOriginalOTR()) messageText.setVisibility(View.VISIBLE); From f023d06ddd485d58aa4f079c9364cf9a8a283745 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 11 Jun 2019 16:24:02 +0500 Subject: [PATCH 148/237] Refactoring references. Implementation parsing of mention and quotes. --- .../data/extension/references/Data.java | 30 +++++ .../data/extension/references/Forward.java | 31 +++++ .../data/extension/references/Markup.java | 56 ++++++++ .../data/extension/references/Mention.java | 33 +++++ .../data/extension/references/Quote.java | 33 +++++ .../references/ReferenceElement.java | 126 +++--------------- .../references/ReferencesManager.java | 28 ++-- .../references/ReferencesProvider.java | 32 +++-- 8 files changed, 241 insertions(+), 128 deletions(-) create mode 100644 xabber/src/main/java/com/xabber/android/data/extension/references/Data.java create mode 100644 xabber/src/main/java/com/xabber/android/data/extension/references/Forward.java create mode 100644 xabber/src/main/java/com/xabber/android/data/extension/references/Markup.java create mode 100644 xabber/src/main/java/com/xabber/android/data/extension/references/Mention.java create mode 100644 xabber/src/main/java/com/xabber/android/data/extension/references/Quote.java diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/Data.java b/xabber/src/main/java/com/xabber/android/data/extension/references/Data.java new file mode 100644 index 0000000000..922af2d433 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/Data.java @@ -0,0 +1,30 @@ +package com.xabber.android.data.extension.references; + +import org.jivesoftware.smack.util.XmlStringBuilder; + +import java.util.List; + +public class Data extends ReferenceElement { + private final List media; + + public Data(int begin, int end, List media) { + super(begin, end); + this.media = media; + } + + @Override + public Type getType() { + return Type.data; + } + + @Override + public void appendToXML(XmlStringBuilder xml) { + for (RefMedia item : media) { + xml.append(item.toXML()); + } + } + + public List getMedia() { + return media; + } +} diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/Forward.java b/xabber/src/main/java/com/xabber/android/data/extension/references/Forward.java new file mode 100644 index 0000000000..d5662b292a --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/Forward.java @@ -0,0 +1,31 @@ +package com.xabber.android.data.extension.references; + +import org.jivesoftware.smack.util.XmlStringBuilder; +import org.jivesoftware.smackx.forward.packet.Forwarded; + +import java.util.List; + +public class Forward extends ReferenceElement { + private final List forwarded; + + public Forward(int begin, int end, List forwarded) { + super(begin, end); + this.forwarded = forwarded; + } + + @Override + public Type getType() { + return Type.forward; + } + + @Override + public void appendToXML(XmlStringBuilder xml) { + for (Forwarded forward : forwarded) { + xml.append(forward.toXML()); + } + } + + public List getForwarded() { + return forwarded; + } +} diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/Markup.java b/xabber/src/main/java/com/xabber/android/data/extension/references/Markup.java new file mode 100644 index 0000000000..2f9aa97081 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/Markup.java @@ -0,0 +1,56 @@ +package com.xabber.android.data.extension.references; + +import org.jivesoftware.smack.util.XmlStringBuilder; + +public class Markup extends ReferenceElement { + private final boolean bold; + private final boolean italic; + private final boolean underline; + private final boolean strike; + private final String url; + + public Markup(int begin, int end, boolean bold, boolean italic, boolean underline, boolean strike, String url) { + super(begin, end); + this.bold = bold; + this.italic = italic; + this.underline = underline; + this.strike = strike; + this.url = url; + } + + @Override + public Type getType() { + return Type.markup; + } + + @Override + public void appendToXML(XmlStringBuilder xml) { + if (bold) xml.emptyElement(ELEMENT_BOLD); + if (italic) xml.emptyElement(ELEMENT_ITALIC); + if (underline) xml.emptyElement(ELEMENT_UNDERLINE); + if (strike) xml.emptyElement(ELEMENT_STRIKE); + if (url != null && url.isEmpty()) { + xml.element(ELEMENT_URL, url); + } + } + + public boolean isBold() { + return bold; + } + + public boolean isItalic() { + return italic; + } + + public boolean isUnderline() { + return underline; + } + + public boolean isStrike() { + return strike; + } + + public String getUrl() { + return url; + } +} diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/Mention.java b/xabber/src/main/java/com/xabber/android/data/extension/references/Mention.java new file mode 100644 index 0000000000..6b43aa056a --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/Mention.java @@ -0,0 +1,33 @@ +package com.xabber.android.data.extension.references; + +import org.jivesoftware.smack.util.XmlStringBuilder; + +public class Mention extends ReferenceElement { + private final String uri; // jid + + public Mention(int begin, int end, String uri) { + super(begin, end); + this.uri = uri; + } + + @Override + public Type getType() { + return Type.mention; + } + + @Override + public CharSequence toXML() { + XmlStringBuilder xml = new XmlStringBuilder(this); + xml.attribute(ATTRIBUTE_TYPE, getType()); + xml.attribute(ATTRIBUTE_BEGIN, begin); + xml.attribute(ATTRIBUTE_END, end); + xml.attribute(ATTRIBUTE_URI, uri); + xml.rightAngleBracket(); + xml.closeElement(this); + return xml; + } + + public String getUri() { + return uri; + } +} diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/Quote.java b/xabber/src/main/java/com/xabber/android/data/extension/references/Quote.java new file mode 100644 index 0000000000..699cccd0b6 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/Quote.java @@ -0,0 +1,33 @@ +package com.xabber.android.data.extension.references; + +import org.jivesoftware.smack.util.XmlStringBuilder; + +public class Quote extends ReferenceElement { + private final int del; + + public Quote(int begin, int end, int del) { + super(begin, end); + this.del = del; + } + + @Override + public Type getType() { + return Type.quote; + } + + @Override + public CharSequence toXML() { + XmlStringBuilder xml = new XmlStringBuilder(this); + xml.attribute(ATTRIBUTE_TYPE, getType()); + xml.attribute(ATTRIBUTE_BEGIN, begin); + xml.attribute(ATTRIBUTE_END, end); + xml.attribute(ATTRIBUTE_DEL, del); + xml.rightAngleBracket(); + xml.closeElement(this); + return xml; + } + + public int getDel() { + return del; + } +} diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java index 3efb8017b2..dc2b997c23 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java @@ -2,11 +2,8 @@ import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.util.XmlStringBuilder; -import org.jivesoftware.smackx.forward.packet.Forwarded; -import java.util.List; - -public class ReferenceElement implements ExtensionElement { +public abstract class ReferenceElement implements ExtensionElement { public static final String NAMESPACE = "urn:xmpp:reference:0"; public static final String ELEMENT = "reference"; @@ -14,56 +11,28 @@ public class ReferenceElement implements ExtensionElement { public static final String ELEMENT_ITALIC = "italic"; public static final String ELEMENT_UNDERLINE = "underline"; public static final String ELEMENT_STRIKE = "strike"; + public static final String ELEMENT_URL = "url"; - private final Type type; - private final int begin; - private final int end; - private final int del; - - private boolean bold; - private boolean italic; - private boolean underline; - private boolean strike; - private String url; - - private List forwarded; - private List media; + public static final String ATTRIBUTE_TYPE = "type"; + public static final String ATTRIBUTE_BEGIN = "begin"; + public static final String ATTRIBUTE_END = "end"; + public static final String ATTRIBUTE_URI = "uri"; + public static final String ATTRIBUTE_DEL = "del"; - public ReferenceElement(Type type, int begin, int end, int del, List forwarded, List media) { - this.type = type; - this.begin = begin; - this.end = end; - this.del = del; - this.forwarded = forwarded; - this.media = media; + public enum Type { + data, + forward, + markup, + mention, + quote } - public ReferenceElement(Type type, int begin, int end, int del, boolean bold, boolean italic, - boolean underline, boolean strike, String url) { - this.type = type; - this.begin = begin; - this.end = end; - this.del = del; - this.bold = bold; - this.italic = italic; - this.underline = underline; - this.strike = strike; - this.url = url; - } + protected final int begin; + protected final int end; - public ReferenceElement(Type type, int begin, int end, int del, boolean bold, boolean italic, - boolean underline, boolean strike, String url, List forwarded, List media) { - this.type = type; + public ReferenceElement(int begin, int end) { this.begin = begin; this.end = end; - this.del = del; - this.bold = bold; - this.italic = italic; - this.underline = underline; - this.strike = strike; - this.url = url; - this.forwarded = forwarded; - this.media = media; } @Override @@ -79,28 +48,16 @@ public String getElementName() { @Override public CharSequence toXML() { XmlStringBuilder xml = new XmlStringBuilder(this); - xml.attribute("type", type); - xml.attribute("begin", begin); - xml.attribute("end", end); - xml.attribute("del", del); + xml.attribute(ATTRIBUTE_TYPE, getType()); + xml.attribute(ATTRIBUTE_BEGIN, begin); + xml.attribute(ATTRIBUTE_END, end); xml.rightAngleBracket(); - if (forwarded != null && !forwarded.isEmpty()) { - for (Forwarded forward : forwarded) { - xml.append(forward.toXML()); - } - } - if (media != null && !media.isEmpty()) { - for (RefMedia media1 : media) { - xml.append(media1.toXML()); - } - } + appendToXML(xml); xml.closeElement(this); return xml; } - public Type getType() { - return type; - } + public void appendToXML(XmlStringBuilder xml) { } public int getBegin() { return begin; @@ -110,44 +67,5 @@ public int getEnd() { return end; } - public int getDel() { - return del; - } - - public boolean isBold() { - return bold; - } - - public boolean isItalic() { - return italic; - } - - public boolean isUnderline() { - return underline; - } - - public boolean isStrike() { - return strike; - } - - public String getUrl() { - return url; - } - - public List getForwarded() { - return forwarded; - } - - public List getMedia() { - return media; - } - - public enum Type { - data, - forward, - markup, - mention, - quote, - legacy - } + public abstract Type getType(); } \ No newline at end of file diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index 0bb743fa4b..468c8b8775 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -32,14 +32,14 @@ public static List getForwardedFromReferences(Stanza packet) { List forwarded = new ArrayList<>(); for (ExtensionElement element : elements) { - if (element instanceof ReferenceElement) { - forwarded.addAll(((ReferenceElement) element).getForwarded()); + if (element instanceof Forward) { + forwarded.addAll(((Forward) element).getForwarded()); } } return forwarded; } - public static ReferenceElement createMediaReferences(RealmList attachments, String legacyBody) { + public static Data createMediaReferences(RealmList attachments, String legacyBody) { List mediaList = new ArrayList<>(); for (Attachment attachment : attachments) { RefFile.Builder builder = RefFile.newBuilder(); @@ -57,10 +57,10 @@ public static ReferenceElement createMediaReferences(RealmList attac } char[] chars = TextUtils.htmlEncode(legacyBody).toCharArray(); - return new ReferenceElement(ReferenceElement.Type.data, 0, chars.length - 1, 0, null, mediaList); + return new Data(0, chars.length - 1, mediaList); } - public static ReferenceElement createForwardReference(RealmResults items, String legacyBody) { + public static Forward createForwardReference(RealmResults items, String legacyBody) { List forwardedList = new ArrayList<>(); for (MessageItem item : items) { try { @@ -72,8 +72,7 @@ public static ReferenceElement createForwardReference(RealmResults } char[] chars = TextUtils.htmlEncode(legacyBody).toCharArray(); - return new ReferenceElement(ReferenceElement.Type.forward, 0, chars.length - 1, 0, - forwardedList, null); + return new Forward(0, chars.length - 1, forwardedList); } @Nonnull @@ -83,8 +82,8 @@ public static List getMediaFromReferences(Stanza packet) { List media = new ArrayList<>(); for (ExtensionElement element : elements) { - if (element instanceof ReferenceElement) { - media.addAll(((ReferenceElement) element).getMedia()); + if (element instanceof Data) { + media.addAll(((Data) element).getMedia()); } } return media; @@ -104,7 +103,7 @@ public static String modifyBodyWithReferences(Message message, String body) { // modify chars with references except markup for (ReferenceElement reference : references) { - if (!reference.getType().equals(ReferenceElement.Type.markup)) + if (!(reference instanceof Markup)) chars = modifyBodyWithReferences(chars, reference); } @@ -114,7 +113,7 @@ public static String modifyBodyWithReferences(Message message, String body) { // modify chars with markup references for (ReferenceElement reference : references) { - if (reference.getType().equals(ReferenceElement.Type.markup)) + if (reference instanceof Markup) chars = modifyBodyWithReferences(chars, reference); } @@ -161,11 +160,8 @@ private static String[] modifyBodyWithReferences(String[] chars, ReferenceElemen case forward: chars = remove(begin, end, chars); break; - case legacy: - chars = remove(begin, end, chars); - break; case markup: - chars = markup(begin, end, chars, reference); + chars = markup(begin, end, chars, (Markup) reference); break; } return chars; @@ -178,7 +174,7 @@ private static String[] remove(int begin, int end, String[] source) { return source; } - private static String[] markup(int begin, int end, String[] source, ReferenceElement reference) { + private static String[] markup(int begin, int end, String[] source, Markup reference) { StringBuilder builderOpen = new StringBuilder(); StringBuilder builderClose = new StringBuilder(); if (reference.isBold()) { diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java index 2fb31630d9..432f10894c 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java @@ -12,7 +12,7 @@ public class ReferencesProvider extends ExtensionElementProvider forwardedMessages = new ArrayList<>(); List mediaElements = new ArrayList<>(); boolean bold = false, italic = false, underline = false, strike = false; @@ -23,10 +23,11 @@ public ReferenceElement parse(XmlPullParser parser, int initialDepth) throws Exc case XmlPullParser.START_TAG: if (ReferenceElement.ELEMENT.equals(parser.getName()) && ReferenceElement.NAMESPACE.equals(parser.getNamespace())) { - type = parser.getAttributeValue("", "type"); - beginS = parser.getAttributeValue("", "begin"); - endS = parser.getAttributeValue("", "end"); - delS = parser.getAttributeValue("", "del"); + type = parser.getAttributeValue("", ReferenceElement.ATTRIBUTE_TYPE); + beginS = parser.getAttributeValue("", ReferenceElement.ATTRIBUTE_BEGIN); + endS = parser.getAttributeValue("", ReferenceElement.ATTRIBUTE_END); + delS = parser.getAttributeValue("", ReferenceElement.ATTRIBUTE_DEL); + uri = parser.getAttributeValue("", ReferenceElement.ATTRIBUTE_URI); } if (Forwarded.ELEMENT.equals(parser.getName()) && Forwarded.NAMESPACE.equals(parser.getNamespace())) { @@ -49,7 +50,9 @@ public ReferenceElement parse(XmlPullParser parser, int initialDepth) throws Exc if (ReferenceElement.ELEMENT_STRIKE.equals(parser.getName())) { strike = true; } - parser.next(); + if (ReferenceElement.ELEMENT_URL.equals(parser.getName())) { + url = parser.nextText(); + } else parser.next(); break; case XmlPullParser.END_TAG: if (ReferenceElement.ELEMENT.equals(parser.getName())) { @@ -65,8 +68,21 @@ public ReferenceElement parse(XmlPullParser parser, int initialDepth) throws Exc if (beginS != null && !beginS.isEmpty()) begin = Integer.valueOf(beginS); if (endS != null && !endS.isEmpty()) end = Integer.valueOf(endS); if (delS != null && !delS.isEmpty()) del = Integer.valueOf(delS); - return new ReferenceElement(ReferenceElement.Type.valueOf(type), begin, end, del, bold, - italic, underline, strike, null, forwardedMessages, mediaElements); + + switch (ReferenceElement.Type.valueOf(type)) { + case forward: + return new Forward(begin, end, forwardedMessages); + case data: + return new Data(begin, end, mediaElements); + case markup: + return new Markup(begin, end, bold, italic, underline, strike, url); + case quote: + return new Quote(begin, end, del); + case mention: + return new Mention(begin, end, uri); + default: + return null; + } } private RefMedia parseMedia(XmlPullParser parser) throws Exception { From 457eedb369c6d3b2c358f25f3c6a68a7ad7f9fd3 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 11 Jun 2019 17:10:15 +0500 Subject: [PATCH 149/237] Added modification message body with quote reference. --- .../references/ReferencesManager.java | 18 +++++++++++++++++- .../android/ui/adapter/chat/MessageVH.java | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index 468c8b8775..2ad36f50cd 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -109,7 +109,7 @@ public static String modifyBodyWithReferences(Message message, String body) { // chars to string and decode from html // then split string into chars - chars = stringToChars(Html.fromHtml(charsToString(chars)).toString()); + chars = stringToChars(Html.fromHtml(charsToString(chars).replace("\n", "
")).toString()); // modify chars with markup references for (ReferenceElement reference : references) { @@ -163,6 +163,9 @@ private static String[] modifyBodyWithReferences(String[] chars, ReferenceElemen case markup: chars = markup(begin, end, chars, (Markup) reference); break; + case quote: + chars = removeInLine(begin, end, chars, (Quote) reference); + break; } return chars; } @@ -174,6 +177,19 @@ private static String[] remove(int begin, int end, String[] source) { return source; } + private static String[] removeInLine(int begin, int end, String[] source, Quote reference) { + int del = reference.getDel(); + int removed = 0; + for (int i = begin; i <= end; i++) { + if (removed < del) { + source[i] = String.valueOf(Character.MIN_VALUE); + removed++; + } + if (source[i].equals("\n")) removed = 0; + } + return source; + } + private static String[] markup(int begin, int end, String[] source, Markup reference) { StringBuilder builderOpen = new StringBuilder(); StringBuilder builderClose = new StringBuilder(); diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java index c1b176eb72..7c817876ae 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java @@ -95,7 +95,7 @@ public void bind(MessageItem messageItem, MessagesAdapter.MessageExtraData extra ivEncrypted.setVisibility(View.GONE); } - messageText.setText(Html.fromHtml(messageItem.getText())); + messageText.setText(Html.fromHtml(messageItem.getText().replace("\n", "
"))); if (OTRManager.getInstance().isEncrypted(messageItem.getText())) { if (extraData.isShowOriginalOTR()) messageText.setVisibility(View.VISIBLE); From 2dc35b8e2a31c4819f94ecd16ec0814b5dc9d763 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 11 Jun 2019 17:21:35 +0500 Subject: [PATCH 150/237] Added unit tests for references --- .../extension/references/RefFileTest.java | 30 +++ .../extension/references/RefMediaTest.java | 34 ++++ .../references/ReferencesManagerTest.java | 78 ++++++++ .../references/ReferencesProviderTest.java | 171 ++++++++++++++++++ 4 files changed, 313 insertions(+) create mode 100644 xabber/src/test/java/com/xabber/android/data/extension/references/RefFileTest.java create mode 100644 xabber/src/test/java/com/xabber/android/data/extension/references/RefMediaTest.java create mode 100644 xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java create mode 100644 xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesProviderTest.java diff --git a/xabber/src/test/java/com/xabber/android/data/extension/references/RefFileTest.java b/xabber/src/test/java/com/xabber/android/data/extension/references/RefFileTest.java new file mode 100644 index 0000000000..d34d696e9a --- /dev/null +++ b/xabber/src/test/java/com/xabber/android/data/extension/references/RefFileTest.java @@ -0,0 +1,30 @@ +package com.xabber.android.data.extension.references; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class RefFileTest { + String xml; + RefFile.Builder builder; + + @Before + public void setUp() throws Exception { + builder = RefFile.newBuilder(); + builder.setMediaType("image/jpeg"); + builder.setName("summit.jpg"); + builder.setHeight(150); + builder.setWidth(160); + builder.setSize(3032449); + builder.setDesc("Photo from the summit."); + + xml = "image/jpegsummit.jpg150160" + + "3032449Photo from the summit."; + } + + @Test + public void toXML() { + assertEquals(xml, builder.build().toXML().toString()); + } +} \ No newline at end of file diff --git a/xabber/src/test/java/com/xabber/android/data/extension/references/RefMediaTest.java b/xabber/src/test/java/com/xabber/android/data/extension/references/RefMediaTest.java new file mode 100644 index 0000000000..1d976089a9 --- /dev/null +++ b/xabber/src/test/java/com/xabber/android/data/extension/references/RefMediaTest.java @@ -0,0 +1,34 @@ +package com.xabber.android.data.extension.references; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class RefMediaTest { + String xml; + RefFile.Builder builder; + RefMedia media; + + @Before + public void setUp() throws Exception { + builder = RefFile.newBuilder(); + builder.setMediaType("image/jpeg"); + builder.setName("summit.jpg"); + builder.setHeight(150); + builder.setWidth(160); + builder.setSize(3032449); + builder.setDesc("Photo from the summit."); + + media = new RefMedia(builder.build(), "https://upload02.xabber.org/5f7IyZ/guide.txt"); + + xml = "image/jpegsummit.jpg150" + + "1603032449Photo from the summit." + + "https://upload02.xabber.org/5f7IyZ/guide.txt"; + } + + @Test + public void toXML() { + assertEquals(xml, media.toXML().toString()); + } +} \ No newline at end of file diff --git a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java new file mode 100644 index 0000000000..5a1ff14930 --- /dev/null +++ b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java @@ -0,0 +1,78 @@ +package com.xabber.android.data.extension.references; + +import com.xabber.android.data.TestApplication; + +import org.jivesoftware.smack.packet.Message; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import static org.junit.Assert.assertEquals; + +@RunWith(RobolectricTestRunner.class) +@Config(application = TestApplication.class) +public class ReferencesManagerTest { + + private String body1, body2, body3, body4; + private Message message1, message2, message3, message4; + + @Before + public void setUp() throws Exception { + body1 = "> Wednesday, June 5, 2019\n> [11:08:45] Валерий Миллер:\n> один\nдва"; + + message1 = new Message("test@jabber.com", body1); + message1.addExtension(new Forward(0, 70, null)); + + // ------- + + body2 = "https://upload02.xabber.org/5ff2744e91/iKIlTIyZ/guide.txt\nhello"; + + message2 = new Message("test@jabber.com", body2); + message2.addExtension(new Data(0, 57, null)); + + // ------- + + body3 = "Тест форматирования текста. Использование нескольких стилей."; + + message3 = new Message("test@jabber.com", body3); + message3.addExtension(new Markup(5, 18, true, true, false, false, null)); + message3.addExtension(new Markup(20, 25, false, true, false, false, null)); + message3.addExtension(new Markup(28, 40, false, false, true, false, null)); + message3.addExtension(new Markup(42, 51, false, false, false, true, null)); + + // ------- + + body4 = "> This is a quote\n" + + "> of two lines\n" + + "Hello world!"; + + message4 = new Message("test@jabber.com", body4); + message4.addExtension(new Quote(0, 37, 5)); + } + + @Test + public void modifyBodyWithReferences1() { + assertEquals("Тест форматирования текстаИспользование нескольких стилей.", + ReferencesManager.modifyBodyWithReferences(message3, body3)); + } + + @Test + public void modifyBodyWithReferences2() { + assertEquals("два", ReferencesManager.modifyBodyWithReferences(message1, body1)); + } + + @Test + public void modifyBodyWithReferences3() { + assertEquals("hello", ReferencesManager.modifyBodyWithReferences(message2, body2)); + } + + @Test + public void modifyBodyWithReferences4() { + String expected = "This is a quote\n" + + "of two lines\n" + + "Hello world!"; + assertEquals(expected, ReferencesManager.modifyBodyWithReferences(message4, body4)); + } +} \ No newline at end of file diff --git a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesProviderTest.java b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesProviderTest.java new file mode 100644 index 0000000000..89bde4f7e8 --- /dev/null +++ b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesProviderTest.java @@ -0,0 +1,171 @@ +package com.xabber.android.data.extension.references; + +import com.xabber.android.data.TestApplication; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserFactory; + +import java.io.StringReader; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +@RunWith(RobolectricTestRunner.class) +@Config(application = TestApplication.class) +public class ReferencesProviderTest { + + private ReferencesProvider provider; + private XmlPullParserFactory factory; + private String stringForward, stringMedia, stringMarkup1, + stringMarkup2, stringMention, stringQuote; + + @Before + public void setUp() throws Exception { + provider = new ReferencesProvider(); + factory = XmlPullParserFactory.newInstance(); + factory.setNamespaceAware(true); + + stringForward = "" + + "" + + "" + + "" + + "hello" + + "" + + "" + + ""; + + stringMedia = "" + + "application/pdfAndroid-Architecture_1-1.pdf4255465" + + "https://upload02.xabber.org/5f70e738285c44c82039a73d42eccf27" + + "44e91/lQk6DkRJ/Android-Architecture_1-1.pdf" + + "image/pngScreenshot_20190414-194652.png251184" + + "1280720https://upload02.xabber.org/5f70" + + "e738285c44c82039a73d42eccf2744e91/rUdy3rHt/Screenshot_20190414-194652.png" + + ""; + + stringMarkup1 = "" + + ""; + + stringMarkup2 = "" + + "https://www.xabber.com"; + + stringMention = ""; + + stringQuote = ""; + + } + + @Test + public void parse1() { + Forward element = (Forward) parseString(stringForward); + assertNotNull(element); + assertEquals("forward", element.getType().toString()); + assertEquals(11, element.getBegin()); + assertEquals(179, element.getEnd()); + assertEquals(1, element.getForwarded().size()); + } + + @Test + public void parse2() { + Data element = (Data) parseString(stringMedia); + assertNotNull(element); + assertEquals("data", element.getType().toString()); + assertEquals(0, element.getBegin()); + assertEquals(89, element.getEnd()); + assertEquals(2, element.getMedia().size()); + + RefMedia media1 = element.getMedia().get(0); + assertNotNull(media1); + assertEquals("https://upload02.xabber.org/5f70e738285c44c82039a73" + + "d42eccf2744e91/lQk6DkRJ/Android-Architecture_1-1.pdf", media1.getUri()); + + RefFile file1 = media1.getFile(); + assertNotNull(file1); + assertEquals("application/pdf", file1.getMediaType()); + assertEquals("Android-Architecture_1-1.pdf", file1.getName()); + assertEquals(4255465, file1.getSize()); + + RefMedia media2 = element.getMedia().get(1); + assertNotNull(media2); + assertEquals("https://upload02.xabber.org/5f70e738285c44c82039a73d42eccf274" + + "4e91/rUdy3rHt/Screenshot_20190414-194652.png", media2.getUri()); + + RefFile file2 = media2.getFile(); + assertNotNull(file2); + assertEquals("image/png", file2.getMediaType()); + assertEquals("Screenshot_20190414-194652.png", file2.getName()); + assertEquals(251184, file2.getSize()); + assertEquals(1280, file2.getHeight()); + assertEquals(720, file2.getWidth()); + } + + @Test + public void parse3() { + Markup element = (Markup) parseString(stringMarkup1); + assertNotNull(element); + assertEquals("markup", element.getType().toString()); + assertEquals(7, element.getBegin()); + assertEquals(10, element.getEnd()); + assertTrue(element.isBold()); + assertTrue(element.isItalic()); + assertFalse(element.isStrike()); + assertFalse(element.isUnderline()); + assertNull(element.getUrl()); + } + + @Test + public void parse4() { + Markup element = (Markup) parseString(stringMarkup2); + assertNotNull(element); + assertEquals("markup", element.getType().toString()); + assertEquals(34, element.getBegin()); + assertEquals(37, element.getEnd()); + assertTrue(element.isBold()); + assertFalse(element.isItalic()); + assertFalse(element.isStrike()); + assertFalse(element.isUnderline()); + assertEquals("https://www.xabber.com", element.getUrl()); + } + + @Test + public void parse5() { + Mention element = (Mention) parseString(stringMention); + assertNotNull(element); + assertEquals("mention", element.getType().toString()); + assertEquals(16, element.getBegin()); + assertEquals(22, element.getEnd()); + assertEquals("xmpp:juliet@capulet.lit", element.getUri()); + } + + @Test + public void parse6() { + Quote element = (Quote) parseString(stringQuote); + assertNotNull(element); + assertEquals("quote", element.getType().toString()); + assertEquals(0, element.getBegin()); + assertEquals(31, element.getEnd()); + assertEquals(5, element.getDel()); + } + + private ReferenceElement parseString(String source) { + ReferenceElement result = null; + try { + XmlPullParser parser = factory.newPullParser(); + parser.setInput(new StringReader(source)); + result = provider.parse(parser, 0); + } catch (Exception e) { + fail("Exception while parsing: " + e.toString()); + } + return result; + } +} \ No newline at end of file From 8be8d61fe7c1732e16634c00d11d03a40761a7a2 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 11 Jun 2019 17:44:21 +0500 Subject: [PATCH 151/237] Up version to 621 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 13a96a2668..181bbbf1c3 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 620 - versionName '2.6.4(620)' + versionCode 621 + versionName '2.6.4(621)' } lintOptions { From c19e19a2829c8f373744c4fdfa5103ddb0c10854 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 13 Jun 2019 15:15:06 +0500 Subject: [PATCH 152/237] Changes in modification body with references --- .../data/extension/mam/NextMamManager.java | 2 +- .../android/data/extension/muc/RoomChat.java | 4 ++-- .../references/ReferencesManager.java | 20 +++++++++++-------- .../android/data/message/MessageManager.java | 2 +- .../android/data/message/RegularChat.java | 4 ++-- 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index d01acb9683..a0c55d12b4 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -653,7 +653,7 @@ private List parseMessage(AccountItem accountItem, AccountJid accou if (forwardComment != null) body = forwardComment; // modify body with references - body = ReferencesManager.modifyBodyWithReferences(message, body); + body = ReferencesManager.modifyBodyWithReferences(message, body).first; boolean incoming = message.getFrom().asBareJid().equals(user.getJid().asBareJid()); diff --git a/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java b/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java index 25cb3e7df2..787b3ce662 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java @@ -275,7 +275,7 @@ protected boolean onPacket(UserJid bareAddress, Stanza stanza, boolean isCarbons if (forwardComment != null) text = forwardComment; // modify body with references - text = ReferencesManager.modifyBodyWithReferences(message, text); + text = ReferencesManager.modifyBodyWithReferences(message, text).first; String originalFrom = stanza.getFrom().toString(); @@ -394,7 +394,7 @@ protected String parseInnerMessage(boolean ui, Message message, String parentMes if (forwardComment != null) text = forwardComment; // modify body with references - text = ReferencesManager.modifyBodyWithReferences(message, text); + text = ReferencesManager.modifyBodyWithReferences(message, text).first; // create message with file-attachments if (attachments.size() > 0) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index 2ad36f50cd..7e0f3e4e5f 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -2,6 +2,7 @@ import android.text.Html; import android.text.TextUtils; +import android.util.Pair; import com.xabber.android.data.database.messagerealm.Attachment; import com.xabber.android.data.database.messagerealm.MessageItem; @@ -89,14 +90,14 @@ public static List getMediaFromReferences(Stanza packet) { return media; } - public static String modifyBodyWithReferences(Message message, String body) { - if (body == null || body.isEmpty() || body.trim().isEmpty()) return body; + public static Pair modifyBodyWithReferences(Message message, String body) { + if (body == null || body.isEmpty() || body.trim().isEmpty()) return new Pair<>(body, null); List elements = message.getExtensions(ReferenceElement.ELEMENT, ReferenceElement.NAMESPACE); - if (elements == null || elements.size() == 0) return body; + if (elements == null || elements.size() == 0) return new Pair<>(body, null); List references = getReferences(elements); - if (references.isEmpty()) return body; + if (references.isEmpty()) return new Pair<>(body, null); // encode HTML and split into chars String[] chars = stringToChars(TextUtils.htmlEncode(body)); @@ -108,19 +109,22 @@ public static String modifyBodyWithReferences(Message message, String body) { } // chars to string and decode from html - // then split string into chars - chars = stringToChars(Html.fromHtml(charsToString(chars).replace("\n", "
")).toString()); + String regularBody = Html.fromHtml(charsToString(chars).replace("\n", "
")).toString(); + String markupBody = null; // modify chars with markup references for (ReferenceElement reference : references) { if (reference instanceof Markup) chars = modifyBodyWithReferences(chars, reference); } + markupBody = charsToString(chars); + if (regularBody.equals(markupBody)) markupBody = null; - // chars to string - return charsToString(chars); + return new Pair<>(regularBody, markupBody); } + + private static List getReferences(List elements) { List references = new ArrayList<>(); for (ExtensionElement element : elements) { diff --git a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java index f349a6dc2c..40f6081d2c 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java +++ b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java @@ -791,7 +791,7 @@ public void processCarbonsMessage(AccountJid account, final Message message, Car if (forwardComment != null) text = forwardComment; // modify body with references - text = ReferencesManager.modifyBodyWithReferences(message, text); + text = ReferencesManager.modifyBodyWithReferences(message, text).first; MessageItem newMessageItem = finalChat.createNewMessageItem(text); newMessageItem.setStanzaId(AbstractChat.getStanzaId(message)); diff --git a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java index 815d1c2ef1..bce735c318 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java @@ -229,7 +229,7 @@ protected boolean onPacket(UserJid bareAddress, Stanza packet, boolean isCarbons return true; // modify body with references - text = ReferencesManager.modifyBodyWithReferences(message, text); + text = ReferencesManager.modifyBodyWithReferences(message, text).first; // create message with file-attachments if (attachments.size() > 0) @@ -280,7 +280,7 @@ protected String parseInnerMessage(boolean ui, Message message, String parentMes if (forwardComment != null && !forwardComment.isEmpty()) text = forwardComment; // modify body with references - text = ReferencesManager.modifyBodyWithReferences(message, text); + text = ReferencesManager.modifyBodyWithReferences(message, text).first; // create message with file-attachments if (attachments.size() > 0) From 989a574dac19980125a3e1105097db9df6543312 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 13 Jun 2019 16:50:59 +0500 Subject: [PATCH 153/237] Added markupText field to messageItem --- .../data/database/MessageDatabaseManager.java | 8 +++++- .../database/messagerealm/MessageItem.java | 10 +++++++ .../data/extension/mam/NextMamManager.java | 7 ++++- .../android/data/extension/muc/RoomChat.java | 21 +++++++++------ .../android/data/message/AbstractChat.java | 27 +++++++++++-------- .../android/data/message/MessageManager.java | 6 ++++- .../android/data/message/RegularChat.java | 19 ++++++++----- .../android/ui/adapter/chat/MessageVH.java | 4 ++- 8 files changed, 72 insertions(+), 30 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java b/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java index 98792e59a3..710873f6b8 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java +++ b/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java @@ -36,7 +36,7 @@ public class MessageDatabaseManager { private static final String REALM_MESSAGE_DATABASE_NAME = "xabber.realm"; - static final int REALM_MESSAGE_DATABASE_VERSION = 21; + static final int REALM_MESSAGE_DATABASE_VERSION = 22; private final RealmConfiguration realmConfiguration; private static MessageDatabaseManager instance; @@ -354,6 +354,12 @@ public void apply(DynamicRealmObject obj) { oldVersion++; } + if (oldVersion == 21) { + schema.get(MessageItem.class.getSimpleName()) + .addField(MessageItem.Fields.MARKUP_TEXT, String.class); + oldVersion++; + } + } }) .build(); diff --git a/xabber/src/main/java/com/xabber/android/data/database/messagerealm/MessageItem.java b/xabber/src/main/java/com/xabber/android/data/database/messagerealm/MessageItem.java index 3fd22489ed..96e44ea745 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/messagerealm/MessageItem.java +++ b/xabber/src/main/java/com/xabber/android/data/database/messagerealm/MessageItem.java @@ -45,6 +45,7 @@ public static class Fields { public static final String USER = "user"; public static final String RESOURCE = "resource"; public static final String TEXT = "text"; + public static final String MARKUP_TEXT = "markupText"; public static final String ACTION = "action"; public static final String INCOMING = "incoming"; public static final String ENCRYPTED = "encrypted"; @@ -100,6 +101,7 @@ public static class Fields { * Text representation. */ private String text; + private String markupText; /** * Optional action. If set message represent not an actual message but some * action in the chat. @@ -593,4 +595,12 @@ public boolean isFromMUC() { public void setFromMUC(boolean fromMUC) { this.fromMUC = fromMUC; } + + public String getMarkupText() { + return markupText; + } + + public void setMarkupText(String markupText) { + this.markupText = markupText; + } } diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index a0c55d12b4..b91b68d784 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -1,5 +1,7 @@ package com.xabber.android.data.extension.mam; +import android.util.Pair; + import com.xabber.android.data.Application; import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.account.AccountManager; @@ -653,7 +655,9 @@ private List parseMessage(AccountItem accountItem, AccountJid accou if (forwardComment != null) body = forwardComment; // modify body with references - body = ReferencesManager.modifyBodyWithReferences(message, body).first; + Pair bodies = ReferencesManager.modifyBodyWithReferences(message, body); + body = bodies.first; + String markupBody = bodies.second; boolean incoming = message.getFrom().asBareJid().equals(user.getJid().asBareJid()); @@ -670,6 +674,7 @@ private List parseMessage(AccountItem accountItem, AccountJid accou messageItem.setUser(user); messageItem.setResource(user.getJid().getResourceOrNull()); messageItem.setText(body); + if (markupBody != null) messageItem.setMarkupText(markupBody); messageItem.setTimestamp(timestamp); if (messageDelay != null) { messageItem.setDelayTimestamp(messageDelay.getStamp().getTime()); diff --git a/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java b/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java index 787b3ce662..e50e1f258b 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java @@ -16,6 +16,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.util.Pair; import com.xabber.android.R; import com.xabber.android.data.Application; @@ -189,7 +190,7 @@ void putInvite(String packetID, UserJid user) { @Override protected MessageItem createNewMessageItem(String text) { - return createMessageItem(nickname, text, null, null, false, + return createMessageItem(nickname, text, null, null, null, false, false, false, false, UUID.randomUUID().toString(), null, null, null, account.getFullJid().toString(), null, true); } @@ -275,7 +276,9 @@ protected boolean onPacket(UserJid bareAddress, Stanza stanza, boolean isCarbons if (forwardComment != null) text = forwardComment; // modify body with references - text = ReferencesManager.modifyBodyWithReferences(message, text).first; + Pair bodies = ReferencesManager.modifyBodyWithReferences(message, text); + text = bodies.first; + String markupText = bodies.second; String originalFrom = stanza.getFrom().toString(); @@ -301,12 +304,12 @@ protected boolean onPacket(UserJid bareAddress, Stanza stanza, boolean isCarbons // create message with file-attachments if (attachments.size() > 0) - createAndSaveFileMessage(true, uid, resource, text, null, delay, true, notify, + createAndSaveFileMessage(true, uid, resource, text, markupText, null, delay, true, notify, false, false, getStanzaId(message), attachments, originalStanza, null, originalFrom, true, false); // create message without attachments - else createAndSaveNewMessage(true, uid, resource, text, null, delay, true, notify, + else createAndSaveNewMessage(true, uid, resource, text, markupText, null, delay, true, notify, false, false, getStanzaId(message), originalStanza, null, originalFrom, forwardIds, true, false); @@ -394,16 +397,18 @@ protected String parseInnerMessage(boolean ui, Message message, String parentMes if (forwardComment != null) text = forwardComment; // modify body with references - text = ReferencesManager.modifyBodyWithReferences(message, text).first; + Pair bodies = ReferencesManager.modifyBodyWithReferences(message, text); + text = bodies.first; + String markupText = bodies.second; // create message with file-attachments if (attachments.size() > 0) - createAndSaveFileMessage(ui, uid, resource, text, null, null, + createAndSaveFileMessage(ui, uid, resource, text, markupText, null, null, true, false, false, false, getStanzaId(message), attachments, originalStanza, parentMessageId, originalFrom, fromMUC, true); // create message without attachments - else createAndSaveNewMessage(ui, uid, resource, text, null, null, + else createAndSaveNewMessage(ui, uid, resource, text, markupText, null, null, true, false, false, false, getStanzaId(message), originalStanza, parentMessageId, originalFrom, forwardIds, fromMUC, true); @@ -473,7 +478,7 @@ private void onAvailable(Resourcepart resource) { if (isRequested()) { if (showStatusChange()) { createAndSaveNewMessage(true, UUID.randomUUID().toString(), resource, Application.getInstance().getString( - R.string.action_join_complete_to, user), + R.string.action_join_complete_to, user), null, ChatAction.complete, null, true, true, false, false, null, null, null, null, null, true, false); diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index f20d0149f2..e6cb29b50d 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -258,8 +258,8 @@ public void enableNotificationsIfNeed() { * @param text can be null. */ public void newAction(Resourcepart resource, String text, ChatAction action, boolean fromMUC) { - createAndSaveNewMessage(true, UUID.randomUUID().toString(), resource, text, action, - null, true, false, false, false, + createAndSaveNewMessage(true, UUID.randomUUID().toString(), resource, text, null, + action, null, true, false, false, false, null, null, null, null, null, fromMUC, false); } @@ -278,28 +278,30 @@ public void newAction(Resourcepart resource, String text, ChatAction action, boo * @param offline Whether message was received from server side offline storage. * @return */ - protected void createAndSaveNewMessage(boolean ui, String uid, Resourcepart resource, String text, final ChatAction action, + protected void createAndSaveNewMessage(boolean ui, String uid, Resourcepart resource, String text, + String markupText, final ChatAction action, final Date delayTimestamp, final boolean incoming, boolean notify, final boolean encrypted, final boolean offline, final String stanzaId, final String originalStanza, final String parentMessageId, final String originalFrom, final RealmList forwardIds, boolean fromMUC, boolean fromMAM) { - final MessageItem messageItem = createMessageItem(uid, resource, text, action, delayTimestamp, - incoming, notify, encrypted, offline, stanzaId, null, + final MessageItem messageItem = createMessageItem(uid, resource, text, markupText, action, + delayTimestamp, incoming, notify, encrypted, offline, stanzaId, null, originalStanza, parentMessageId, originalFrom, forwardIds, fromMUC, fromMAM); saveMessageItem(ui, messageItem); //EventBus.getDefault().post(new NewMessageEvent()); } - protected void createAndSaveFileMessage(boolean ui, String uid, Resourcepart resource, String text, final ChatAction action, + protected void createAndSaveFileMessage(boolean ui, String uid, Resourcepart resource, String text, + String markupText, final ChatAction action, final Date delayTimestamp, final boolean incoming, boolean notify, final boolean encrypted, final boolean offline, final String stanzaId, RealmList attachments, final String originalStanza, final String parentMessageId, final String originalFrom, boolean fromMUC, boolean fromMAM) { - final MessageItem messageItem = createMessageItem(uid, resource, text, action, delayTimestamp, - incoming, notify, encrypted, offline, stanzaId, attachments, + final MessageItem messageItem = createMessageItem(uid, resource, text, markupText, action, + delayTimestamp, incoming, notify, encrypted, offline, stanzaId, attachments, originalStanza, parentMessageId, originalFrom, null, fromMUC, fromMAM); saveMessageItem(ui, messageItem); @@ -323,18 +325,20 @@ public void execute(Realm realm) { } } - protected MessageItem createMessageItem(Resourcepart resource, String text, ChatAction action, + protected MessageItem createMessageItem(Resourcepart resource, String text, + String markupText, ChatAction action, Date delayTimestamp, boolean incoming, boolean notify, boolean encrypted, boolean offline, String stanzaId, RealmList attachments, String originalStanza, String parentMessageId, String originalFrom, RealmList forwardIds, boolean fromMUC) { - return createMessageItem(UUID.randomUUID().toString(), resource, text, action, + return createMessageItem(UUID.randomUUID().toString(), resource, text, markupText, action, delayTimestamp, incoming, notify, encrypted, offline, stanzaId, attachments, originalStanza, parentMessageId, originalFrom, forwardIds, fromMUC, false); } - protected MessageItem createMessageItem(String uid, Resourcepart resource, String text, ChatAction action, + protected MessageItem createMessageItem(String uid, Resourcepart resource, String text, + String markupText, ChatAction action, Date delayTimestamp, boolean incoming, boolean notify, boolean encrypted, boolean offline, String stanzaId, RealmList attachments, String originalStanza, String parentMessageId, String originalFrom, @@ -388,6 +392,7 @@ protected MessageItem createMessageItem(String uid, Resourcepart resource, Strin messageItem.setAction(action.toString()); } messageItem.setText(text); + if (markupText != null) messageItem.setMarkupText(markupText); messageItem.setTimestamp(timestamp.getTime()); if (delayTimestamp != null) { messageItem.setDelayTimestamp(delayTimestamp.getTime()); diff --git a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java index 40f6081d2c..3303150cdd 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java +++ b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java @@ -18,6 +18,7 @@ import android.os.Environment; import android.os.Looper; import android.support.annotation.Nullable; +import android.util.Pair; import com.xabber.android.R; import com.xabber.android.data.Application; @@ -791,12 +792,15 @@ public void processCarbonsMessage(AccountJid account, final Message message, Car if (forwardComment != null) text = forwardComment; // modify body with references - text = ReferencesManager.modifyBodyWithReferences(message, text).first; + Pair bodies = ReferencesManager.modifyBodyWithReferences(message, text); + text = bodies.first; + String markupText = bodies.second; MessageItem newMessageItem = finalChat.createNewMessageItem(text); newMessageItem.setStanzaId(AbstractChat.getStanzaId(message)); newMessageItem.setSent(true); newMessageItem.setForwarded(true); + if (markupText != null) newMessageItem.setMarkupText(markupText); // forwarding if (forwardIds != null) newMessageItem.setForwardedIds(forwardIds); diff --git a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java index bce735c318..fa4fb05c9b 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java @@ -17,6 +17,7 @@ import android.content.Intent; import android.support.annotation.NonNull; import android.text.TextUtils; +import android.util.Pair; import com.xabber.android.data.NetworkException; import com.xabber.android.data.SettingsManager; @@ -143,7 +144,7 @@ protected String prepareText(String text) { @Override protected MessageItem createNewMessageItem(String text) { - return createMessageItem(null, text, null, null, false, + return createMessageItem(null, text, null, null, null, false, false, false, false, UUID.randomUUID().toString(), null, null, null, account.getFullJid().toString(), null, false); @@ -229,18 +230,20 @@ protected boolean onPacket(UserJid bareAddress, Stanza packet, boolean isCarbons return true; // modify body with references - text = ReferencesManager.modifyBodyWithReferences(message, text).first; + Pair bodies = ReferencesManager.modifyBodyWithReferences(message, text); + text = bodies.first; + String markupText = bodies.second; // create message with file-attachments if (attachments.size() > 0) - createAndSaveFileMessage(true, uid, resource, text, null, getDelayStamp(message), + createAndSaveFileMessage(true, uid, resource, text, markupText, null, getDelayStamp(message), true, true, encrypted, isOfflineMessage(account.getFullJid().getDomain(), packet), getStanzaId(message), attachments, originalStanza, null, originalFrom, false, false); // create message without attachments - else createAndSaveNewMessage(true, uid, resource, text, null, getDelayStamp(message), + else createAndSaveNewMessage(true, uid, resource, text, markupText, null, getDelayStamp(message), true, true, encrypted, isOfflineMessage(account.getFullJid().getDomain(), packet), getStanzaId(message), originalStanza, null, @@ -280,16 +283,18 @@ protected String parseInnerMessage(boolean ui, Message message, String parentMes if (forwardComment != null && !forwardComment.isEmpty()) text = forwardComment; // modify body with references - text = ReferencesManager.modifyBodyWithReferences(message, text).first; + Pair bodies = ReferencesManager.modifyBodyWithReferences(message, text); + text = bodies.first; + String markupText = bodies.second; // create message with file-attachments if (attachments.size() > 0) - createAndSaveFileMessage(ui, uid, resource, text, null, null, true, + createAndSaveFileMessage(ui, uid, resource, text, markupText, null, null, true, false, encrypted, false, getStanzaId(message), attachments, originalStanza, parentMessageId, originalFrom, fromMuc, true); // create message without attachments - else createAndSaveNewMessage(ui, uid, resource, text, null, null, true, + else createAndSaveNewMessage(ui, uid, resource, text, markupText, null, null, true, false, encrypted, false, getStanzaId(message), originalStanza, parentMessageId, originalFrom, forwardIds, fromMuc, true); diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java index 7c817876ae..4006c70910 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java @@ -95,7 +95,9 @@ public void bind(MessageItem messageItem, MessagesAdapter.MessageExtraData extra ivEncrypted.setVisibility(View.GONE); } - messageText.setText(Html.fromHtml(messageItem.getText().replace("\n", "
"))); + if (messageItem.getMarkupText() != null && !messageItem.getMarkupText().isEmpty()) + messageText.setText(Html.fromHtml(messageItem.getMarkupText().replace("\n", "
"))); + else messageText.setText(messageItem.getText()); if (OTRManager.getInstance().isEncrypted(messageItem.getText())) { if (extraData.isShowOriginalOTR()) messageText.setVisibility(View.VISIBLE); From 869ae743a6fe8f27624784cf96da6d646bdbd4ba Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 13 Jun 2019 18:35:41 +0500 Subject: [PATCH 154/237] Fixed bug with unicode characters with high-surrogate range. --- .../references/ReferencesManager.java | 11 ++-- .../references/ReferencesManagerTest.java | 53 ++++++++++++++++--- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index 7e0f3e4e5f..7031830be2 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -143,10 +143,13 @@ private static String charsToString(String[] array) { } private static String[] stringToChars(String source) { - char[] chars = source.toCharArray(); - String[] result = new String[chars.length]; - for (int i = 0; i < chars.length; i++) { - result[i] = String.valueOf(chars[i]); + String[] result = new String[source.codePointCount(0, source.length())]; + int i = 0; + for (int offset = 0; offset < source.length(); ) { + int codepoint = source.codePointAt(offset); + result[i] = String.valueOf(Character.toChars(codepoint)); + offset += Character.charCount(codepoint); + i++; } return result; } diff --git a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java index 5a1ff14930..a6a6623834 100644 --- a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java +++ b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java @@ -1,5 +1,7 @@ package com.xabber.android.data.extension.references; +import android.util.Pair; + import com.xabber.android.data.TestApplication; import org.jivesoftware.smack.packet.Message; @@ -10,13 +12,14 @@ import org.robolectric.annotation.Config; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; @RunWith(RobolectricTestRunner.class) @Config(application = TestApplication.class) public class ReferencesManagerTest { - private String body1, body2, body3, body4; - private Message message1, message2, message3, message4; + private String body1, body2, body3, body4, body5, body6; + private Message message1, message2, message3, message4, message5, message6; @Before public void setUp() throws Exception { @@ -50,22 +53,42 @@ public void setUp() throws Exception { message4 = new Message("test@jabber.com", body4); message4.addExtension(new Quote(0, 37, 5)); + + // ------- + + body5 = "Тест > форматирования текста. "; + + message5 = new Message("test@jabber.com", body5); + message5.addExtension(new Markup(10, 23, true, true, false, false, null)); + + // ------- + + body6 = ">> 😄😃😀 привет"; + + message6 = new Message("test@jabber.com", body6); + message6.addExtension(new Markup(13, 18, true, false, false, false, null)); } @Test public void modifyBodyWithReferences1() { - assertEquals("Тест форматирования текстаИспользование нескольких стилей.", - ReferencesManager.modifyBodyWithReferences(message3, body3)); + Pair result = ReferencesManager.modifyBodyWithReferences(message1, body1); + assertEquals("два", result.first); + assertNull(result.second); } @Test public void modifyBodyWithReferences2() { - assertEquals("два", ReferencesManager.modifyBodyWithReferences(message1, body1)); + Pair result = ReferencesManager.modifyBodyWithReferences(message2, body2); + assertEquals("hello", result.first); + assertNull(result.second); } @Test public void modifyBodyWithReferences3() { - assertEquals("hello", ReferencesManager.modifyBodyWithReferences(message2, body2)); + Pair result = ReferencesManager.modifyBodyWithReferences(message3, body3); + assertEquals("Тест форматирования текста. Использование нескольких стилей.", result.first); + assertEquals("Тест форматирования текста. " + + "Использование нескольких стилей.", result.second); } @Test @@ -73,6 +96,22 @@ public void modifyBodyWithReferences4() { String expected = "This is a quote\n" + "of two lines\n" + "Hello world!"; - assertEquals(expected, ReferencesManager.modifyBodyWithReferences(message4, body4)); + Pair result = ReferencesManager.modifyBodyWithReferences(message4, body4); + assertEquals(expected, result.first); + assertNull(result.second); + } + + @Test + public void modifyBodyWithReferences5() { + Pair result = ReferencesManager.modifyBodyWithReferences(message5, body5); + assertEquals("Тест > форматирования текста. ", result.first); + assertEquals("Тест > форматирования текста. <b>", result.second); + } + + @Test + public void modifyBodyWithReferences6() { + Pair result = ReferencesManager.modifyBodyWithReferences(message6, body6); + assertEquals(">> 😄😃😀 привет", result.first); + assertEquals(">> 😄😃😀 привет", result.second); } } \ No newline at end of file From a52c7b09d463263267bcce73211f8789909580ce Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 13 Jun 2019 18:56:26 +0500 Subject: [PATCH 155/237] Up version to 622 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 181bbbf1c3..4cbd8fbe74 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 621 - versionName '2.6.4(621)' + versionCode 622 + versionName '2.6.4(622)' } lintOptions { From 7baa5618957bc87b80a51c735450a40ce84aed7e Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 14 Jun 2019 15:08:50 +0500 Subject: [PATCH 156/237] Fixed guava dependency --- xabber/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/xabber/build.gradle b/xabber/build.gradle index 4cbd8fbe74..407941c3b1 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -195,4 +195,5 @@ apply plugin: 'com.google.gms.google-services' configurations { all*.exclude group: 'xpp3', module: 'xpp3' + all*.exclude group: 'com.google.guava', module:'guava-jdk5' } From 487695154238bdc0a5c2b70e693b13366df7623b Mon Sep 17 00:00:00 2001 From: Valeriy Miller Date: Mon, 17 Jun 2019 18:58:14 +0500 Subject: [PATCH 157/237] Added gradle.properties to git --- gradle.properties | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 gradle.properties diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000000..6f7b22ee93 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,4 @@ +android.enableJetifier=false +android.useAndroidX=false +android.enableR8=false +android.enableUnitTestBinaryResources=false From 0a3b75614993359b7ffe60a034c96da9eb33702c Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 17 Jun 2019 14:27:08 +0500 Subject: [PATCH 158/237] Changes in AvatarManager --- .../xabber/android/data/ActivityManager.java | 1 - .../data/extension/avatar/AvatarManager.java | 203 +++++++++--------- .../data/extension/muc/RoomContact.java | 5 - .../android/data/roster/AbstractContact.java | 7 - .../ui/contactlist/viewobjects/ContactVO.java | 2 +- .../ui/adapter/BlockedListAdapter.java | 2 +- .../ui/adapter/chat/IncomingMessageVH.java | 4 +- 7 files changed, 101 insertions(+), 123 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/ActivityManager.java b/xabber/src/main/java/com/xabber/android/data/ActivityManager.java index a61b40c33d..42ba4f7c89 100644 --- a/xabber/src/main/java/com/xabber/android/data/ActivityManager.java +++ b/xabber/src/main/java/com/xabber/android/data/ActivityManager.java @@ -214,7 +214,6 @@ public void onResume(final Activity activity) { } AccountManager.getInstance().onPreInitialize(); RosterManager.getInstance().onPreInitialize(); - AvatarManager.getInstance().onPreInitialize(); Application.getInstance().runInBackground(new Runnable() { @Override public void run() { diff --git a/xabber/src/main/java/com/xabber/android/data/extension/avatar/AvatarManager.java b/xabber/src/main/java/com/xabber/android/data/extension/avatar/AvatarManager.java index 66acd99867..6357be85af 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/avatar/AvatarManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/avatar/AvatarManager.java @@ -35,6 +35,7 @@ import com.amulyakhare.textdrawable.util.ColorGenerator; import com.xabber.android.R; import com.xabber.android.data.Application; +import com.xabber.android.data.OnLoadListener; import com.xabber.android.data.OnLowMemoryListener; import com.xabber.android.data.SettingsManager; import com.xabber.android.data.account.AccountItem; @@ -79,7 +80,7 @@ * * @author alexander.ivanov */ -public class AvatarManager implements OnLowMemoryListener, OnPacketListener { +public class AvatarManager implements OnLoadListener, OnLowMemoryListener, OnPacketListener { /** * Maximum image width / height to be loaded. @@ -107,14 +108,7 @@ public class AvatarManager implements OnLowMemoryListener, OnPacketListener { * Map with drawable used in contact list only for specified uses. */ private final Map contactListDrawables; - /** - * Users' default avatar set. - */ - private final BaseAvatarSet userAvatarSet; - /** - * Rooms' default avatar set. - */ - private final BaseAvatarSet roomAvatarSet; + private final Map contactListDefaultDrawables; public static AvatarManager getInstance() { if (instance == null) { @@ -126,12 +120,11 @@ public static AvatarManager getInstance() { private AvatarManager() { this.application = Application.getInstance(); - userAvatarSet = new BaseAvatarSet(application, R.array.default_avatars_icons, R.array.default_avatars_colors); - roomAvatarSet = new BaseAvatarSet(application, R.array.muc_avatars, R.array.default_avatars_colors); hashes = new HashMap<>(); bitmaps = new HashMap<>(); contactListDrawables = new HashMap<>(); + contactListDefaultDrawables = new HashMap<>(); } /** @@ -206,7 +199,8 @@ public static Bitmap getCircleBitmap(Bitmap bitmap) { return output; } - public void onPreInitialize() { + @Override + public void onLoad() { final Map hashes = new HashMap<>(); final Map bitmaps = new HashMap<>(); Cursor cursor = AvatarTable.getInstance().list(); @@ -242,7 +236,6 @@ public void run() { private void onLoaded(Map hashes, Map bitmaps) { this.hashes.putAll(hashes); this.bitmaps.putAll(bitmaps); - this.contactListDrawables.clear(); for (OnContactChangedListener onContactChangedListener : Application .getInstance().getUIListeners(OnContactChangedListener.class)) { onContactChangedListener.onContactsChanged(Collections.emptyList()); @@ -258,6 +251,7 @@ private void onLoaded(Map hashes, Map bitmaps) { private void setHash(final Jid jid, final String hash) { hashes.put(jid, hash == null ? EMPTY_HASH : hash); contactListDrawables.remove(jid); + contactListDefaultDrawables.remove(jid); application.runInBackground(new Runnable() { @Override public void run() { @@ -314,8 +308,7 @@ public void run() { @Override public void onLowMemory() { contactListDrawables.clear(); - userAvatarSet.onLowMemory(); - roomAvatarSet.onLowMemory(); + contactListDefaultDrawables.clear(); } /** @@ -358,46 +351,102 @@ public Drawable getDefaultAccountAvatarForSync(AccountJid account, int color) { return generateDefaultAvatar(account.getFullJid().asBareJid().toString(), name, color); } - /** - * Gets avatar for regular user. - * - * @param user - * @return - */ - public Drawable getUserAvatar(UserJid user, String name) { + /** Gets and caches drawable with avatar for regular user. + * Or generate and caches text-based avatar. */ + public Drawable getUserAvatarForContactList(UserJid user, String name) { + Drawable drawable = contactListDrawables.get(user.getJid()); + if (drawable == null) { + drawable = getUserAvatar(user); + if (drawable != null) { + contactListDrawables.put(user.getJid(), drawable); + contactListDefaultDrawables.remove(user.getJid()); + return drawable; + } else { + return getDefaultAvatar(user, name); + } + } + return drawable; + } + + /** Gets and caches drawable with room's avatar. + * Or generate and caches text-based avatar. */ + public Drawable getRoomAvatarForContactList(UserJid user) { + Drawable drawable = contactListDrawables.get(user.getJid()); + if (drawable == null) { + drawable = getRoomAvatar(user); + if (drawable != null) { + contactListDrawables.put(user.getJid(), drawable); + contactListDefaultDrawables.remove(user.getJid()); + return drawable; + } else { + return getDefaultRoomAvatar(user); + } + } + return drawable; + } + + /** Gets bitmap with avatar for regular user. */ + public Bitmap getUserBitmap(UserJid user, String name) { Bitmap value = getBitmap(user.getJid()); if (value != null) { - return new BitmapDrawable(application.getResources(), value); + return getCircleBitmap(value); } else { - return generateDefaultAvatar(user.getBareJid().toString(), name); + return drawableToBitmap(generateDefaultAvatar(user.getBareJid().toString(), name)); } } - private Drawable getDefaultAvatarDrawable(BaseAvatarSet.DefaultAvatar defaultAvatar) { - Drawable[] layers = new Drawable[2]; - layers[0] = new ColorDrawable(defaultAvatar.getBackgroundColor()); - layers[1] = application.getResources().getDrawable(defaultAvatar.getIconResource()); - + /** Gets bitmap with avatar for room. */ + public Bitmap getRoomBitmap(UserJid user) { + return drawableToBitmap(getRoomAvatar(user)); + } - return new LayerDrawable(layers); + /** Generate text-based avatar for regular user. */ + public Drawable generateDefaultAvatar(@NonNull String jid, @NonNull String name) { + return generateDefaultAvatar(jid, name, ColorGenerator.MATERIAL.getColor(jid)); } - public Drawable generateDefaultRoomAvatar(@NonNull String jid) { - Drawable[] layers = new Drawable[2]; - layers[0] = new ColorDrawable(ColorGenerator.MATERIAL.getColor(jid)); - layers[1] = application.getResources().getDrawable(R.drawable.ic_conference_white); + /** PRIVATE */ - LayerDrawable layerDrawable = new LayerDrawable(layers); - layerDrawable.setLayerInset(1, 25, 25, 25, 30); + /** Gets avatar drawable for regular user from bitmap. */ + private Drawable getUserAvatar(UserJid user) { + Bitmap value = getBitmap(user.getJid()); + if (value != null) { + return new BitmapDrawable(application.getResources(), value); + } + return null; + } - return layerDrawable; + /** Gets avatar drawable for room from bitmap. */ + private Drawable getRoomAvatar(UserJid user) { + Bitmap value = getBitmap(user.getJid()); + if (value != null) { + return new BitmapDrawable(application.getResources(), value); + } + return null; } - public Drawable generateDefaultAvatar(@NonNull String jid, @NonNull String name) { - return generateDefaultAvatar(jid, name, ColorGenerator.MATERIAL.getColor(jid)); + /** Gets and caches text-base avatar for regular user from cached drawables. */ + private Drawable getDefaultAvatar(UserJid user, String name) { + Drawable drawable = contactListDefaultDrawables.get(user.getJid()); + if (drawable == null) { + drawable = generateDefaultAvatar(user.getBareJid().toString(), name); + contactListDefaultDrawables.put(user.getJid(), drawable); + } + return drawable; + } + + /** Gets and caches text-base avatar for room from cached drawables. */ + private Drawable getDefaultRoomAvatar(UserJid user) { + Drawable drawable = contactListDefaultDrawables.get(user.getJid()); + if (drawable == null) { + drawable = generateDefaultRoomAvatar(user.getBareJid().toString()); + contactListDefaultDrawables.put(user.getJid(), drawable); + } + return drawable; } - public Drawable generateDefaultAvatar(@NonNull String jid, @NonNull String name, int color) { + /** Generate text-based avatar for regular user. */ + private Drawable generateDefaultAvatar(@NonNull String jid, @NonNull String name, int color) { String[] words = name.split("\\s+"); String chars = ""; @@ -412,74 +461,16 @@ public Drawable generateDefaultAvatar(@NonNull String jid, @NonNull String name, .buildRound(chars.toUpperCase(), color); } - /** - * Gets bitmap with avatar for regular user. - * - * @param user - * @return - */ - public Bitmap getUserBitmap(UserJid user, String name) { - Bitmap value = getBitmap(user.getJid()); - if (value != null) { - return getCircleBitmap(value); - } else { - return drawableToBitmap(generateDefaultAvatar(user.getBareJid().toString(), name)); - } - } - - /** - * Gets and caches drawable with avatar for regular user. - * - * @param user - * @return - */ - public Drawable getUserAvatarForContactList(UserJid user, String name) { - Drawable drawable = contactListDrawables.get(user.getJid()); - if (drawable == null) { - drawable = getUserAvatar(user, name); - contactListDrawables.put(user.getJid(), drawable); - } - return drawable; - } - - /** - * Gets avatar for the room. - * - * @param user - * @return - */ - public Drawable getRoomAvatar(UserJid user) { - Bitmap value = getBitmap(user.getJid()); - if (value != null) { - return new BitmapDrawable(application.getResources(), value); - } else { - return generateDefaultRoomAvatar(user.getBareJid().toString()); - } - } + /** Generate text-based avatar for room. */ + private Drawable generateDefaultRoomAvatar(@NonNull String jid) { + Drawable[] layers = new Drawable[2]; + layers[0] = new ColorDrawable(ColorGenerator.MATERIAL.getColor(jid)); + layers[1] = application.getResources().getDrawable(R.drawable.ic_conference_white); - /** - * Gets bitmap for the room. - * - * @param user - * @return - */ - public Bitmap getRoomBitmap(UserJid user) { - return drawableToBitmap(getRoomAvatar(user)); - } + LayerDrawable layerDrawable = new LayerDrawable(layers); + layerDrawable.setLayerInset(1, 25, 25, 25, 30); - /** - * Gets and caches drawable with room's avatar. - * - * @param user - * @return - */ - public Drawable getRoomAvatarForContactList(UserJid user) { - Drawable drawable = contactListDrawables.get(user.getJid()); - if (drawable == null) { - drawable = getRoomAvatar(user); - contactListDrawables.put(user.getJid(), drawable); - } - return drawable; + return layerDrawable; } /** diff --git a/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomContact.java b/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomContact.java index 303ff95194..443d9e4eef 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomContact.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomContact.java @@ -48,11 +48,6 @@ public StatusMode getStatusMode() { @Override public Drawable getAvatar() { - return AvatarManager.getInstance().getRoomAvatar(user); - } - - @Override - public Drawable getAvatarForContactList() { return AvatarManager.getInstance().getRoomAvatarForContactList(user); } diff --git a/xabber/src/main/java/com/xabber/android/data/roster/AbstractContact.java b/xabber/src/main/java/com/xabber/android/data/roster/AbstractContact.java index 096d105585..1edacd8c8d 100644 --- a/xabber/src/main/java/com/xabber/android/data/roster/AbstractContact.java +++ b/xabber/src/main/java/com/xabber/android/data/roster/AbstractContact.java @@ -116,13 +116,6 @@ public Collection getGroups() { } public Drawable getAvatar() { - return AvatarManager.getInstance().getUserAvatar(user, getName()); - } - - /** - * @return Cached avatar's drawable for contact list. - */ - public Drawable getAvatarForContactList() { return AvatarManager.getInstance().getUserAvatarForContactList(user, getName()); } diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java index b02cc6d787..9a3bd4deb6 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java +++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java @@ -140,7 +140,7 @@ public static ContactVO convert(AbstractContact contact, ContactClickListener li .getAccountMainColor(contact.getAccount()); accountColorIndicatorBack = ColorManager.getInstance().getAccountPainter() .getAccountIndicatorBackColor(contact.getAccount()); - avatar = contact.getAvatarForContactList(); + avatar = contact.getAvatar(); String name = contact.getName(); diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/BlockedListAdapter.java b/xabber/src/main/java/com/xabber/android/ui/adapter/BlockedListAdapter.java index 2559fc9668..a4fe4c1695 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/BlockedListAdapter.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/BlockedListAdapter.java @@ -57,7 +57,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { final AbstractContact rosterContact = RosterManager.getInstance().getBestContact(account, contact); if (viewHolder.avatar != null) { - viewHolder.avatar.setImageDrawable(rosterContact.getAvatarForContactList()); + viewHolder.avatar.setImageDrawable(rosterContact.getAvatar()); } viewHolder.name.setText(rosterContact.getName()); diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/IncomingMessageVH.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/IncomingMessageVH.java index 52411d44e8..c4018e5f16 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/IncomingMessageVH.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/IncomingMessageVH.java @@ -150,7 +150,7 @@ private void setUpAvatar(MessageItem messageItem, boolean isMUC, String userName avatar.setVisibility(View.VISIBLE); avatarBackground.setVisibility(View.VISIBLE); - if (!isMUC) avatar.setImageDrawable(AvatarManager.getInstance().getUserAvatar(user, userName)); + if (!isMUC) avatar.setImageDrawable(AvatarManager.getInstance().getUserAvatarForContactList(user, userName)); else { if ((MUCManager.getInstance() .getNickname(account, user.getJid().asEntityBareJidIfPossible()) @@ -158,7 +158,7 @@ private void setUpAvatar(MessageItem messageItem, boolean isMUC, String userName avatar.setImageDrawable(AvatarManager.getInstance().getAccountAvatar(account)); } else { if (resource.equals(Resourcepart.EMPTY)) { - avatar.setImageDrawable(AvatarManager.getInstance().getRoomAvatar(user)); + avatar.setImageDrawable(AvatarManager.getInstance().getRoomAvatarForContactList(user)); } else { String nick = resource.toString(); From 7f3ac6613b713203d91f808fa212f9e7f706c8ed Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 17 Jun 2019 15:06:38 +0500 Subject: [PATCH 159/237] Fixed references parsing --- .../references/ReferencesProvider.java | 34 ++++++++++++------- .../references/ReferencesProviderTest.java | 14 +++++++- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java index 432f10894c..b736695560 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java @@ -1,5 +1,7 @@ package com.xabber.android.data.extension.references; +import com.xabber.android.data.log.LogManager; + import org.jivesoftware.smack.provider.ExtensionElementProvider; import org.jivesoftware.smackx.forward.packet.Forwarded; import org.jivesoftware.smackx.forward.provider.ForwardedProvider; @@ -69,19 +71,25 @@ public ReferenceElement parse(XmlPullParser parser, int initialDepth) throws Exc if (endS != null && !endS.isEmpty()) end = Integer.valueOf(endS); if (delS != null && !delS.isEmpty()) del = Integer.valueOf(delS); - switch (ReferenceElement.Type.valueOf(type)) { - case forward: - return new Forward(begin, end, forwardedMessages); - case data: - return new Data(begin, end, mediaElements); - case markup: - return new Markup(begin, end, bold, italic, underline, strike, url); - case quote: - return new Quote(begin, end, del); - case mention: - return new Mention(begin, end, uri); - default: - return null; + try { + ReferenceElement.Type refType = ReferenceElement.Type.valueOf(type); + switch (refType) { + case forward: + return new Forward(begin, end, forwardedMessages); + case data: + return new Data(begin, end, mediaElements); + case markup: + return new Markup(begin, end, bold, italic, underline, strike, url); + case quote: + return new Quote(begin, end, del); + case mention: + return new Mention(begin, end, uri); + default: + return null; + } + } catch (Exception e) { + LogManager.d(ReferencesProvider.class, e.toString()); + return null; } } diff --git a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesProviderTest.java b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesProviderTest.java index 89bde4f7e8..1ab5544822 100644 --- a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesProviderTest.java +++ b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesProviderTest.java @@ -26,7 +26,7 @@ public class ReferencesProviderTest { private ReferencesProvider provider; private XmlPullParserFactory factory; private String stringForward, stringMedia, stringMarkup1, - stringMarkup2, stringMention, stringQuote; + stringMarkup2, stringMention, stringQuote, stringNull, stringUnknown; @Before public void setUp() throws Exception { @@ -63,6 +63,9 @@ public void setUp() throws Exception { stringQuote = ""; + stringUnknown = ""; + stringNull = ""; + } @Test @@ -157,6 +160,15 @@ public void parse6() { assertEquals(5, element.getDel()); } + @Test + public void parse7() { + ReferenceElement element = parseString(stringUnknown); + assertNull(element); + + ReferenceElement element1 = parseString(stringNull); + assertNull(element1); + } + private ReferenceElement parseString(String source) { ReferenceElement result = null; try { From d35f9cc81f08102413d1762e1933c5cb66754eb9 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 17 Jun 2019 18:06:18 +0500 Subject: [PATCH 160/237] Fixed exception with avatars --- .../com/xabber/android/data/extension/avatar/AvatarStorage.java | 1 + 1 file changed, 1 insertion(+) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/avatar/AvatarStorage.java b/xabber/src/main/java/com/xabber/android/data/extension/avatar/AvatarStorage.java index c15f1672bc..a29aae01a9 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/avatar/AvatarStorage.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/avatar/AvatarStorage.java @@ -62,6 +62,7 @@ byte[] read(String hash) { byte[] value; FileInputStream inputStream; try { + if (!getFile(hash).exists()) return null; inputStream = new FileInputStream(getFile(hash)); value = new byte[inputStream.available()]; inputStream.read(value); From 3d3d2dcc29a7b3c20d05a7d30173e20c9a585268 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 17 Jun 2019 18:16:19 +0500 Subject: [PATCH 161/237] Fixed bug in ReferencesManager --- .../android/data/extension/references/ReferencesManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index 7031830be2..4710b7f38c 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -159,6 +159,7 @@ private static String[] modifyBodyWithReferences(String[] chars, ReferenceElemen if (begin < 0) begin = 0; int end = reference.getEnd(); if (end >= chars.length) end = chars.length - 1; + if (begin > end) return chars; switch (reference.getType()) { case data: From e1af73c8900b9e7ca5f083d3b7fb2668c63a1bc0 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 17 Jun 2019 18:54:55 +0500 Subject: [PATCH 162/237] Up version to 623 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 407941c3b1..81aa633c8e 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 622 - versionName '2.6.4(622)' + versionCode 623 + versionName '2.6.4(623)' } lintOptions { From 339a15395f1b5e556a18ba101001647f3156f660 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 18 Jun 2019 11:54:59 +0500 Subject: [PATCH 163/237] Changes in mam synchronization at start --- .../android/data/extension/mam/NextMamManager.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index b91b68d784..3498fb5644 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -103,7 +103,7 @@ public void onAccountConnected(AccountItem accountItem) { Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); accountItem.setStartHistoryTimestamp(getLastMessageTimestamp(accountItem, realm)); if (accountItem.getStartHistoryTimestamp() == 0) { - initializeStartTimestamp(accountItem); + initializeStartTimestamp(realm, accountItem); loadLastMessagesAsync(accountItem); } else { if (isNeedMigration(accountItem, realm)) { @@ -224,7 +224,8 @@ public void onStanza(ConnectionItem connection, Stanza packet) { (MamElements.MamResultExtension) packetExtension; String resultID = resultExtension.getQueryId(); if (waitingRequests.contains(resultID)) { - parseAndSaveMessageFromMamResult(connection.getAccount(), resultExtension); + Realm realm = MessageDatabaseManager.getInstance().getRealmUiThread(); + parseAndSaveMessageFromMamResult(realm, connection.getAccount(), resultExtension.getForwarded()); waitingRequests.remove(resultID); } } @@ -414,13 +415,14 @@ private void loadMissedMessages(Realm realm, AccountItem accountItem, AbstractCh /** Request most recent message from all history and save it timestamp to startHistoryTimestamp * If message is null save current time to startHistoryTimestamp */ - private void initializeStartTimestamp(@Nonnull AccountItem accountItem) { + private void initializeStartTimestamp(Realm realm, @Nonnull AccountItem accountItem) { long startHistoryTimestamp = System.currentTimeMillis(); MamManager.MamQueryResult queryResult = requestLastMessage(accountItem, null); if (queryResult != null && !queryResult.forwardedMessages.isEmpty()) { Forwarded forwarded = queryResult.forwardedMessages.get(0); startHistoryTimestamp = forwarded.getDelayInformation().getStamp().getTime(); + parseAndSaveMessageFromMamResult(realm, accountItem.getAccount(), forwarded); } accountItem.setStartHistoryTimestamp(startHistoryTimestamp); } @@ -568,8 +570,7 @@ MamManager.MamPrefsResult execute(MamManager manager) throws Exception { /** PARSING */ - private void parseAndSaveMessageFromMamResult(AccountJid account, MamElements.MamResultExtension resultExtension) { - Forwarded forwarded = resultExtension.getForwarded(); + private void parseAndSaveMessageFromMamResult(Realm realm, AccountJid account,Forwarded forwarded) { Stanza stanza = forwarded.getForwardedStanza(); AccountItem accountItem = AccountManager.getInstance().getAccount(account); Jid user = stanza.getFrom().asBareJid(); @@ -580,7 +581,6 @@ private void parseAndSaveMessageFromMamResult(AccountJid account, MamElements.Ma AbstractChat chat = MessageManager.getInstance().getOrCreateChat(account, UserJid.from(user)); MessageItem messageItem = parseMessage(accountItem, account, chat.getUser(), forwarded, null); if (messageItem != null) { - Realm realm = MessageDatabaseManager.getInstance().getRealmUiThread(); saveOrUpdateMessages(realm, Collections.singletonList(messageItem), true); updateLastMessageId(chat, realm); } From 724f55fa0cd3cd701f2e4015b1957c83a1b6f002 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 18 Jun 2019 15:04:35 +0500 Subject: [PATCH 164/237] Fixed NPE --- .../xabber/android/ui/fragment/ContactAddFragment.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/ContactAddFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/ContactAddFragment.java index 2f8a92bb52..eead9ce1dc 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/ContactAddFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/ContactAddFragment.java @@ -147,7 +147,8 @@ public void onItemSelected(AdapterView parent, View view, int position, long onNothingSelected(parent); setAccount(null); } else { - listenerActivity.onAccountSelected(selectedAccount); + if (listenerActivity != null) + listenerActivity.onAccountSelected(selectedAccount); if (!selectedAccount.equals(getAccount())) { setAccount(selectedAccount); @@ -201,7 +202,8 @@ public void addContact() { return; } - listenerActivity.showProgress(true); + if (listenerActivity != null) + listenerActivity.showProgress(true); final String name = nameView.getText().toString(); final ArrayList groups = getSelected(); @@ -237,7 +239,8 @@ private void stopAddContactProcess(final boolean success) { Application.getInstance().runOnUiThread(new Runnable() { @Override public void run() { - listenerActivity.showProgress(false); + if (listenerActivity != null) + listenerActivity.showProgress(false); if (success) getActivity().finish(); } }); From dcb799401dd998ab0b74b6b8542e51b857d00681 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 18 Jun 2019 15:28:31 +0500 Subject: [PATCH 165/237] Changed google icons --- .../src/main/res/drawable/ic_google_plus.xml | 49 ++++++++++--------- .../res/drawable/ic_google_plus_disabled.xml | 45 ++++++++--------- 2 files changed, 50 insertions(+), 44 deletions(-) diff --git a/xabber/src/main/res/drawable/ic_google_plus.xml b/xabber/src/main/res/drawable/ic_google_plus.xml index 137d79d439..db35fc3ef8 100644 --- a/xabber/src/main/res/drawable/ic_google_plus.xml +++ b/xabber/src/main/res/drawable/ic_google_plus.xml @@ -1,22 +1,27 @@ - - - - - - - \ No newline at end of file + + + + + + + + diff --git a/xabber/src/main/res/drawable/ic_google_plus_disabled.xml b/xabber/src/main/res/drawable/ic_google_plus_disabled.xml index cfed3eb9b4..bdf9656f5f 100644 --- a/xabber/src/main/res/drawable/ic_google_plus_disabled.xml +++ b/xabber/src/main/res/drawable/ic_google_plus_disabled.xml @@ -1,22 +1,23 @@ - - - - - - - \ No newline at end of file + + + + + + + From 143f8abbbd6f71cd192bb0bd73366b89ffc50132 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 18 Jun 2019 15:30:45 +0500 Subject: [PATCH 166/237] Changed google provider name --- .../main/java/com/xabber/android/data/xaccount/AuthManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/data/xaccount/AuthManager.java b/xabber/src/main/java/com/xabber/android/data/xaccount/AuthManager.java index 04541808f9..321b7181c0 100644 --- a/xabber/src/main/java/com/xabber/android/data/xaccount/AuthManager.java +++ b/xabber/src/main/java/com/xabber/android/data/xaccount/AuthManager.java @@ -348,7 +348,7 @@ public static String getProviderName(String provider) { case AuthManager.PROVIDER_FACEBOOK: return "Facebook"; default: - return "Google+"; + return "Google"; } } From 26b85d8ef27e7dedfc2a91454f1d5d860a395797 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 18 Jun 2019 18:35:42 +0500 Subject: [PATCH 167/237] Enabled notification sound in chat screen --- .../android/ui/fragment/ChatFragment.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java index c91038dc78..038d6cda9f 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java @@ -9,6 +9,7 @@ import android.media.AudioAttributes; import android.media.AudioManager; import android.media.MediaPlayer; +import android.net.Uri; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.FragmentManager; @@ -658,7 +659,7 @@ public void onEvent(MessageUpdateEvent event) { public void onEvent(NewIncomingMessageEvent event) { if (event.getAccount().equals(account) && event.getUser().equals(user)) { listener.playIncomingAnimation(); - //playIncomingSound(); + playIncomingSound(); } } @@ -1189,16 +1190,27 @@ public void onAccountsChanged(Collection accounts) { } public void playIncomingSound() { - if (SettingsManager.eventsInChatSounds()) { + AbstractChat chat = getChat(); + boolean event = false; + Uri soundUri = null; + if (chat instanceof RoomChat) { + event = SettingsManager.eventsOnMuc(); + soundUri = SettingsManager.eventsSoundMuc(); + } else { + event = SettingsManager.eventsOnChat(); + soundUri = SettingsManager.eventsSound(); + } + + if (event) { final MediaPlayer mp; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { AudioAttributes attr = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) .setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT).build(); - mp = MediaPlayer.create(getActivity(), SettingsManager.eventsSound(), + mp = MediaPlayer.create(getActivity(), soundUri, null, attr, AudioManager.AUDIO_SESSION_ID_GENERATE); } else { - mp = MediaPlayer.create(getActivity(), SettingsManager.eventsSound()); + mp = MediaPlayer.create(getActivity(), soundUri); mp.setAudioStreamType(AudioManager.STREAM_NOTIFICATION); } From a2510cb76975ad3f0e3f0373dfefcdfd71c52e8e Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 18 Jun 2019 18:57:54 +0500 Subject: [PATCH 168/237] Changed priority of message statuses --- .../presentation/ui/contactlist/viewobjects/ContactVO.java | 6 +++--- .../xabber/android/ui/adapter/chat/OutgoingMessageVH.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java index 9a3bd4deb6..3397c563fc 100644 --- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java +++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java @@ -191,15 +191,15 @@ public static ContactVO convert(AbstractContact contact, ContactClickListener li // message status if (isOutgoing) { - if (lastMessage.isError()) { - messageStatus = 4; - } else if (!MessageItem.isUploadFileMessage(lastMessage) && !lastMessage.isSent() + if (!MessageItem.isUploadFileMessage(lastMessage) && !lastMessage.isSent() && System.currentTimeMillis() - lastMessage.getTimestamp() > 1000) { messageStatus = 5; } else if (lastMessage.isDisplayed() || lastMessage.isReceivedFromMessageArchive()) { messageStatus = 1; } else if (lastMessage.isDelivered() || lastMessage.isForwarded()) { messageStatus = 2; + } else if (lastMessage.isError()) { + messageStatus = 4; } else if (lastMessage.isAcknowledged()) { messageStatus = 3; } diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/OutgoingMessageVH.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/OutgoingMessageVH.java index cbc3976ebf..d0d5f6844d 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/OutgoingMessageVH.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/OutgoingMessageVH.java @@ -107,14 +107,14 @@ private void setStatusIcon(MessageItem messageItem) { int messageIcon = R.drawable.ic_message_not_sent_14dp; - if (messageItem.isError()) { - messageIcon = R.drawable.ic_message_has_error_14dp; - } else if (!isFileUploadInProgress && !messageItem.isSent()) { + if (!isFileUploadInProgress && !messageItem.isSent()) { messageIcon = R.drawable.ic_message_not_sent_14dp; } else if (messageItem.isDisplayed() || messageItem.isReceivedFromMessageArchive()) { messageIcon = R.drawable.ic_message_displayed; } else if (messageItem.isDelivered() || messageItem.isForwarded()) { messageIcon = R.drawable.ic_message_delivered_14dp; + } else if (messageItem.isError()) { + messageIcon = R.drawable.ic_message_has_error_14dp; } else if (messageItem.isAcknowledged()) { messageIcon = R.drawable.ic_message_acknowledged_14dp; } From 0fb82be3416510c6c359177601e1c43e8f2b85fc Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 18 Jun 2019 19:05:34 +0500 Subject: [PATCH 169/237] Added scroll down on send message --- .../main/java/com/xabber/android/ui/fragment/ChatFragment.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java index 038d6cda9f..25e07fab89 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java @@ -762,6 +762,7 @@ public void saveInputState() { private void sendMessage() { String text = inputView.getText().toString().trim(); clearInputText(); + scrollDown(); if (forwardIds != null && !forwardIds.isEmpty()) { sendForwardMessage(forwardIds, text); @@ -806,6 +807,7 @@ private void onScrollDownClick() { } private void scrollDown() { + realmRecyclerView.scrollToPosition(chatMessageAdapter.getItemCount() - 1); } From d58bd9130f177fc5f85a4859dbbe9dc44b3dafa3 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 18 Jun 2019 19:06:41 +0500 Subject: [PATCH 170/237] Up version to 624 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 81aa633c8e..b27f08cdb2 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 623 - versionName '2.6.4(623)' + versionCode 624 + versionName '2.6.4(624)' } lintOptions { From 71582e3e4f0cca094d0a4ce30f9648bdb61eacb2 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 19 Jun 2019 14:15:39 +0500 Subject: [PATCH 171/237] Fixed copy message to clipboard with attachments --- .../com/xabber/android/data/message/ClipManager.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/xabber/src/main/java/com/xabber/android/data/message/ClipManager.java b/xabber/src/main/java/com/xabber/android/data/message/ClipManager.java index 1533c46801..0b350bbcd9 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/ClipManager.java +++ b/xabber/src/main/java/com/xabber/android/data/message/ClipManager.java @@ -5,6 +5,7 @@ import com.xabber.android.data.Application; import com.xabber.android.data.database.MessageDatabaseManager; +import com.xabber.android.data.database.messagerealm.Attachment; import com.xabber.android.data.database.messagerealm.MessageItem; import com.xabber.android.data.roster.RosterManager; import com.xabber.android.utils.StringUtils; @@ -93,6 +94,14 @@ private static String messageToText(Realm realm, MessageItem message, stringBuilder.append("\n"); } + if (message.haveAttachments()) { + for (Attachment attachment : message.getAttachments()) { + stringBuilder.append(space); + stringBuilder.append(attachment.getFileUrl()); + stringBuilder.append("\n"); + } + } + if (!message.getText().isEmpty()) { stringBuilder.append(space); stringBuilder.append(message.getText()); From d6318e31cd9f95ca3cb06b1b2e0ae84c17881b82 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 19 Jun 2019 17:44:45 +0500 Subject: [PATCH 172/237] Added loading missed last messages from archive --- .../android/data/database/RealmManager.java | 9 +++- .../data/database/realm/ChatDataRealm.java | 9 ++++ .../data/extension/mam/NextMamManager.java | 44 ++++++++++++++++--- .../android/data/message/AbstractChat.java | 10 +++++ .../xabber/android/data/message/ChatData.java | 9 +++- .../android/data/message/MessageManager.java | 2 + .../data/message/chat/ChatManager.java | 4 +- 7 files changed, 79 insertions(+), 8 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java b/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java index 0e190621bb..888ed63850 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java +++ b/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java @@ -36,7 +36,7 @@ public class RealmManager { private static final String REALM_DATABASE_NAME = "realm_database.realm"; - private static final int REALM_DATABASE_VERSION = 25; + private static final int REALM_DATABASE_VERSION = 26; private static final String LOG_TAG = RealmManager.class.getSimpleName(); private final RealmConfiguration realmConfiguration; @@ -344,6 +344,13 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { oldVersion++; } + + if (oldVersion == 25) { + schema.get(ChatDataRealm.class.getSimpleName()) + .addField("historyRequestedAtStart", boolean.class); + + oldVersion++; + } } }) .modules(new RealmDatabaseModule()) diff --git a/xabber/src/main/java/com/xabber/android/data/database/realm/ChatDataRealm.java b/xabber/src/main/java/com/xabber/android/data/database/realm/ChatDataRealm.java index a0a7c0e116..6c73e6e09f 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/realm/ChatDataRealm.java +++ b/xabber/src/main/java/com/xabber/android/data/database/realm/ChatDataRealm.java @@ -23,6 +23,7 @@ public class ChatDataRealm extends RealmObject { private boolean archived; private NotificationStateRealm notificationState; private int lastPosition; + private boolean historyRequestedAtStart; public ChatDataRealm(String accountJid, String userJid) { this.id = accountJid + "-" + userJid; @@ -89,4 +90,12 @@ public int getLastPosition() { public void setLastPosition(int lastPosition) { this.lastPosition = lastPosition; } + + public boolean isHistoryRequestedAtStart() { + return historyRequestedAtStart; + } + + public void setHistoryRequestedAtStart(boolean historyRequestedAtStart) { + this.historyRequestedAtStart = historyRequestedAtStart; + } } diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index 3498fb5644..72fd5f0270 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -45,6 +45,7 @@ import org.jivesoftware.smackx.forward.packet.Forwarded; import org.jivesoftware.smackx.mam.MamManager; import org.jivesoftware.smackx.mam.element.MamElements; +import org.jivesoftware.smackx.mam.element.MamFinIQ; import org.jivesoftware.smackx.mam.element.MamPrefsIQ; import org.jivesoftware.smackx.mam.element.MamQueryIQ; import org.jivesoftware.smackx.rsm.packet.RSMSet; @@ -59,11 +60,9 @@ import java.util.Comparator; import java.util.Date; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -84,7 +83,7 @@ public class NextMamManager implements OnRosterReceivedListener, OnPacketListene private Map supportedByAccount = new ConcurrentHashMap<>(); private boolean isRequested = false; private final Object lock = new Object(); - private Set waitingRequests = new HashSet<>(); + private Map waitingRequests = new HashMap<>(); public static NextMamManager getInstance() { if (instance == null) @@ -114,6 +113,8 @@ public void onAccountConnected(AccountItem accountItem) { boolean historyCompleted = loadAllNewMessages(realm, accountItem, lastArchivedId); if (!historyCompleted) loadLastMessagesAsync(accountItem); } else loadLastMessagesAsync(accountItem); + + loadLastMessagesInMissedChatsAsync(realm, accountItem); } realm.close(); } @@ -223,14 +224,29 @@ public void onStanza(ConnectionItem connection, Stanza packet) { MamElements.MamResultExtension resultExtension = (MamElements.MamResultExtension) packetExtension; String resultID = resultExtension.getQueryId(); - if (waitingRequests.contains(resultID)) { + if (waitingRequests.containsKey(resultID)) { Realm realm = MessageDatabaseManager.getInstance().getRealmUiThread(); parseAndSaveMessageFromMamResult(realm, connection.getAccount(), resultExtension.getForwarded()); + UserJid userJid = waitingRequests.get(resultID); + AbstractChat chat = MessageManager.getInstance().getChat(connection.getAccount(), userJid); + if (chat != null && !chat.isHistoryRequestedAtStart()) + chat.setHistoryRequestedAtStart(true); waitingRequests.remove(resultID); } } } } + if (packet instanceof MamFinIQ) { + MamFinIQ finIQ = (MamFinIQ) packet; + if (finIQ.isComplete() && waitingRequests.containsKey(finIQ.getQueryId())) { + UserJid userJid = waitingRequests.get(finIQ.getQueryId()); + AbstractChat chat = MessageManager.getInstance().getChat(connection.getAccount(), userJid); + if (chat != null) { + if (!chat.isHistoryRequestedAtStart()) + chat.setHistoryRequestedAtStart(true); + } + } + } } public boolean isSupported(AccountJid accountJid) { @@ -241,6 +257,24 @@ public boolean isSupported(AccountJid accountJid) { /** MAIN */ + /** For load messages that was missed because of errors or crash */ + private void loadLastMessagesInMissedChatsAsync(Realm realm, AccountItem accountItem) { + if (accountItem.getLoadHistorySettings() != LoadHistorySettings.all + || !isSupported(accountItem.getAccount())) return; + + Collection contacts = RosterManager.getInstance() + .getAccountRosterContacts(accountItem.getAccount()); + + for (RosterContact contact : contacts) { + AbstractChat chat = MessageManager.getInstance() + .getOrCreateChat(contact.getAccount(), contact.getUser()); + if (getFirstMessage(chat, realm) == null && !chat.isHistoryRequestedAtStart()) { + LogManager.d(LOG_TAG, "load missed messages in: " + contact.getUser()); + requestLastMessageAsync(accountItem, chat); + } + } + } + private void loadLastMessagesAsync(AccountItem accountItem) { if (accountItem.getLoadHistorySettings() != LoadHistorySettings.all || !isSupported(accountItem.getAccount())) return; @@ -493,7 +527,7 @@ private void requestLastMessageAsync(@Nonnull final AccountItem accountItem, @No MamManager.MamQueryResult execute(MamManager manager) throws Exception { // add request id to waiting list String queryID = UUID.randomUUID().toString(); - waitingRequests.add(queryID); + waitingRequests.put(queryID, chat.getUser()); // send request stanza RSMSet rsmSet = new RSMSet(null, "", -1, -1, null, 1, null, -1); diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index e6cb29b50d..25d8078f2a 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -120,6 +120,7 @@ public abstract class AbstractChat extends BaseEntity implements RealmChangeList private RealmResults messages; private String lastMessageId = null; private boolean historyIsFull = false; + private boolean historyRequestedAtStart = false; protected AbstractChat(@NonNull final AccountJid account, @NonNull final UserJid user, boolean isPrivateMucChat) { super(account, isPrivateMucChat ? user : user.getBareUserJid()); @@ -931,6 +932,15 @@ public void setHistoryIsFull() { this.historyIsFull = true; } + public boolean isHistoryRequestedAtStart() { + return historyRequestedAtStart; + } + + public void setHistoryRequestedAtStart(boolean needSaveToRealm) { + this.historyRequestedAtStart = true; + if (needSaveToRealm) ChatManager.getInstance().saveOrUpdateChatDataToRealm(this); + } + public static String getStanzaId(Message message) { String stanzaId = null; diff --git a/xabber/src/main/java/com/xabber/android/data/message/ChatData.java b/xabber/src/main/java/com/xabber/android/data/message/ChatData.java index de5884abad..4155c8528d 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/ChatData.java +++ b/xabber/src/main/java/com/xabber/android/data/message/ChatData.java @@ -12,15 +12,18 @@ public class ChatData { private boolean archived; private NotificationState notificationState; private int lastPosition; + private boolean historyRequestedAtStart; public ChatData(String subject, String accountJid, String userJid, - boolean archived, NotificationState notificationState, int lastPosition) { + boolean archived, NotificationState notificationState, int lastPosition, + boolean historyRequestedAtStart) { this.subject = subject; this.accountJid = accountJid; this.userJid = userJid; this.archived = archived; this.notificationState = notificationState; this.lastPosition = lastPosition; + this.historyRequestedAtStart = historyRequestedAtStart; } public String getSubject() { @@ -70,4 +73,8 @@ public int getLastPosition() { public void setLastPosition(int lastPosition) { this.lastPosition = lastPosition; } + + public boolean isHistoryRequestedAtStart() { + return historyRequestedAtStart; + } } diff --git a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java index 3303150cdd..3a6a081dd0 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java +++ b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java @@ -211,6 +211,7 @@ private RegularChat createChat(AccountJid account, UserJid user) { chat.setLastPosition(chatData.getLastPosition()); chat.setArchived(chatData.isArchived(), false); chat.setNotificationState(chatData.getNotificationState(), false); + if (chatData.isHistoryRequestedAtStart()) chat.setHistoryRequestedAtStart(false); } addChat(chat); return chat; @@ -223,6 +224,7 @@ private RegularChat createPrivateMucChat(AccountJid account, FullJid fullJid) th chat.setLastPosition(chatData.getLastPosition()); chat.setArchived(chatData.isArchived(), false); chat.setNotificationState(chatData.getNotificationState(), false); + if (chatData.isHistoryRequestedAtStart()) chat.setHistoryRequestedAtStart(false); } addChat(chat); return chat; diff --git a/xabber/src/main/java/com/xabber/android/data/message/chat/ChatManager.java b/xabber/src/main/java/com/xabber/android/data/message/chat/ChatManager.java index c7111125ca..091cc2507f 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/chat/ChatManager.java +++ b/xabber/src/main/java/com/xabber/android/data/message/chat/ChatManager.java @@ -511,6 +511,7 @@ public void execute(Realm realm) { chatRealm.setLastPosition(chat.getLastPosition()); chatRealm.setArchived(chat.isArchived()); + chatRealm.setHistoryRequestedAtStart(chat.isHistoryRequestedAtStart()); NotificationStateRealm notificationStateRealm = chatRealm.getNotificationState(); if (notificationStateRealm == null) @@ -557,7 +558,8 @@ public ChatData loadChatDataFromRealm(AbstractChat chat) { realmChat.getUserJid(), realmChat.isArchived(), notificationState, - realmChat.getLastPosition()); + realmChat.getLastPosition(), + realmChat.isHistoryRequestedAtStart()); } realm.close(); From 098852fb09e2a5b60e0208e34f690cb465f9405d Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 19 Jun 2019 18:22:33 +0500 Subject: [PATCH 173/237] 3rd page was hide in crowdfunding chat --- .../com/xabber/android/ui/adapter/ChatViewerAdapter.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/ChatViewerAdapter.java b/xabber/src/main/java/com/xabber/android/ui/adapter/ChatViewerAdapter.java index b9a88f5b23..15d25e1558 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/ChatViewerAdapter.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/ChatViewerAdapter.java @@ -61,7 +61,10 @@ public void selectChat(@NonNull AccountJid accountJid, @NonNull UserJid userJid) } private void setChat(@NonNull AccountJid accountJid, @NonNull UserJid userJid) { - itemCount = 3; + // Crowdfunding chat have only 2 page, other chat types have 3 page + if (CrowdfundingChat.USER.equals(userJid.getBareJid().toString())) + itemCount = 2; + else itemCount = 3; this.accountJid = accountJid; this.userJid = userJid; } From f11ce728d5461922c85adedc9a717b35e96ef756 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 20 Jun 2019 11:42:13 +0500 Subject: [PATCH 174/237] Up gradle tools version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5da5213e5d..1d68e19cee 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { maven { url 'https://maven.fabric.io/public' } } dependencies { - classpath 'com.android.tools.build:gradle:3.4.0' + classpath 'com.android.tools.build:gradle:3.4.1' classpath "io.realm:realm-gradle-plugin:3.1.1" classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' classpath 'com.frogermcs.androiddevmetrics:androiddevmetrics-plugin:0.4' From 1cf2c468c3130326e6b02644eabfcd19a6ae766d Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 20 Jun 2019 15:49:31 +0500 Subject: [PATCH 175/237] Fixed avatars in notification --- .../data/extension/avatar/AvatarManager.java | 35 +++++++++---------- .../MessageNotificationCreator.java | 18 ++++++---- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/avatar/AvatarManager.java b/xabber/src/main/java/com/xabber/android/data/extension/avatar/AvatarManager.java index 6357be85af..90c0f88180 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/avatar/AvatarManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/avatar/AvatarManager.java @@ -18,12 +18,10 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; -import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; @@ -179,23 +177,27 @@ public static Bitmap drawableToBitmap(Drawable drawable) { } public static Bitmap getCircleBitmap(Bitmap bitmap) { - final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), - bitmap.getHeight(), Bitmap.Config.ARGB_8888); - final Canvas canvas = new Canvas(output); + if (bitmap.getWidth() != bitmap.getHeight()) { + int min = Math.min(bitmap.getWidth(), bitmap.getHeight()); + int max = Math.max(bitmap.getWidth(), bitmap.getHeight()); + int x = bitmap.getWidth() > min ? ((max - min) / 2) : 0; + int y = bitmap.getHeight() > min ? ((max - min) / 2) : 0; + bitmap = Bitmap.createBitmap(bitmap, x, y, min, min); + } + final int size = bitmap.getWidth(); + final Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); - final int color = Color.RED; + final Canvas canvas = new Canvas(output); final Paint paint = new Paint(); - final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); - final RectF rectF = new RectF(rect); + final Rect rect = new Rect(0, 0, size, size); + final float r = size / 2; paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); - paint.setColor(color); - canvas.drawOval(rectF, paint); - + paint.setColor(0xff424242); + canvas.drawCircle(r, r, r, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); - return output; } @@ -387,17 +389,12 @@ public Drawable getRoomAvatarForContactList(UserJid user) { /** Gets bitmap with avatar for regular user. */ public Bitmap getUserBitmap(UserJid user, String name) { - Bitmap value = getBitmap(user.getJid()); - if (value != null) { - return getCircleBitmap(value); - } else { - return drawableToBitmap(generateDefaultAvatar(user.getBareJid().toString(), name)); - } + return getCircleBitmap(drawableToBitmap(getUserAvatarForContactList(user, name))); } /** Gets bitmap with avatar for room. */ public Bitmap getRoomBitmap(UserJid user) { - return drawableToBitmap(getRoomAvatar(user)); + return getCircleBitmap(drawableToBitmap(getRoomAvatarForContactList(user))); } /** Generate text-based avatar for regular user. */ diff --git a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationCreator.java b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationCreator.java index 65b38b2d3d..80d664b7c9 100644 --- a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationCreator.java +++ b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationCreator.java @@ -12,6 +12,7 @@ import android.support.v4.app.NotificationCompat; import android.support.v4.app.Person; import android.support.v4.app.RemoteInput; +import android.support.v4.graphics.drawable.IconCompat; import android.text.Spannable; import android.text.SpannableString; import android.text.style.ForegroundColorSpan; @@ -184,19 +185,22 @@ private CharSequence createTitleSingleChat(int messageCount, CharSequence chatTi } private NotificationCompat.Style createMessageStyle(MessageNotificationManager.Chat chat, boolean showText) { - NotificationCompat.Style messageStyle = new NotificationCompat.MessagingStyle( + NotificationCompat.MessagingStyle messageStyle = new NotificationCompat.MessagingStyle( new Person.Builder().setName(context.getString(R.string.sender_is_you)).build()); for (MessageNotificationManager.Message message : chat.getMessages()) { Person person = null; - if (message.getAuthor() != null && message.getAuthor().length() > 0) - person = new Person.Builder().setName(message.getAuthor()).build(); - ((NotificationCompat.MessagingStyle) messageStyle).addMessage( - new NotificationCompat.MessagingStyle.Message( + if (message.getAuthor() != null && message.getAuthor().length() > 0) { + person = new Person.Builder() + .setName(message.getAuthor()) + .setIcon(IconCompat.createWithBitmap(getLargeIcon(chat))) + .build(); + } + messageStyle.addMessage(new NotificationCompat.MessagingStyle.Message( showText ? message.getMessageText() : messageHidden, message.getTimestamp(), person)); } - ((NotificationCompat.MessagingStyle) messageStyle).setConversationTitle(chat.getChatTitle()); - ((NotificationCompat.MessagingStyle) messageStyle).setGroupConversation(chat.isGroupChat()); + messageStyle.setConversationTitle(chat.getChatTitle()); + messageStyle.setGroupConversation(chat.isGroupChat()); return messageStyle; } From b7d9cd0bc6c6a868012022cac6418273b0cb4c42 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 20 Jun 2019 19:04:36 +0500 Subject: [PATCH 176/237] Changes in validation user name in process of adding new contact --- .../ui/fragment/ContactAddFragment.java | 20 +++++-------------- .../main/res/values-ru-rRU/account_editor.xml | 2 +- xabber/src/main/res/values/account_editor.xml | 2 +- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/ContactAddFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/ContactAddFragment.java index eead9ce1dc..40defa04bc 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/ContactAddFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/ContactAddFragment.java @@ -168,9 +168,9 @@ public void onNothingSelected(AdapterView parent) { @Override public void addContact() { - if (getAccount() == null) { - Toast.makeText(getActivity(), getString(R.string.EMPTY_ACCOUNT), - Toast.LENGTH_LONG).show(); + final AccountJid account = (AccountJid) accountView.getSelectedItem(); + if (account == null || getAccount() == null) { + Toast.makeText(getActivity(), getString(R.string.EMPTY_ACCOUNT), Toast.LENGTH_LONG).show(); return; } @@ -178,8 +178,7 @@ public void addContact() { contactString = contactString.replace(" ", ""); if (TextUtils.isEmpty(contactString)) { - Toast.makeText(getActivity(), getString(R.string.EMPTY_USER_NAME), - Toast.LENGTH_LONG).show(); + userView.setError(getString(R.string.EMPTY_USER_NAME)); return ; } @@ -189,16 +188,7 @@ public void addContact() { user = UserJid.from(entityFullJid); } catch (XmppStringprepException | UserJid.UserJidCreateException e) { e.printStackTrace(); - Toast.makeText(getActivity(), getString(R.string.INCORRECT_USER_NAME), Toast.LENGTH_LONG).show(); - return; - } - - LogManager.i(this, "user: " + user); - - final AccountJid account = (AccountJid) accountView.getSelectedItem(); - if (account == null) { - Toast.makeText(getActivity(), getString(R.string.EMPTY_ACCOUNT), - Toast.LENGTH_LONG).show(); + userView.setError(getString(R.string.INCORRECT_USER_NAME)); return; } diff --git a/xabber/src/main/res/values-ru-rRU/account_editor.xml b/xabber/src/main/res/values-ru-rRU/account_editor.xml index 36662e5968..678dc9c6ec 100644 --- a/xabber/src/main/res/values-ru-rRU/account_editor.xml +++ b/xabber/src/main/res/values-ru-rRU/account_editor.xml @@ -42,7 +42,7 @@ Требовать TLS шифрование при подключении к серверу Включить протокол шифрования TLS Подключаться через анонимную сеть TOR (необходим Orbot proxy) - Неправильное имя пользователя. Просмотрите подсказку внизу экрана + Неправильное имя пользователя Для использования TOR необходимо установить приложение Orbot и активировать в нём передачу данных. Вы хотите установить его из Google Play? Установить Orbot? Установить Orbot diff --git a/xabber/src/main/res/values/account_editor.xml b/xabber/src/main/res/values/account_editor.xml index edfeed8020..77c96289d7 100644 --- a/xabber/src/main/res/values/account_editor.xml +++ b/xabber/src/main/res/values/account_editor.xml @@ -41,7 +41,7 @@ Require TLS encryption when connect to server Enable TLS cryptographic protocol Use TOR anonymity network (requires Orbot proxy) - Incorrect user name. Check help text below for details. + Incorrect user name In order to process using TOR you must have Orbot installed and activated to proxy traffic through it. Would you like to install it from Google Play? Install Orbot? Install Orbot From 685de9e44fb3c536e96a3d80a7732816c881c328 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 21 Jun 2019 11:33:23 +0500 Subject: [PATCH 177/237] On contact removing also removes it history --- .../xabber/android/ui/dialog/ContactDeleteDialogFragment.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/dialog/ContactDeleteDialogFragment.java b/xabber/src/main/java/com/xabber/android/ui/dialog/ContactDeleteDialogFragment.java index ee3f054d16..80485f7979 100644 --- a/xabber/src/main/java/com/xabber/android/ui/dialog/ContactDeleteDialogFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/dialog/ContactDeleteDialogFragment.java @@ -65,8 +65,10 @@ public void onClick(DialogInterface dialog, int which) { // delete chat AbstractChat chat = MessageManager.getInstance().getChat(account, user); - if (chat != null) + if (chat != null) { + MessageManager.getInstance().clearHistory(account, user); MessageManager.getInstance().removeChat(chat); + } // remove roster contact RosterManager.getInstance().removeContact(account, user); From ae94b325d2d08044836a59fab72e3aa32686ced8 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 21 Jun 2019 19:00:12 +0500 Subject: [PATCH 178/237] Try to fix MissingBackpressureException --- .../xabber/android/data/message/BackpressureMessageSaver.java | 1 + 1 file changed, 1 insertion(+) diff --git a/xabber/src/main/java/com/xabber/android/data/message/BackpressureMessageSaver.java b/xabber/src/main/java/com/xabber/android/data/message/BackpressureMessageSaver.java index 2faf5f84ae..c77cba9e68 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/BackpressureMessageSaver.java +++ b/xabber/src/main/java/com/xabber/android/data/message/BackpressureMessageSaver.java @@ -43,6 +43,7 @@ private BackpressureMessageSaver() { private void createSubject() { subject = PublishSubject.create(); subject.buffer(500, TimeUnit.MILLISECONDS) + .onBackpressureBuffer(50) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1>() { @Override From 76918ce234fb0e59c02a48d1aee33c7c25941dab Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 21 Jun 2019 19:05:48 +0500 Subject: [PATCH 179/237] Up version to 625 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index b27f08cdb2..15e6a3cd2f 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 624 - versionName '2.6.4(624)' + versionCode 625 + versionName '2.6.4(625)' } lintOptions { From 4a34f96596060b84cdb55211bd1b8b71281db46b Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 24 Jun 2019 11:40:05 +0500 Subject: [PATCH 180/237] Changes in about --- xabber/src/main/res/values/about_viewer.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/res/values/about_viewer.xml b/xabber/src/main/res/values/about_viewer.xml index 931f8d0ed9..007c8a1fb3 100644 --- a/xabber/src/main/res/values/about_viewer.xml +++ b/xabber/src/main/res/values/about_viewer.xml @@ -3,7 +3,7 @@ open source XMPP client About - Xabber is an open-source XMPP messenger for Android platform. It is built around open standards, interoperability, design and user experience. Xabber supports many popular XMPP extension protocols, Off-The-Record Chat Encryption and is available in multiple languages. + Xabber is an open source XMPP messenger for Android, iOS and Web platforms. It is build around open standards, interoperability, design and great user experience. Versions of Xabber for every platform are built to provide a continuous chat experience between them. XMPP protocol Extensible Messaging and Presence Protocol (XMPP) is a communications protocol for message-oriented middleware based on XML (Extensible Markup Language). It enables the near-real-time exchange of structured yet extensible data between any two or more network entities. The protocol was originally named Jabber, and was developed by the Jabber open-source community in 1999 for near real-time instant messaging (IM),presence information, and contact list maintenance. @@ -13,7 +13,7 @@ XMPP is highly extensible, via extensions known as XEPs (XMPP Extension Protocol). Xabber supports a number of popular XEPs that are essential to providing great chat experience for our users. Developers - Xabber was originally developed by Redsolution, Inc. — an international software and services company based in Russia and United States. Xabber was licensed under GNU/GPL v.3 license early in 2013. Since then, a number of individuals joined Xabber as developers, testers and translators.\n\nOur goal is to create a stable, reliable and user friendly ecosystem for instant messaging that does not rely on proprietary services. We welcome anyone who believes in open standards and free information interchange to take part in moving Xabber forward.\n\nFollow us on Twitter and Github. + Xabber for Android was originally developed by Redsolution, Inc. — an international software and services company currently based in Estonia. Since then, a number of individuals joined Xabber as developers, testers and translators.\n\nOur goal is to create a stable, reliable, interoperable and user friendly ecosystem for instant messaging that does not rely on proprietary services and data silos. We welcome anyone who believes in open standards and free information interchange to take part in moving Xabber forward.\n\nFollow us on Twitter and Github. http://www.redsolution.com/ http://www.xabber.com From 8dd658f702badfdd2637d920aef8ad317f1ad8c8 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 24 Jun 2019 14:01:16 +0500 Subject: [PATCH 181/237] Changed message width in crowdfunding chat --- .../adapter/chat/CrowdfundingChatAdapter.java | 4 +- .../item_message_incoming_crowdfunding.xml | 52 +++++++++++++++++++ ...m_message_incoming_noflex_crowdfunding.xml | 52 +++++++++++++++++++ 3 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 xabber/src/main/res/layout/item_message_incoming_crowdfunding.xml create mode 100644 xabber/src/main/res/layout/item_message_incoming_noflex_crowdfunding.xml diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/CrowdfundingChatAdapter.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/CrowdfundingChatAdapter.java index 618c4ae752..40bb44e25c 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/CrowdfundingChatAdapter.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/CrowdfundingChatAdapter.java @@ -66,9 +66,9 @@ public CrowdfundingMessage getMessage(int position) { public CrowdMessageVH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_MESSAGE_NOFLEX) return new CrowdMessageVH(LayoutInflater.from(parent.getContext()) - .inflate(R.layout.item_message_incoming_noflex, parent, false)); + .inflate(R.layout.item_message_incoming_noflex_crowdfunding, parent, false)); else return new CrowdMessageVH(LayoutInflater.from(parent.getContext()) - .inflate(R.layout.item_message_incoming, parent, false)); + .inflate(R.layout.item_message_incoming_crowdfunding, parent, false)); } @Override diff --git a/xabber/src/main/res/layout/item_message_incoming_crowdfunding.xml b/xabber/src/main/res/layout/item_message_incoming_crowdfunding.xml new file mode 100644 index 0000000000..7aa0790c38 --- /dev/null +++ b/xabber/src/main/res/layout/item_message_incoming_crowdfunding.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xabber/src/main/res/layout/item_message_incoming_noflex_crowdfunding.xml b/xabber/src/main/res/layout/item_message_incoming_noflex_crowdfunding.xml new file mode 100644 index 0000000000..8dbc289b16 --- /dev/null +++ b/xabber/src/main/res/layout/item_message_incoming_noflex_crowdfunding.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 4a68b7efee900e80f90cea62f92e56d1a4da11f6 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 24 Jun 2019 14:08:08 +0500 Subject: [PATCH 182/237] Changes in references --- .../data/extension/references/Markup.java | 14 +++--- .../references/{Data.java => Media.java} | 6 +-- .../data/extension/references/Mention.java | 11 +---- .../data/extension/references/Quote.java | 21 +++------ .../references/ReferenceElement.java | 12 ++--- .../references/ReferencesManager.java | 12 ++--- .../references/ReferencesProvider.java | 47 ++++++++++--------- .../references/ReferencesManagerTest.java | 4 +- .../references/ReferencesProviderTest.java | 31 ++++++------ 9 files changed, 73 insertions(+), 85 deletions(-) rename xabber/src/main/java/com/xabber/android/data/extension/references/{Data.java => Media.java} (79%) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/Markup.java b/xabber/src/main/java/com/xabber/android/data/extension/references/Markup.java index 2f9aa97081..b4fd485e5f 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/Markup.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/Markup.java @@ -7,15 +7,15 @@ public class Markup extends ReferenceElement { private final boolean italic; private final boolean underline; private final boolean strike; - private final String url; + private final String uri; - public Markup(int begin, int end, boolean bold, boolean italic, boolean underline, boolean strike, String url) { + public Markup(int begin, int end, boolean bold, boolean italic, boolean underline, boolean strike, String uri) { super(begin, end); this.bold = bold; this.italic = italic; this.underline = underline; this.strike = strike; - this.url = url; + this.uri = uri; } @Override @@ -29,8 +29,8 @@ public void appendToXML(XmlStringBuilder xml) { if (italic) xml.emptyElement(ELEMENT_ITALIC); if (underline) xml.emptyElement(ELEMENT_UNDERLINE); if (strike) xml.emptyElement(ELEMENT_STRIKE); - if (url != null && url.isEmpty()) { - xml.element(ELEMENT_URL, url); + if (uri != null && uri.isEmpty()) { + xml.element(ELEMENT_URI, uri); } } @@ -50,7 +50,7 @@ public boolean isStrike() { return strike; } - public String getUrl() { - return url; + public String getUri() { + return uri; } } diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/Data.java b/xabber/src/main/java/com/xabber/android/data/extension/references/Media.java similarity index 79% rename from xabber/src/main/java/com/xabber/android/data/extension/references/Data.java rename to xabber/src/main/java/com/xabber/android/data/extension/references/Media.java index 922af2d433..0227dada9d 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/Data.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/Media.java @@ -4,17 +4,17 @@ import java.util.List; -public class Data extends ReferenceElement { +public class Media extends ReferenceElement { private final List media; - public Data(int begin, int end, List media) { + public Media(int begin, int end, List media) { super(begin, end); this.media = media; } @Override public Type getType() { - return Type.data; + return Type.media; } @Override diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/Mention.java b/xabber/src/main/java/com/xabber/android/data/extension/references/Mention.java index 6b43aa056a..06c2e66eac 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/Mention.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/Mention.java @@ -16,15 +16,8 @@ public Type getType() { } @Override - public CharSequence toXML() { - XmlStringBuilder xml = new XmlStringBuilder(this); - xml.attribute(ATTRIBUTE_TYPE, getType()); - xml.attribute(ATTRIBUTE_BEGIN, begin); - xml.attribute(ATTRIBUTE_END, end); - xml.attribute(ATTRIBUTE_URI, uri); - xml.rightAngleBracket(); - xml.closeElement(this); - return xml; + public void appendToXML(XmlStringBuilder xml) { + xml.element(ELEMENT_URI, uri); } public String getUri() { diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/Quote.java b/xabber/src/main/java/com/xabber/android/data/extension/references/Quote.java index 699cccd0b6..e3ddb2aba5 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/Quote.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/Quote.java @@ -3,11 +3,11 @@ import org.jivesoftware.smack.util.XmlStringBuilder; public class Quote extends ReferenceElement { - private final int del; + private final String marker; - public Quote(int begin, int end, int del) { + public Quote(int begin, int end, String marker) { super(begin, end); - this.del = del; + this.marker = marker; } @Override @@ -16,18 +16,11 @@ public Type getType() { } @Override - public CharSequence toXML() { - XmlStringBuilder xml = new XmlStringBuilder(this); - xml.attribute(ATTRIBUTE_TYPE, getType()); - xml.attribute(ATTRIBUTE_BEGIN, begin); - xml.attribute(ATTRIBUTE_END, end); - xml.attribute(ATTRIBUTE_DEL, del); - xml.rightAngleBracket(); - xml.closeElement(this); - return xml; + public void appendToXML(XmlStringBuilder xml) { + xml.element(ELEMENT_MARKER, marker); } - public int getDel() { - return del; + public String getMarker() { + return marker; } } diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java index dc2b997c23..6bcd996197 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java @@ -5,26 +5,26 @@ public abstract class ReferenceElement implements ExtensionElement { - public static final String NAMESPACE = "urn:xmpp:reference:0"; + public static final String NAMESPACE = "https://xabber.com/protocol/reference"; public static final String ELEMENT = "reference"; public static final String ELEMENT_BOLD = "bold"; public static final String ELEMENT_ITALIC = "italic"; public static final String ELEMENT_UNDERLINE = "underline"; public static final String ELEMENT_STRIKE = "strike"; - public static final String ELEMENT_URL = "url"; + public static final String ELEMENT_URI = "uri"; + public static final String ELEMENT_MARKER = "marker"; public static final String ATTRIBUTE_TYPE = "type"; public static final String ATTRIBUTE_BEGIN = "begin"; public static final String ATTRIBUTE_END = "end"; - public static final String ATTRIBUTE_URI = "uri"; - public static final String ATTRIBUTE_DEL = "del"; public enum Type { - data, + media, forward, markup, mention, - quote + quote, + voice } protected final int begin; diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index 4710b7f38c..92bbfa616a 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -40,7 +40,7 @@ public static List getForwardedFromReferences(Stanza packet) { return forwarded; } - public static Data createMediaReferences(RealmList attachments, String legacyBody) { + public static Media createMediaReferences(RealmList attachments, String legacyBody) { List mediaList = new ArrayList<>(); for (Attachment attachment : attachments) { RefFile.Builder builder = RefFile.newBuilder(); @@ -58,7 +58,7 @@ public static Data createMediaReferences(RealmList attachments, Stri } char[] chars = TextUtils.htmlEncode(legacyBody).toCharArray(); - return new Data(0, chars.length - 1, mediaList); + return new Media(0, chars.length - 1, mediaList); } public static Forward createForwardReference(RealmResults items, String legacyBody) { @@ -83,8 +83,8 @@ public static List getMediaFromReferences(Stanza packet) { List media = new ArrayList<>(); for (ExtensionElement element : elements) { - if (element instanceof Data) { - media.addAll(((Data) element).getMedia()); + if (element instanceof Media) { + media.addAll(((Media) element).getMedia()); } } return media; @@ -162,7 +162,7 @@ private static String[] modifyBodyWithReferences(String[] chars, ReferenceElemen if (begin > end) return chars; switch (reference.getType()) { - case data: + case media: chars = remove(begin, end, chars); break; case forward: @@ -186,7 +186,7 @@ private static String[] remove(int begin, int end, String[] source) { } private static String[] removeInLine(int begin, int end, String[] source, Quote reference) { - int del = reference.getDel(); + int del = reference.getMarker().length(); int removed = 0; for (int i = begin; i <= end; i++) { if (removed < del) { diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java index b736695560..d0eacb6df8 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java @@ -1,5 +1,7 @@ package com.xabber.android.data.extension.references; +import android.text.TextUtils; + import com.xabber.android.data.log.LogManager; import org.jivesoftware.smack.provider.ExtensionElementProvider; @@ -14,7 +16,7 @@ public class ReferencesProvider extends ExtensionElementProvider forwardedMessages = new ArrayList<>(); List mediaElements = new ArrayList<>(); boolean bold = false, italic = false, underline = false, strike = false; @@ -28,33 +30,33 @@ public ReferenceElement parse(XmlPullParser parser, int initialDepth) throws Exc type = parser.getAttributeValue("", ReferenceElement.ATTRIBUTE_TYPE); beginS = parser.getAttributeValue("", ReferenceElement.ATTRIBUTE_BEGIN); endS = parser.getAttributeValue("", ReferenceElement.ATTRIBUTE_END); - delS = parser.getAttributeValue("", ReferenceElement.ATTRIBUTE_DEL); - uri = parser.getAttributeValue("", ReferenceElement.ATTRIBUTE_URI); - } - if (Forwarded.ELEMENT.equals(parser.getName()) + parser.next(); + } else if (Forwarded.ELEMENT.equals(parser.getName()) && Forwarded.NAMESPACE.equals(parser.getNamespace())) { Forwarded forwarded = ForwardedProvider.INSTANCE.parse(parser); if (forwarded != null) forwardedMessages.add(forwarded); - } - if (RefMedia.ELEMENT.equals(parser.getName())) { + parser.next(); + } else if (RefMedia.ELEMENT.equals(parser.getName())) { RefMedia media = parseMedia(parser); if (media != null) mediaElements.add(media); - } - if (ReferenceElement.ELEMENT_BOLD.equals(parser.getName())) { + parser.next(); + } else if (ReferenceElement.ELEMENT_BOLD.equals(parser.getName())) { bold = true; - } - if (ReferenceElement.ELEMENT_ITALIC.equals(parser.getName())) { + parser.next(); + } else if (ReferenceElement.ELEMENT_ITALIC.equals(parser.getName())) { italic = true; - } - if (ReferenceElement.ELEMENT_UNDERLINE.equals(parser.getName())) { + parser.next(); + } else if (ReferenceElement.ELEMENT_UNDERLINE.equals(parser.getName())) { underline = true; - } - if (ReferenceElement.ELEMENT_STRIKE.equals(parser.getName())) { + parser.next(); + } else if (ReferenceElement.ELEMENT_STRIKE.equals(parser.getName())) { strike = true; + parser.next(); + } else if (ReferenceElement.ELEMENT_URI.equals(parser.getName())) { + uri = parser.nextText(); + } else if (ReferenceElement.ELEMENT_MARKER.equals(parser.getName())) { + marker = TextUtils.htmlEncode(parser.nextText()); } - if (ReferenceElement.ELEMENT_URL.equals(parser.getName())) { - url = parser.nextText(); - } else parser.next(); break; case XmlPullParser.END_TAG: if (ReferenceElement.ELEMENT.equals(parser.getName())) { @@ -69,19 +71,18 @@ public ReferenceElement parse(XmlPullParser parser, int initialDepth) throws Exc int begin = 0, end = 0, del = 0; if (beginS != null && !beginS.isEmpty()) begin = Integer.valueOf(beginS); if (endS != null && !endS.isEmpty()) end = Integer.valueOf(endS); - if (delS != null && !delS.isEmpty()) del = Integer.valueOf(delS); try { ReferenceElement.Type refType = ReferenceElement.Type.valueOf(type); switch (refType) { case forward: return new Forward(begin, end, forwardedMessages); - case data: - return new Data(begin, end, mediaElements); + case media: + return new Media(begin, end, mediaElements); case markup: - return new Markup(begin, end, bold, italic, underline, strike, url); + return new Markup(begin, end, bold, italic, underline, strike, uri); case quote: - return new Quote(begin, end, del); + return new Quote(begin, end, marker); case mention: return new Mention(begin, end, uri); default: diff --git a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java index a6a6623834..f6c9a11dfe 100644 --- a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java +++ b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java @@ -33,7 +33,7 @@ public void setUp() throws Exception { body2 = "https://upload02.xabber.org/5ff2744e91/iKIlTIyZ/guide.txt\nhello"; message2 = new Message("test@jabber.com", body2); - message2.addExtension(new Data(0, 57, null)); + message2.addExtension(new Media(0, 57, null)); // ------- @@ -52,7 +52,7 @@ public void setUp() throws Exception { "Hello world!"; message4 = new Message("test@jabber.com", body4); - message4.addExtension(new Quote(0, 37, 5)); + message4.addExtension(new Quote(0, 37, "> ")); // ------- diff --git a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesProviderTest.java b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesProviderTest.java index 1ab5544822..eb8142b72a 100644 --- a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesProviderTest.java +++ b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesProviderTest.java @@ -34,7 +34,7 @@ public void setUp() throws Exception { factory = XmlPullParserFactory.newInstance(); factory.setNamespaceAware(true); - stringForward = "" + + stringForward = "" + "" + "" + "" + @@ -43,7 +43,7 @@ public void setUp() throws Exception { "" + ""; - stringMedia = "" + + stringMedia = "" + "application/pdfAndroid-Architecture_1-1.pdf4255465" + "https://upload02.xabber.org/5f70e738285c44c82039a73d42eccf27" + "44e91/lQk6DkRJ/Android-Architecture_1-1.pdf" + @@ -52,19 +52,20 @@ public void setUp() throws Exception { "e738285c44c82039a73d42eccf2744e91/rUdy3rHt/Screenshot_20190414-194652.png" + ""; - stringMarkup1 = "" + + stringMarkup1 = "" + ""; - stringMarkup2 = "" + - "https://www.xabber.com"; + stringMarkup2 = "" + + "https://www.xabber.com"; - stringMention = ""; + stringMention = "" + + "xmpp:juliet@capulet.lit"; - stringQuote = ""; + stringQuote = "" + + "> "; - stringUnknown = ""; - stringNull = ""; + stringUnknown = ""; + stringNull = ""; } @@ -80,9 +81,9 @@ public void parse1() { @Test public void parse2() { - Data element = (Data) parseString(stringMedia); + Media element = (Media) parseString(stringMedia); assertNotNull(element); - assertEquals("data", element.getType().toString()); + assertEquals("media", element.getType().toString()); assertEquals(0, element.getBegin()); assertEquals(89, element.getEnd()); assertEquals(2, element.getMedia().size()); @@ -123,7 +124,7 @@ public void parse3() { assertTrue(element.isItalic()); assertFalse(element.isStrike()); assertFalse(element.isUnderline()); - assertNull(element.getUrl()); + assertNull(element.getUri()); } @Test @@ -137,7 +138,7 @@ public void parse4() { assertFalse(element.isItalic()); assertFalse(element.isStrike()); assertFalse(element.isUnderline()); - assertEquals("https://www.xabber.com", element.getUrl()); + assertEquals("https://www.xabber.com", element.getUri()); } @Test @@ -157,7 +158,7 @@ public void parse6() { assertEquals("quote", element.getType().toString()); assertEquals(0, element.getBegin()); assertEquals(31, element.getEnd()); - assertEquals(5, element.getDel()); + assertEquals("> ", element.getMarker()); } @Test From 212e8d888c6d1c49196a8cc3b7cf272130b89ed5 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 24 Jun 2019 14:14:42 +0500 Subject: [PATCH 183/237] Removed voice flag from RefFile --- .../data/extension/references/RefFile.java | 16 ---------------- .../extension/references/ReferencesManager.java | 1 - .../extension/references/ReferencesProvider.java | 3 --- 3 files changed, 20 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/RefFile.java b/xabber/src/main/java/com/xabber/android/data/extension/references/RefFile.java index 5c891396a3..835e56f6b3 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/RefFile.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/RefFile.java @@ -13,7 +13,6 @@ public class RefFile { public static final String ELEMENT_WIDTH = "width"; public static final String ELEMENT_SIZE = "size"; public static final String ELEMENT_DURATION = "duration"; - public static final String ELEMENT_VOICE = "voice"; private String mediaType; private String name; @@ -22,7 +21,6 @@ public class RefFile { private int width; private long size; private long duration; - private boolean voice; public String getMediaType() { return mediaType; @@ -52,10 +50,6 @@ public long getDuration() { return duration; } - public boolean isVoice() { - return voice; - } - public CharSequence toXML() { XmlStringBuilder xml = new XmlStringBuilder(); xml.openElement(ELEMENT); @@ -94,11 +88,6 @@ public CharSequence toXML() { xml.append(String.valueOf(getDuration())); xml.closeElement(ELEMENT_DURATION); } - if (isVoice()) { - xml.openElement(ELEMENT_VOICE); - xml.append(String.valueOf(isVoice())); - xml.closeElement(ELEMENT_VOICE); - } xml.closeElement(ELEMENT); return xml; } @@ -148,11 +137,6 @@ public Builder setDuration(long duration) { RefFile.this.duration = duration; return this; } - - public Builder setVoice(boolean voice) { - RefFile.this.voice = voice; - return this; - } } } diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index 92bbfa616a..866e60b065 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -46,7 +46,6 @@ public static Media createMediaReferences(RealmList attachments, Str RefFile.Builder builder = RefFile.newBuilder(); builder.setName(attachment.getTitle()); builder.setMediaType(attachment.getMimeType()); - builder.setVoice(false); builder.setDuration(attachment.getDuration()); builder.setSize(attachment.getFileSize()); if (attachment.getImageHeight() != null) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java index d0eacb6df8..62d747a29a 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java @@ -154,9 +154,6 @@ private RefFile parseFile(XmlPullParser parser) throws Exception { case RefFile.ELEMENT_DURATION: builder.setDuration(Long.valueOf(parser.nextText())); break; - case RefFile.ELEMENT_VOICE: - builder.setVoice(Boolean.valueOf(parser.nextText())); - break; default: parser.next(); } From 890d401b9dbf6b10ec67ee6d559321c25f2a7344 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 24 Jun 2019 14:58:39 +0500 Subject: [PATCH 184/237] Changes in media references --- .../references/ReferencesManager.java | 31 +++++++++---------- .../android/data/message/AbstractChat.java | 23 +++++++++----- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index 866e60b065..e7309449df 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -40,24 +40,21 @@ public static List getForwardedFromReferences(Stanza packet) { return forwarded; } - public static Media createMediaReferences(RealmList attachments, String legacyBody) { + public static Media createMediaReferences(Attachment attachment, int begin, int end) { List mediaList = new ArrayList<>(); - for (Attachment attachment : attachments) { - RefFile.Builder builder = RefFile.newBuilder(); - builder.setName(attachment.getTitle()); - builder.setMediaType(attachment.getMimeType()); - builder.setDuration(attachment.getDuration()); - builder.setSize(attachment.getFileSize()); - if (attachment.getImageHeight() != null) - builder.setHeight(attachment.getImageHeight()); - if (attachment.getImageWidth() != null) - builder.setWidth(attachment.getImageWidth()); - RefMedia media = new RefMedia(builder.build(), attachment.getFileUrl()); - mediaList.add(media); - } - - char[] chars = TextUtils.htmlEncode(legacyBody).toCharArray(); - return new Media(0, chars.length - 1, mediaList); + RefFile.Builder builder = RefFile.newBuilder(); + builder.setName(attachment.getTitle()); + builder.setMediaType(attachment.getMimeType()); + builder.setDuration(attachment.getDuration()); + builder.setSize(attachment.getFileSize()); + if (attachment.getImageHeight() != null) + builder.setHeight(attachment.getImageHeight()); + if (attachment.getImageWidth() != null) + builder.setWidth(attachment.getImageWidth()); + RefMedia media = new RefMedia(builder.build(), attachment.getFileUrl()); + mediaList.add(media); + + return new Media(begin, end, mediaList); } public static Forward createForwardReference(RealmResults items, String legacyBody) { diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index 25d8078f2a..9753bce385 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -17,6 +17,7 @@ import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.text.TextUtils; import com.xabber.android.data.Application; import com.xabber.android.data.NetworkException; @@ -574,19 +575,27 @@ public Message createFileMessagePacket(String stanzaId, RealmList at message.setThread(threadId); if (stanzaId != null) message.setStanzaId(stanzaId); - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(body); for (Attachment attachment : attachments) { - if (builder.length() > 0) builder.append("\n"); - builder.append(attachment.getFileUrl()); + StringBuilder rowBuilder = new StringBuilder(); + if (builder.length() > 0) rowBuilder.append("\n"); + rowBuilder.append(attachment.getFileUrl()); + + int begin = getSizeOfEncodedChars(builder.toString()); + builder.append(rowBuilder); + ReferenceElement reference = ReferencesManager.createMediaReferences(attachment, + begin, getSizeOfEncodedChars(builder.toString()) - 1); + message.addExtension(reference); } - String legacyBody = builder.toString(); - ReferenceElement reference = ReferencesManager.createMediaReferences(attachments, legacyBody); - message.addExtension(reference); - message.setBody(body + legacyBody); + message.setBody(builder); return message; } + private int getSizeOfEncodedChars(String str) { + return TextUtils.htmlEncode(str).toCharArray().length; + } + /** * Prepare text to be send. * From eb594c34be41cd14777b3564f5daf78083032367 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 24 Jun 2019 14:59:03 +0500 Subject: [PATCH 185/237] Temporary changed namespace --- .../android/data/extension/references/ReferenceElement.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java index 6bcd996197..e4c1d60d86 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferenceElement.java @@ -5,7 +5,7 @@ public abstract class ReferenceElement implements ExtensionElement { - public static final String NAMESPACE = "https://xabber.com/protocol/reference"; + public static final String NAMESPACE = "urn:xmpp:reference:0"; public static final String ELEMENT = "reference"; public static final String ELEMENT_BOLD = "bold"; public static final String ELEMENT_ITALIC = "italic"; From 203f60ac3ae13cf89026565bd19f25e41ec5e2a0 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 24 Jun 2019 15:56:48 +0500 Subject: [PATCH 186/237] Update forwarded references --- .../references/ReferencesManager.java | 17 ++++++------- .../android/data/message/AbstractChat.java | 24 ++++++++++++++----- .../android/data/message/ClipManager.java | 5 ++-- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index e7309449df..7e1ee93eca 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -57,19 +57,16 @@ public static Media createMediaReferences(Attachment attachment, int begin, int return new Media(begin, end, mediaList); } - public static Forward createForwardReference(RealmResults items, String legacyBody) { + public static Forward createForwardReference(MessageItem item, int begin, int end) { List forwardedList = new ArrayList<>(); - for (MessageItem item : items) { - try { - Message forwarded = PacketParserUtils.parseStanza(item.getOriginalStanza()); - forwardedList.add(new Forwarded(new DelayInformation(new Date(item.getTimestamp())), forwarded)); - } catch (Exception e) { - e.printStackTrace(); - } + try { + Message forwarded = PacketParserUtils.parseStanza(item.getOriginalStanza()); + forwardedList.add(new Forwarded(new DelayInformation(new Date(item.getTimestamp())), forwarded)); + } catch (Exception e) { + e.printStackTrace(); } - char[] chars = TextUtils.htmlEncode(legacyBody).toCharArray(); - return new Forward(0, chars.length - 1, forwardedList); + return new Forward(begin, end, forwardedList); } @Nonnull diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index 9753bce385..869da71cbb 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -61,6 +61,7 @@ import org.jxmpp.jid.parts.Resourcepart; import java.io.File; +import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; @@ -663,13 +664,24 @@ boolean sendMessage(MessageItem messageItem) { RealmResults items = realm.where(MessageItem.class) .in(MessageItem.Fields.UNIQUE_ID, messageItem.getForwardedIdsAsArray()).findAll(); - String modifiedBody = ClipManager.createMessageTree(realm, messageItem.getForwardedIdsAsArray()) + "\n"; - text = modifiedBody + text; - message = createMessagePacket(text, messageItem.getStanzaId()); - + List references = new ArrayList<>(); + StringBuilder builder = new StringBuilder(); if (items != null && !items.isEmpty()) { - ReferenceElement reference = ReferencesManager.createForwardReference(items, modifiedBody); - message.addExtension(reference); + for (MessageItem item : items) { + String forward = ClipManager.createMessageTree(realm, item.getUniqueId()) + "\n"; + int begin = getSizeOfEncodedChars(builder.toString()); + builder.append(forward); + ReferenceElement reference = ReferencesManager.createForwardReference(item, + begin, getSizeOfEncodedChars(builder.toString()) - 1); + references.add(reference); + } + } + builder.append(text); + text = builder.toString(); + + message = createMessagePacket(text, messageItem.getStanzaId()); + for (ReferenceElement element : references) { + message.addExtension(element); } } else if (text != null) { diff --git a/xabber/src/main/java/com/xabber/android/data/message/ClipManager.java b/xabber/src/main/java/com/xabber/android/data/message/ClipManager.java index 0b350bbcd9..01a92c415d 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/ClipManager.java +++ b/xabber/src/main/java/com/xabber/android/data/message/ClipManager.java @@ -33,8 +33,9 @@ public void run() { }); } - public static String createMessageTree(Realm realm, String[] messagesIDs) { - return messagesToText(realm, messagesIDs, 1); + public static String createMessageTree(Realm realm, String id) { + String[] str = {id}; + return messagesToText(realm, str, 1); } private static void insertDataToClipboard(final String text) { From 435107a0c8effeaf28adcab414c3344755cd9292 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 24 Jun 2019 16:33:26 +0500 Subject: [PATCH 187/237] Changes in parsing references --- .../extension/references/ReferencesProvider.java | 2 +- .../references/ReferencesProviderTest.java | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java index 62d747a29a..ae0ad5baeb 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java @@ -56,7 +56,7 @@ public ReferenceElement parse(XmlPullParser parser, int initialDepth) throws Exc uri = parser.nextText(); } else if (ReferenceElement.ELEMENT_MARKER.equals(parser.getName())) { marker = TextUtils.htmlEncode(parser.nextText()); - } + } else parser.next(); break; case XmlPullParser.END_TAG: if (ReferenceElement.ELEMENT.equals(parser.getName())) { diff --git a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesProviderTest.java b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesProviderTest.java index eb8142b72a..206d0b9b95 100644 --- a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesProviderTest.java +++ b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesProviderTest.java @@ -34,7 +34,7 @@ public void setUp() throws Exception { factory = XmlPullParserFactory.newInstance(); factory.setNamespaceAware(true); - stringForward = "" + + stringForward = "" + "" + "" + "" + @@ -43,7 +43,7 @@ public void setUp() throws Exception { "" + ""; - stringMedia = "" + + stringMedia = "" + "application/pdfAndroid-Architecture_1-1.pdf4255465" + "https://upload02.xabber.org/5f70e738285c44c82039a73d42eccf27" + "44e91/lQk6DkRJ/Android-Architecture_1-1.pdf" + @@ -52,19 +52,19 @@ public void setUp() throws Exception { "e738285c44c82039a73d42eccf2744e91/rUdy3rHt/Screenshot_20190414-194652.png" + ""; - stringMarkup1 = "" + + stringMarkup1 = "" + ""; - stringMarkup2 = "" + + stringMarkup2 = "" + "https://www.xabber.com"; - stringMention = "" + + stringMention = "" + "xmpp:juliet@capulet.lit"; - stringQuote = "" + + stringQuote = "" + "> "; - stringUnknown = ""; + stringUnknown = ""; stringNull = ""; } From fc7c7593a4c66459dc62ca2e143e0ca016bd91ee Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 24 Jun 2019 17:20:53 +0500 Subject: [PATCH 188/237] Fixed issue in ContactVcardViewerFragment.getResource --- .../xabber/android/ui/fragment/ContactVcardViewerFragment.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/ContactVcardViewerFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/ContactVcardViewerFragment.java index 24db65d9dc..151fe0dcb2 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/ContactVcardViewerFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/ContactVcardViewerFragment.java @@ -415,8 +415,7 @@ private void fillResourceList(AccountJid account, Jid bareAddress, List re ImageView statusIcon = (ImageView) resourceView.findViewById(R.id.contact_info_right_icon); statusIcon.setVisibility(View.VISIBLE); - - statusIcon.setImageDrawable(getResources().getDrawable(R.drawable.ic_status)); + statusIcon.setImageResource(R.drawable.ic_status); statusIcon.setImageLevel(statusMode.getStatusLevel()); resourcesList.add(resourceView); From 178c4901e4cba63a5283b93156b8f5887da17ad0 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 24 Jun 2019 17:57:08 +0500 Subject: [PATCH 189/237] Fixed error in ChatFragment.onEvent --- .../main/java/com/xabber/android/ui/fragment/ChatFragment.java | 1 - 1 file changed, 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java index 25e07fab89..bfd9da3454 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java @@ -651,7 +651,6 @@ public void onEvent(PreviousHistoryLoadFinishedEvent event) { public void onEvent(MessageUpdateEvent event) { if (account.equals(event.getAccount()) && user.equals(event.getUser())) { updateUnread(); - chatMessageAdapter.onChange(); } } From c7419221a4fd0ca0f86485138fc51abe6dfb75d5 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 24 Jun 2019 18:27:29 +0500 Subject: [PATCH 190/237] Added crashlytics key in manifest --- xabber/build.gradle | 12 ++++++++++++ xabber/src/main/AndroidManifest.xml | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/xabber/build.gradle b/xabber/build.gradle index 15e6a3cd2f..2a8748731e 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -12,6 +12,7 @@ android { targetSdkVersion 28 versionCode 625 versionName '2.6.4(625)' + manifestPlaceholders = [crashlytics:getLocalProperty("crashlytics.key")] } lintOptions { @@ -114,6 +115,17 @@ if (build_param == "open") { } } +def getLocalProperty(String propertyName) { + def propsFile = rootProject.file('local.properties') + if (propsFile.exists()) { + def props = new Properties() + props.load(new FileInputStream(propsFile)) + return props[propertyName] + } else { + return "" + } +} + ext { smackVersion = '4.2.1-SNAPSHOT' supportVersion = '28.0.0' diff --git a/xabber/src/main/AndroidManifest.xml b/xabber/src/main/AndroidManifest.xml index 4ccee7f9c4..999b60e3d7 100644 --- a/xabber/src/main/AndroidManifest.xml +++ b/xabber/src/main/AndroidManifest.xml @@ -49,6 +49,12 @@ android:label="@string/application_title_full" android:theme="@style/Theme" tools:replace="label, icon, allowBackup"> + + + Date: Mon, 24 Jun 2019 18:29:09 +0500 Subject: [PATCH 191/237] Up version to 626 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 2a8748731e..413ec1eff2 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 625 - versionName '2.6.4(625)' + versionCode 626 + versionName '2.6.4(626)' manifestPlaceholders = [crashlytics:getLocalProperty("crashlytics.key")] } From 34b9fce483f05f71845c44b065f7afe28258fe74 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 25 Jun 2019 13:44:49 +0500 Subject: [PATCH 192/237] Fixed bug in parsing references --- .../com/xabber/android/data/extension/references/Mention.java | 4 +++- .../com/xabber/android/data/extension/references/Quote.java | 4 +++- .../android/data/extension/references/ReferencesProvider.java | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/Mention.java b/xabber/src/main/java/com/xabber/android/data/extension/references/Mention.java index 06c2e66eac..6c4d872c9b 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/Mention.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/Mention.java @@ -17,7 +17,9 @@ public Type getType() { @Override public void appendToXML(XmlStringBuilder xml) { - xml.element(ELEMENT_URI, uri); + if (uri != null && uri.isEmpty()) { + xml.element(ELEMENT_URI, uri); + } } public String getUri() { diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/Quote.java b/xabber/src/main/java/com/xabber/android/data/extension/references/Quote.java index e3ddb2aba5..b59358c9a0 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/Quote.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/Quote.java @@ -17,7 +17,9 @@ public Type getType() { @Override public void appendToXML(XmlStringBuilder xml) { - xml.element(ELEMENT_MARKER, marker); + if (marker != null && !marker.isEmpty()) { + xml.element(ELEMENT_MARKER, marker); + } } public String getMarker() { diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java index ae0ad5baeb..a0ce1cb0ca 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java @@ -68,7 +68,7 @@ public ReferenceElement parse(XmlPullParser parser, int initialDepth) throws Exc } } - int begin = 0, end = 0, del = 0; + int begin = 0, end = 0; if (beginS != null && !beginS.isEmpty()) begin = Integer.valueOf(beginS); if (endS != null && !endS.isEmpty()) end = Integer.valueOf(endS); From 628366f619ea393c4370468584f2276076c38c68 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 25 Jun 2019 15:54:10 +0500 Subject: [PATCH 193/237] Fixed order of crowdfunding messages --- .../com/xabber/android/data/http/CrowdfundingManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/http/CrowdfundingManager.java b/xabber/src/main/java/com/xabber/android/data/http/CrowdfundingManager.java index 3a7d7826ba..409032af9e 100644 --- a/xabber/src/main/java/com/xabber/android/data/http/CrowdfundingManager.java +++ b/xabber/src/main/java/com/xabber/android/data/http/CrowdfundingManager.java @@ -158,7 +158,7 @@ public RealmResults getMessagesWithDelay(int delay) { Realm realm = RealmManager.getInstance().getNewRealm(); return realm.where(CrowdfundingMessage.class) .lessThanOrEqualTo("delay", delay) - .findAllSorted("timestamp"); + .findAllSorted("receivedTimestamp"); } public void removeDelay(int delay) { @@ -176,7 +176,7 @@ public void removeDelay(int delay) { public CrowdfundingMessage getLastMessageFromRealm() { Realm realm = RealmManager.getInstance().getNewRealm(); - RealmResults messages = realm.where(CrowdfundingMessage.class).findAllSorted("timestamp"); + RealmResults messages = realm.where(CrowdfundingMessage.class).findAllSorted("receivedTimestamp"); if (messages != null && !messages.isEmpty()) return messages.last(); else return null; } @@ -185,7 +185,7 @@ public CrowdfundingMessage getLastNotDelayedMessageFromRealm() { Realm realm = RealmManager.getInstance().getNewRealm(); RealmResults messages = realm.where(CrowdfundingMessage.class) .equalTo("delay", 0) - .findAllSorted("timestamp"); + .findAllSorted("receivedTimestamp"); if (messages != null && !messages.isEmpty()) return messages.last(); else return null; } @@ -232,7 +232,7 @@ public void markMessagesAsRead(String[] ids) { private void removeAllMessages() { Realm realm = RealmManager.getInstance().getNewRealm(); - RealmResults messages = realm.where(CrowdfundingMessage.class).findAllSorted("timestamp"); + RealmResults messages = realm.where(CrowdfundingMessage.class).findAll(); realm.beginTransaction(); for (CrowdfundingMessage message : messages) message.deleteFromRealm(); From 785308bae156d71fd9f4331949c35d6ae8c39cc4 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 25 Jun 2019 16:16:31 +0500 Subject: [PATCH 194/237] Changes in autolink rules in crowdfunding messages --- .../res/layout/item_message_crowdfunding.xml | 150 +++++++++++++++++ .../item_message_incoming_crowdfunding.xml | 2 +- ...m_message_incoming_noflex_crowdfunding.xml | 2 +- .../item_message_noflex_crowdfunding.xml | 154 ++++++++++++++++++ 4 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 xabber/src/main/res/layout/item_message_crowdfunding.xml create mode 100644 xabber/src/main/res/layout/item_message_noflex_crowdfunding.xml diff --git a/xabber/src/main/res/layout/item_message_crowdfunding.xml b/xabber/src/main/res/layout/item_message_crowdfunding.xml new file mode 100644 index 0000000000..dac350681e --- /dev/null +++ b/xabber/src/main/res/layout/item_message_crowdfunding.xml @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xabber/src/main/res/layout/item_message_incoming_crowdfunding.xml b/xabber/src/main/res/layout/item_message_incoming_crowdfunding.xml index 7aa0790c38..da517c6180 100644 --- a/xabber/src/main/res/layout/item_message_incoming_crowdfunding.xml +++ b/xabber/src/main/res/layout/item_message_incoming_crowdfunding.xml @@ -45,7 +45,7 @@ layout="@layout/forwarded_layout" android:visibility="gone" /> - + diff --git a/xabber/src/main/res/layout/item_message_incoming_noflex_crowdfunding.xml b/xabber/src/main/res/layout/item_message_incoming_noflex_crowdfunding.xml index 8dbc289b16..3a26b9c969 100644 --- a/xabber/src/main/res/layout/item_message_incoming_noflex_crowdfunding.xml +++ b/xabber/src/main/res/layout/item_message_incoming_noflex_crowdfunding.xml @@ -45,7 +45,7 @@ layout="@layout/forwarded_layout" android:visibility="gone" /> - + diff --git a/xabber/src/main/res/layout/item_message_noflex_crowdfunding.xml b/xabber/src/main/res/layout/item_message_noflex_crowdfunding.xml new file mode 100644 index 0000000000..6d769c4da5 --- /dev/null +++ b/xabber/src/main/res/layout/item_message_noflex_crowdfunding.xml @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From d497be06225bc940e1405407c1c2e698360d9846 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 25 Jun 2019 18:21:21 +0500 Subject: [PATCH 195/237] Fixed ConcurrentModificationException in getEnabledAccount --- .../android/data/account/AccountManager.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java index 5d5ce0bf21..ccb48323f5 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java @@ -750,21 +750,21 @@ public void setEnabled(AccountJid account, boolean enabled) { * @return List of enabled accounts. */ public Collection getEnabledAccounts() { - Collection accounts = Collections.unmodifiableCollection(accountItems.values()); + Map accountsCopy = new HashMap<>(accountItems); List enabledAccounts = new ArrayList<>(); - for (AccountItem accountItem : accounts) { + for (AccountItem accountItem : accountsCopy.values()) { if (accountItem.isEnabled()) { AccountJid accountJid = accountItem.getAccount(); accountJid.setOrder(accountItem.getOrder()); enabledAccounts.add(accountJid); } } - return Collections.unmodifiableCollection(enabledAccounts); } public Collection getCachedEnabledAccounts() { - return Collections.unmodifiableCollection(cachedEnabledAccounts); + List copyCachedEnabledAccounts = new ArrayList<>(cachedEnabledAccounts); + return Collections.unmodifiableCollection(copyCachedEnabledAccounts); } public boolean hasAccounts() { @@ -781,11 +781,13 @@ public boolean checkAccounts() { * @return List of all accounts including disabled. */ public Collection getAllAccounts() { - return Collections.unmodifiableCollection(accountItems.keySet()); + Map accountsCopy = new HashMap<>(accountItems); + return Collections.unmodifiableCollection(accountsCopy.keySet()); } public Collection getAllAccountItems() { - return Collections.unmodifiableCollection(accountItems.values()); + Map accountsCopy = new HashMap<>(accountItems); + return Collections.unmodifiableCollection(accountsCopy.values()); } public CommonState getCommonState() { From a3de10320f86d38b937610c48d86cfcbd0b3b33f Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 25 Jun 2019 18:58:09 +0500 Subject: [PATCH 196/237] Fixed ConcurrentModificationException --- .../com/xabber/android/data/entity/NestedMap.java | 5 +++++ .../com/xabber/android/data/roster/RosterManager.java | 11 +++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/entity/NestedMap.java b/xabber/src/main/java/com/xabber/android/data/entity/NestedMap.java index b2b354b68a..8ae2e2f84b 100644 --- a/xabber/src/main/java/com/xabber/android/data/entity/NestedMap.java +++ b/xabber/src/main/java/com/xabber/android/data/entity/NestedMap.java @@ -20,6 +20,7 @@ import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Set; /** * Map of map with string value as keys for both maps. @@ -130,6 +131,10 @@ public void addAll(NestedMap nestedMap) { put(entry.getFirst(), entry.getSecond(), entry.getValue()); } + public Set keySet() { + return map.keySet(); + } + /** * Entry stored in {@link NestedMap}. * diff --git a/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java b/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java index 673a06d2b4..fe3258b822 100644 --- a/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java +++ b/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java @@ -60,6 +60,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Set; @@ -161,11 +162,17 @@ public boolean isSubscribed(AccountJid account, UserJid user) { } public Collection getAccountRosterContacts(final AccountJid accountJid) { - return Collections.unmodifiableCollection(rosterContacts.getNested(accountJid.toString()).values()); + List contactsCopy = new ArrayList<>(rosterContacts.getNested(accountJid.toString()).values()); + return Collections.unmodifiableCollection(contactsCopy); } public Collection getAllContacts() { - return Collections.unmodifiableCollection(rosterContacts.values()); + List contactsCopy = new ArrayList<>(); + Set keys = new HashSet<>(rosterContacts.keySet()); + for (String key : keys) { + contactsCopy.addAll(rosterContacts.getNested(key).values()); + } + return Collections.unmodifiableCollection(contactsCopy); } void onContactsAdded(final AccountJid account, Collection addresses) { From 06d949d7846bf1c05460af64332b2ae7c88cb447 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 25 Jun 2019 19:01:07 +0500 Subject: [PATCH 197/237] Up version to 627 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 413ec1eff2..064cbfbbf3 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 626 - versionName '2.6.4(626)' + versionCode 627 + versionName '2.6.4(627)' manifestPlaceholders = [crashlytics:getLocalProperty("crashlytics.key")] } From 80698db11cca51956c73792565d27b08cdabcf77 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Wed, 26 Jun 2019 18:29:41 +0500 Subject: [PATCH 198/237] Some fixes in NextMamManager --- .../xabber/android/data/extension/mam/NextMamManager.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java index 72fd5f0270..f122b08ea1 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/NextMamManager.java @@ -443,6 +443,10 @@ private void loadMissedMessages(Realm realm, AccountItem accountItem, AbstractCh m1.setPreviousId(savedMessages.get(savedMessages.size() - 1).getArchivedId()); realm.commitTransaction(); } + } else { + realm.beginTransaction(); + m1.setPreviousId(m2.getArchivedId()); + realm.commitTransaction(); } } } @@ -751,7 +755,7 @@ private List saveOrUpdateMessages(Realm realm, final Collection Date: Wed, 26 Jun 2019 18:39:49 +0500 Subject: [PATCH 199/237] Up version to 628 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 064cbfbbf3..c71a8fbb1d 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 627 - versionName '2.6.4(627)' + versionCode 628 + versionName '2.6.4(628)' manifestPlaceholders = [crashlytics:getLocalProperty("crashlytics.key")] } From 0d677e9141e12fa0287b0b3d0299c299dde7760e Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 27 Jun 2019 12:24:23 +0500 Subject: [PATCH 200/237] Text no more need to be hided if message have attachments. --- .../ui/adapter/chat/FileMessageVH.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/FileMessageVH.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/FileMessageVH.java index 17a1d2cc49..86378fc5b9 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/FileMessageVH.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/FileMessageVH.java @@ -90,7 +90,7 @@ protected void setupImageOrFile(MessageItem messageItem, Context context) { messageImage.setVisibility(View.GONE); imageGridContainer.removeAllViews(); imageGridContainer.setVisibility(View.GONE); - messageText.setVisibility(View.VISIBLE); + //messageText.setVisibility(View.VISIBLE); if (messageItem.haveAttachments()) { setUpImage(messageItem.getAttachments()); @@ -125,7 +125,7 @@ private void setUpImage(RealmList attachments) { imageGridContainer.addView(imageGridView); imageGridContainer.setVisibility(View.VISIBLE); - messageText.setVisibility(View.GONE); + //messageText.setVisibility(View.GONE); } } @@ -140,7 +140,7 @@ private void setUpFile(RealmList attachments, Context context) { rvFileList.setLayoutManager(layoutManager); FilesAdapter adapter = new FilesAdapter(fileAttachments, this); rvFileList.setAdapter(adapter); - messageText.setVisibility(View.GONE); + //messageText.setVisibility(View.GONE); fileLayout.setVisibility(View.VISIBLE); } } @@ -155,7 +155,7 @@ private void setUpImage(String imagePath, String imageUrl, final String uniqueId if (result) { messageImage.setVisibility(View.VISIBLE); - messageText.setVisibility(View.GONE); + //messageText.setVisibility(View.GONE); } else { final Realm realm = MessageDatabaseManager.getInstance().getRealmUiThread(); realm.executeTransactionAsync(new Realm.Transaction() { @@ -181,7 +181,7 @@ public void execute(Realm realm) { @Override public boolean onException(Exception e, String model, Target target, boolean isFirstResource) { messageImage.setVisibility(View.GONE); - messageText.setVisibility(View.VISIBLE); + //messageText.setVisibility(View.VISIBLE); return true; } @@ -193,7 +193,7 @@ public boolean onResourceReady(GlideDrawable resource, String model, Target Date: Fri, 28 Jun 2019 14:59:26 +0500 Subject: [PATCH 201/237] Added parsing markup.url and mention references. Added ClickSpan and ClickTagHandler --- .../references/ReferencesManager.java | 35 ++++-- .../android/ui/adapter/chat/MessageVH.java | 8 +- .../com/xabber/android/ui/text/ClickSpan.java | 30 +++++ .../android/ui/text/ClickTagHandler.java | 103 ++++++++++++++++++ 4 files changed, 167 insertions(+), 9 deletions(-) create mode 100644 xabber/src/main/java/com/xabber/android/ui/text/ClickSpan.java create mode 100644 xabber/src/main/java/com/xabber/android/ui/text/ClickTagHandler.java diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index 7e1ee93eca..b1a93affb3 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -21,9 +21,6 @@ import javax.annotation.Nonnull; -import io.realm.RealmList; -import io.realm.RealmResults; - public class ReferencesManager { @Nonnull @@ -95,9 +92,9 @@ public static Pair modifyBodyWithReferences(Message message, Str // encode HTML and split into chars String[] chars = stringToChars(TextUtils.htmlEncode(body)); - // modify chars with references except markup + // modify chars with references except markup and mention for (ReferenceElement reference : references) { - if (!(reference instanceof Markup)) + if (!(reference instanceof Markup) && !(reference instanceof Mention)) chars = modifyBodyWithReferences(chars, reference); } @@ -105,9 +102,9 @@ public static Pair modifyBodyWithReferences(Message message, Str String regularBody = Html.fromHtml(charsToString(chars).replace("\n", "
")).toString(); String markupBody = null; - // modify chars with markup references + // modify chars with markup and mention references for (ReferenceElement reference : references) { - if (reference instanceof Markup) + if (reference instanceof Markup || reference instanceof Mention) chars = modifyBodyWithReferences(chars, reference); } markupBody = charsToString(chars); @@ -167,6 +164,9 @@ private static String[] modifyBodyWithReferences(String[] chars, ReferenceElemen case quote: chars = removeInLine(begin, end, chars, (Quote) reference); break; + case mention: + chars = mention(begin, end, chars, (Mention) reference); + break; } return chars; } @@ -210,6 +210,27 @@ private static String[] markup(int begin, int end, String[] source, Markup refer builderOpen.append(""); builderClose.append(new StringBuilder("").reverse()); } + if (reference.getUri() != null && !reference.getUri().isEmpty()) { + builderOpen.append(""); + builderClose.append(new StringBuilder("").reverse()); + } + source[begin] = builderOpen.append(source[begin]).toString(); + builderClose.append(new StringBuilder(source[end]).reverse()); + source[end] = builderClose.reverse().toString(); + return source; + } + + private static String[] mention(int begin, int end, String[] source, Mention reference) { + StringBuilder builderOpen = new StringBuilder(); + StringBuilder builderClose = new StringBuilder(); + if (reference.getUri() != null && !reference.getUri().isEmpty()) { + builderOpen.append(""); + builderClose.append(new StringBuilder("").reverse()); + } source[begin] = builderOpen.append(source[begin]).toString(); builderClose.append(new StringBuilder(source[end]).reverse()); source[end] = builderClose.reverse().toString(); diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java index 4006c70910..9dfb778ab4 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java @@ -15,7 +15,6 @@ import android.widget.TextView; import com.amulyakhare.textdrawable.util.ColorGenerator; -import com.google.android.gms.common.util.ArrayUtils; import com.xabber.android.R; import com.xabber.android.data.database.MessageDatabaseManager; import com.xabber.android.data.database.messagerealm.MessageItem; @@ -23,6 +22,7 @@ import com.xabber.android.data.log.LogManager; import com.xabber.android.ui.color.ColorManager; import com.xabber.android.ui.fragment.ChatFragment; +import com.xabber.android.ui.text.ClickTagHandler; import com.xabber.android.utils.StringUtils; import java.util.Arrays; @@ -96,7 +96,10 @@ public void bind(MessageItem messageItem, MessagesAdapter.MessageExtraData extra } if (messageItem.getMarkupText() != null && !messageItem.getMarkupText().isEmpty()) - messageText.setText(Html.fromHtml(messageItem.getMarkupText().replace("\n", "
"))); + messageText.setText(Html.fromHtml( + messageItem.getMarkupText().replace("\n", "
"), + null, new ClickTagHandler(extraData.getContext())), + TextView.BufferType.SPANNABLE); else messageText.setText(messageItem.getText()); if (OTRManager.getInstance().isEncrypted(messageItem.getText())) { if (extraData.isShowOriginalOTR()) @@ -107,6 +110,7 @@ public void bind(MessageItem messageItem, MessagesAdapter.MessageExtraData extra messageText.setVisibility(View.VISIBLE); messageNotDecrypted.setVisibility(View.GONE); } + messageText.setMovementMethod(LinkMovementMethod.getInstance()); String time = StringUtils.getTimeText(new Date(messageItem.getTimestamp())); diff --git a/xabber/src/main/java/com/xabber/android/ui/text/ClickSpan.java b/xabber/src/main/java/com/xabber/android/ui/text/ClickSpan.java new file mode 100644 index 0000000000..c4f8583d27 --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/ui/text/ClickSpan.java @@ -0,0 +1,30 @@ +package com.xabber.android.ui.text; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.text.style.ClickableSpan; +import android.view.View; + +public class ClickSpan extends ClickableSpan { + + private final String url; + private final Context context; + + public ClickSpan(String url, Context context) { + this.url = url; + this.context = context; + } + + @Override + public void onClick(View view) { + if (url != null && context != null) { + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + context.startActivity(browserIntent); + } + } + + public String getUrl() { + return url; + } +} diff --git a/xabber/src/main/java/com/xabber/android/ui/text/ClickTagHandler.java b/xabber/src/main/java/com/xabber/android/ui/text/ClickTagHandler.java new file mode 100644 index 0000000000..44c6017d5a --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/ui/text/ClickTagHandler.java @@ -0,0 +1,103 @@ +package com.xabber.android.ui.text; + +import android.content.Context; +import android.text.Editable; +import android.text.Html; +import android.text.Spannable; +import android.util.Log; + +import org.xml.sax.XMLReader; + +import java.lang.reflect.Field; + +public class ClickTagHandler implements Html.TagHandler { + + private final static String FIELD_NEW_ELEMENT = "theNewElement"; + private final static String FIELD_ATTS = "theAtts"; + private final static String FIELD_DATA = "data"; + private final static String FIELD_LENGTH = "length"; + private final static String ATTRIBUTE_URI = "uri"; + private final static String TAG = "click"; + + private Context context; + + public ClickTagHandler(Context context) { + this.context = context; + } + + @Override + public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) { + if (tag.equalsIgnoreCase(TAG)) { + processTag(opening, output, xmlReader); + } + } + + private void processTag(boolean opening, Editable output, XMLReader xmlReader) { + int len = output.length(); + + if (opening) { + String uri = getAttrubute(xmlReader, ATTRIBUTE_URI); + output.setSpan(new ClickSpan(uri, context), len, len, Spannable.SPAN_MARK_MARK); + } else { + Object obj = getLast(output, ClickSpan.class); + int where = output.getSpanStart(obj); + String uri = null; + + if (obj instanceof ClickSpan) { + uri = ((ClickSpan)obj).getUrl(); + } + + output.removeSpan(obj); + + if (where != len && uri != null) { + output.setSpan(new ClickSpan(uri, context), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + } + + private Object getLast(Editable text, Class kind) { + Object[] objs = text.getSpans(0, text.length(), kind); + + if (objs.length == 0) { + return null; + } else { + for(int i = objs.length;i>0;i--) { + if(text.getSpanFlags(objs[i-1]) == Spannable.SPAN_MARK_MARK) { + return objs[i-1]; + } + } + return null; + } + } + + private String getAttrubute(XMLReader xmlReader, String attrName) { + String attribute = null; + try { + Field elementField = xmlReader.getClass().getDeclaredField(FIELD_NEW_ELEMENT); + elementField.setAccessible(true); + Object element = elementField.get(xmlReader); + + Field attsField = element.getClass().getDeclaredField(FIELD_ATTS); + attsField.setAccessible(true); + Object atts = attsField.get(element); + + Field dataField = atts.getClass().getDeclaredField(FIELD_DATA); + dataField.setAccessible(true); + String[] data = (String[]) dataField.get(atts); + + Field lengthField = atts.getClass().getDeclaredField(FIELD_LENGTH); + lengthField.setAccessible(true); + int length = (Integer) lengthField.get(atts); + + for (int i = 0; i < length; i++) { + if (attrName.equals(data[i * 5 + 1])) { + attribute = data[i * 5 + 4]; + } + } + } catch (NoSuchFieldException | IllegalAccessException | NullPointerException e) { + Log.d(ClickTagHandler.class.getSimpleName(), + "Error on getting attribute '" + attrName + "': " + e.toString()); + } + return attribute; + } +} From c5bd61aacfe61a961551f4e1f98affc4cbc3196b Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 28 Jun 2019 15:29:18 +0500 Subject: [PATCH 202/237] Added tests for Markup.url and Mention --- .../references/ReferencesManagerTest.java | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java index f6c9a11dfe..eb72e5b027 100644 --- a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java +++ b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java @@ -18,8 +18,8 @@ @Config(application = TestApplication.class) public class ReferencesManagerTest { - private String body1, body2, body3, body4, body5, body6; - private Message message1, message2, message3, message4, message5, message6; + private String body1, body2, body3, body4, body5, body6, body7, body8; + private Message message1, message2, message3, message4, message5, message6, message7, message8; @Before public void setUp() throws Exception { @@ -67,6 +67,20 @@ public void setUp() throws Exception { message6 = new Message("test@jabber.com", body6); message6.addExtension(new Markup(13, 18, true, false, false, false, null)); + + // ------- + + body7 = "Тест форматирования текста"; + + message7 = new Message("test@jabber.com", body7); + message7.addExtension(new Markup(20, 26, false, false, false, false, "www.xabber.com")); + + // ------- + + body8 = "Пользователь, привет!"; + + message8 = new Message("test@jabber.com", body8); + message8.addExtension(new Mention(0, 11, "xmpp:test@jabber.com")); } @Test @@ -114,4 +128,18 @@ public void modifyBodyWithReferences6() { assertEquals(">> 😄😃😀 привет", result.first); assertEquals(">> 😄😃😀 привет", result.second); } + + @Test + public void modifyBodyWithReferences7() { + Pair result = ReferencesManager.modifyBodyWithReferences(message7, body7); + assertEquals("Тест форматирования текста", result.first); + assertEquals("Тест форматирования текста", result.second); + } + + @Test + public void modifyBodyWithReferences8() { + Pair result = ReferencesManager.modifyBodyWithReferences(message8, body8); + assertEquals("Пользователь, привет!", result.first); + assertEquals("Пользователь, привет!", result.second); + } } \ No newline at end of file From ca5200c3b4b33bfe34270e202f58fe13b86150c5 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 28 Jun 2019 15:50:21 +0500 Subject: [PATCH 203/237] Fixed bug with custom tag at start of string --- .../data/extension/references/ReferencesManager.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index b1a93affb3..9c4fb13a37 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -211,7 +211,9 @@ private static String[] markup(int begin, int end, String[] source, Markup refer builderClose.append(new StringBuilder("").reverse()); } if (reference.getUri() != null && !reference.getUri().isEmpty()) { - builderOpen.append(""); builderClose.append(new StringBuilder("").reverse()); @@ -226,7 +228,9 @@ private static String[] mention(int begin, int end, String[] source, Mention ref StringBuilder builderOpen = new StringBuilder(); StringBuilder builderClose = new StringBuilder(); if (reference.getUri() != null && !reference.getUri().isEmpty()) { - builderOpen.append(""); builderClose.append(new StringBuilder("").reverse()); From 22d49092a26501ea29aa8a60892e6b1d89c52c41 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 28 Jun 2019 17:17:35 +0500 Subject: [PATCH 204/237] Added color background to mention Added type of click span --- .../references/ReferencesManager.java | 5 ++++ .../com/xabber/android/ui/text/ClickSpan.java | 17 ++++++++++--- .../android/ui/text/ClickTagHandler.java | 25 +++++++++++++++---- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index 9c4fb13a37..f50aa7e356 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -6,6 +6,7 @@ import com.xabber.android.data.database.messagerealm.Attachment; import com.xabber.android.data.database.messagerealm.MessageItem; +import com.xabber.android.ui.text.ClickSpan; import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.Message; @@ -215,6 +216,8 @@ private static String[] markup(int begin, int end, String[] source, Markup refer // https://stackoverflow.com/questions/23568481/weird-taghandler-behavior-detecting-opening-and-closing-tags builderOpen.append("‍"); builderClose.append(new StringBuilder("").reverse()); } @@ -232,6 +235,8 @@ private static String[] mention(int begin, int end, String[] source, Mention ref // https://stackoverflow.com/questions/23568481/weird-taghandler-behavior-detecting-opening-and-closing-tags builderOpen.append("‍"); builderClose.append(new StringBuilder("").reverse()); } diff --git a/xabber/src/main/java/com/xabber/android/ui/text/ClickSpan.java b/xabber/src/main/java/com/xabber/android/ui/text/ClickSpan.java index c4f8583d27..39b5844c33 100644 --- a/xabber/src/main/java/com/xabber/android/ui/text/ClickSpan.java +++ b/xabber/src/main/java/com/xabber/android/ui/text/ClickSpan.java @@ -8,23 +8,34 @@ public class ClickSpan extends ClickableSpan { + public final static String TYPE_HYPERLINK = "hyperlink"; + public final static String TYPE_MENTION = "mention"; + private final String url; + private final String type; private final Context context; - public ClickSpan(String url, Context context) { + public ClickSpan(String url, String type, Context context) { this.url = url; + this.type = type; this.context = context; } @Override public void onClick(View view) { if (url != null && context != null) { - Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - context.startActivity(browserIntent); + if (TYPE_HYPERLINK.equals(type)) { + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + context.startActivity(browserIntent); + } } } public String getUrl() { return url; } + + public String getType() { + return type; + } } diff --git a/xabber/src/main/java/com/xabber/android/ui/text/ClickTagHandler.java b/xabber/src/main/java/com/xabber/android/ui/text/ClickTagHandler.java index 44c6017d5a..fccaaaf604 100644 --- a/xabber/src/main/java/com/xabber/android/ui/text/ClickTagHandler.java +++ b/xabber/src/main/java/com/xabber/android/ui/text/ClickTagHandler.java @@ -4,8 +4,12 @@ import android.text.Editable; import android.text.Html; import android.text.Spannable; +import android.text.style.BackgroundColorSpan; +import android.text.style.ForegroundColorSpan; import android.util.Log; +import com.xabber.android.R; + import org.xml.sax.XMLReader; import java.lang.reflect.Field; @@ -17,12 +21,15 @@ public class ClickTagHandler implements Html.TagHandler { private final static String FIELD_DATA = "data"; private final static String FIELD_LENGTH = "length"; private final static String ATTRIBUTE_URI = "uri"; + private final static String ATTRIBUTE_TYPE = "type"; private final static String TAG = "click"; private Context context; + private int backgroundColor; - public ClickTagHandler(Context context) { + public ClickTagHandler(Context context, int backgroundColor) { this.context = context; + this.backgroundColor = backgroundColor; } @Override @@ -37,20 +44,28 @@ private void processTag(boolean opening, Editable output, XMLReader xmlReader) { if (opening) { String uri = getAttrubute(xmlReader, ATTRIBUTE_URI); - output.setSpan(new ClickSpan(uri, context), len, len, Spannable.SPAN_MARK_MARK); + String type = getAttrubute(xmlReader, ATTRIBUTE_TYPE); + output.setSpan(new ClickSpan(uri, type, context), len, len, Spannable.SPAN_MARK_MARK); } else { Object obj = getLast(output, ClickSpan.class); int where = output.getSpanStart(obj); - String uri = null; + String uri = null, type = null; if (obj instanceof ClickSpan) { uri = ((ClickSpan)obj).getUrl(); + type = ((ClickSpan)obj).getType(); } output.removeSpan(obj); - if (where != len && uri != null) { - output.setSpan(new ClickSpan(uri, context), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + if (where != len && uri != null && type != null) { + output.setSpan(new ClickSpan(uri, type, context), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + + if (ClickSpan.TYPE_MENTION.equals(type)) { + output.setSpan(new BackgroundColorSpan(backgroundColor), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + output.setSpan(new ForegroundColorSpan(context.getResources().getColor(R.color.black_text)), + where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } } } } From bcf624156f421b67233bbca740cfc708abde7b67 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 28 Jun 2019 17:18:48 +0500 Subject: [PATCH 205/237] Set color of mention --- .../android/ui/adapter/chat/ForwardedAdapter.java | 2 +- .../xabber/android/ui/adapter/chat/MessageVH.java | 4 ++-- .../android/ui/adapter/chat/MessagesAdapter.java | 14 +++++++++++--- .../android/ui/fragment/ForwardedFragment.java | 6 ++++-- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/ForwardedAdapter.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/ForwardedAdapter.java index 56c9f79ae9..2a256e299c 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/ForwardedAdapter.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/ForwardedAdapter.java @@ -95,7 +95,7 @@ public void onBindViewHolder(final BasicMessageVH holder, int position) { MessagesAdapter.MessageExtraData extraData = new MessagesAdapter.MessageExtraData( null, null, null, this.extraData.getContext(), messageItem.getOriginalFrom(), - this.extraData.getColorStateList(), this.extraData.getAccountMainColor(), + this.extraData.getColorStateList(), this.extraData.getAccountMainColor(), this.extraData.getMentionColor(), false, false, false, false, false, false); final int viewType = getItemViewType(position); diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java index 9dfb778ab4..433ea4e6be 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java @@ -98,8 +98,8 @@ public void bind(MessageItem messageItem, MessagesAdapter.MessageExtraData extra if (messageItem.getMarkupText() != null && !messageItem.getMarkupText().isEmpty()) messageText.setText(Html.fromHtml( messageItem.getMarkupText().replace("\n", "
"), - null, new ClickTagHandler(extraData.getContext())), - TextView.BufferType.SPANNABLE); + null, new ClickTagHandler(extraData.getContext(), + extraData.getMentionColor())), TextView.BufferType.SPANNABLE); else messageText.setText(messageItem.getText()); if (OTRManager.getInstance().isEncrypted(messageItem.getText())) { if (extraData.isShowOriginalOTR()) diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessagesAdapter.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessagesAdapter.java index ee07266826..ae1e1015be 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessagesAdapter.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessagesAdapter.java @@ -53,6 +53,7 @@ public class MessagesAdapter extends RealmRecyclerViewAdapter 0) { ForwardedAdapter adapter = new ForwardedAdapter(forwardedMessages, extraData); From 07e1cb71ab820ccc94614b33e68bae8ef61ebbe0 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 28 Jun 2019 17:23:41 +0500 Subject: [PATCH 206/237] Update tests for markup and mention --- .../data/extension/references/ReferencesManagerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java index eb72e5b027..4645493bde 100644 --- a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java +++ b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java @@ -133,13 +133,13 @@ public void modifyBodyWithReferences6() { public void modifyBodyWithReferences7() { Pair result = ReferencesManager.modifyBodyWithReferences(message7, body7); assertEquals("Тест форматирования текста", result.first); - assertEquals("Тест форматирования текста", result.second); + assertEquals("Тест форматирования ‍текста", result.second); } @Test public void modifyBodyWithReferences8() { Pair result = ReferencesManager.modifyBodyWithReferences(message8, body8); assertEquals("Пользователь, привет!", result.first); - assertEquals("Пользователь, привет!", result.second); + assertEquals("‍Пользователь, привет!", result.second); } } \ No newline at end of file From 1df5f2df16065ca17b73a4cdf983fbdcbb3598f6 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 28 Jun 2019 19:09:35 +0500 Subject: [PATCH 207/237] Up version to 629 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index c71a8fbb1d..2377fe4876 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 628 - versionName '2.6.4(628)' + versionCode 629 + versionName '2.6.4(629)' manifestPlaceholders = [crashlytics:getLocalProperty("crashlytics.key")] } From 264360227c1f41c72ad214ef25d26efca5706333 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 1 Jul 2019 11:40:10 +0500 Subject: [PATCH 208/237] Added settings to in-chat sound alert --- .../java/com/xabber/android/data/SettingsManager.java | 3 +-- .../com/xabber/android/ui/fragment/ChatFragment.java | 2 +- .../src/main/res/values-ru-rRU/preference_editor.xml | 1 + xabber/src/main/res/values/preference_editor.xml | 1 + xabber/src/main/res/xml/preference_notifications.xml | 11 +++++++++++ 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/SettingsManager.java b/xabber/src/main/java/com/xabber/android/data/SettingsManager.java index 082c6838dc..3dd9edb6a9 100644 --- a/xabber/src/main/java/com/xabber/android/data/SettingsManager.java +++ b/xabber/src/main/java/com/xabber/android/data/SettingsManager.java @@ -367,9 +367,8 @@ public static boolean eventsOnMuc() { // R.bool.events_in_app_preview_default); // } - @Deprecated public static boolean eventsInChatSounds() { - return getBoolean(R.string.events_in_chat_sounds_key, + return getNotifBoolean(R.string.events_in_chat_sounds_key, R.bool.events_in_chat_sounds_default); } diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java index bfd9da3454..bb3a17af7a 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java @@ -658,7 +658,7 @@ public void onEvent(MessageUpdateEvent event) { public void onEvent(NewIncomingMessageEvent event) { if (event.getAccount().equals(account) && event.getUser().equals(user)) { listener.playIncomingAnimation(); - playIncomingSound(); + if (SettingsManager.eventsInChatSounds()) playIncomingSound(); } } diff --git a/xabber/src/main/res/values-ru-rRU/preference_editor.xml b/xabber/src/main/res/values-ru-rRU/preference_editor.xml index e69a605d81..6e4e78bb5e 100644 --- a/xabber/src/main/res/values-ru-rRU/preference_editor.xml +++ b/xabber/src/main/res/values-ru-rRU/preference_editor.xml @@ -123,6 +123,7 @@ Уведомления в приложении Ключевые фразы Специальные уведомления + Другое Оповещение Уведомлять о новых сообщениях в чатах Оповещение diff --git a/xabber/src/main/res/values/preference_editor.xml b/xabber/src/main/res/values/preference_editor.xml index 9a60e17c18..cd22f90833 100644 --- a/xabber/src/main/res/values/preference_editor.xml +++ b/xabber/src/main/res/values/preference_editor.xml @@ -144,6 +144,7 @@ In-app notification Key phrases Custom notifications + Other Alert Alert about new messages in chats diff --git a/xabber/src/main/res/xml/preference_notifications.xml b/xabber/src/main/res/xml/preference_notifications.xml index 272154309f..9693e0e51c 100644 --- a/xabber/src/main/res/xml/preference_notifications.xml +++ b/xabber/src/main/res/xml/preference_notifications.xml @@ -130,6 +130,17 @@ android:targetClass="com.xabber.android.ui.preferences.PhraseList"/> + + + + + From eb74408522beb0d4fb0576fde374a633b621af0e Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 1 Jul 2019 12:18:15 +0500 Subject: [PATCH 209/237] Added custom alert sound to play on message in chat. Added playing alert sound on sending message. --- .../android/ui/fragment/ChatFragment.java | 51 +++++++----------- xabber/src/main/res/raw/message_alert.wav | Bin 0 -> 63532 bytes 2 files changed, 20 insertions(+), 31 deletions(-) create mode 100644 xabber/src/main/res/raw/message_alert.wav diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java index bb3a17af7a..e865236bfd 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/ChatFragment.java @@ -9,7 +9,6 @@ import android.media.AudioAttributes; import android.media.AudioManager; import android.media.MediaPlayer; -import android.net.Uri; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.FragmentManager; @@ -658,7 +657,7 @@ public void onEvent(MessageUpdateEvent event) { public void onEvent(NewIncomingMessageEvent event) { if (event.getAccount().equals(account) && event.getUser().equals(user)) { listener.playIncomingAnimation(); - if (SettingsManager.eventsInChatSounds()) playIncomingSound(); + playMessageSound(); } } @@ -762,6 +761,7 @@ private void sendMessage() { String text = inputView.getText().toString().trim(); clearInputText(); scrollDown(); + playMessageSound(); if (forwardIds != null && !forwardIds.isEmpty()) { sendForwardMessage(forwardIds, text); @@ -1190,39 +1190,28 @@ public void onAccountsChanged(Collection accounts) { chatMessageAdapter.notifyDataSetChanged(); } - public void playIncomingSound() { - AbstractChat chat = getChat(); - boolean event = false; - Uri soundUri = null; - if (chat instanceof RoomChat) { - event = SettingsManager.eventsOnMuc(); - soundUri = SettingsManager.eventsSoundMuc(); + public void playMessageSound() { + if (!SettingsManager.eventsInChatSounds()) return; + + final MediaPlayer mp; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + AudioAttributes attr = new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) + .setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT).build(); + mp = MediaPlayer.create(getActivity(), R.raw.message_alert, + attr, AudioManager.AUDIO_SESSION_ID_GENERATE); } else { - event = SettingsManager.eventsOnChat(); - soundUri = SettingsManager.eventsSound(); + mp = MediaPlayer.create(getActivity(), R.raw.message_alert); + mp.setAudioStreamType(AudioManager.STREAM_NOTIFICATION); } - if (event) { - final MediaPlayer mp; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - AudioAttributes attr = new AudioAttributes.Builder() - .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) - .setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT).build(); - mp = MediaPlayer.create(getActivity(), soundUri, - null, attr, AudioManager.AUDIO_SESSION_ID_GENERATE); - } else { - mp = MediaPlayer.create(getActivity(), soundUri); - mp.setAudioStreamType(AudioManager.STREAM_NOTIFICATION); + mp.start(); + mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + mp.release(); } - - mp.start(); - mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { - @Override - public void onCompletion(MediaPlayer mediaPlayer) { - mp.release(); - } - }); - } + }); } @Override diff --git a/xabber/src/main/res/raw/message_alert.wav b/xabber/src/main/res/raw/message_alert.wav new file mode 100644 index 0000000000000000000000000000000000000000..f181e4bd63b1fc150c779cf1b34860e16e9a2130 GIT binary patch literal 63532 zcmY(s1)LSt|NnnyZtb!x?6Pz%-61MSNGK(UC3nk$d*@4xTInK^U%oH^&+bGLh^4jrlmT&`yx>D7M7t8Z3Ha=BcF z%XGC{>T)IhVY)o7B-fyUZw_=(Mt_FOvQ1ai_7F_s#(!yU=h?PZ!X{Ov6m0%tF_n$Q zb&r+%ziX_l(*+lmQ~Qd=O2={xQr)!ca=Be$#t`d2)|W=0(fnT@vHsM~y-_It|39*O z?WwQ5!^wH2FXtUsmcFV>2#>f>ImdnJ{oRJD4q{aF8+Rjl3E zJvP4Bo4D8V|J#Q~a_?RLUoRT5-j0IaNv!RA>#lpO4b399GWTYq@;>KH{9iBk<{BHl zMyNks)lMwjo9VszSoCZYG!p%J7=!7Q_mZYyk`e>0M69*gb1dKeUv8|N$_UhEY(4Ld zO6_|YacoXni`d(Z&FlYt>#^OX5yke5+R+=tHc>OpO&$IyQeb)Ldb%_!+Mtp#aGWeT_kcnT8JJyVgWyqIRy+N*<$$%`!^9Myolfl+H$!l-NiEPM$^_ zaDrwVrKHBL85Yp0Myq>-GJ@EM3rN#?2PmJ{-(T4}y&NiFDn$KJTsQaM`1d${o484%`EUn;BC)TU~wWNhcyj5jtr zt(``x^-zxiXDs=|b4k-kWA8wFT>DgIa(Op-q~Ckb`8?_U>8`cXEDP+rl#kWd?g^2r zy{%P@?NQCiCOr!16zhEIT(}*K;pOTl?*9+sxck5-39dpwysI$JgN+tV z@`NFkE4-s|Yc~tSs)g7d*Itcr7BLEuW}-c*`3PU?)M*Ea zmS~*u^rQC@!%Y!qzv>(X>>Q_Ejj4cC?blrABnV^VI`2^DB0yfgolPjP)2MgXNzr-8 zrHTEN3L50@`yrnZjo=>@IAlndtlq$7zoSX(fii z^6595+2oLxM^1oIq>+;2jP9y^mDC*C&n6Vux4GWp`5L+R`qWxvQ%9r7Vt%m|O{a9a z)3fH4!K^c>r+XGx%~P|_VC9r^$EhDBO>3|BrB!gbl&&$~n}hJZ-k-2iVcxP%tIlye z=g7-GN_G`zg>;fj@SMQjigWg;PJ{M(0_B7)?r}9bkFnEV$SGMIEFzp!+*OL!ih)f^ z(T>_K;wlRy(Nk&ClSwN>A7x!BuJWXm8~iQ6?LA~Mrm3r zM!s;8+9^d^5#qvWhErRoB8l=PC|d&1DNF=(MvGFiI6W34udJ&AJtosaah{5~YPwQg zl}W4Sszkgdu`0xClb=ki63^wiRs_mB*GjIcPMYRj(^ZSqYCKn`l^Vn=xa#m+lN$A1 zbqNh=yAruI$*oUL9iRc@Po@2eQ2Wt^$BR*@1lNvT6xWzxz~ zt~^f-|7))eTBuCR z<%u_-&zd~daNX~EkXTL9YPsr>UY}44sLPYaTOFuIsOgNQF4ub0s^*l`s@11#b4H?C zb^oj1#MPK~@8{`0MpKP4_ffx|tEsCQ*Sf^3l2^yogz-O2xrfNF#|R#v_1fgBL~Bx; zIWufPYfZ^%%yTQ?VPf}@(v%V{Y5M^}Lsu8q+(VRV;d%sUM`%L%R+Mc> z*;@2jmp-)~O?Ym=y$+!sISq+5CST)9WySBOUVT6_)7srf`D)Bw^J>Jk25=v>wElIS z@i(AeMQ2RfUsb7DmAPmy#-O6JlG^*#|EsI{YCZK98_~bU(TFx1(xO)Xeqwq%l}Ue) zS!kE(y{LRcde_dXM~w#bYi##Xs|l@X{Z*$jBhyaTzSPdtKB`Tc zc4G<7koJjos#5g!E6}snstjW<15{#ur6{9Zoz?oZQI?dV#8p29s6ejvyZX{zQQyJ{ zI%k?`Y3i%pTC@>c!|If%PHsiccuB4`$kmL?6H}eqPP^5du~(p8eJ5WSrZQ!8srNBkv5fhkG31(S=)fEm+A-%AJ?TWLLs_;~d znU|+dIaaM2G2y}u5~I$NO7n^0xK;%EG{sfnkisp_2_jdh`1r~I-()s$3zpv zO^9M8k|y3s@|Gy<4dyASSDZlxadEAppyKF7sYGdYzsEb@p_M%6-NYnEH&|T!8$=B1 zqn5>`i0Z`T6N8?U0F_B}Mp~ShI68wTVf&)YMKdVDTvLgOT8SFP=tvz_L3^n@Y2{d< z5|oJH&MK^>&SXW>QrKm}@#Uyhlp5O0iKJ9_+O5j^>13y}^F)WV&RR|NqW4jjP?V9B zBF)d}N)yvK3h`#WKpd-Fl$zowlS$JIB^$)3tGKQhN2gs0G-FVvkaGqTSqC4jtA^;cWCPK9wWazh zAAA4eLgL|%1B_WaUi_U($7F~&XS`ZB?Go`Ps;?7d&{kn`RU*aZE zG=81$WcI1}h*I3ej}>Dd#xS+`pd#$p@{H8&Bvv`So5WoFUwSfb>#Wl+ zzF54k@Qlt@GOMF^CfX?6qP-zJrQIXRPNzfIRl8JYU1vh_uVl=a92$kr_>d2!o$~QM zBG3|P34~8$T((Y4QOf(Bdm&b8TKwB?D zUv83nh1g}NsVMSw!cCqp*=GqCDSLx(jWSo98fSPG4ZcOWi`;J@K`G@j`PZp&g?cB* zISt)DYM--Da`JBjH#z@Vq+g_FCiMIoecvTqq4jf&GuP?q4!O5!Px7k9C~n{uJ)ELF zjq@@!uhPpI+P%R2k~0r+2j`sB^Y(G-Xl7^0IcFcR588j*JDqUYK5Xx>x7%Co&7>%{ z!~WMkVsElH*nin;>@C2b_G;oQ>{a&fq^`DqwHMm+?Vs)G_K&1*Bz=wj3wg^Zv%p@$ zb&dUlJ;$DB&!xm1%FU$CGHNa0zSN##Pa|cHJ)8U`_Ht4e(%J&roacn4_F`f)NS#UP z1=LjCg~S)zE1i@dC^yIciM+-3Z}hDZtf%cI&X|8?ESsG9>|(s@?REBA#`G6;*Ew@p zP5xTy?Pac-0QHHdbkc{fDy-YslZiO0A`=R$~n@t=LAV);g|R z>_v=WJ?UzD8|8M|d$|8Y`PI&dHWJ@To>qSk@q>WIx}PV#$3r~ta%$^M?BMAz@8cNh z$9XHq?0xobr{yEmIK7Ej`tJO^Df{JJszSR)l=_>se736`zdjPo{q84{-K5Q?7+i}@C^HKKd_T>M;PZm zU^j5w8S_!nj! zmdK=KVVoF<9}w;memhGm(h8}yEA%V8ca0$VYUwG@et=Y)^o(aw&I#xy9D^96ep7C%qxPpQDsJ#!R($PC7HzY8W zRn7^g+zF?@>{<#5VXHe5HeV$Ys9Y7!VPlLdDhs@Q9~8ja8IZ?I!UY;yFMrbwxWuT*W;~LnvBgLt|oG7K|6E zlK$f0re%i^RT8IbBCDi9`(he&)m55km9)pw)5oM3tzH&+hD-g$>^+i)Vsef&)UtC( zhLcWDyF>GmOeA?nGSY2Er+s$=(EKHHo@7>6$k9BmI%}nQo_5wvYjB&j(B9N8Nq2UL zR`440O(Xp(`8fp1p%OcJjET0(uwkF)zgSwqd#dcb(chPh5Q=?=})srzrkFt zGjGvR?IZ16%|@q2L9uJ>gFDGYucNqY4IdA zj)6t?5kE)1@V55o39!r#(oV4}h4qAa6gvU7+Dq@3h#jL{ore9y57Ew1%Iu}gKId6A zbz%-tLj7qM>on_~Do?mhF}0u(YOFe^+TA*pXNaF8eiP6*(^-w{w5Ru?70^m)|7y(A zvrCICZYPVi)|zV1Yd^`JqVY-kR{jZkRGwt+{a`@pztxh)C(I*x|FDNvbk6kd0<#YvMO zy|ZL4Y4ud2Iz2StsyyizrNfinOFBwvDXWr}N}altmR_y_y1!JQ84`$eeGky?1CBgX zi>FHD)^ngfS7}bAQtclC93C+8X3>Fs)&v|d1OpucO7YY6F2yPhNdEGa!` zYXI@SwD34%d765CNbN%WDOzmpYC}KWXs@R;4~?QHEj&YuT`1ep(H?iDv}$*xPG@2r zD6h1(jI0xF_HuH&QC5AcZH-%Vd6IIPcUwShKMr(ao?4GqPI#2oy6~(VtxRuHI}q>c z%>PMx?7`?C`)`!3simC0fXZ|O`qO_O%Dv3&yV6!ao}Q+R=Ad3LSC z2QYwpSL&&)Ue3s$Cf0`*x;k~#PY33#GHn@Qd&aHNH{-3f4lITrIoA587SwRpt76`Ny4SM>%3xs`-0JGJcHNnE9u6eXAJEB%gSOWDz-4U+Cq{sPhp>8#7nBh8R# zxNKX}_UIbZfJrWv-B#8!>6(-qlc#0NlMjWs2XP9*t$CD@{Y~wsfq}#sldd;L zU9VD7wCfx=S#oCAkh^I)W>=|dglB!i#luUh`C0(tb zQ;EygCF5sgpWS zeI+hP64xdAyGdQW^RuMued^7Nmp?`c@qN<7=xs?ZjO{+9rBP02NBj7+(}q^%BI7#6 zRs7o}QguR(Q{n^&VpWRFWxTJc&ggvg?Z< z5#AC;lPyHLdVwFFMzTxHKCe9*d%N;vlb=YGQKm6gjY~M`CT-;t*ZYwNQUNt?6AwEp z8^cpdmybn`GYawN@|=>ET|RJrcCF+i#U#rJx5m5%b&uJnrJ0tG zP8@M*AY=MUX={rxBkB1Ku)nPHC7fBxE+IZkUM)Hy>Q_2OQ3L6kWrq;XizQqq|?OpiJ2k^Q7f2Prv5xJvxL(Jx7m;@0!%Q=Gd%(#RcWFR6V= z$J(wVWau5Y`>xZVK%=la++8W`t#&o$Qd zj_WJeBw(^@s_PrqEZ20`m#&G#rvRV1esTRw+7IN+c75-fto03~)g&x#+U#CF$i*Iw5?!Vc080!M)(gq_qq={n>(#gp3G zNtu6nI_Ny_BJZf{m}|f51lK*Zwx6>9l6Qy_`)Tor>#*w_aLsjt*kNj(b)Dw<46&m; zUjoj#F1jwb&byA2qTGw*UMBT2saMFqLds=ACJ+E_12+hl$+-pGAY{1GU3a)&=P92u zd0Y#CbXOLT4}`cEkX}H`XI(k2Y|7tt<&vW|vM71ib<>qbyLV~jn$zP2TD!^I&i*&I z1I`>ykaB=o?qiNxwLPrfKZFge`c~e@2Hu3;#vH+Ll&xD{hQgWh9F*=wUZ&zTMMy~xLx?o+gj#$U6GlUbwPFTmSHP&itv$f9p zllxNZ4{JWKz?x&twx(OttS`BKWqkxpvc9lJTkjGZ3%p~E0-gtkSOcvQ)@#;C>s4T= z^*T@etQV~T)(hPG0{yHftR7Z-u1{G{TaR0hS;HvzxYd<1&smRHt-1EM+EU_4@;g~w zh;^h?XRD3Xil@$$ecbA4b*F|>+gk0&X~VU%)s389q<3c|1ITSlOTDSz*6L$D!zlVQ zis!9CjBzMW8s{KVUb9}dUgG%;Mm@%Q-+G(tJ6u1pCX)81^_ex^dXL$DM9MeTROlTE6|g-{h~dH zUGTj9vOUCph3mV(d-iDiGkZMnp*_|93i#aq4vW(d*p6hSn!)`KcG^;`JWBxCc($`U zH$h`pKv%awfwd?1LSaQWWiQyno|Q}>9iOBi-KCMb?NH3i&@5>`?>Ky${09Qi9r59k z5oMEh6DtPo5yvI{OA7R;65NS=L!^6=Cx>j^((%Z{LmCqKP(9!Td0aJg&TkVW#f zuetzjp-$3qNH@@tr|#T)bCsT<1JBYQ^nprAi_p%I><5tk6eW5)^h-3XCr=%L9>lvk zZFNM0(UNlQxVNE)X6Rw0lWE7e4RjEuH-z+W-UK1$=$Mx%N8#GM){w~ zGbYL5(!|LX0jtEkY-BN(4}|#o+u#uKT@D}lcpYu*a1gG+gne>wMgj@5Ai*9FcVn9p?{xJ8!8AHXv+f$s@(fob-)_LpFs zX;>tuvS&WFC$f9K=01t^uZVqPe`-&*|Ht(``+fG#kAoUZbI*@4|b10N3>%)b(TFQ#h;Ha8C1}ybByYYYAM`VmPHO@IM=Y^{zjm)?46x zM7Os<$q&H69D(~d?{E|Qq3;1#7%t!%yhWDFG`xnm1IuN*qCgN3hr#5Ge7Fgp;W2V~ z_85tV?MmP&!6*zQ5y~6ojEY8SqnJ^YSb3uiP{fGmIl(AtlmN;aRg79jHKT@+0^Dab zBHTw>HKVc71ZZxwHXZ>UHR_Z8sL|1AWjt&QFrG1b8c!MRNqL6*Q$}Z_H?c0p^so};eTwgRs7;kZX(RhQ{IAbhN?-(B&6OE6INyZ1j7shAC6yl#6|KmQ@m}Sf{ z#uHz}eI8-HvCvp*EHf4uKN+iy6~vYrYmGI=I%B1=+4#%YVyriI8r!+=;AuN>z}Rmb zH}-NpZ=5soj4b0c&lik~#wp+mF@-b6Nh8-tGj0%1Gp-vUBj3n0ZgS5u?(lq<)T`X@ zIM*|jyF%_I>fAMM(bj3>gmIbF!?bgr=i|mv<1GChC;Ur%A0yC6b~B=_#zw}t#rVhA z#%R|u`n9C)Fn%|FF@AIAv(Z>g>{n9$Aa?<2KQQ<2fM19!bvkP^%~_vWtkbuw(*olw zVpCYbDaO~V*vG8mWZ*O6?;B%S>Cvq9+r}u?eiZNGIioM(X`s8&mG{<_H`>l<%G++l z8-CDe$Xl*wRAsMJH7c;93K?;R&nRFY=CTKG!j+zbFFpXrybq3aD_s62`2HR2?cd=$ zXS#lZ&zu5(IT7jOGdRrmk!vKsh^u@S{&IjrWx8>y+CnK>bK>NAEm|diMR_zyFIx$m zFP~xgvq@%_?o|GElHc_w8;JBsv9B(2krgG8%GxcRsBNX{>2ggee z-VUx=52jxY4wt{lPhhLB@f(>9#uAR63MQZBaE!v!!q1bPoC)CJ55UWBbNv8}{5F{P zbui{o!XR+ri@>v_ygFb|<^3-5Tg_)^&+hyTdlHoN=*_E7YF*^>9CdDp6NP+7V-|4oCQl=!&N$@)+{7zBgZpxYel}#eI zl3j!R6k??bW#EIVl2V<18qr$=xZOt?O&dnn9&V^3)SwR|9|&e2>d=?Z9KL6oJ%Ke5 zU6T)rd~nvWn){)l(oKlI3L8sDCOwb7VUd@We9>e1r^nB+$*sK^u@6cOhYJK_2{v9ebR8yU&piFCgcgMh-ki+C^l!yI|T( z_PC_DG(w2op3SrHY=95}A7_!G)I>0-?ec;}3xP!oIXE>QTw4YVo5($x)MT)43Mr+* zzNJV{AyynH%TqGAIEi|tNUcn|$B4S(Y0YvOoU;%Rp`Rcp?G|IY#dD_XszVK~G1`;P z`MZj&coF(=2)dzpNe+}ey#uLmBlF$L+}A>LB$KaaEtauLt4aHrwOR^2`jfNzvm@Ux zb}i&S4GCX5fG^P!%wT1|bNxv8j;F6#_wUL7j(0Et%Ju`NdJ=SP7UgD;{w>cFsWA(B z_Y>FIoc^iQneNor+xi~(jXu{gmLGv7=n-aCrh6m^Qm<^_)7k;`tD7-Q`x7brwep`V$<%wcm18QJ9Bs8L-B_iooslruqJ(V`o!y>T>s?!N9Vsg{@wBG z2W}oXz4PMEz}C>#*EYVs@$lMXYcH+7zB*%7&Z;#l*RA|`<%E@;S9MucX?2y=W!F|- z``d;!8;)-|w_e6!jC%R2VY!JP*m*wbXsOFM?|=(+Xjt;IGK-n4H0s`byU>$@&_UHrNb zkhrn<#!6diZ>he$=Jua<&E2(o|E~T2JMzJiKTiE|YW&4X7th|fdSgt+xQvzsEepyC zwmaJ%*imOkhh2~C>bS4tzAA@m99nRE$?+p+PoDkp%DgL6Zhw3GLe}N1j={FU2}lTk z_?P-e78zD#d+{yBzbreo?4{IOsh?GwRBb}7PixJpJG<`6`m5_7Z*aCje8Z%M4>xGt z;H`RZ*E?PNSnc;~jIQx)m1nC=uQ0Phx6(aIPbxOK*lUGfEnM1H+9#h_SI`VD%3hc~ zmkSFT^YzWdU?OHZ78>f9%%#-DoS_=w}FM{6FPdw9{|;Gu#;6%Lm=-26zBBaa+w zajfXcxRXoSE0-@^y|DA@KUY(4SH8V7<3Pslyn}g%!iT~h(_@y2D;HO#NYx@IQ;w%p zC{w;na>e9|y{h!CaOa@|wbmbX*3?O>n^X7sdV}j_)J>~d$3=F8g)DG-Y>oKE!hzQ@^_x_aWq@f-iU^UOf569#Do$L zBtMk=bKzeLmxwDKH`+bQT@-F?e`t4TPyT`Y`Z@RKL^I6HUTOW)+TMBm&YoLGZ{^&~ zzxmJ2zi&QttHG^7xBJ{Kb2sJg!1R9U^|NYZy^z~4*9cez!Ehj~@7~6H#(T2j(&L^; z?3_3=`TOKmCH^ciw#-Lm7L;FBzH{p1sWU3isQgydF;!1gJ6mm5^&hH#T76>mQ`Ih2 z`=IIvRsX5Hwet6=(^D^%zf^u+nFVD|l{iu2M)LLKONloUOBYHlRM=O<7coq;qE+2` zJv1Veou8f`pKIi<%lb2GU&ii?SJH>1f137DTD7#wX|JTcl=f2k;PhP?+cQ>X{g%}{ zw^43k)M>Rtsi7~U6QcEy3zED^-ji|1_OfT4%yF0gc_Osc|GFxUYNne~kH*HQ@v9z*4 z^|ak-`_eY1Z%J>K**3FEcHQicazD9LefDT7K3Dp99Y^-?2B4=ephnTN|vEAvH}m&?3ZW^L(pr6-sAvQ&DB z>=I{E&ZhKAekOTpk#CB8nlK@ueO$-5JDyC>Fyz)iG!mU1`aU$YU~s|Pxg&E=WgW_z zmN6;g*R(}x4emC&TlG%8JM(V;e0wgCbSL3X+MPRh2B!^4tC3MFqjgrxtkpSda$e7W zBY#lvrQl1E*CJn{ADU;*H$z77C75l!}@RSiL z+f#O?tWVjJ@<2+jRvDD!pp-y24@8K7wjx(lK)Wt<=pGJft;M20Xe;L%I1{Jsg+YF z=hvJ+a>nI;l)EBtbzZrG@{R|A~D(51+gNOk0y!NxG-7x!=O+un3<`M9ca)e2Q9 zWF-U=zGN-W6}epGOwp4?KTi4}>3GtSq=QNOlHN>uJ!wPHwM919rjNtvzRFxb51lnS|(C5GA{H%C_b1FJXmn3;A;N${73TJ<>&FI z%ai$C^KQo_lEvxUzTo|`x~u~?B}MOqeV1D35(WO3r+#Js|}h3_V$B`hkmv`}h%jrd{y z;r>b9&%ATp^WD>onT9mfA4dNd{U$s;{7-OCuv{QD@O%F1{P*%c&YPI~Mef<0^EvMW z{c@hmnVYjPr*dxP+#A5Dyc2ox1w{(p3XBf8L%z`R@T%~D=u6QmSUO}Q8)=R(&$-XJ z8+jXhpYZkYwf495AN8N~KM>a>?!mamah5;ITl~Vm&-agSn|HnUJo1b4jq72{Q7 zDtf+E(bds^;WhRJ4+pagvJ0x@r{<5!eKq%L_Vw)dvfj<=mHBk$@QmRZf2VIwADKQp zy;XX1?ysd^OTV5zA!B^T;LO39q%A}3@22IFE=sa2h^U%LtK^G9R@~pGb6VaKG?;_2^jl(;G ze+Rn+9t)hyKa)Q+Z)l!BH$L}Z_Mz-$S-)oO&D@z8%E-$Y48&!`XIx1?mmW+{Pk%I{ zb;f33c;>5_?XucuJ(m4=_KP_$=8Vt%BzI@t-n@i@!Ue4ZZ33?ZU*p|>5E>u;EIcGK zG?ExC7M&9PE_yzCDeAZ4tU$CNx-_~d`be~SbYbMj$kp(ra6-6nxOAv&C=xJ(rwc9? z9LYbHzd3Jn-e0-va<}IElXELOBfDO9gY56JzRhZoRXZyy^JeDN%(I!%%s^)MtnOJm zvvy~_pFJkKOU`3CkLI?_ZJ*a7@8$d<`BMs}7HkM?;-?wH!D`{M;YT9PA|0Y_qjjvR z)>W)jZ`mUqzZ3n|iu@kr`=Re->R>CGf(>SCbX)X#EXWy^Gcspb&I>u8<@_(_RL;?y?z!D^!?}Un zzw&<1n~?uO{)~bt1rq}w1!f1o3(gA74s8r?32%&SiL8qL8C_t_vz|j2E${V@k>Ac@ zk2TP5#v@VRLL!$PQ&#lf(GVAc20xC?>&@tx=nt&phVa_(xzNc_VkjZhF4!hGIWU2x z4i=0oc(tH*LDhon{IvWd`A73l=AX(hQBa~_RKaTn;ewokPXprv4TFtv3vh?lhqi`( z3$F-&6`36Qm~+(~yH_=|CGuC8iX2)IUD!-x2716Wqk>t|e9)|IRyNC-1xC=(PCjOI zFxDgC>ifMn&L-Yl#Yf0#Q_95wwcD;%2*K*B7FK8JB z#>?h#bDp`xJZD}sFPoRlyJm*@uX)`3-kf7TZa!(|Qs!IZN24~ny+6?bG(+;0AGmA- zK`U%6!qWB>7Q(7l4aV%Xu7bBR!Oh8532cUsVWpg8S)8MhXt(rz!$4%{1jEm~=NOI5 z`^^jHS+l>pm-~YIjJt=Yhi9>8k;m;dy$^budY|{c;2jEd_jdEP0xVD1v(dBGGXO9> zah_T3dG7n%54um7C(LKe?q(7A&EJhB#A<}f*Lg(l<4D`_t884$#-hvLb zteI*~G`})a++~q$esDMRH1@3bZ1D{84))&l-tmt0jq!Q>KL4lw@%{{dw!d;*jkr;9 zBjV=A&52tR_gCD{am(VS#C;$4X584g_P|a5E&pf0gZ?J|b-vBM?!ISzXT2A^|MR}@ zt?8}o-RarsdEfJ)rHEu9!(Yok%|FYZ=FjtYje9!oC&qCi?qpoy_#*KQ;_Jn?if5I;7)BV+W( zTa0`b)bg>obbpqAoc|MlSzx(u88dyt=l7Yu_1-_7_g=(X)O*`=la>41v)Z$goiX3@ zlV_%9p=X}wkmrD>0B8VD@QU|M?@!*j-s7xToUf3tFR;Y-i|>l>x-aO9`s%TEPx_zm z5A(n5f89UAKay)-e}8``e@A~ge;NN7-#Onx-_O2&yt694%D$c6-QIV-W4*O`bN|r$ zThOUWo^qaZ?o;ls++Vw2bPsk{b60k|aoP$XGh8*Vn12JS%)hwqGEcLsZ*h)XZqr@C zUC#ZayNmlJ_Yn8z?uk&~AKh!*E8Pd&huyc_Y3{o~25`rHgWYh+ebRl*{jYnE`%hpJ zH3qwfy4$(ix=Xv0-9a`%MJZmnV7sv6?2!StC7;j5# zn_a-jqp+%ubH48U4H_bynZ9t;w~+Fm(>Igr8U3GJ7h|9NiE+zIe;`6bFr!{yjY_bjj2d#b9X~uJdxn9RtB#e)O z)>hj4#;j#GS{{PdeZ2jNqixr>topW7T6Nhp_1+p|r|*bv@(r|`U*O3jU#ox7Y-gdT z_CX`7V5w;iX6y(J>cqYnhJEJ^EN|oChCVeWaFr$PQ><=dc^c1-k}c?6qX!nd=Io~0 zMjbTKC9v~&(LZO>_P^-S*PwS@gr@gve1zUcXWAc4X(#*#^eZ`y(0`W4$49>!p|8Ia zp?do2THl0JcKn1oudJGi!E&s7SE@Q$GEoOY<4!f5%0>0?FR+xWelXm%f=8a zoTIVOeF=y94K~f+nD18XgU6WjO{0(*Z&ooYK}qjtlr7EYnbQmAi(rSh%x}!8=3HdN zU(8?4MO>Gdi=pasp!ajk>EwM51)O3|Hor7KGvA}eFjl0$*_-|{~`Z4e}dhX}VA?$)~ ztXea(mRS}4p@^9ezjFpykKDBgyYV99XRM(Uv4xICN*Q6iM34=%D*>5U>Z;Ml+GWPOn*v)0vNn$^H;8eYwpeR=Qn|SwK zV7KqWDkIzfRL<<%_zURQp7bq>yzJ%OEq{{<*cRot(GELYL%44fta}@erk&Q`;FC4* zX7ll!nuwp&2Y86RVZDW?)tmTM^}`G6Swatdvbw^(b-`QfX(#psURyojj=R9Sb+8@< zp2C-_BOYD%fhVh5)vQuLQSfF0!HW8hv?&yx__UH`Y%jj3pH>2-FJ4K(2 zHi@>5mWY;)h9kkqEoAO9k;9QSk(H4-kwuY7k#8a&MLvnV7a0@zFfumsO5~-;V4yG1 z3+NtsD)KDQJJK)GHPS88A<{Y0Cek|6F7hbh5uToiJRE6B&XbgUf|C6rkMqJdVD<49^YE zV>IiKa<+v34Ic?#3|~VE$O?zUp>TX8E>bw+kCcy;j?|9S08*J>)5rsn`<&VLWBp!5 zNAv~j`#mzwvdD_as>tfdp2$Ad|7;{Zk^=-I*^xlR8};*kk_m}O#-*dhfg;GBWujGy zm5Ek~R*%+-)^-3INw9xZAmTJ@o< zvWa|-*WL;|7&Gy7Ooslo!EXH?*6$Tq(9hvXC12|1$P@#xuuTTmK|6E?^597-a#9|4 z_?7n1nt{Lf0MxgZ4KD zgHv_ykMF_&2lEazKB0||z{4}a$}91Y_#2OkY$L<)m?7gnvj$kMl{wOU9d2v3x!v3b zpLf+P1|Qbi-Q3;B-P=9d{h@max}#(6L+*Tcw!4Ip1J2Fl?&tsmtK(ePOvOpovO*p|D*s>0|_q&(7e@CjB@BS2c8=dj9?q}Q& zyPLV|xNEyhx{JFFw{6}uZ<}YppxeNf%fN24!EQfrod8Dv$owB8e%$V{?x|HV7`3LEd6 zV4@Dtas6^yd8oF&A(Ng&UW%LXkoXxMZakdQOZY*`XY6S>lqUF2ia(SOLevUaIq+_W zfunFhd#v5oE^E8B6>PNye6=1}%5GVV2j^n2*KB+{7ZCf-`jLG!4bRRWtdHT-#^D$G zlJ$y%$2x+eT3F4IKC4@$tzzJ$X!Kh2N^}p{Xj^n$^haP!^!?}{pl`HS^x^13(FW1F z?DTTc5I;J5JaRg+KXNFtHnI_{v?{VVvM};l5 zz$h<=2Le69y~2-%+lT9gA3&2+G@KpE2%Qg|2pz$$@n>jBXi;cx=$p`#(8rY*y3ih%NxLq$W?LKQ-_f%>#lh16=4dJwpe=gOfc+iWs8^^j;~o%tJ~SjWnDA2Q zW#;rr==IR3&|ARkq2Zx7La$+Ic$s#)hT1dICQi>y>9=~QPN-(61W+tgCS->Ep>Qx5 zyc|3iyn+toZ16z0D8=Q!R^8I!9Rl1)9nxL4IV=~ax8cxcq4c{7zpME<3k>1 zk;-Z{W5k_8gF?eXV_4Y`L=e{VsAUr!fhd2Clcun{Z-uU|PU+6}+@%DFz_k+97hi`~#z&SdEY;g_g;x4>EKHx*^m53x(9~rC} z=dm*~jeIj-KzbOCx6ZdnSwG|V{x9AF`h8dZCR}~^^v?J#j&Qw&hsS*UU^Y8GEme>h zI^gp)(s<4B729BJ0JGeL@AjKD;Y53bdEPKbnO}g5eunoF_jeACFVD<3J?=PnA$OuX z1w2;CUD4gj-O}9wXb1E}2lPCW^#Jz^?)Tj9yFW%&p6s6L9*@L5&;2u4b_Lk+5V-af zm@>m{dc2_HS;~>d(cG zulUDclllVf`FH*w{PX;a{2Tn6{X6{I{C@$9@dxU+`m3bjY0Tl&oRzV8EC zUEurG_q%VcZzCF`L%!|4ozDD@GRG^x4c|>PQR&2P`Swy`FPf#jzJsj7Hr8XQZzdy~ z<(rMhX{2u$t+xf*_}cMqs<8eEzASGh@9jLAnq6pq7I?qHCOnGw+Y_Bt18;qAS#NnS zufQuE(M8W?&wlhp>(H(J>iNylG0yOOk7vtttf-UG@4V@G4LUv8(-+T|fu5e8UY<^# zr##I)tvn4q4LtQcb)eNHJSm=H9*CkR4V~RxG&Xmk+eh37-8+C~?!{3~%B^HpG|NKYi3ZBkYnZ}!+d~mr*xma(FnCi-n`GaA4#ORp)Zp5ybacN(9gsrd*=57KQACG4*v$;o(>kD4o#l!;Ph|9--FL*bDai;{~GN6HL)4t3CIEO z!jpdzo)~^TJOVl}B-}6j4DfXLS>SP?P56;;m2h3?_(MnsO^H_wCqd7B@c;RtywH`< z<-m8#))t3FU{1g;T8w`v*hmGWEjuGkiy92(KgX`(Vo#~qeGAmCIO3)3)V*0 zME9e4yMb;lf{<%kE;MyzdEcqL`4-N%MqT+js5?^V(?|`^@m|HP+oCD!hezLsXr89P@6N?1aSJw&Q}|6@0P@g3<)S%DKxc}9 zi69$O0v?&kNd0Az^;5Z)C&dq%a2X+F82No>p%**ld>g1Q1J62N8XhM_-y-VE!UNp( zwcs^E0DHN<0mLj%Tk`%ajfPIzf;w0)nxb!Lf}W@g^3726a3kT|$DtYe0vYB9q?nlw zPrt(P_Fe^-zlrm|(g{oP0-uAw_d>#Qyu`mjOFZA0i~ejj8mZa%e1D0S<5PUXzk{xS z>iBz)qwRN*u7)6YJ}2{eSAz#R{v`KyEGuRNNL3dm^17-u0zhvC7pFi zdy`q60k)%WT#sb;I~t9pjx}x$xaK=n`4jvt-@{w?O*oCN@Eh&W5#Gm}xR0+dit-z; z8E7)^qGR39R~{?Tu*zRie%Esx-N#txi#vWO1i)S>Fcd0kx<$?&rjfO{S=y%zF@bWgl7o@Xsb7MTJrtZ{a7|@;$2+= z{Vf6*KGT=@cI=FG63y)zq?P%|C|{ss8OgqUfgSpSRS)^Mq*Vqz7Fmi6vjQISH!PzYD7V%L%3FY3GdnUPGB+{{oGDK8 zFS_aK01^q&~Xr*WcLVchDkix7>Mk_P#6f_N~#LA;% zs2;6I$#UdtO;XT6q>@sGlH~}=XeN@;Q|OK>L9`Sg{X{8B!-%0{vLZ$_E*ekGM5lZb zvR+Nvu7upz8feFQw}+?h9ep`EJo;Jm^XSjOUvSo&u@{_+p2cz*jFzz~AWv3=P-UO=K!ui%g{=@^pL+_%sACC@P-&@ax zK5s)0z8SCVBVde+;1LV^W^r&&eXv6-^dwIL!yUf-Q|C*MW$21`@zsdFT?wO$PDD4J zYL-VU&<1UHJGhCS@D#n!`n~|a@uvA2+{Re*eRRR2%@56YiH$bDMyopk{qPu`#*q6i z*C}X^zi>3i6VbpfbhNXp(6z2Lx4_k$L_2ZY48!r)gYT*1u7UOH5qA&x`xmigy@5{S zQ@Hvc+_T;L(0CkmA9r8D5^B4H?qcXdYI;&V4|?wRbcLtyiVkHk{Mh@Rcd?v~^Na;X zc!tC2zvg)rPHhO#A6sxAuD!XogkNhzr~}95_at~C?kH_vb)R)#q@Tm?&F_O4YpVDWW%a^WMdWBJyY zeqcl|x?e`$)8E|!eNSoZ(k9Z<9WxW%(;hg))sAL;lKBbnfjNk`))jk(Z0MDErzIW! z&oBdMu&$x!Ic6LJ^Dl=g%r-s;x4#Ju2cpZnb*buW@SjrEvul~TB zUOw}a@Q{B2`(HP_+l7<$d&2rcL%)}B1xx;)XrO2D_2TDPx;|j%KL^Ha4qw;+D2k0M zA5D*JR-3GiaDrPoKRQ8Eq110cxd-zFaXY>+Zfn)XN6f(SJr|4IF?fU(z%2Y;-ip2v z?FxQ;INFS}UlzX46U~j}f(!ov(<}$?%>)O1f}Znb^uB$NqT5C)Mk+*7B8icl@EtTT zN6?h%X0+14HQJMF)BWdk6al`#8NnOMEb67!Z7xlwQGpT!#R| z8P&`9RlOhlF!(`mbntU}n+5z#|4X4tXudAPAM&NK zd`*{O*FFdp)9+L1cNa{UU;RFKXTEvq3cTg~ZphcJ6<`qke#T`W0wf}1HpE8O6Bvho z-8aA*bVfVzR>(k7ErqSNJyz8ISY^LJ0{#^n-&r7RM$8iKQtqzqC-8w7j4#Aw_cZr+ z?p+SmH~}`!19IJ^Jf)G)9|Zq)@^nOIe+?Lozs6+G=V*hbdw%fD@%-#rf?nuXGyvN@ z|DXfdLD+>~#{tg~&%d6tp2MCq#19ca;5kUxL+mnsC$~N6o-9wU$Lsvrp2A+Yw+cQo zHMq9GW2TL_wf9-?bKZXV48809&^sF4(nRm)-l@Ps?|knH?<()#-W_O}ws;Q%$M8?N z>rM0K10J6TJw_bCk4~ck+N9EGiOTtse2KogzFO#58aeu=nvVXZs;@ftc=C#&i7A6F zrkpR;mx6XFmwA8lF7Yn)e&L;h zx6Iq#cYtSsC%s+qwR#W_rOIea{N6k0&Gs|@wZKB)8?Enz_a9Pteu9>;3>gm#3j!t?_s%>$Z4<8Neyt%?Q^)V5HP?R5 zcl>>s!EmfIFFD_z>K6lKi+c|W{x;XonDxh4aNcn|UPe$uzh?3T-YXrQ@z+C!ZiruF zZSE!c#?-{y$79=$jyaoa5Xf;fL3gnBUH$)xIukgbs{jAb@|hX?KK5-ap^%i6tt2WX z(l<*|DWXLAw&+V62}PSyT4?>Y`9?}gdyz%dNW)3d|@O`*5#B)-rzqJ~~$?1VWWY{#K;ERD~x4i^Qay?}4(XjSv^NPUO3 zIFH}2kX=jIH@fIs;vg6C|7+N8$I@FBYJ+3QIo4J^7Dp7d2VW<~u(_O3DeU(*j>S=t z9;L_Plk_%xg+7S(8-0(SkRP%9iY0Hq<~1oB>0`M%SipyfJlZ!&pZX74c}=__V2MFAz!b7RdfB+U-ZQ->={)e}uDKL6qp0w0&uZ(jaltilryg zOMy|V(&B5R*8%O4IK68|WD4$Ft>Zy`}$N2VB)|55r}BIV|=^&zt6dvNjstOXg@pIDcKSULTs+rjsH z(s!W~_NE^sqLRS@i4M&Ir8MxaTiRy`ZiPMP9KMyORGdR6Fo>*;%o3Sv4CPrXg zjDZh+7LD<2;uU1xG`40XK4kqUF(>gEzh5L)CDtU?vgV=}3KEHoA~Zu`A}!-&A}^7d zQ7oe(taAk-C+ngg>eHv99Px`e8MQN-5=YpOr9PUY0zQcv8C6MHi#W@QT$PcL${q3( z#}X%44&u4khVEIF*qm6B_yc{lod3U&gRc^wvd&7(CPs7~>l~I3&};KJH=pg< zRhLK{#Xs)1T7v%mE`4G8Ol++;u)ij!Pr%Q8Z}9(ghcEApwRm>=nd$Y?YvS)NPmE=1 z`T=;hsVJBF5M9L`?&y7e%1E9l{E59d$9SXk5H z1fM|)OhBjn8#{dRMK27z<6HAPyS&ln(0h+?ZqR9h(`(Vdyd5fyhMVg5uiEk{;4 zBZOnZyocp9jpapT?E`3+QD~FvVWloXVz-7@I0N~bjXW<4x1NtI-H8SDHKRby4r3q< zgZaFP_ivGzVk0B$}iKEOLF2XZ?a|AkdT$bCQPdvJyBn z6ONfqV#Lp!%ug@KC^(saoJq&>K&!h!uLoET68(P!6#F;(2jQmw!Y13m_Tl`W@_)fM zx&&5!Vg4t?-_K)x7k2)2knvQO=U67fyHCu2JpbYRvH4^0yXtAx=lVL!Gcfm$v;74B zUuJm$F8tm6ncU%n{OMSGAHnv&$&vrDyhHl`a^H{e$9}^TzsUbGcx4ym|H#w7BNsnn zCw_+Cen~*#OGEDT-7h8Wr{wJuJi2qZ(+50ZCU={`GhPXKcpaaw&wifYX&iq7&+x09 zeG6p&8Q1*?s$T@YUx^QRHE+LzB`^P2eo8?)Wm%EPbZqGBOLvuF!R^r1-=1q z#t7K=@$hSp!`!`EFumY;{=W^!_664Ol7hup!7B^a6l~|4ZXu#)9ecTKZRdAm!48M>_;So<@F~=njyFh+13vgIISrSgH2FzGJ;MfS^LwXZaFnJ*Tdk4VPKt+ zc(5LXs~C?>GZBpUD9Bx=({G98GB)XCDY-c#Y!!{aiB=wB*QMw{y3_+*_uj z54O?GJnL$Z$~9mlM+EB%#_GvaWsV1s&K&e3^#HCGH{QZ?MuV|r2pWv&&B_3!Jy4K z)|90QX^CHJ&43|m zQWMI7qD!2LH!nxOlr*sPQIPaDu;&h9A~#WsekCsACu-Up>fCJNir&X7`6~7C4eIE4 zJdtpQe zw}~=;E;$YM>Nz}L6JW4L5Os88auD9ItFgvAz(8L_4=$tW$|uWVrDwxrmrWjp>tBgK z?GLvVd|ei5=_9(e<-l4Fk0X(*9Y>GF)eQ*+1_TE$^O(J^`3*zn1bA!hHv!I{6~<|a%}ez$v6T}>1d)ShXjx1 za5%SX;6r*5OVcyI0})SGuw0wphhtaecZVnG5tb|SFXmjA{7xL}!kNzbm%!6?WW5kR z#p74t18vW8UVa;nwheKV7jad4QgkBq`5bS-(uOV1cjbva@-O91ZHVM)PP(=sZCAXh zrs>8tmvOc`sd|&2f3XZA*7FwPF(1X}I~hN#e&Ol7yL}xOAkkOD&updi4xsN+D9?(- zk)Dahycqtmckn{@!&7oQJqDjIc#hv!`G)gD?B!1dTanLtMoJ-t%O*>NSj&cZKh8l4 zpNHqP8+BwLzHa63pyW--N0JXwo1P6d>NRBXOuVU|(3|1g)MNeluo-v&W zBl#A&pXD$x+lUQ1N=#5%W+v=SRU(U85<7D-5iOnRC)R_=ncInQ8Ju}v=16*-jm#WF zG|osOgdQQ9W=iJsA)aP5F*T25KFaz35D{}n=0L6(#(!gWZeSV8k$yz(^vUeaZ}-fO zM9Z8{6i;)W)rM!arEl^@9Br9-CR^=cms%3p)H<_8=6RXzGB4%KWke@ko_Q7VKLbNN z&mf*Pnsrp>13deg%x5zvu{@JGIdf{}Q<*Q4uh&?n6QlDMy{BF!hUjUQ*NEJCiE~rf z9?fz;>jNylqj5qvu%5+JFCh<&;JGSMB9-|q%E%)E>sZF0@MOOd)$?h_?2Hd7!x@z3 zOBqw(*6zp{L7%uDES7rfjB~NFap2jk{pB{C?So&j= zoR3ebW$?XZCejlp@VxAT!CFm3*$S-757QrGxjTJ0{;6Tutk#h<*RglPb8wZD@rw;&v2V#mSk|W#kHhdR*c|C;TZpz@j=kYnZSTNfJxct| zIF^C<(v6=xAAg?qz)4L9kcd;34!7)}}=|i-e<@ zIj?|op}j|sBj=xcktn{0;c@Ok&-Vv`T+8ppFgIrtf!hpSSqZJ}g4>ZO+@p*-yAyqA zw9aB8Za;zp{;+Twu@jSsBz&AG+hK6Sy;-`mw8ze9Nkn&p!g|E#RHK(?@k09}??w-9 zNp216Vj?`gMHjwLFXdUF#!P*N?|BYB=LxN-<%A4Mvyq~CK<2s*AK9PJnIW_qb{nTcGA}qg|tRL_@mt{HS zx-|JKo-q;l+T=QX)Ekig+dv@pVLO>DOjZv)->TCiqjF&*mNrCGU4n1zGJI@(=+AL8 zw&FcR%1onw+mm4MSzsWetv9ml1Rtdp{AN<@s& zEpepl1RR*-PnKt?Lo`Vh`oh?UrZwzW8gWnOn9SKh?Z8y34aN4wA?>XOiR ztPAHa$1~fPUSi!jYp5rDl zc42Bd5HO!u-2~e*BZ<(z`w$~s=CbT&-HG>jJALW)vbB@ZDIMi<72f2vVQW2}u52F?^><^c@__x3lNqgM7tX zk%9yGy8Veo>&ZxF^9b<8~LjN{um(w<|XJHENNeQ*#Jabrd;g^dJ_%Ma&gcPHo6-CZCz|tQd-u@xSJCfkIX1{I$(6{6rO4kekskC zNYQ4<&CB7G+TfEvhvi}zrf%Frd3Pb{FXRrFbL@(+c4fOeaADO(D-$&?MG>PBm_Y4LWHL(s2V!#nI$pq+<$9MHY6OWmmeeOkrKhu^CYZ=b_Qg!M1Bk9DRHG zkaP^Ao7)qvdl;j95HW`X7`xmt$;YycfxmbXZ>fv%tnZ>R=YgviviyN2-ApXlR{Sz2 z3JdVbe5mK=^^7p)a(fg^q)Tc!p&L zKB=iiFQeZ-4D-`E*X<&F7tTcL+;z?eE18#So=XS&tb)|2W zJf-6n_6cLC-pmLYchfc=4lE)a=Jb2>3JZU^O4*gPI0OBH1CB3?@9X}Ks&#dMJYa<)_)^Ml;wkA zV29w*xRdCV{}7+z_`OrDllXdwY^eR0ARM-N$#va1T^3LGIOOWhck@J0tzUl*CeJMwJqDkzp+#Nlj4Ri%M%D%*n zxw<|~c0+!%k?k3HN%P6IV~PCD?fXUD`dtTd^w!WLc>uoH zd)XSo;`q$Bb9@MQ?8`l`CDni+(~TPK#?q61%~znuyW_QOAFRUmA^tpv+LVK=uS%qA zDbR3wYEg)lJxH9beE_$ID1uFR(^e7tCW@HHIv0feHu0pN5~cJaXk!L4{y8kuhv}pC z408SI+3vu2 zou@JGK_gmIWwz@Q|5PpXRd)s$XN+-H8Rs(Fh^}xBGw1SMgirB9*tfUQ87~E&vf}_e z1@AWoR&gS2UGA_4>|rmWQZGY~T!BouFmPv$u*qw|oK<5f#*#^-=?VO)M_KmcL$zP; zro#0wTAPqH>+lHw#NH-2(sgK=#n|}sz;ttoNBtUPHy?KEeNg>}SpPGaHDWs2XByh) z1;%4}7HKvi%o%Z4n0a9++UG`ePwxkx- zWI1er-SquEguHdc1^I||tUt4S1z$W5rs4}CD`z6HXNO4sH;A-+o!GADunnfeX}p32 ze-RBe8LsT9EMz{fHu~|yDv+Bv`Al$ zy4@Xp(-}?FIamO#iTCV?wrb7qg)rUC(N*UY8`G5E^OL8e(W-?A(|RH9^fc@PSK~!% za-WXUGV)VNgRQO{t%8TV?&9a|*Ng1u?Y-P)n|x?-91B0qi5aaV)=|AltD z0Zx4gh<|8^{e37oIyny9Kbbe3#QHLt?CHSqya@K6Ny*H>gYz;a_P?4=wN%$hey$cjz5=GSPJ}5 zj&E6!@0vrO?$ZN*-vR#qGQPO;eHd47+`YWLh~?$LkiH2&|1Gu588m)?NpfV0pNW9p zh=>0#FwfS);xNRgF!CPyOn8b>OAk*ybr9e9m&>fINy zmZoydv5Mct>i-BmZ0zMs(CchQVR1z2FX?^z8B*^{mTy=ck9ry7HQRUKC$^R`Qox@? zZaQkU<5MpK4~vP#!;470Bt*n4tBSb%pAkxdRMD8Iv`5xr#%}CeY$W&+LboP#}^bdB%({7aL zg~(AcNNY;k*kIs-*9#rn!XvSrv z)7#iFkez>xfptik9mYaP=d3et715LY5Tl5D-fIZ~2&vOaoyne@iO(*^lEv!WYc+}W zXo%0&IUSmjN5^hHj~MJu=mY0+aBi(WXc5OSd6;+iJ3Gd-W2o3C+VQ_P5$&;qXzW5_ zJ2L3`Ax1hawIN8TEitwifq1S7{jLV1BS&EUJOavjJd7wY9{Xr2(HpOaISQuIA47X- z2J19D)XrlNmnmTc{^7)a+{!&}LZ=$Tdm){dpN%7t?N>W3?}L_1^cQdmWGcZd%Xi&_;|UwhcID_k8Nxk08wj zA)0+D?D3W`MtTXfe>PlLHb|fqHef4CZ~#`~Q1HcVytA_rh+>?r;4Q3v=Q;QWdvh_% zT5SGJV6_7vK*xY_zJ|=SG!R*-fXW;rr3$ey<=C%7EKGJ+PwoWyZ3bbk=KkwL1i=bo(w1QJE(2?6;l4*s-r&1E%Qt(0FYEjXkAr3J zBfk%VYDbWFZQcI-9|SVG2847qsJI8H=qjSvy73)56UEk=FL@C?YcAz~7gF^On5h%z zx`CQ{vRp~}>nVqUptauAD#th&%)Rf%rXCtzm;=pi(dw{WhA4~en+9Hw$U(RQEn`xUEupDHr^Xz%osGip<5)M2oidFcMUTM%+)u9VA$RwX%R4ET{=9+Z(uH^K z#BUpL;aRE8S(_4--iTht^{_ljQy*$#dpHA0C3;jP_;2)77B!_LXUnjZgFULwFiTwH$8SIR8^N|mZpg)(mk^j<% z>~*BSR#OzMRuk9QRqgd`hZ#qwvxKrD+ zGuZP2bZj$pZF4NtCTL>)zAjb3q1E|yo`|X}j^9uQdp3dZy(IY5=#+9{G^^t5l}67y z*F>2x`d5BoDyc-UrQn+rY?a`;ERGrbSDEWeb3Co+ATfi^y>*Zn#$6y=k?vM7#U||N z4fy|8vit(h_?D;uZSDEQ2)vKoEhf=(JDolSjxYFF;luPQ{WqNTaFFbv5P|S7d|(&D zp8NcRiVij_TTBr^SP@Sa)tUz5*ZE9gbvIdx_IN0_eXf_F|-H(@dJ07+Z za0o|W6Sl%~i?fb{rPc?|WeMkZfxCWzby)!FS_eA&g1x2uehDi3G4y9xM)bsD_Dnkm zj$$wO`WDo-4vyjgcUw&QV?6J7{u5$P6wfxEx-%fQ&FmG2yO8;<4(~3vQNFM|KIjuk z@pv(~jj}BI|0=_8)aG3p!qGbpn%gT?W@4$Y0Qgq-ox52(M9?U-0+Ih1%GoO@>Am33N5uH$h{)1 zw|I!_s1I(pFKu=9n&2@oLc?+S&O(A1(P8{rXIQQ-#Fc2_c1O}&2WRS7ftL~^)0G~X z*Ma1XEWQyxRbTv6jzeK=&Fw7CQTA`VSoh$U9>y}BNSPl;Q+*mbzuYIT&+#OvJGL3>wp-~B38IH2-o@WTEQH&=YNZUkUD^m z+9AC!#h&O2uIdgpj`M)sz<=km?}gm&ALb2l?vP%=`jDNtA@sYt2JCqq=dU5<0C=Kvy|4${7BOeMf@k9^(JM(OGu}oF~>B$#d`K z4i9s8X9E=}-%UDam>q+Ddw|qq*nSiwct1}V#ToDBEG(0Q9W|LP=azL&7-wsF6^*Iw zF@q5aw4gplht9(?`XJ2HV^{kDv2ek1*6 zFob=if8{FYW_6C)r95W=PhQBc^ALG&ZMmOV7qk9=HTNaC(Wd)~J#Dy!^-Iedxfq@Kxl znacVi>vY!FsY}oE1*Znva1!5j9N$|zU|g74$2xE?_2n+=`c2f%TSLvYZ|ik|k-k3E z_J2|LwLokoF70SX7t?YsVl@Wec_l9k`&~dn?P*U}1k17+akusrKZjQ6s-<}vt<$+G z8_{N+4@?WMIgz=p_AGD8`DS6ZzSFQjYtgoA(2~VewZK%e=US)PwDx+z7Il1U=POq> zXjvv<+K(VNj>084AN^tEh_g|zM!qOhwj*D*;wg1jt5qERlSn;hw01sg=ZeVLPhU@9h5`WZ4?FzNa69EaNinvy{Foa*n2778d99 zS%8=J8(7FM@mswYbJW zGg5dP@zC4hW46Q0tmk(FN1dnFc{c4IZG7WK&TM6S6I;&5y@u}|amUs+ zuG%!4S$0$2&U&<-)w$eGu;lVZjw9clGs&lxh6!+MAL}u`oO6Yz!4vG^Ud8$Ej7mk! zw&dJ!&bZ{<-)w>!XdeSiBUIWKtvRPT(GbXE#H23>{WLdpfrWF3{ia1JT0 z0J#hMt2l?UbG^1e4^>55l}Cfs3pKj|b-EfY;!Nsv4qH`7-zxASRXEdx>zqALZFde_ zcy+ew&?@TkTZ`2eAvdl0$iyqwO-c~Lmlj(0qZbL~T1TMN=UldSUKY>qSz zlA|pW!y_J3!#Cr9Gw$7vd$%Ih`GF&n4{6V_4&3n?p45RSIG=#r$@Q>eH=>QNM55h@ zhQ69JO1wLffX)Z1Z=xqxslCm1fqdN> z?svy2%y1VPU0JSve;{b_abasRvi&9G{xj%swfj?{N7VD^@#nx2PoT$Ng8zI9Z7_ko z$>0GkUh%|Z=>Et-jS9%%A<%-O9Nb5KZUsGvT<$_s$iI#xUn4>(3}Sz1SZ?Fo0P^X~ zY=il|oe~mvh;8lzVOWY|*%Nt)I7Wx_qK(JMiGCsHS{)glJ)UEeNoVdJ4F1rO;f#?2 z52L>(a?giY9_0yl^TuMPh+v$xRh;z*SKiOPEF)th$FSbVJ;YA;vTa|HiCjOC^v*Rm zg)(v9^0Oo?*9Sv7wdSMTFV0Ojo^A8%9ZVVDMl5w7UuJlCi#w@J))b#;y&8sQb#__t zpv(0vS5gD6qaF<8jQaLEj$O;zH>Bvz7dO2O;2_diEAODp2l1ZwQgWkt&M0y)mSqg( zBVsdGPw)N@`qq`Vw^MTYm zTg3?KXYO=JqpWN3%+{r%d0`+*#{He4U-NN={}y*+kokQ4)vG*@yDJtJOq1GPqZbR+M1Cwn&{ zQLYX3%9g67Gk~+Mmm{lsQwO^vm7Tw}C$dr>fvGzosjQcJ3VL&u|e(3RY=2LLFQe}p56)PAs@`U-%73q z@XVWevS@S=d3UZyzu^$_?*D6e`~JL@veLZ!JX_C2ELV^(rG5u;b3Pit`Ox(tw?fOb zM-Qntv=eKf_gZkKBATx$i*t~xS1Vv!IyY?z@(0dUW-ND zoXxe4x!Mqo-h{N?F9*%qj-@{T8?v0nmgB3-59(LZZf$|~It%S}8v8k1dj`kU*QRy6 z^+qh!d73&K1xN)CsGc8TJ)@mrA~zZ z`|0&|6nx`Rk00dsC|xoOz+V{wOFQT5e(+BcoaIcs`$10$`ei%6rRnwA90^#=KDo|Z zug@owYqiu1ib_#NCqYO0gUYa-K|b`$XNCVqId9HVI8%<}g&{Y^!5;d4Oef|mAphPY zk3Hkv50T50q&4s6EsgxR$P$P<|7MXlI7%wtU$0X!@|NUSAxHKHOnHphd4^!%ymNFO z3P^7^d;7v$ibHpi(h_oxdG97iu?6gRfK(#Poh*7RxASX!!4@#$Hnz5~zdB%I@vpsq z{s2)rzvo(PgGYXKw|_cq0tR@1V<#91~@4;7yM4gk18qhg9O%t)vr$?&Nvm z)jg!$7;-JX-pr9zq*}?-R`cKaTlRxg?K{7n#op5*-0kdpKga9ZLpjK`_#5-Im)xx5 zKC9VZ%m3f$&-8o1!M@)bj{QJRf5LjuHrmRW<=8gb3_dgF-FZ!yaYoB%1!=bM_FlO$ zJVQ%CZ0)%%=r{pyVTYwqV;dkr#IquEErU<6 z$c!zqZ`b2+V{c-+ZKiYzX+gHf<-E&eShL&kmEXiz1*3>9Tfkc%q8=Qj_HCrZj2oAK zyP5O$efy1LTlsbesma<|v$6Z`f|Kh_%;RYM?Q^jV^QiBoXp>rPdKpH**4@ZmM&OY* zZcW?NZ@-tCq_sPpr;HeNw9>z!y~-&MDF(hsittxS16g6dFo5y zF0Y0;M;<4|^W4$ia>h72V!&s7^G|r1@$~a4TW#dUl$ZAN*W_e2cJa5^;NSCWf4g5P zt>vfc$G4+rRz) z`tuW4SevcmT8!4S-}t&eQ+{!da(f9{?#nr|hGiLh@}8S$!&=1~sekJ@Zp`3r+P3os zZ{e77+IG8}Z>4PA#Wy(|a%aTEN#t^p`lJ<|f<3&OTIHC0O2ob7bvO0oI9vNzb2++$ z{b*}%B#*1fn{r1R-SrRhrft4~d~D{tV=q`gRyy0GA&zAt^Yf6x>Kt`Tg7%~D>;>L11#+GR;X}OX^?C%dxI>z&NbH~59yL^Ef=>S^H z`Rq@g%5&7asXS43Dw8*qwe$Dww{#zAwIc*DdZGEWo>anP8*HV*rPzP-}+i7pBId5y($&nqT*~@=x z?*`IrW8D$H^L~ESq_!j5ldDmJM_K%8+rnL=em_PUb0crHkNo~j8;JVeJgM>i;J$xy z=hz?HLr)~%$nMVnIDAqvSz|gkM;dHQs3h={Iu^b(!Z}ET_m>t|Cvn!u{p2lvcUn-L{3=@7Up%@FCvWH&iN! z7DP^d1HaF1mRwfLLoRO6#R{0eDJZiI* zkVn7O5zggOD{X^^`7Pl8QEHx8_85Cb z)JJuz7|{BgN*z4P*HK;+atE1VMbooC+F7Ma2SlHAKN|K$F(Ov>`ST38F_S`JY=qaLEBWOj2p<7zfrMSRMWs)yQ7vu-4#gJ$|)&8ndm% zQ1cti zr0=dK$68{)=>urWmicLeUFB061}n-4vC~=42uGTbvN3P!S;q>h%`>#sss~F-e$^w{ zoY8*E4)0WxoYxB}DpHCiD7|WY@oJo}AIhRB_pZfJnNdqyA4VgdXpCZuP?j;jjX72~ zlt)d@)Csw2P6^cIiPf+iExS5A-|u369E+rCU{~d8MVz%rTaEKIsV&->4fw4<%4)1N zgEcBETb&U?HF735Y)ZM>D%`mQcPT|3l#>>dYIR!bmHGAFwOL}>7(1;+ znN4j~(^$*Bt_)IKZIKabFC8b@F2OU)lgiqx{>kE;`X@b>-}s&wpTH!Ud7D42c)9t~Y#XO&Y@@ASdsN?YIad8m#n=)Dlw`3C)q1|0^*|X> zjC2LOQxUng&Zy@t6WgF|Sl#RUs%gbI;y3+Kwr%B>2u4XM&i)&@mWx~z;iwh0K6fAs z)r-o?9i$N(>ZNgfPwhv&8^^hue)C-{5&wt|3rKmCvwAK}q3xW<{de&H5b|(0DVRQ% zMH|=LcvTT4EOyd2~OaVJh?R2RO7$W)U#zt zXDchu6*buR+gBx3X}+l1!BMa)awdm6)ZmD<-WpPp`(#r>dWs6E`;nWmzPTDRYa5cm zQ8Jh>^Cb6Ei&fjLEcfuu<$P-J4subxfw2wBK>NhiXEoA6$yqDhsTTRG!&NoHovh=v z$(!#~nx~cKdgt;}UMMAGNR&Xf9!pMrWowUhJ)dt^n!N-mZ8>fm_gjYaeo;%y@~A|5 zzlAyXt6CmDBT9HBo4Il(!8&}Ey5v;}XAda3th%h0ZGE=RL6)iqjO6%7;~3W=ht?Q5 zT7fG(UX}Yb;tq{C?sryWG!FY}gqoz(OXZuZ#m=IPWaS$1jul9!N6na#hU6oMC+kIv z^4fdU<5*pO^*5<4<=)g!XQO+}n|z%fsivGeE1Wa(PrtRAwk3D8#O9#n%_zkOfJzXtg)%YW-ttQCHR@_Ykjv30}RQJ$|+CTuH< zjGDGqS4KAX*fKpr2@YDPip8 znTOmij_lNnpA526OG%uhq)Xw9e5Lk~@=N4kM4+iL@P=?Bj(>r*~koPLqz=~`V{RS zkuwio4= z@p)d3L`iA#?0J$)D?M!TDi&o26mg+6*tjI2fZS|Cr)_f>!yi&d) zN=~IiWu!%2o~Ayrgk#An3zP}!mh!CXWzR(EWXWfP>$GM>az4@LYGbK+%TTs?=%AQq zrALBt6H!^N`aFCuxe`k*qSoT%Kt{*AS$8bUboTU4WbxlRR#a4xT$Bqb(@vF`wI!7_ zdJIajT`atXvNX1FOV83S%X#md#g?TTeH)gw-}@gv$66q(C8pie@M%XW5ti&HUrJf$Dx0E}Z(FhL=y~!Dm1o8S$py&v z9pt~vpU;X1DmkfqQ&B=aZNX-<#vt2BAFo92uph1~kS=w0?kdN?miJW|O;9zbQqn z1M&<inn!& zp|pH#m$u+iMA*2F`)Mnw<(vEQJz(H_}^=^D=d9&7O}3DkJ8!lly&g###`D?MRcc5ltmDq z*A4%Dio8d4Qfde3baufhm_nV_LfVsYOT8)z*|$GG(3yZH{qu#4pYvciAM&T_D1wSbiA=D>Pj32Aj`-C3e?6Y6|XzU5w)qvbe~ z%`xv0Z945a^>@6NIz=7kch`Csw^{?NMY7qxk9t>qVxA6?PwgS=lx@e{+g|;%9r_;P zFnug)3|n0)EyCI%u2bTOwd6@{Bg(2hp_b`C5UI&#YWus0-wubitZY%nC{N_omF415 z+qL$#vdr47Zjon~hqt{&DQc_Kj!Wl@Rt!fix2U%wPSQSCf2;4*JK|F7w&f^F@OtHi z-@$w8CycUoH@T3H-4XJjj1xJ^S45AM{vbJLb&2>=KiQgaUZ0p=Y2Q@&W`8LCyvjDY zVZF|OkVfy>D*RB9cFW%966{B93=INHUZCBK8`<7=>QrLdgVM=t8BC+f#artTZ{gjz9 zH?cjdmz4^ZrES`BQd(J59`6oCem zGnR63o-c2s&K2j2wB_Wq1){8$Yx6GIl#QrYKc^Ai>gr-4|D}17cd|T1&*rKYmWHJ+ ztES3gLaN6KVuCN3;uX{ZDd$BNVSR~o0H2UB#rImnD?Nhnp6E8)Lq&b;$A(TMg(|7DQpQC?;sMk=Y_ovynE!aMeSR7@=C7V$~*1kIYwovb+)n{ zJ&@+WSbk-m(q8nfjxhg97#Va+FZysr_~uiezuy0&>_?4esUPFGvQHVTt>o5U;k?=| z@;7P-YlQ5*I8o`YjP;AE11x9nC>~a4D&w?E)ZNN%d3|jSC9|5*D=mG!)V`56l)g{P z!g{10^($CHG3r6Tt$F*46n=qi>>nh>7LIBQXc0u-CQ4V?BkPRpm(fBoB2T0itpE|P zF$k%lWkp%(o5*8Wua#gTa(yr&PVru8WUyF4f5txKkS$M1S%&tJN~@OXQv;NtEs37B z6{0oHE!mIv(pnbFD^r!=)>Yf6ZP~V@oYnf(@>hmxd#Hac7qO-?+-MA+X;~}VeX4eg z@>N+QcPIy!8mt4`?g7p!6{BZKlp6WS$o%=0Y~MzB_1= zlFDp}iRD%G!YW&3PnBEBaLY%(r@jGMsY;|*Dv8IHsai&IOX@OZwW%TpRTfOHU#}Vx zE!q&WC|%b@EGm20-or2Y!GwG#9gYOClc zF^}@$-m@~lB3ZwwERL+R5?AX+Y;Jk`uCjINYBire1>Z!@$~xqE?Fg~7siQquo_%YA zHdWN-))n~_rLy|ezA=%fi_D58rj?~;RHQ_3e?;4I8RbnienA%7y5w5;I zIT0D{SGoQY^+|DPz@w9^Xs~ zvFs+!DdCj&$}{z(*F+{q9qIdu%VoTcN{ewSJ5J?EWbgCzb^31VrKp9JzUnLEb@gkC zw7s+MV40YY?c~FEmV;65uVZg3`{rF_Eq0eT*9H+mYg5QAMUC!zM-Io*_M7-c{08b$ zc_W#3?G8B^c`$W`rKsI3-jFL(-fLk*)?I9{mGp<$KN#LkZqKq&8XDJP4UE2J**)!* zV#vXh)NSjum`1s%EK`zet7|J35g%5b)=-LLqIPAEtxnXebh1U|uorzy9utS!_GOzZ zAuIGFiV$UNZL79!xeZa8%udAM$}0V(<&Zx5wdCOSNtLD5sR7c$-Nap9>Ap`=4=5|W zmk75Id9O^AFHv%6Q;E6Fkvhm6i&90@Y8G3uOtaqpD5Fgy`<%_)vcg;WJmsEGiXKQ~ zAbf^i0Hu~3xz>dIl^%k~h8XE$S^4%N-Rhi|QPG#FUsb6qo_9OSZ5b84k+C;{Wh+0U z7uU#+QoMmOxGL$RTvh%@+3xof1&g}XzU4@vHQ|51qqH~ zfg?T@Gae$Hwt=Wo7EOj-2_7Sh)V4B8)(>^4_e@9U$r)}mX2S#RLHsh7ZHFwj5R_(W5ga6cweIz^T7$$SbHI;sl*#3Z>8e6EyNfe<4rxp__iYmp7N6D+! zq4}{z87mV#r1G-rR(ZmRe4=gQzW7Ll6WP;>T+#E?rUAs z$6cNKIo7J_Vj1`x+oPOwWSQf5W_q-$@+4!=B974OXsa^^wmk1!kIj@kh)GqUzTCc6+uG-+rPr1#w z+LpwR4S3I*q=^1`M$Q-!Vg!h|*!V!p)urDb zz=~|;gc322ma9Hd@w9c;Ym7&cZI^>rzZhrY93CQZ?Fe%aqspv*8GI9^VB}z;j>sV= z+Fa%$Mkv}AZ1=`R8Lw#l_KW#NMEd4LuH5tbC5-Y=cd0vU6V@N&+0^L1pPZB5$p|U$ zq;=u@ScdkxZa{t;QZ{~fBXEp8vef-D+AG>1)&t*7d*&=s7!4CkwkG+qHL3Zkkfs{@ z<;lHrtcX7A6?t!4T#SL&c6M8P)}H-x9%49=jxo<#>oOeLZ8FPZD-mEGDI$L^Yw$NM zuaJEsB9zwRFt1Uv{uAYJfR-mSDZj2IoCq;))>Q2jbEkEpUJ|>=r>QISGg(({*J1>9 znB}favK=c&l?Apg<(j%)NvZD9rb*%KKRztqUj|1@!zjrld%mYON3=aesJl3_kK@OA zPZ$WhOeSje^`p3&wgjZa*kzcCOo!b{C*YmhY&r>Sey#p;@f!^HyXfMS$sRq`u} z5dYg^jLj_{%H2{De~A6n6p?q9WhledN|D$`#p<#q>R5HFzt*q#9wJG~}MoOSGr86vw8O`-{F2eIB+s<%hoG*fO-qjI~YDGNKPgHqWxsij?crZrej! zG>S?;i&t7sk&}v?p>jYEfSOu+&Ab~Cp&YXHSf=J&hD2|+?34Zs**&d1|6+e0{jch4@ZC{QUqy4Ur${uC*9*efIC8A`q@2u?cwh-4KpQ-FpF0ExX0>V^U z@iMqF%H}bqi@jOY3ict9E73Zafl&rVUVS51$;xaamqtxT*|&~+DkbFu9FI&tW0Z$- zuCl_hr(2BC@M^h+I3A260NE?%5AJ1Y*pqSEm)cxKY}?=GICb3dpkiN1IUE^dSM6i@U=e_;?aaJ-+%~ITuy>Kt zU8~G?suof+Xq&}&P^E+C%-_MFkJv?q7&D^v8PS85fUVDcv5zvxaUB#EmL?yLoUFmPEjruIctY{snbxNS2YLG(xt^KZ+iakmqw;|e9GnGhM2B{n=D}qzCiHw)m{_%T6wnrvQi&9%j z9csDy{ro2CXRSGPbF{Q#yprYXxAAM3URiBhF~_nW%Hyckl)%GzCnx`(Yq+uevpzV4EIr`5-^Va@fTZB|NF*DQLPDm!qLm6+&|8}taozZMwM7rO68cw_z?MU z`RmO*M?PD|J4XDdrL`Hv(Y{ag+N!~f#!>qmB89$Zd2X!`OTs?5>an9-wTHSO-j>JK zev7i+Qj|B-_u)u=;sd|2x=KGrtQBewOVzJxPPVXpoI6KfwK(7Cm}o1VU`wuEe%> Date: Mon, 1 Jul 2019 12:20:25 +0500 Subject: [PATCH 210/237] Changed description of events on chat --- xabber/src/main/res/values-ru-rRU/preference_editor.xml | 2 +- xabber/src/main/res/values/preference_editor.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/res/values-ru-rRU/preference_editor.xml b/xabber/src/main/res/values-ru-rRU/preference_editor.xml index 6e4e78bb5e..cfc38bc794 100644 --- a/xabber/src/main/res/values-ru-rRU/preference_editor.xml +++ b/xabber/src/main/res/values-ru-rRU/preference_editor.xml @@ -139,7 +139,7 @@ Предпросмотр в приложении Предпросмотр при сообщениях в других чатах Звук в текущем чате - Воспроизводить уведомление при сообщениях в текущем чате + Воспроизводить уведомление при получении и отправке сообщений в текущем чате Сброс Все настройки уведомлений будут установлены в значения по умолчанию Сбросить настройки уведомлений? diff --git a/xabber/src/main/res/values/preference_editor.xml b/xabber/src/main/res/values/preference_editor.xml index cd22f90833..75c79b40a6 100644 --- a/xabber/src/main/res/values/preference_editor.xml +++ b/xabber/src/main/res/values/preference_editor.xml @@ -163,7 +163,7 @@ In-app preview Show preview on message in another chat In-chat sounds - Play sound on message in current chat + Play sound on receiving and sending message in current chat Reset All notification settings would be set to default values From f9964afcd4ede975e3c6cc4ef00b30444f8fa7b0 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 1 Jul 2019 13:41:07 +0500 Subject: [PATCH 211/237] Do not show underline in mention span --- .../main/java/com/xabber/android/ui/text/ClickSpan.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/xabber/src/main/java/com/xabber/android/ui/text/ClickSpan.java b/xabber/src/main/java/com/xabber/android/ui/text/ClickSpan.java index 39b5844c33..2cf5cb2593 100644 --- a/xabber/src/main/java/com/xabber/android/ui/text/ClickSpan.java +++ b/xabber/src/main/java/com/xabber/android/ui/text/ClickSpan.java @@ -3,6 +3,8 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.support.annotation.NonNull; +import android.text.TextPaint; import android.text.style.ClickableSpan; import android.view.View; @@ -31,6 +33,12 @@ public void onClick(View view) { } } + @Override + public void updateDrawState(@NonNull TextPaint ds) { + if (TYPE_HYPERLINK.equals(type)) ds.setUnderlineText(true); + ds.setColor(ds.linkColor); + } + public String getUrl() { return url; } From dbae2ec816483ed84503dfe89b9925e1c6ee7d3c Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 1 Jul 2019 14:08:57 +0500 Subject: [PATCH 212/237] Changed about screen --- xabber/src/main/res/values/about_viewer.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xabber/src/main/res/values/about_viewer.xml b/xabber/src/main/res/values/about_viewer.xml index 007c8a1fb3..f2f30a4a15 100644 --- a/xabber/src/main/res/values/about_viewer.xml +++ b/xabber/src/main/res/values/about_viewer.xml @@ -13,7 +13,7 @@ XMPP is highly extensible, via extensions known as XEPs (XMPP Extension Protocol). Xabber supports a number of popular XEPs that are essential to providing great chat experience for our users. Developers - Xabber for Android was originally developed by Redsolution, Inc. — an international software and services company currently based in Estonia. Since then, a number of individuals joined Xabber as developers, testers and translators.\n\nOur goal is to create a stable, reliable, interoperable and user friendly ecosystem for instant messaging that does not rely on proprietary services and data silos. We welcome anyone who believes in open standards and free information interchange to take part in moving Xabber forward.\n\nFollow us on Twitter and Github. + Xabber for Android was originally developed by Redsolution — an international software and services company currently based in Estonia. Since then, a number of individuals joined Xabber as developers, testers and translators.\n\nOur goal is to create a stable, reliable, interoperable and user friendly ecosystem for instant messaging that does not rely on proprietary services and data silos. We welcome anyone who believes in open standards and free information interchange to take part in moving Xabber forward.\n\nFollow us on Twitter and Github. http://www.redsolution.com/ http://www.xabber.com From c090def4953e08aa820b342c5952977b98e3dab9 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 1 Jul 2019 16:22:13 +0500 Subject: [PATCH 213/237] Changes in crowdfunding messages --- .../android/data/database/RealmManager.java | 9 ++++- .../database/realm/CrowdfundingMessage.java | 16 ++++----- .../data/http/CrowdfundingManager.java | 36 ++++++++++--------- .../data/message/CrowdfundingChat.java | 2 +- .../data/roster/CrowdfundingContact.java | 2 +- .../adapter/chat/CrowdfundingChatAdapter.java | 8 ++--- 6 files changed, 40 insertions(+), 33 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java b/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java index 888ed63850..928bb5d032 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java +++ b/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java @@ -36,7 +36,7 @@ public class RealmManager { private static final String REALM_DATABASE_NAME = "realm_database.realm"; - private static final int REALM_DATABASE_VERSION = 26; + private static final int REALM_DATABASE_VERSION = 27; private static final String LOG_TAG = RealmManager.class.getSimpleName(); private final RealmConfiguration realmConfiguration; @@ -351,6 +351,13 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { oldVersion++; } + + if (oldVersion == 26) { + schema.get(CrowdfundingMessage.class.getSimpleName()) + .removeField("receivedTimestamp"); + + oldVersion++; + } } }) .modules(new RealmDatabaseModule()) diff --git a/xabber/src/main/java/com/xabber/android/data/database/realm/CrowdfundingMessage.java b/xabber/src/main/java/com/xabber/android/data/database/realm/CrowdfundingMessage.java index 3d04be60ed..af50e10692 100644 --- a/xabber/src/main/java/com/xabber/android/data/database/realm/CrowdfundingMessage.java +++ b/xabber/src/main/java/com/xabber/android/data/database/realm/CrowdfundingMessage.java @@ -11,12 +11,18 @@ public class CrowdfundingMessage extends RealmObject { + public static class Fields { + public static final String ID = "id"; + public static final String TIMESTAMP = "timestamp"; + public static final String READ = "read"; + public static final String DELAY = "delay"; + } + @PrimaryKey @Required private String id; private boolean isLeader; private int timestamp; - private int receivedTimestamp; private String messageRu; private String messageEn; private boolean read; @@ -119,14 +125,6 @@ public void setDelay(int delay) { this.delay = delay; } - public int getReceivedTimestamp() { - return receivedTimestamp; - } - - public void setReceivedTimestamp(int receivedTimestamp) { - this.receivedTimestamp = receivedTimestamp; - } - public String getNameForCurrentLocale() { Locale currentLocale = Application.getInstance().getResources().getConfiguration().locale; if (currentLocale.getLanguage().equals("ru") && getAuthorNameRu() != null) diff --git a/xabber/src/main/java/com/xabber/android/data/http/CrowdfundingManager.java b/xabber/src/main/java/com/xabber/android/data/http/CrowdfundingManager.java index 409032af9e..cdbc26bf16 100644 --- a/xabber/src/main/java/com/xabber/android/data/http/CrowdfundingManager.java +++ b/xabber/src/main/java/com/xabber/android/data/http/CrowdfundingManager.java @@ -49,7 +49,7 @@ public void onLoad() { else if (isTimeToCrowdfunding() && isLeaderCacheExpired()) requestLeader(); } else if (!CrowdfundingManager.getInstance().haveDelayedMessages() && isCacheExpired()) - requestFeed(lastMessage.getReceivedTimestamp()); + requestFeed(lastMessage.getTimestamp()); } private void requestLeader() { @@ -75,7 +75,7 @@ public void startUpdateTimer(final int delay, final int step) { if (timer != null) timer.cancel(); if (!CrowdfundingManager.getInstance().haveDelayedMessages()) { CrowdfundingMessage lastMessage = getLastMessageFromRealm(); - if (lastMessage != null && isCacheExpired()) requestFeed(lastMessage.getReceivedTimestamp()); + if (lastMessage != null && isCacheExpired()) requestFeed(lastMessage.getTimestamp()); return; } @@ -129,8 +129,9 @@ private CrowdfundingMessage messageToRealm(CrowdfundingClient.Message message) { realmMessage.setRead(false); realmMessage.setDelay(message.getDelay()); realmMessage.setLeader(message.isLeader()); - realmMessage.setTimestamp(message.getTimestamp()); - realmMessage.setReceivedTimestamp(getCurrentTime()); + if (message.isLeader()) + realmMessage.setTimestamp(getCurrentTime()); + else realmMessage.setTimestamp(message.getTimestamp()); realmMessage.setAuthorAvatar(message.getAuthor().getAvatar()); realmMessage.setAuthorJid(message.getAuthor().getJabberId()); @@ -150,15 +151,15 @@ private CrowdfundingMessage messageToRealm(CrowdfundingClient.Message message) { public boolean haveDelayedMessages() { Realm realm = RealmManager.getInstance().getNewRealm(); CrowdfundingMessage message = realm.where(CrowdfundingMessage.class) - .notEqualTo("delay", 0).findFirst(); + .notEqualTo(CrowdfundingMessage.Fields.DELAY, 0).findFirst(); return message != null; } public RealmResults getMessagesWithDelay(int delay) { Realm realm = RealmManager.getInstance().getNewRealm(); return realm.where(CrowdfundingMessage.class) - .lessThanOrEqualTo("delay", delay) - .findAllSorted("receivedTimestamp"); + .lessThanOrEqualTo(CrowdfundingMessage.Fields.DELAY, delay) + .findAllSorted(CrowdfundingMessage.Fields.TIMESTAMP); } public void removeDelay(int delay) { @@ -168,7 +169,7 @@ public void removeDelay(int delay) { for (CrowdfundingMessage message : messages) { // remove delay and update received time message.setDelay(0); - message.setReceivedTimestamp(getCurrentTime()); + message.setTimestamp(getCurrentTime()); } realm.commitTransaction(); realm.close(); @@ -176,7 +177,8 @@ public void removeDelay(int delay) { public CrowdfundingMessage getLastMessageFromRealm() { Realm realm = RealmManager.getInstance().getNewRealm(); - RealmResults messages = realm.where(CrowdfundingMessage.class).findAllSorted("receivedTimestamp"); + RealmResults messages = realm.where(CrowdfundingMessage.class) + .findAllSorted(CrowdfundingMessage.Fields.TIMESTAMP); if (messages != null && !messages.isEmpty()) return messages.last(); else return null; } @@ -184,23 +186,23 @@ public CrowdfundingMessage getLastMessageFromRealm() { public CrowdfundingMessage getLastNotDelayedMessageFromRealm() { Realm realm = RealmManager.getInstance().getNewRealm(); RealmResults messages = realm.where(CrowdfundingMessage.class) - .equalTo("delay", 0) - .findAllSorted("receivedTimestamp"); + .equalTo(CrowdfundingMessage.Fields.DELAY, 0) + .findAllSorted(CrowdfundingMessage.Fields.TIMESTAMP); if (messages != null && !messages.isEmpty()) return messages.last(); else return null; } public int getUnreadMessageCount() { Realm realm = RealmManager.getInstance().getNewRealm(); - Long count = realm.where(CrowdfundingMessage.class).equalTo("read", false) - .equalTo("delay", 0).count(); + Long count = realm.where(CrowdfundingMessage.class).equalTo(CrowdfundingMessage.Fields.READ, false) + .equalTo(CrowdfundingMessage.Fields.DELAY, 0).count(); return count.intValue(); } public Observable> getUnreadMessageCountAsObservable() { Realm realm = RealmManager.getInstance().getNewRealm(); - return realm.where(CrowdfundingMessage.class).equalTo("read", false) - .equalTo("delay", 0).findAll().asObservable(); + return realm.where(CrowdfundingMessage.class).equalTo(CrowdfundingMessage.Fields.READ, false) + .equalTo(CrowdfundingMessage.Fields.DELAY, 0).findAll().asObservable(); } public void reloadMessages() { @@ -214,14 +216,14 @@ public void reloadMessages() { /** Ignore business rules. Use only for debug */ public void fetchFeedForDebug() { CrowdfundingMessage lastMessage = getLastMessageFromRealm(); - if (lastMessage != null) requestFeed(lastMessage.getReceivedTimestamp()); + if (lastMessage != null) requestFeed(lastMessage.getTimestamp()); } public void markMessagesAsRead(String[] ids) { if (ids.length == 0) return; Realm realm = RealmManager.getInstance().getNewRealm(); RealmResults messages = realm.where(CrowdfundingMessage.class) - .equalTo("read", false).in("id", ids).findAll(); + .equalTo(CrowdfundingMessage.Fields.READ, false).in(CrowdfundingMessage.Fields.ID, ids).findAll(); realm.beginTransaction(); for (CrowdfundingMessage message : messages) { diff --git a/xabber/src/main/java/com/xabber/android/data/message/CrowdfundingChat.java b/xabber/src/main/java/com/xabber/android/data/message/CrowdfundingChat.java index 9637deacba..a07de3ee1c 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/CrowdfundingChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/CrowdfundingChat.java @@ -42,7 +42,7 @@ public static CrowdfundingChat createCrowdfundingChat(int unreadCount, Crowdfund public Date getLastTime() { if (lastMessage != null) - return new Date((long) lastMessage.getReceivedTimestamp() * 1000); + return new Date((long) lastMessage.getTimestamp() * 1000); return new Date(0); } diff --git a/xabber/src/main/java/com/xabber/android/data/roster/CrowdfundingContact.java b/xabber/src/main/java/com/xabber/android/data/roster/CrowdfundingContact.java index 1e3d4da8d9..4a39133397 100644 --- a/xabber/src/main/java/com/xabber/android/data/roster/CrowdfundingContact.java +++ b/xabber/src/main/java/com/xabber/android/data/roster/CrowdfundingContact.java @@ -16,7 +16,7 @@ public CrowdfundingContact(CrowdfundingChat chat) { CrowdfundingMessage lastMessage = chat.getLastCrowdMessage(); if (lastMessage != null) { this.lastMessageText = lastMessage.getMessageForCurrentLocale(); - this.lastMessageTime = new Date((long) lastMessage.getReceivedTimestamp() * 1000); + this.lastMessageTime = new Date((long) lastMessage.getTimestamp() * 1000); } this.unreadCount = chat.getUnreadCount(); } diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/CrowdfundingChatAdapter.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/CrowdfundingChatAdapter.java index 40bb44e25c..53a22ee657 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/CrowdfundingChatAdapter.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/CrowdfundingChatAdapter.java @@ -142,7 +142,7 @@ public void onResourceReady(GlideDrawable resource, GlideAnimation Date: Mon, 1 Jul 2019 17:09:50 +0500 Subject: [PATCH 214/237] Added settings of compress images --- .../xabber/android/data/SettingsManager.java | 5 ++ .../xabber/android/service/UploadService.java | 3 +- .../ConnectionSettingsFragment.java | 56 +------------------ .../res/values-ru-rRU/preference_editor.xml | 1 + .../src/main/res/values/preference_editor.xml | 1 + xabber/src/main/res/values/preferences.xml | 3 + .../main/res/xml/preference_connection.xml | 20 ++----- 7 files changed, 19 insertions(+), 70 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/SettingsManager.java b/xabber/src/main/java/com/xabber/android/data/SettingsManager.java index 3dd9edb6a9..68895142be 100644 --- a/xabber/src/main/java/com/xabber/android/data/SettingsManager.java +++ b/xabber/src/main/java/com/xabber/android/data/SettingsManager.java @@ -527,6 +527,11 @@ public static boolean connectionUseCarbons() { R.bool.connection_use_carbons_default); } + public static boolean connectionCompressImage() { + return getBoolean(R.string.connection_compress_image_on_upload_key, + R.bool.connection_compress_image_on_upload_default); + } + public static DnsResolverType connectionDnsResolver() { String value = getString(R.string.connection_dns_resolver_type_key, R.string.connection_dns_resolver_type_default); diff --git a/xabber/src/main/java/com/xabber/android/service/UploadService.java b/xabber/src/main/java/com/xabber/android/service/UploadService.java index ebee560278..64e5d8cb74 100644 --- a/xabber/src/main/java/com/xabber/android/service/UploadService.java +++ b/xabber/src/main/java/com/xabber/android/service/UploadService.java @@ -11,6 +11,7 @@ import android.support.annotation.Nullable; import android.webkit.MimeTypeMap; +import com.xabber.android.data.SettingsManager; import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.account.AccountManager; import com.xabber.android.data.entity.AccountJid; @@ -202,7 +203,7 @@ private void startWork(AccountJid account, UserJid user, List filePaths, final File file; // compress file if image - if (FileManager.fileIsImage(uncompressedFile)) { + if (FileManager.fileIsImage(uncompressedFile) && SettingsManager.connectionCompressImage()) { file = ImageCompressor.compressImage(uncompressedFile, getCompressedDirPath()); if (file == null) throw new Exception("Compress image failed"); diff --git a/xabber/src/main/java/com/xabber/android/ui/preferences/ConnectionSettingsFragment.java b/xabber/src/main/java/com/xabber/android/ui/preferences/ConnectionSettingsFragment.java index 249e4e99b3..ee950bb32e 100644 --- a/xabber/src/main/java/com/xabber/android/ui/preferences/ConnectionSettingsFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/preferences/ConnectionSettingsFragment.java @@ -1,23 +1,13 @@ package com.xabber.android.ui.preferences; -import android.content.SharedPreferences; import android.os.Bundle; -import android.preference.CheckBoxPreference; import android.preference.Preference; -import android.preference.PreferenceManager; import com.xabber.android.R; -import com.xabber.android.data.SettingsManager; -import com.xabber.android.data.account.AccountItem; -import com.xabber.android.data.account.AccountManager; -import com.xabber.android.data.entity.AccountJid; import com.xabber.android.ui.activity.PreferenceSummaryHelperActivity; import com.xabber.android.ui.helper.BatteryHelper; -import java.util.Collection; - -public class ConnectionSettingsFragment extends android.preference.PreferenceFragment - implements SharedPreferences.OnSharedPreferenceChangeListener { +public class ConnectionSettingsFragment extends android.preference.PreferenceFragment { private Preference batteryOptimizationPreference; @@ -29,8 +19,6 @@ public void onCreate(Bundle savedInstanceState) { PreferenceSummaryHelperActivity.updateSummary(getPreferenceScreen()); - //setDnsResolverSummary(SettingsManager.connectionDnsResolver()); - batteryOptimizationPreference = findPreference(getString(R.string.battery_optimization_disable_key)); batteryOptimizationPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override @@ -45,51 +33,9 @@ public boolean onPreferenceClick(Preference preference) { @Override public void onResume() { super.onResume(); - PreferenceManager.getDefaultSharedPreferences(getActivity()) - .registerOnSharedPreferenceChangeListener(this); - updateBatteryOptimizationPreference(); } - @Override - public void onPause() { - super.onPause(); - PreferenceManager.getDefaultSharedPreferences(getActivity()) - .unregisterOnSharedPreferenceChangeListener(this); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { -// if (key.equals(getString(R.string.connection_dns_resolver_type_key))) { -// String value = sharedPreferences.getString(key, getString(R.string.connection_dns_resolver_type_default)); -// SettingsManager.DnsResolverType dnsResolverType = SettingsManager.getDnsResolverType(value); -// setDnsResolverSummary(dnsResolverType); -// -// // reconnect all enabled account to apply and check changes -// Collection enabledAccounts = AccountManager.getInstance().getEnabledAccounts(); -// for (AccountJid accountJid : enabledAccounts) { -// AccountItem accountItem = AccountManager.getInstance().getAccount(accountJid); -// if (accountItem != null) { -// accountItem.recreateConnection(); -// } -// } -// } - } - - private void setDnsResolverSummary(SettingsManager.DnsResolverType dnsResolverType) { - Preference preference = findPreference(getString(R.string.connection_dns_resolver_type_key)); - String summary = ""; - switch (dnsResolverType) { - case dnsJavaResolver: - summary = getString(R.string.connection_dns_resolver_type_dns_java_resolver); - break; - case miniDnsResolver: - summary = getString(R.string.connection_dns_resolver_type_mini_dns_resolver); - break; - } - preference.setSummary(summary); - } - private void updateBatteryOptimizationPreference() { if (!BatteryHelper.isOptimizingBattery()) batteryOptimizationPreference.setSummary(R.string.battery_optimization_disabled); diff --git a/xabber/src/main/res/values-ru-rRU/preference_editor.xml b/xabber/src/main/res/values-ru-rRU/preference_editor.xml index cfc38bc794..ace532f3f7 100644 --- a/xabber/src/main/res/values-ru-rRU/preference_editor.xml +++ b/xabber/src/main/res/values-ru-rRU/preference_editor.xml @@ -100,6 +100,7 @@ Загружать vCard\nЗагружать и обновлять персональную информацию и аватары контактов. Отключение поможет сэкономить трафик. Загружать изображения\nЗагружать изображения по ссылкам автоматически. Отключите для экономии трафика. Сообщения carbons\nПринимать сообщения других сессий Вашей учетной записи. Отключение поможет сэкономить трафик. + Сжатие изображений\nСжимать изображения при загрузке на сервер. Включение поможет сэкономить трафика. Некоторые серверы могут иметь ограничение размера загружаемого файла. Включите, чтобы обойти ограничение. DNSJavaResolver MiniDNSResolver (экспериментальный) Ключевые фразы diff --git a/xabber/src/main/res/values/preference_editor.xml b/xabber/src/main/res/values/preference_editor.xml index 75c79b40a6..41a70aa840 100644 --- a/xabber/src/main/res/values/preference_editor.xml +++ b/xabber/src/main/res/values/preference_editor.xml @@ -117,6 +117,7 @@ Load vCard\nLoad and update contact\'s personal info and avatar. Disable to reduce traffic usage. Load images\nLoad images from file URL automatically. Disable to reduce traffic usage. Carbon-copied mode\nWill share sessions for the same account on this client. Disable to reduce traffic usage. + Compress images\nCompress images on upload to reduce traffic usage. Some servers may have upload size restrictions, use this option to avoid it. DNSJavaResolver MiniDNSResolver (experimental) diff --git a/xabber/src/main/res/values/preferences.xml b/xabber/src/main/res/values/preferences.xml index b2b2460ac2..e73dc077e8 100644 --- a/xabber/src/main/res/values/preferences.xml +++ b/xabber/src/main/res/values/preferences.xml @@ -353,6 +353,9 @@ connection_use_carbons_new true + connection_compress_image_on_upload + true + connection_dns_resolver_type connection_dns_resolver_type_dns_java_resolver diff --git a/xabber/src/main/res/xml/preference_connection.xml b/xabber/src/main/res/xml/preference_connection.xml index aee7c5e468..0530d4d233 100644 --- a/xabber/src/main/res/xml/preference_connection.xml +++ b/xabber/src/main/res/xml/preference_connection.xml @@ -4,12 +4,6 @@ - - - - - - - + - - - - - - - + \ No newline at end of file From 1b6c594ad2dce327de59a0915db5b4875d1b6a5a Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 1 Jul 2019 17:13:32 +0500 Subject: [PATCH 215/237] Fixed in preference_editor --- xabber/src/main/res/values-ru-rRU/preference_editor.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xabber/src/main/res/values-ru-rRU/preference_editor.xml b/xabber/src/main/res/values-ru-rRU/preference_editor.xml index ace532f3f7..d64d9d63e5 100644 --- a/xabber/src/main/res/values-ru-rRU/preference_editor.xml +++ b/xabber/src/main/res/values-ru-rRU/preference_editor.xml @@ -100,7 +100,7 @@ Загружать vCard\nЗагружать и обновлять персональную информацию и аватары контактов. Отключение поможет сэкономить трафик. Загружать изображения\nЗагружать изображения по ссылкам автоматически. Отключите для экономии трафика. Сообщения carbons\nПринимать сообщения других сессий Вашей учетной записи. Отключение поможет сэкономить трафик. - Сжатие изображений\nСжимать изображения при загрузке на сервер. Включение поможет сэкономить трафика. Некоторые серверы могут иметь ограничение размера загружаемого файла. Включите, чтобы обойти ограничение. + Сжатие изображений\nСжимать изображения при загрузке на сервер. Включение поможет сэкономить трафик. Некоторые серверы могут иметь ограничение размера загружаемого файла. Включите, чтобы обойти ограничение. DNSJavaResolver MiniDNSResolver (экспериментальный) Ключевые фразы From 76583dcf2d9b65346de19ed317ceeda98844f56b Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 1 Jul 2019 18:07:11 +0500 Subject: [PATCH 216/237] Up version to 630 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 2377fe4876..e67d39d559 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 629 - versionName '2.6.4(629)' + versionCode 630 + versionName '2.6.4(630)' manifestPlaceholders = [crashlytics:getLocalProperty("crashlytics.key")] } From b92cb4a84e66ba311bb9df2d16eb7d7b96b28313 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 2 Jul 2019 11:54:41 +0500 Subject: [PATCH 217/237] Fixed bug with message notification id's. --- .../android/data/notification/MessageNotificationManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java index 59fdec7807..f1baac8cf6 100644 --- a/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java +++ b/xabber/src/main/java/com/xabber/android/data/notification/MessageNotificationManager.java @@ -326,7 +326,7 @@ private void callUiUpdate() { } private int getNextChatNotificationId() { - return 100 + chats.size() + 1; + return (int) System.currentTimeMillis(); } private String getNotificationText(MessageItem message) { From 771231e8e2de7f8d1b545de50d1bdd7a1fec438b Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 2 Jul 2019 17:08:31 +0500 Subject: [PATCH 218/237] Added CorrectlyTouchEventTextView --- .../adapter/chat/CrowdfundingChatAdapter.java | 5 +- .../android/ui/adapter/chat/MessageVH.java | 4 +- .../ui/widget/CorrectlyMeasuringTextView.java | 3 +- .../widget/CorrectlyTouchEventTextView.java | 123 ++++++++++++++++++ xabber/src/main/res/values/ids.xml | 4 + 5 files changed, 132 insertions(+), 7 deletions(-) create mode 100644 xabber/src/main/java/com/xabber/android/ui/widget/CorrectlyTouchEventTextView.java create mode 100644 xabber/src/main/res/values/ids.xml diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/CrowdfundingChatAdapter.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/CrowdfundingChatAdapter.java index 53a22ee657..e99342092d 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/CrowdfundingChatAdapter.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/CrowdfundingChatAdapter.java @@ -7,7 +7,6 @@ import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; import android.text.Html; -import android.text.method.LinkMovementMethod; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -22,10 +21,10 @@ import com.bumptech.glide.request.target.SimpleTarget; import com.xabber.android.R; import com.xabber.android.data.SettingsManager; -import com.xabber.android.data.database.messagerealm.MessageItem; import com.xabber.android.data.database.realm.CrowdfundingMessage; import com.xabber.android.data.extension.file.FileManager; import com.xabber.android.ui.color.ColorManager; +import com.xabber.android.ui.widget.CorrectlyMeasuringTextView; import com.xabber.android.utils.StringUtils; import com.xabber.android.utils.Utils; @@ -95,7 +94,7 @@ public void onBindViewHolder(@NonNull CrowdMessageVH holder, int i) { holder.messageText.setText(Html.fromHtml(text)); // to avoid bug - https://issuetracker.google.com/issues/36907309 holder.messageText.setAutoLinkMask(0); - holder.messageText.setMovementMethod(LinkMovementMethod.getInstance()); + holder.messageText.setMovementMethod(CorrectlyMeasuringTextView.LocalLinkMovementMethod.getInstance()); // text or image if (FileManager.isImageUrl(text)) { diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java index 433ea4e6be..6f2c0fe5ae 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java @@ -8,7 +8,6 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.Html; -import android.text.method.LinkMovementMethod; import android.view.View; import android.view.ViewTreeObserver; import android.widget.ImageView; @@ -23,6 +22,7 @@ import com.xabber.android.ui.color.ColorManager; import com.xabber.android.ui.fragment.ChatFragment; import com.xabber.android.ui.text.ClickTagHandler; +import com.xabber.android.ui.widget.CorrectlyMeasuringTextView; import com.xabber.android.utils.StringUtils; import java.util.Arrays; @@ -110,7 +110,7 @@ null, new ClickTagHandler(extraData.getContext(), messageText.setVisibility(View.VISIBLE); messageNotDecrypted.setVisibility(View.GONE); } - messageText.setMovementMethod(LinkMovementMethod.getInstance()); + messageText.setMovementMethod(CorrectlyMeasuringTextView.LocalLinkMovementMethod.getInstance()); String time = StringUtils.getTimeText(new Date(messageItem.getTimestamp())); diff --git a/xabber/src/main/java/com/xabber/android/ui/widget/CorrectlyMeasuringTextView.java b/xabber/src/main/java/com/xabber/android/ui/widget/CorrectlyMeasuringTextView.java index c43b7a1656..34fe4be946 100644 --- a/xabber/src/main/java/com/xabber/android/ui/widget/CorrectlyMeasuringTextView.java +++ b/xabber/src/main/java/com/xabber/android/ui/widget/CorrectlyMeasuringTextView.java @@ -1,11 +1,10 @@ package com.xabber.android.ui.widget; import android.content.Context; -import android.support.v7.widget.AppCompatTextView; import android.text.Layout; import android.util.AttributeSet; -public class CorrectlyMeasuringTextView extends AppCompatTextView { +public class CorrectlyMeasuringTextView extends CorrectlyTouchEventTextView { public CorrectlyMeasuringTextView(Context context) { super(context); diff --git a/xabber/src/main/java/com/xabber/android/ui/widget/CorrectlyTouchEventTextView.java b/xabber/src/main/java/com/xabber/android/ui/widget/CorrectlyTouchEventTextView.java new file mode 100644 index 0000000000..be6729485e --- /dev/null +++ b/xabber/src/main/java/com/xabber/android/ui/widget/CorrectlyTouchEventTextView.java @@ -0,0 +1,123 @@ +package com.xabber.android.ui.widget; + +import android.content.Context; +import android.support.v7.widget.AppCompatTextView; +import android.text.Layout; +import android.text.Selection; +import android.text.Spannable; +import android.text.method.LinkMovementMethod; +import android.text.method.Touch; +import android.text.style.BackgroundColorSpan; +import android.text.style.ClickableSpan; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.widget.TextView; + +import com.xabber.android.R; + +public class CorrectlyTouchEventTextView extends AppCompatTextView { + boolean clickableSpanClicked; + + public CorrectlyTouchEventTextView(Context context) { + super(context); + } + + public CorrectlyTouchEventTextView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CorrectlyTouchEventTextView( + Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + clickableSpanClicked = false; + super.onTouchEvent(event); + return clickableSpanClicked; + } + + public static class LocalLinkMovementMethod extends LinkMovementMethod { + static LocalLinkMovementMethod instance; + + private boolean isUrlHighlighted; + + public static LocalLinkMovementMethod getInstance() { + if (instance == null) + instance = new LocalLinkMovementMethod(); + return instance; + } + + @Override + public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { + int action = event.getAction(); + + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) { + int x = (int) event.getX(); + int y = (int) event.getY(); + + x -= widget.getTotalPaddingLeft(); + y -= widget.getTotalPaddingTop(); + + x += widget.getScrollX(); + y += widget.getScrollY(); + + Layout layout = widget.getLayout(); + int line = layout.getLineForVertical(y); + int off = layout.getOffsetForHorizontal(line, x); + + ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); + + if (link.length != 0) { + if (action == MotionEvent.ACTION_UP) { + link[0].onClick(widget); + removeUrlHighlightColor(widget); + } else if (action == MotionEvent.ACTION_DOWN) { + Selection.setSelection(buffer, + buffer.getSpanStart(link[0]), + buffer.getSpanEnd(link[0])); + highlightUrl(widget, link[0], buffer); + } + + if (widget instanceof CorrectlyTouchEventTextView){ + ((CorrectlyTouchEventTextView) widget).clickableSpanClicked = true; + } + + return true; + } else { + Selection.removeSelection(buffer); + Touch.onTouchEvent(widget, buffer, event); + return false; + } + } + return Touch.onTouchEvent(widget, buffer, event); + } + + protected void highlightUrl(TextView textView, ClickableSpan clickableSpan, Spannable text) { + if (isUrlHighlighted) return; + isUrlHighlighted = true; + + int spanStart = text.getSpanStart(clickableSpan); + int spanEnd = text.getSpanEnd(clickableSpan); + BackgroundColorSpan highlightSpan; + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) { + highlightSpan = new BackgroundColorSpan(textView.getHighlightColor()); + } else highlightSpan = new BackgroundColorSpan(textView.getLinkTextColors().getDefaultColor()); + text.setSpan(highlightSpan, spanStart, spanEnd, Spannable.SPAN_INCLUSIVE_INCLUSIVE); + textView.setTag(R.id.clickable_span_highlight_background, highlightSpan); + Selection.setSelection(text, spanStart, spanEnd); + } + + protected void removeUrlHighlightColor(TextView textView) { + if (!isUrlHighlighted) return; + isUrlHighlighted = false; + + Spannable text = (Spannable) textView.getText(); + BackgroundColorSpan highlightSpan = (BackgroundColorSpan) textView.getTag(R.id.clickable_span_highlight_background); + text.removeSpan(highlightSpan); + Selection.removeSelection(text); + } + } +} diff --git a/xabber/src/main/res/values/ids.xml b/xabber/src/main/res/values/ids.xml new file mode 100644 index 0000000000..30020bb66b --- /dev/null +++ b/xabber/src/main/res/values/ids.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 7cad2c9a8c1e085b53afd45c46e047d70e261973 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 2 Jul 2019 18:02:33 +0500 Subject: [PATCH 219/237] Fixed bug with clicking by empty space after ClickableSpan --- .../android/ui/adapter/chat/CrowdfundingChatAdapter.java | 4 +++- .../java/com/xabber/android/ui/adapter/chat/MessageVH.java | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/CrowdfundingChatAdapter.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/CrowdfundingChatAdapter.java index e99342092d..c70b984c58 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/CrowdfundingChatAdapter.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/CrowdfundingChatAdapter.java @@ -91,7 +91,9 @@ public void onBindViewHolder(@NonNull CrowdMessageVH holder, int i) { // text String text = message.getMessageForCurrentLocale(); if (text == null) text = ""; - holder.messageText.setText(Html.fromHtml(text)); + // Added .concat("‍") + // to avoid click by empty space after ClickableSpan + holder.messageText.setText(Html.fromHtml(text.concat("‍"))); // to avoid bug - https://issuetracker.google.com/issues/36907309 holder.messageText.setAutoLinkMask(0); holder.messageText.setMovementMethod(CorrectlyMeasuringTextView.LocalLinkMovementMethod.getInstance()); diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java index 6f2c0fe5ae..ee9665fea9 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java @@ -95,12 +95,14 @@ public void bind(MessageItem messageItem, MessagesAdapter.MessageExtraData extra ivEncrypted.setVisibility(View.GONE); } + // Added .concat("‍") and .concat(String.valueOf(Character.MIN_VALUE) + // to avoid click by empty space after ClickableSpan if (messageItem.getMarkupText() != null && !messageItem.getMarkupText().isEmpty()) messageText.setText(Html.fromHtml( - messageItem.getMarkupText().replace("\n", "
"), + messageItem.getMarkupText().replace("\n", "
").concat("‍"), null, new ClickTagHandler(extraData.getContext(), extraData.getMentionColor())), TextView.BufferType.SPANNABLE); - else messageText.setText(messageItem.getText()); + else messageText.setText(messageItem.getText().concat(String.valueOf(Character.MIN_VALUE))); if (OTRManager.getInstance().isEncrypted(messageItem.getText())) { if (extraData.isShowOriginalOTR()) messageText.setVisibility(View.VISIBLE); From 7337438ab8845818f7f84170d91b3569dd3d3e6b Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 2 Jul 2019 18:23:10 +0500 Subject: [PATCH 220/237] Up version to 631 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index e67d39d559..e90fa4dcb6 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 630 - versionName '2.6.4(630)' + versionCode 631 + versionName '2.6.4(631)' manifestPlaceholders = [crashlytics:getLocalProperty("crashlytics.key")] } From 975b29d04b2ec9cafecf6b236872a3847245077b Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Thu, 4 Jul 2019 14:03:19 +0500 Subject: [PATCH 221/237] Temporary disabled quotes --- .../references/ReferencesManager.java | 2 +- .../references/ReferencesManagerTest.java | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index f50aa7e356..b810b61d1d 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -163,7 +163,7 @@ private static String[] modifyBodyWithReferences(String[] chars, ReferenceElemen chars = markup(begin, end, chars, (Markup) reference); break; case quote: - chars = removeInLine(begin, end, chars, (Quote) reference); + //chars = removeInLine(begin, end, chars, (Quote) reference); break; case mention: chars = mention(begin, end, chars, (Mention) reference); diff --git a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java index 4645493bde..ae982c4521 100644 --- a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java +++ b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java @@ -105,15 +105,15 @@ public void modifyBodyWithReferences3() { "Использование нескольких стилей.", result.second); } - @Test - public void modifyBodyWithReferences4() { - String expected = "This is a quote\n" + - "of two lines\n" + - "Hello world!"; - Pair result = ReferencesManager.modifyBodyWithReferences(message4, body4); - assertEquals(expected, result.first); - assertNull(result.second); - } +// @Test +// public void modifyBodyWithReferences4() { +// String expected = "This is a quote\n" + +// "of two lines\n" + +// "Hello world!"; +// Pair result = ReferencesManager.modifyBodyWithReferences(message4, body4); +// assertEquals(expected, result.first); +// assertNull(result.second); +// } @Test public void modifyBodyWithReferences5() { From 6e2f2175e73e14a7ca12c3b6c1dec780687a6196 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 5 Jul 2019 15:24:17 +0500 Subject: [PATCH 222/237] Try to fix ANR in GoAwayReceiver and GoXaReceiver --- .../java/com/xabber/android/receiver/GoAwayReceiver.java | 8 +++++++- .../java/com/xabber/android/receiver/GoXaReceiver.java | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/receiver/GoAwayReceiver.java b/xabber/src/main/java/com/xabber/android/receiver/GoAwayReceiver.java index 64055253dd..3769d0cdfc 100644 --- a/xabber/src/main/java/com/xabber/android/receiver/GoAwayReceiver.java +++ b/xabber/src/main/java/com/xabber/android/receiver/GoAwayReceiver.java @@ -18,6 +18,7 @@ import android.content.Context; import android.content.Intent; +import com.xabber.android.data.Application; import com.xabber.android.data.account.AccountManager; /** @@ -29,7 +30,12 @@ public class GoAwayReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - AccountManager.getInstance().goAway(); + Application.getInstance().runInBackgroundUserRequest(new Runnable() { + @Override + public void run() { + AccountManager.getInstance().goAway(); + } + }); } public static Intent createIntent(Context context) { diff --git a/xabber/src/main/java/com/xabber/android/receiver/GoXaReceiver.java b/xabber/src/main/java/com/xabber/android/receiver/GoXaReceiver.java index b48d98a7b8..2ccb269d2f 100644 --- a/xabber/src/main/java/com/xabber/android/receiver/GoXaReceiver.java +++ b/xabber/src/main/java/com/xabber/android/receiver/GoXaReceiver.java @@ -18,6 +18,7 @@ import android.content.Context; import android.content.Intent; +import com.xabber.android.data.Application; import com.xabber.android.data.account.AccountManager; /** @@ -29,7 +30,12 @@ public class GoXaReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - AccountManager.getInstance().goXa(); + Application.getInstance().runInBackgroundUserRequest(new Runnable() { + @Override + public void run() { + AccountManager.getInstance().goXa(); + } + }); } public static Intent createIntent(Context context) { From e4e5df1fecf89094cd0099ea3fc128cd738a5a8d Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 5 Jul 2019 16:47:47 +0500 Subject: [PATCH 223/237] Try to fix ANR in ScreenManager --- .../android/data/account/ScreenManager.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/ScreenManager.java b/xabber/src/main/java/com/xabber/android/data/account/ScreenManager.java index 378000c390..6058115c2c 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/ScreenManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/ScreenManager.java @@ -102,14 +102,18 @@ public void onScreen(Intent intent) { if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) { LogManager.i(LOG_TAG, "onScreen ACTION_SCREEN_ON isOptimizingBattery: " + BatteryHelper.isOptimizingBattery()); -// ConnectionManager.getInstance().updateConnections(false); alarmManager.cancel(goAwayPendingIntent); alarmManager.cancel(goXaPendingIntent); - AccountManager.getInstance().wakeUp(); - AccountManager.getInstance().stopGracePeriod(); - // notify server(s) that client is now active - ClientStateManager.setActive(); + AccountManager.getInstance().stopGracePeriod(); + Application.getInstance().runInBackgroundUserRequest(new Runnable() { + @Override + public void run() { + // notify server(s) that client is now active + AccountManager.getInstance().wakeUp(); + ClientStateManager.setActive(); + } + }); } else if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { LogManager.i(LOG_TAG, "onScreen ACTION_SCREEN_OFF isOptimizingBattery: " + BatteryHelper.isOptimizingBattery()); @@ -120,8 +124,13 @@ public void onScreen(Intent intent) { alarmManager.set(AlarmManager.RTC_WAKEUP, getTime(goXa), goXaPendingIntent); - // notify server(s) that client is now inactive - ClientStateManager.setInactive(); + Application.getInstance().runInBackgroundUserRequest(new Runnable() { + @Override + public void run() { + // notify server(s) that client is now inactive + ClientStateManager.setInactive(); + } + }); } } From a4a5361a05b502a975bed113a2ff8486fcb90718 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 5 Jul 2019 17:41:10 +0500 Subject: [PATCH 224/237] htmlEncode replaced with xmlEncode to resolve issue with apostrophe --- .../references/ReferencesManager.java | 4 +-- .../references/ReferencesProvider.java | 5 ++-- .../android/data/message/AbstractChat.java | 3 +- .../com/xabber/android/utils/StringUtils.java | 29 +++++++++++++++++++ 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index b810b61d1d..191f239777 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -1,12 +1,12 @@ package com.xabber.android.data.extension.references; import android.text.Html; -import android.text.TextUtils; import android.util.Pair; import com.xabber.android.data.database.messagerealm.Attachment; import com.xabber.android.data.database.messagerealm.MessageItem; import com.xabber.android.ui.text.ClickSpan; +import com.xabber.android.utils.StringUtils; import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.Message; @@ -91,7 +91,7 @@ public static Pair modifyBodyWithReferences(Message message, Str if (references.isEmpty()) return new Pair<>(body, null); // encode HTML and split into chars - String[] chars = stringToChars(TextUtils.htmlEncode(body)); + String[] chars = stringToChars(StringUtils.xmlEncode(body)); // modify chars with references except markup and mention for (ReferenceElement reference : references) { diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java index a0ce1cb0ca..7d92b35e15 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java @@ -1,8 +1,7 @@ package com.xabber.android.data.extension.references; -import android.text.TextUtils; - import com.xabber.android.data.log.LogManager; +import com.xabber.android.utils.StringUtils; import org.jivesoftware.smack.provider.ExtensionElementProvider; import org.jivesoftware.smackx.forward.packet.Forwarded; @@ -55,7 +54,7 @@ public ReferenceElement parse(XmlPullParser parser, int initialDepth) throws Exc } else if (ReferenceElement.ELEMENT_URI.equals(parser.getName())) { uri = parser.nextText(); } else if (ReferenceElement.ELEMENT_MARKER.equals(parser.getName())) { - marker = TextUtils.htmlEncode(parser.nextText()); + marker = StringUtils.xmlEncode(parser.nextText()); } else parser.next(); break; case XmlPullParser.END_TAG: diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index 869da71cbb..f1ddd66301 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -17,7 +17,6 @@ import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.text.TextUtils; import com.xabber.android.data.Application; import com.xabber.android.data.NetworkException; @@ -594,7 +593,7 @@ public Message createFileMessagePacket(String stanzaId, RealmList at } private int getSizeOfEncodedChars(String str) { - return TextUtils.htmlEncode(str).toCharArray().length; + return com.xabber.android.utils.StringUtils.xmlEncode(str).toCharArray().length; } /** diff --git a/xabber/src/main/java/com/xabber/android/utils/StringUtils.java b/xabber/src/main/java/com/xabber/android/utils/StringUtils.java index ffb667f189..3dafe7c267 100644 --- a/xabber/src/main/java/com/xabber/android/utils/StringUtils.java +++ b/xabber/src/main/java/com/xabber/android/utils/StringUtils.java @@ -122,6 +122,35 @@ else if (codePoint >= 0 && codePoint < 160) return builder.toString(); } + public static String xmlEncode(String s) { + StringBuilder sb = new StringBuilder(); + char c; + for (int i = 0; i < s.length(); i++) { + c = s.charAt(i); + switch (c) { + case '<': + sb.append("<"); //$NON-NLS-1$ + break; + case '>': + sb.append(">"); //$NON-NLS-1$ + break; + case '&': + sb.append("&"); //$NON-NLS-1$ + break; + case '\'': + // In this implementation we use ' instead of ' because we encode XML, not HTML. + sb.append("'"); //$NON-NLS-1$ + break; + case '"': + sb.append("""); //$NON-NLS-1$ + break; + default: + sb.append(c); + } + } + return sb.toString(); + } + /** * @param timeStamp * @return String with date and time to be display. From 6f50c49d796df356971a40102ef50b52d080891b Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 5 Jul 2019 17:48:13 +0500 Subject: [PATCH 225/237] Changed counter in image grid --- .../com/xabber/android/ui/widget/ImageGridBuilder.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/widget/ImageGridBuilder.java b/xabber/src/main/java/com/xabber/android/ui/widget/ImageGridBuilder.java index a3a8a51f1e..56b6b3daa1 100644 --- a/xabber/src/main/java/com/xabber/android/ui/widget/ImageGridBuilder.java +++ b/xabber/src/main/java/com/xabber/android/ui/widget/ImageGridBuilder.java @@ -8,11 +8,8 @@ import android.widget.TextView; import com.bumptech.glide.Glide; -import com.bumptech.glide.load.resource.drawable.GlideDrawable; -import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.animation.GlideAnimation; import com.bumptech.glide.request.target.SimpleTarget; -import com.bumptech.glide.request.target.Target; import com.xabber.android.R; import com.xabber.android.data.database.MessageDatabaseManager; import com.xabber.android.data.database.messagerealm.Attachment; @@ -24,6 +21,8 @@ public class ImageGridBuilder { + private static final int MAX_IMAGE_IN_GRID = 5; + public View inflateView(ViewGroup parent, int imageCount) { return LayoutInflater.from(parent.getContext()).inflate(getLayoutResource(imageCount), parent, false); } @@ -51,8 +50,8 @@ public void bindView(View view, RealmList attachments, View.OnClickL } if (tvCounter != null) { - if (attachments.size() > 6) { - tvCounter.setText("+" + (attachments.size() - 6)); + if (attachments.size() > MAX_IMAGE_IN_GRID) { + tvCounter.setText(new StringBuilder("+").append(attachments.size() - MAX_IMAGE_IN_GRID)); tvCounter.setVisibility(View.VISIBLE); } else tvCounter.setVisibility(View.GONE); } From b8b2420f7e4be5badfaa2102202edfbf65286b31 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 5 Jul 2019 18:00:18 +0500 Subject: [PATCH 226/237] Try to fix ANR in sendReceived and sendDisplayed chat markers --- .../chat_markers/ChatMarkerManager.java | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/chat_markers/ChatMarkerManager.java b/xabber/src/main/java/com/xabber/android/data/extension/chat_markers/ChatMarkerManager.java index 7829c8f253..4652bd078f 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/chat_markers/ChatMarkerManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/chat_markers/ChatMarkerManager.java @@ -1,5 +1,6 @@ package com.xabber.android.data.extension.chat_markers; +import com.xabber.android.data.Application; import com.xabber.android.data.NetworkException; import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.account.AccountManager; @@ -102,11 +103,8 @@ public void sendDisplayed(MessageItem messageItem) { Message displayed = new Message(messageItem.getUser().getJid()); displayed.addExtension(new ChatMarkersElements.DisplayedExtension(messageItem.getStanzaId())); displayed.setType(Message.Type.chat); - try { - StanzaSender.sendStanza(messageItem.getAccount(), displayed); - } catch (NetworkException e) { - LogManager.exception(this, e); - } + + sendMessageInBackgroundUserRequest(displayed, messageItem.getAccount()); } public void processCarbonsMessage(AccountJid account, final Message message, CarbonExtension.Direction direction) { @@ -164,11 +162,20 @@ private void sendReceived(Message message, AccountJid account) { received.setThread(message.getThread()); received.setType(Message.Type.chat); - try { - StanzaSender.sendStanza(account, received); - } catch (NetworkException e) { - LogManager.exception(this, e); - } + sendMessageInBackgroundUserRequest(received, account); + } + + private void sendMessageInBackgroundUserRequest(final Message message, final AccountJid account) { + Application.getInstance().runInBackgroundUserRequest(new Runnable() { + @Override + public void run() { + try { + StanzaSender.sendStanza(account, message); + } catch (NetworkException e) { + LogManager.exception(this, e); + } + } + }); } private void markAsDisplayed(final String messageID) { From bc13367717ead8b73286cdbf7db5477bd0679b98 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 5 Jul 2019 18:13:39 +0500 Subject: [PATCH 227/237] xmlEncode replaced from StringUtils to Utils --- .../references/ReferencesManager.java | 4 +-- .../references/ReferencesProvider.java | 4 +-- .../android/data/message/AbstractChat.java | 3 +- .../com/xabber/android/utils/StringUtils.java | 29 ------------------- .../java/com/xabber/android/utils/Utils.java | 28 ++++++++++++++++++ 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index 191f239777..a96eb77deb 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -6,7 +6,7 @@ import com.xabber.android.data.database.messagerealm.Attachment; import com.xabber.android.data.database.messagerealm.MessageItem; import com.xabber.android.ui.text.ClickSpan; -import com.xabber.android.utils.StringUtils; +import com.xabber.android.utils.Utils; import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.Message; @@ -91,7 +91,7 @@ public static Pair modifyBodyWithReferences(Message message, Str if (references.isEmpty()) return new Pair<>(body, null); // encode HTML and split into chars - String[] chars = stringToChars(StringUtils.xmlEncode(body)); + String[] chars = stringToChars(Utils.xmlEncode(body)); // modify chars with references except markup and mention for (ReferenceElement reference : references) { diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java index 7d92b35e15..fccd46e176 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesProvider.java @@ -1,7 +1,7 @@ package com.xabber.android.data.extension.references; import com.xabber.android.data.log.LogManager; -import com.xabber.android.utils.StringUtils; +import com.xabber.android.utils.Utils; import org.jivesoftware.smack.provider.ExtensionElementProvider; import org.jivesoftware.smackx.forward.packet.Forwarded; @@ -54,7 +54,7 @@ public ReferenceElement parse(XmlPullParser parser, int initialDepth) throws Exc } else if (ReferenceElement.ELEMENT_URI.equals(parser.getName())) { uri = parser.nextText(); } else if (ReferenceElement.ELEMENT_MARKER.equals(parser.getName())) { - marker = StringUtils.xmlEncode(parser.nextText()); + marker = Utils.xmlEncode(parser.nextText()); } else parser.next(); break; case XmlPullParser.END_TAG: diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index f1ddd66301..5e6caea70c 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -44,6 +44,7 @@ import com.xabber.android.data.notification.MessageNotificationManager; import com.xabber.android.data.notification.NotificationManager; import com.xabber.android.data.roster.RosterCacheManager; +import com.xabber.android.utils.Utils; import com.xabber.xmpp.sid.OriginIdElement; import com.xabber.xmpp.sid.UniqStanzaHelper; @@ -593,7 +594,7 @@ public Message createFileMessagePacket(String stanzaId, RealmList at } private int getSizeOfEncodedChars(String str) { - return com.xabber.android.utils.StringUtils.xmlEncode(str).toCharArray().length; + return Utils.xmlEncode(str).toCharArray().length; } /** diff --git a/xabber/src/main/java/com/xabber/android/utils/StringUtils.java b/xabber/src/main/java/com/xabber/android/utils/StringUtils.java index 3dafe7c267..ffb667f189 100644 --- a/xabber/src/main/java/com/xabber/android/utils/StringUtils.java +++ b/xabber/src/main/java/com/xabber/android/utils/StringUtils.java @@ -122,35 +122,6 @@ else if (codePoint >= 0 && codePoint < 160) return builder.toString(); } - public static String xmlEncode(String s) { - StringBuilder sb = new StringBuilder(); - char c; - for (int i = 0; i < s.length(); i++) { - c = s.charAt(i); - switch (c) { - case '<': - sb.append("<"); //$NON-NLS-1$ - break; - case '>': - sb.append(">"); //$NON-NLS-1$ - break; - case '&': - sb.append("&"); //$NON-NLS-1$ - break; - case '\'': - // In this implementation we use ' instead of ' because we encode XML, not HTML. - sb.append("'"); //$NON-NLS-1$ - break; - case '"': - sb.append("""); //$NON-NLS-1$ - break; - default: - sb.append(c); - } - } - return sb.toString(); - } - /** * @param timeStamp * @return String with date and time to be display. diff --git a/xabber/src/main/java/com/xabber/android/utils/Utils.java b/xabber/src/main/java/com/xabber/android/utils/Utils.java index 612a4c96a9..fc647dc3c9 100644 --- a/xabber/src/main/java/com/xabber/android/utils/Utils.java +++ b/xabber/src/main/java/com/xabber/android/utils/Utils.java @@ -48,4 +48,32 @@ private static void startXabberServiceCompat(Context context, Intent intent) { else context.startService(intent); } + public static String xmlEncode(String s) { + StringBuilder sb = new StringBuilder(); + char c; + for (int i = 0; i < s.length(); i++) { + c = s.charAt(i); + switch (c) { + case '<': + sb.append("<"); //$NON-NLS-1$ + break; + case '>': + sb.append(">"); //$NON-NLS-1$ + break; + case '&': + sb.append("&"); //$NON-NLS-1$ + break; + case '\'': + // In this implementation we use ' instead of ' because we encode XML, not HTML. + sb.append("'"); //$NON-NLS-1$ + break; + case '"': + sb.append("""); //$NON-NLS-1$ + break; + default: + sb.append(c); + } + } + return sb.toString(); + } } From d7175c892f9388857f46b04d11da3ad33f675be0 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 5 Jul 2019 18:27:37 +0500 Subject: [PATCH 228/237] Try to fix ANR in AccountActivity and blockListAdapter --- .../java/com/xabber/android/ui/activity/AccountActivity.java | 2 +- .../java/com/xabber/android/ui/adapter/BlockedListAdapter.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/activity/AccountActivity.java b/xabber/src/main/java/com/xabber/android/ui/activity/AccountActivity.java index e075ab90ed..ff87f9b8ca 100644 --- a/xabber/src/main/java/com/xabber/android/ui/activity/AccountActivity.java +++ b/xabber/src/main/java/com/xabber/android/ui/activity/AccountActivity.java @@ -194,7 +194,7 @@ private void updateBlockListOption() { } else if (!supported) { description = getString(R.string.blocked_contacts_not_supported); } else { - int size = blockingManager.getBlockedContacts(account).size(); + int size = blockingManager.getCachedBlockedContacts(account).size(); if (size == 0) { description = getString(R.string.blocked_contacts_empty); } else { diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/BlockedListAdapter.java b/xabber/src/main/java/com/xabber/android/ui/adapter/BlockedListAdapter.java index a4fe4c1695..fe0fe614c7 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/BlockedListAdapter.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/BlockedListAdapter.java @@ -74,7 +74,7 @@ public int getItemCount() { @Override public void onChange() { blockedContacts.clear(); - final Collection blockedContacts = BlockingManager.getInstance().getBlockedContacts(account); + final Collection blockedContacts = BlockingManager.getInstance().getCachedBlockedContacts(account); if (blockedContacts != null) { this.blockedContacts.addAll(blockedContacts); } From 426df17921ed3379c157285b735db2f40195eaf5 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 5 Jul 2019 18:33:31 +0500 Subject: [PATCH 229/237] Removed redundant request of blocked contacts --- .../android/data/extension/vcard/VCardManager.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/vcard/VCardManager.java b/xabber/src/main/java/com/xabber/android/data/extension/vcard/VCardManager.java index 769f00e7a8..71c182cc7d 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/vcard/VCardManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/vcard/VCardManager.java @@ -15,7 +15,6 @@ package com.xabber.android.data.extension.vcard; import android.database.Cursor; -import android.util.Log; import com.xabber.android.data.Application; import com.xabber.android.data.NetworkException; @@ -45,11 +44,9 @@ import org.jivesoftware.smack.AbstractXMPPConnection; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ.Type; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Stanza; -import org.jivesoftware.smack.packet.XMPPError; import org.jivesoftware.smackx.vcardtemp.packet.VCard; import org.jxmpp.jid.BareJid; import org.jxmpp.jid.EntityBareJid; @@ -153,16 +150,12 @@ public void onRosterReceived(AccountItem accountItem) { } } - Collection blockedContacts = BlockingManager.getInstance().getBlockedContacts(account); - Collection accountRosterContacts = RosterManager.getInstance().getAccountRosterContacts(account); // Request vCards for new contacts. for (RosterContact contact : accountRosterContacts) { if (!names.containsKey(contact.getUser().getJid())) { - if (!blockedContacts.contains(contact.getUser())) { - request(account, contact.getUser().getJid()); - } + request(account, contact.getUser().getJid()); } } } From c031acaeebbfe8739b14973d96fb7324270573bf Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Fri, 5 Jul 2019 18:36:15 +0500 Subject: [PATCH 230/237] Up version to 632 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index e90fa4dcb6..c5f9082b2f 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 631 - versionName '2.6.4(631)' + versionCode 632 + versionName '2.6.4(632)' manifestPlaceholders = [crashlytics:getLocalProperty("crashlytics.key")] } From 14c55b28c6c6824e9c4d091753fc0656cbd2b07a Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 8 Jul 2019 16:02:00 +0500 Subject: [PATCH 231/237] Fixed timestamp in forwarded messages and order of forwarded messages --- .../android/data/extension/muc/RoomChat.java | 20 ++++++------ .../android/data/message/AbstractChat.java | 31 +++++++++++++------ .../data/message/CrowdfundingChat.java | 2 +- .../android/data/message/RegularChat.java | 30 +++++++----------- .../android/ui/adapter/chat/MessageVH.java | 4 ++- 5 files changed, 45 insertions(+), 42 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java b/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java index e50e1f258b..e3e0fa4e06 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java @@ -261,11 +261,7 @@ protected boolean onPacket(UserJid bareAddress, Stanza stanza, boolean isCarbons } else { boolean notify = true; - DelayInformation delayInformation = DelayInformation.from(message); - Date delay = null; - if (delayInformation != null) { - delay = delayInformation.getStamp(); - } + Date delay = getDelayStamp(message); if (delay != null) { notify = false; @@ -304,12 +300,14 @@ protected boolean onPacket(UserJid bareAddress, Stanza stanza, boolean isCarbons // create message with file-attachments if (attachments.size() > 0) - createAndSaveFileMessage(true, uid, resource, text, markupText, null, delay, true, notify, + createAndSaveFileMessage(true, uid, resource, text, markupText, null, + null, delay, true, notify, false, false, getStanzaId(message), attachments, originalStanza, null, originalFrom, true, false); // create message without attachments - else createAndSaveNewMessage(true, uid, resource, text, markupText, null, delay, true, notify, + else createAndSaveNewMessage(true, uid, resource, text, markupText, null, + null, delay, true, notify, false, false, getStanzaId(message), originalStanza, null, originalFrom, forwardIds, true, false); @@ -373,7 +371,7 @@ false, false, getStanzaId(message), } @Override - protected String parseInnerMessage(boolean ui, Message message, String parentMessageId) { + protected String parseInnerMessage(boolean ui, Message message, Date timestamp, String parentMessageId) { if (message.getType() == Message.Type.error) return null; final org.jxmpp.jid.Jid from = message.getFrom(); @@ -403,12 +401,12 @@ protected String parseInnerMessage(boolean ui, Message message, String parentMes // create message with file-attachments if (attachments.size() > 0) - createAndSaveFileMessage(ui, uid, resource, text, markupText, null, null, + createAndSaveFileMessage(ui, uid, resource, text, markupText, null, timestamp, getDelayStamp(message), true, false, false, false, getStanzaId(message), attachments, originalStanza, parentMessageId, originalFrom, fromMUC, true); // create message without attachments - else createAndSaveNewMessage(ui, uid, resource, text, markupText, null, null, + else createAndSaveNewMessage(ui, uid, resource, text, markupText, null, timestamp, getDelayStamp(message), true, false, false, false, getStanzaId(message), originalStanza, parentMessageId, originalFrom, forwardIds, fromMUC, true); @@ -479,7 +477,7 @@ private void onAvailable(Resourcepart resource) { if (showStatusChange()) { createAndSaveNewMessage(true, UUID.randomUUID().toString(), resource, Application.getInstance().getString( R.string.action_join_complete_to, user), null, - ChatAction.complete, null, true, true, + ChatAction.complete, null, null, true, true, false, false, null, null, null, null, null, true, false); } diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java index 5e6caea70c..d32ea0927a 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java @@ -262,7 +262,7 @@ public void enableNotificationsIfNeed() { */ public void newAction(Resourcepart resource, String text, ChatAction action, boolean fromMUC) { createAndSaveNewMessage(true, UUID.randomUUID().toString(), resource, text, null, - action, null, true, false, false, false, + action, null, null, true, false, false, false, null, null, null, null, null, fromMUC, false); } @@ -282,14 +282,14 @@ public void newAction(Resourcepart resource, String text, ChatAction action, boo * @return */ protected void createAndSaveNewMessage(boolean ui, String uid, Resourcepart resource, String text, - String markupText, final ChatAction action, + String markupText, final ChatAction action, final Date timestamp, final Date delayTimestamp, final boolean incoming, boolean notify, final boolean encrypted, final boolean offline, final String stanzaId, final String originalStanza, final String parentMessageId, final String originalFrom, final RealmList forwardIds, boolean fromMUC, boolean fromMAM) { final MessageItem messageItem = createMessageItem(uid, resource, text, markupText, action, - delayTimestamp, incoming, notify, encrypted, offline, stanzaId, null, + timestamp, delayTimestamp, incoming, notify, encrypted, offline, stanzaId, null, originalStanza, parentMessageId, originalFrom, forwardIds, fromMUC, fromMAM); saveMessageItem(ui, messageItem); @@ -297,14 +297,14 @@ protected void createAndSaveNewMessage(boolean ui, String uid, Resourcepart reso } protected void createAndSaveFileMessage(boolean ui, String uid, Resourcepart resource, String text, - String markupText, final ChatAction action, + String markupText, final ChatAction action, final Date timestamp, final Date delayTimestamp, final boolean incoming, boolean notify, final boolean encrypted, final boolean offline, final String stanzaId, RealmList attachments, final String originalStanza, final String parentMessageId, final String originalFrom, boolean fromMUC, boolean fromMAM) { final MessageItem messageItem = createMessageItem(uid, resource, text, markupText, action, - delayTimestamp, incoming, notify, encrypted, offline, stanzaId, attachments, + timestamp, delayTimestamp, incoming, notify, encrypted, offline, stanzaId, attachments, originalStanza, parentMessageId, originalFrom, null, fromMUC, fromMAM); saveMessageItem(ui, messageItem); @@ -336,12 +336,12 @@ protected MessageItem createMessageItem(Resourcepart resource, String text, RealmList forwardIds, boolean fromMUC) { return createMessageItem(UUID.randomUUID().toString(), resource, text, markupText, action, - delayTimestamp, incoming, notify, encrypted, offline, stanzaId, attachments, + null, delayTimestamp, incoming, notify, encrypted, offline, stanzaId, attachments, originalStanza, parentMessageId, originalFrom, forwardIds, fromMUC, false); } protected MessageItem createMessageItem(String uid, Resourcepart resource, String text, - String markupText, ChatAction action, + String markupText, ChatAction action, Date timestamp, Date delayTimestamp, boolean incoming, boolean notify, boolean encrypted, boolean offline, String stanzaId, RealmList attachments, String originalStanza, String parentMessageId, String originalFrom, @@ -361,7 +361,7 @@ protected MessageItem createMessageItem(String uid, Resourcepart resource, Strin send = true; } - final Date timestamp = new Date(); + if (timestamp == null) timestamp = new Date(); if (text.trim().isEmpty()) { notify = false; @@ -928,14 +928,16 @@ public RealmList parseForwardedMessage(boolean ui, Stanza packet, Str RealmList forwardedIds = new RealmList<>(); for (Forwarded forward : forwarded) { Stanza stanza = forward.getForwardedStanza(); + DelayInformation delayInformation = forward.getDelayInformation(); + Date timestamp = delayInformation.getStamp(); if (stanza instanceof Message) { - forwardedIds.add(new ForwardId(parseInnerMessage(ui, (Message) stanza, parentMessageId))); + forwardedIds.add(new ForwardId(parseInnerMessage(ui, (Message) stanza, timestamp, parentMessageId))); } } return forwardedIds; } - protected abstract String parseInnerMessage(boolean ui, Message message, String parentMessageId); + protected abstract String parseInnerMessage(boolean ui, Message message, Date timestamp, String parentMessageId); public String getLastMessageId() { return lastMessageId; @@ -974,4 +976,13 @@ public static String getStanzaId(Message message) { stanzaId = message.getStanzaId(); return stanzaId; } + + public static Date getDelayStamp(Message message) { + DelayInformation delayInformation = DelayInformation.from(message); + if (delayInformation != null) { + return delayInformation.getStamp(); + } else { + return null; + } + } } \ No newline at end of file diff --git a/xabber/src/main/java/com/xabber/android/data/message/CrowdfundingChat.java b/xabber/src/main/java/com/xabber/android/data/message/CrowdfundingChat.java index a07de3ee1c..38afd58418 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/CrowdfundingChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/CrowdfundingChat.java @@ -56,7 +56,7 @@ public CrowdfundingMessage getLastCrowdMessage() { } @Override - protected String parseInnerMessage(boolean ui, Message message, String parentMessageId) { + protected String parseInnerMessage(boolean ui, Message message, Date timestamp, String parentMessageId) { return null; } diff --git a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java index fa4fb05c9b..bf21d12ac7 100644 --- a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java +++ b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java @@ -236,15 +236,15 @@ protected boolean onPacket(UserJid bareAddress, Stanza packet, boolean isCarbons // create message with file-attachments if (attachments.size() > 0) - createAndSaveFileMessage(true, uid, resource, text, markupText, null, getDelayStamp(message), - true, true, encrypted, + createAndSaveFileMessage(true, uid, resource, text, markupText, null, + null, getDelayStamp(message), true, true, encrypted, isOfflineMessage(account.getFullJid().getDomain(), packet), getStanzaId(message), attachments, originalStanza, null, originalFrom, false, false); // create message without attachments - else createAndSaveNewMessage(true, uid, resource, text, markupText, null, getDelayStamp(message), - true, true, encrypted, + else createAndSaveNewMessage(true, uid, resource, text, markupText, null, + null, getDelayStamp(message), true, true, encrypted, isOfflineMessage(account.getFullJid().getDomain(), packet), getStanzaId(message), originalStanza, null, originalFrom, forwardIds,false, false); @@ -255,7 +255,7 @@ else createAndSaveNewMessage(true, uid, resource, text, markupText, null, getDel } @Override - protected String parseInnerMessage(boolean ui, Message message, String parentMessageId) { + protected String parseInnerMessage(boolean ui, Message message, Date timestamp, String parentMessageId) { if (message.getType() == Message.Type.error) return null; MUCUser mucUser = MUCUser.from(message); @@ -289,13 +289,15 @@ protected String parseInnerMessage(boolean ui, Message message, String parentMes // create message with file-attachments if (attachments.size() > 0) - createAndSaveFileMessage(ui, uid, resource, text, markupText, null, null, true, - false, encrypted, false, getStanzaId(message), attachments, + createAndSaveFileMessage(ui, uid, resource, text, markupText, null, + timestamp, getDelayStamp(message), true, false, encrypted, + false, getStanzaId(message), attachments, originalStanza, parentMessageId, originalFrom, fromMuc, true); // create message without attachments - else createAndSaveNewMessage(ui, uid, resource, text, markupText, null, null, true, - false, encrypted, false, getStanzaId(message), originalStanza, + else createAndSaveNewMessage(ui, uid, resource, text, markupText, null, + timestamp, getDelayStamp(message), true, false, encrypted, + false, getStanzaId(message), originalStanza, parentMessageId, originalFrom, forwardIds, fromMuc, true); return uid; @@ -311,16 +313,6 @@ public static boolean isOfflineMessage(Domainpart server, Stanza stanza) { && TextUtils.equals(delayInformation.getFrom(), server); } - public static Date getDelayStamp(Message message) { - DelayInformation delayInformation = DelayInformation.from(message); - if (delayInformation != null) { - return delayInformation.getStamp(); - } else { - return null; - } - } - - @Override protected void onComplete() { super.onComplete(); diff --git a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java index ee9665fea9..ca5f6a333b 100644 --- a/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java +++ b/xabber/src/main/java/com/xabber/android/ui/adapter/chat/MessageVH.java @@ -29,6 +29,7 @@ import java.util.Date; import io.realm.RealmResults; +import io.realm.Sort; public class MessageVH extends BasicMessageVH implements View.OnClickListener, View.OnLongClickListener { @@ -162,7 +163,8 @@ protected void setupForwarded(MessageItem messageItem, MessagesAdapter.MessageEx if (!Arrays.asList(forwardedIDs).contains(null)) { RealmResults forwardedMessages = MessageDatabaseManager.getInstance().getRealmUiThread().where(MessageItem.class) - .in(MessageItem.Fields.UNIQUE_ID, forwardedIDs).findAll(); + .in(MessageItem.Fields.UNIQUE_ID, forwardedIDs) + .findAllSorted(MessageItem.Fields.TIMESTAMP, Sort.ASCENDING); if (forwardedMessages.size() > 0) { RecyclerView recyclerView = forwardLayout.findViewById(R.id.recyclerView); From 45f2493f142160e3763c7f9562e3f9aee8f171aa Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 8 Jul 2019 16:21:47 +0500 Subject: [PATCH 232/237] Now, when a contact is deleted, the chat is not deleted, but archived. --- .../xabber/android/ui/dialog/ContactDeleteDialogFragment.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/dialog/ContactDeleteDialogFragment.java b/xabber/src/main/java/com/xabber/android/ui/dialog/ContactDeleteDialogFragment.java index 80485f7979..f656c98628 100644 --- a/xabber/src/main/java/com/xabber/android/ui/dialog/ContactDeleteDialogFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/dialog/ContactDeleteDialogFragment.java @@ -66,8 +66,7 @@ public void onClick(DialogInterface dialog, int which) { // delete chat AbstractChat chat = MessageManager.getInstance().getChat(account, user); if (chat != null) { - MessageManager.getInstance().clearHistory(account, user); - MessageManager.getInstance().removeChat(chat); + chat.setArchived(true, true); } // remove roster contact From 34e1a2e2fc282fd57245ec640739d8c5ef63b6b1 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 8 Jul 2019 18:27:54 +0500 Subject: [PATCH 233/237] Changes in alert dialog about hot supported file uploading. --- .../xabber/android/ui/fragment/FileInteractionFragment.java | 3 ++- xabber/src/main/res/values-ar-rSA/chat_viewer.xml | 1 - xabber/src/main/res/values-ca-rES/chat_viewer.xml | 1 - xabber/src/main/res/values-cs-rCZ/chat_viewer.xml | 1 - xabber/src/main/res/values-de-rDE/chat_viewer.xml | 1 - xabber/src/main/res/values-el-rGR/chat_viewer.xml | 1 - xabber/src/main/res/values-es-rES/chat_viewer.xml | 1 - xabber/src/main/res/values-fi-rFI/chat_viewer.xml | 1 - xabber/src/main/res/values-fil-rPH/chat_viewer.xml | 1 - xabber/src/main/res/values-in-rID/chat_viewer.xml | 1 - xabber/src/main/res/values-it-rIT/chat_viewer.xml | 1 - xabber/src/main/res/values-iw-rIL/chat_viewer.xml | 1 - xabber/src/main/res/values-ja-rJP/chat_viewer.xml | 1 - xabber/src/main/res/values-ms-rMY/chat_viewer.xml | 1 - xabber/src/main/res/values-nb-rNO/chat_viewer.xml | 1 - xabber/src/main/res/values-pl-rPL/chat_viewer.xml | 1 - xabber/src/main/res/values-pt-rBR/chat_viewer.xml | 1 - xabber/src/main/res/values-ru-rRU/chat_viewer.xml | 2 +- xabber/src/main/res/values-sk-rSK/chat_viewer.xml | 1 - xabber/src/main/res/values-sl-rSI/chat_viewer.xml | 1 - xabber/src/main/res/values-sv-rSE/chat_viewer.xml | 1 - xabber/src/main/res/values-tr-rTR/chat_viewer.xml | 1 - xabber/src/main/res/values-uk-rUA/chat_viewer.xml | 1 - xabber/src/main/res/values-zh-rCN/chat_viewer.xml | 1 - xabber/src/main/res/values/chat_viewer.xml | 2 +- 25 files changed, 4 insertions(+), 25 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/FileInteractionFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/FileInteractionFragment.java index bf203aa1fa..6f57d9bdd3 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/FileInteractionFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/FileInteractionFragment.java @@ -280,8 +280,9 @@ public void onForwardClick(String messageId) { protected void onAttachButtonPressed() { if (!HttpFileUploadManager.getInstance().isFileUploadSupported(account)) { // show notification + String serverName = account.getFullJid().getDomain().toString(); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setMessage(R.string.error_file_upload_not_support) + builder.setMessage(getActivity().getResources().getString(R.string.error_file_upload_not_support, serverName)) .setTitle(getString(R.string.error_sending_file, "")) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override diff --git a/xabber/src/main/res/values-ar-rSA/chat_viewer.xml b/xabber/src/main/res/values-ar-rSA/chat_viewer.xml index 7100675e99..c17311622d 100644 --- a/xabber/src/main/res/values-ar-rSA/chat_viewer.xml +++ b/xabber/src/main/res/values-ar-rSA/chat_viewer.xml @@ -110,7 +110,6 @@ الدردشات الأرشيف هو مبين الدردشات الأرشيف مخفية إشعار لهذه الدردشة - الخادم الذي تستخدمه لا يدعم نقل الملفات. يمكنك تجربة خادم xabber.org. الانضمام إلى المؤتمر اسحب لليمين لفتح الدردشات الحديثة اسحب لليسار لفتح معلومات الاتصال diff --git a/xabber/src/main/res/values-ca-rES/chat_viewer.xml b/xabber/src/main/res/values-ca-rES/chat_viewer.xml index fc58859b54..9951c7bccc 100644 --- a/xabber/src/main/res/values-ca-rES/chat_viewer.xml +++ b/xabber/src/main/res/values-ca-rES/chat_viewer.xml @@ -108,7 +108,6 @@ Arxivar xats mostrats Arxivar xats ocults Notificació per aquest xat - El servidor que està utilitzant no dóna suport transferència d\'arxiu. Pot provar el servidor xabber.org. Uneix-te a la conferència Llisqueu a la dreta per obrir els xats recents Llisqueu a l\'esquerra per obrir la informació de contacte diff --git a/xabber/src/main/res/values-cs-rCZ/chat_viewer.xml b/xabber/src/main/res/values-cs-rCZ/chat_viewer.xml index 36a0ac03d3..36d5aaaacc 100644 --- a/xabber/src/main/res/values-cs-rCZ/chat_viewer.xml +++ b/xabber/src/main/res/values-cs-rCZ/chat_viewer.xml @@ -108,7 +108,6 @@ Archív chatů zobrazen Arcvhív chatů skryt Oznámení pro tento chat - Server, který používáte nepodporuje přenos souborů. Můžete vyzkoušet na serveru xabber.org. Připojit se do konference Potáhnutím doprava otevřete současné chaty Potáhnutím doleva otevřete informace o kontaktu diff --git a/xabber/src/main/res/values-de-rDE/chat_viewer.xml b/xabber/src/main/res/values-de-rDE/chat_viewer.xml index 6660684084..c401e9f6a9 100644 --- a/xabber/src/main/res/values-de-rDE/chat_viewer.xml +++ b/xabber/src/main/res/values-de-rDE/chat_viewer.xml @@ -108,7 +108,6 @@ Angezeigte Chats archivieren Verborgene Chats archivieren Benachrichtigung für diesen Chat - Der Server, den Sie verwenden unterstützt keine Dateiübertragung. Sie können es mit dem Server xabber.org versuchen. Konferenz beitreten Wischen Sie nach rechts um den letzten Chat zu öffnen Wischen Sie nach links, um Kontaktinformationen zu öffnen diff --git a/xabber/src/main/res/values-el-rGR/chat_viewer.xml b/xabber/src/main/res/values-el-rGR/chat_viewer.xml index bd084aac91..3cf551ff5b 100644 --- a/xabber/src/main/res/values-el-rGR/chat_viewer.xml +++ b/xabber/src/main/res/values-el-rGR/chat_viewer.xml @@ -108,7 +108,6 @@ Αρχειοθέτηση εμφανιζόμενων συνομιλιών Αρχειοθέτηση κρυμμένων συνομιλιών Ειδοποίηση για αυτήν τη συνομιλία - Ο διακομιστής που χρησιμοποιείτε δεν υποστηρίζει μεταφορά αρχείων. Μπορείτε να δοκιμάσετε το διακομιστή xabber.org. Συμμετοχή στη συνεδρία Σαρώστε προς τα δεξιά για να ανοίξετε τις πρόσφατες συνομιλίες Σαρώστε προς τα αριστερά για να ανοίξετε στοιχεία επικοινωνίας diff --git a/xabber/src/main/res/values-es-rES/chat_viewer.xml b/xabber/src/main/res/values-es-rES/chat_viewer.xml index acc244700a..434aa66f30 100644 --- a/xabber/src/main/res/values-es-rES/chat_viewer.xml +++ b/xabber/src/main/res/values-es-rES/chat_viewer.xml @@ -108,7 +108,6 @@ Muestra archivo de chats Archivo de chats oculto Notificación para este chat - El servidor que está utilizando no soporta la transferencia de archivos. Puede probar el servidor xabber.org. Unirse a la sala de charla Deslice a la derecha para abrir las charlas recientes Deslice a la izquierda para abrir la información de contacto diff --git a/xabber/src/main/res/values-fi-rFI/chat_viewer.xml b/xabber/src/main/res/values-fi-rFI/chat_viewer.xml index 921db6d01d..979f7b0ad9 100644 --- a/xabber/src/main/res/values-fi-rFI/chat_viewer.xml +++ b/xabber/src/main/res/values-fi-rFI/chat_viewer.xml @@ -106,7 +106,6 @@ Keskustelun arkisto näytetty Keskustelu arkisto piilotettu Ilmoitus tälle keskustelulle - Palvelin jota käytät ei tue tiedostonsiirtoa. Voit kokeilla xabber.org palvelinta. Liity konferenssiin Pyyhkäise oikealle avataksesi viimeaikaiset keskustelut Pyyhkäise vasemmalle avataksesi yhteystiedon tiedot diff --git a/xabber/src/main/res/values-fil-rPH/chat_viewer.xml b/xabber/src/main/res/values-fil-rPH/chat_viewer.xml index d719368cfa..e849dd7d16 100644 --- a/xabber/src/main/res/values-fil-rPH/chat_viewer.xml +++ b/xabber/src/main/res/values-fil-rPH/chat_viewer.xml @@ -106,7 +106,6 @@ I-archive ang mga chats na pinapakita Nakatago ang mga chat sa archive Abiso para sa chat na ito - Ang server na iyong ginagamit ay hindi sumusuporta sa paglilipat ng file. Maaari mong subukan ang xabber.org server. Sumali sa kumperensya Mag-swipe pakanan upang buksan ang mga kamakailang mga chat Mag-swipe pakaliwa upang buksan ang impormasyon ng kontak diff --git a/xabber/src/main/res/values-in-rID/chat_viewer.xml b/xabber/src/main/res/values-in-rID/chat_viewer.xml index a7fd4bc8c4..f3962a0050 100644 --- a/xabber/src/main/res/values-in-rID/chat_viewer.xml +++ b/xabber/src/main/res/values-in-rID/chat_viewer.xml @@ -108,7 +108,6 @@ Arsipkan obrolan tertampil Arsipkan obrolan tersembunyi Notifikasi obrolan ini - Server yang Anda gunakan tidak mendukung pengiriman berkas. Silakan coba server xabber.org. Gabung konferensi Geser ke kanan untuk membuka obrolan terbaru Geser ke kiri untuk membuka informasi kontak diff --git a/xabber/src/main/res/values-it-rIT/chat_viewer.xml b/xabber/src/main/res/values-it-rIT/chat_viewer.xml index 7159f69960..c55770bf3e 100644 --- a/xabber/src/main/res/values-it-rIT/chat_viewer.xml +++ b/xabber/src/main/res/values-it-rIT/chat_viewer.xml @@ -108,7 +108,6 @@ Chat archiviate mostrate Chat archiviate nascoste Notifica per questa chat - Il server che stai usando non supporta il trasferimento di file. Puoi provare il server xabber.org . Entra nella conferenza Scorri verso destra per aprire le chat recenti Scorri verso sinistra per aprire le informazioni di contatto diff --git a/xabber/src/main/res/values-iw-rIL/chat_viewer.xml b/xabber/src/main/res/values-iw-rIL/chat_viewer.xml index 3c04cce787..ccb7fda75e 100644 --- a/xabber/src/main/res/values-iw-rIL/chat_viewer.xml +++ b/xabber/src/main/res/values-iw-rIL/chat_viewer.xml @@ -105,7 +105,6 @@ התכתבויות מהארכיון מוצגות התכתבויות מהארכיון מוסתרות התראה להתכתבות זו - השרת בו נעשה שימוש כרגע אינו תומך בהעברת קבצים. ניתן לנסות את השרת xabber.org. הצטרפות לוועידה העתקת קישור הורדה diff --git a/xabber/src/main/res/values-ja-rJP/chat_viewer.xml b/xabber/src/main/res/values-ja-rJP/chat_viewer.xml index 6f5b9daff7..07e4feba4b 100644 --- a/xabber/src/main/res/values-ja-rJP/chat_viewer.xml +++ b/xabber/src/main/res/values-ja-rJP/chat_viewer.xml @@ -106,7 +106,6 @@ アーカイブ チャットを表示しました アーカイブ チャットを非表示にしました このチャットの通知 - 使用しているサーバーはファイル転送をサポートしていません。Xabber.org サーバーを試してください。 会議に参加 右にスワイプすると、最近のチャットを開きます 左にスワイプすると、連絡先情報を開きます diff --git a/xabber/src/main/res/values-ms-rMY/chat_viewer.xml b/xabber/src/main/res/values-ms-rMY/chat_viewer.xml index bad59c40bd..cb51aeed86 100644 --- a/xabber/src/main/res/values-ms-rMY/chat_viewer.xml +++ b/xabber/src/main/res/values-ms-rMY/chat_viewer.xml @@ -106,7 +106,6 @@ Arkib chat ditunjukkan Arkib chat sembunyi Notifikasi untuk chat ini - Pelayan yang anda gunakan tiada sokongan untuk pemindahan fail. Anda boleh cuba di xabber.org server. Sertai persidangan Leret kanan untuk buka chat sebelumnya Leret kiri untuk buka info kenalan diff --git a/xabber/src/main/res/values-nb-rNO/chat_viewer.xml b/xabber/src/main/res/values-nb-rNO/chat_viewer.xml index e47dac3294..7f028c5ec3 100644 --- a/xabber/src/main/res/values-nb-rNO/chat_viewer.xml +++ b/xabber/src/main/res/values-nb-rNO/chat_viewer.xml @@ -106,7 +106,6 @@ Arkiver viste sludringer Arkiver skjulte sludringer Merknad for denne sludringen - Tjeneren du bruker støtter ikke filoverføringer. Du kan prøve xabber.org-tjeneren. Ta del i konferanse Dra til høyre for å åpne nylige sludringer Dra til venstre for å åpne kontaktinfo diff --git a/xabber/src/main/res/values-pl-rPL/chat_viewer.xml b/xabber/src/main/res/values-pl-rPL/chat_viewer.xml index efe49cb0b6..2832ad0595 100644 --- a/xabber/src/main/res/values-pl-rPL/chat_viewer.xml +++ b/xabber/src/main/res/values-pl-rPL/chat_viewer.xml @@ -108,7 +108,6 @@ Archiwum chatów widoczne Archiwum czatów ukryte Powiadomienie dla tego czatu - Server, którego używasz nie obsługuje transferu plików. Możesz spróbować na serwerze xabber.org. Dołącz do konferencji Przesuń palcem w prawo, aby otworzyć ostatnie rozmowy Przesuń w lewo, aby otworzyć informacje kontaktowe diff --git a/xabber/src/main/res/values-pt-rBR/chat_viewer.xml b/xabber/src/main/res/values-pt-rBR/chat_viewer.xml index 6bd9aad03d..6e328f018b 100644 --- a/xabber/src/main/res/values-pt-rBR/chat_viewer.xml +++ b/xabber/src/main/res/values-pt-rBR/chat_viewer.xml @@ -108,7 +108,6 @@ Mostrar arquivos do bate-papo Arquivos de bate-papo ocultos Notificação para este bate-papo - O servidor que você está usando não suporta a transferência de arquivos. Você pode tentar o servidor xabber.org. Junte-se a conferência Deslize para a direita para abrir as conversas recentes Deslize para a esquerda para abrir as informações de contato diff --git a/xabber/src/main/res/values-ru-rRU/chat_viewer.xml b/xabber/src/main/res/values-ru-rRU/chat_viewer.xml index f713ec8246..2b526de02b 100644 --- a/xabber/src/main/res/values-ru-rRU/chat_viewer.xml +++ b/xabber/src/main/res/values-ru-rRU/chat_viewer.xml @@ -110,7 +110,7 @@ Архивные диалоги отображены Архивные диалоги скрыты Уведомления для этого чата - Используемый сервер не поддерживает передачу данных. Попробуйте использовать сервер xabber.org + Похоже, сервер %1$s, не поддерживает передачу данных. Возможно, Xabber еще не получил информацию о сервере, или произошел какой-то сбой.\n\nОбновите информацию о сервере в разделе Настройки учетной записи → Информация о сервере. Если это не поможет, подумайте об использовании сервера, который наверняка поддерживает передачу файлов. Одним из таких серверов является xabber.org Присоединиться Смахните вправо чтобы открыть список недавних чатов Смахните влево чтобы увидеть данные собеседника diff --git a/xabber/src/main/res/values-sk-rSK/chat_viewer.xml b/xabber/src/main/res/values-sk-rSK/chat_viewer.xml index c0e241e1e2..db2b1667f7 100644 --- a/xabber/src/main/res/values-sk-rSK/chat_viewer.xml +++ b/xabber/src/main/res/values-sk-rSK/chat_viewer.xml @@ -106,7 +106,6 @@ Archívy chatov zobrazené Archívy chatov skryté Oznámenie pre tento chat - Server ktorý používate nepodporuje prenos súborov. Môžete skúsiť xabber.org server. Pridať sa do konferencie Potiahnutím doprava otvorte súčasné chaty Potiahnutím doľava otvorte informácie o kontakte diff --git a/xabber/src/main/res/values-sl-rSI/chat_viewer.xml b/xabber/src/main/res/values-sl-rSI/chat_viewer.xml index fc50ae482c..a8dc8ba556 100644 --- a/xabber/src/main/res/values-sl-rSI/chat_viewer.xml +++ b/xabber/src/main/res/values-sl-rSI/chat_viewer.xml @@ -108,7 +108,6 @@ Prikazani arhivirani klepeti Arhiviraj skrite pogovore Obvestila za ta pogovor - Server ki ga uporabljaš ne podpira prenosa podatkov. Lahko poizkusiš xabber.org server. Pridruži se konferenci Podrsaj desno da odprete prejšnje pogovore Podrsaj levo da odprete informacije stika diff --git a/xabber/src/main/res/values-sv-rSE/chat_viewer.xml b/xabber/src/main/res/values-sv-rSE/chat_viewer.xml index 0c8727b295..5ba8ce5f40 100644 --- a/xabber/src/main/res/values-sv-rSE/chat_viewer.xml +++ b/xabber/src/main/res/values-sv-rSE/chat_viewer.xml @@ -108,7 +108,6 @@ Arkiverade chattar visas Arkiverade chattar är dolda Den här chattens aviseringar - Servern som du använder har inte stöd för filöverföring. Du kan prova servern xabber.org. Anslut till konferens Dra åt höger för att visa senaste chattar Dra åt vänster för att visa kontaktinformation diff --git a/xabber/src/main/res/values-tr-rTR/chat_viewer.xml b/xabber/src/main/res/values-tr-rTR/chat_viewer.xml index c853c9ac0b..a7cdffb7f6 100644 --- a/xabber/src/main/res/values-tr-rTR/chat_viewer.xml +++ b/xabber/src/main/res/values-tr-rTR/chat_viewer.xml @@ -106,7 +106,6 @@ Gösterilen sohbetleri arşivle Gizlenen sohbetleri arşivle Bu sohbet için bildirimler - Kullandığınız sunucu dosya aktarımını desteklemiyor. Bunun için xabber.org sunucusunu deneyebilirsiniz. Konferansa katıl Son sohbetleri açmak için sağa kaydırın Kişi bilgisini görüntülemek için sola kaydırın diff --git a/xabber/src/main/res/values-uk-rUA/chat_viewer.xml b/xabber/src/main/res/values-uk-rUA/chat_viewer.xml index 01bf518359..2be9337d43 100644 --- a/xabber/src/main/res/values-uk-rUA/chat_viewer.xml +++ b/xabber/src/main/res/values-uk-rUA/chat_viewer.xml @@ -108,7 +108,6 @@ Архівні діалоги відображені Архівні діалоги приховано Сповіщення для цього чату - Цей сервер не підтримує передачу даних. Спробуйте сервер xabber.org. Долучитися Проведіть праворуч щоб відкрити крайні чати Проведіть ліворуч щоб відкрити контактну інформацію diff --git a/xabber/src/main/res/values-zh-rCN/chat_viewer.xml b/xabber/src/main/res/values-zh-rCN/chat_viewer.xml index 81de7711fa..fec332eaab 100644 --- a/xabber/src/main/res/values-zh-rCN/chat_viewer.xml +++ b/xabber/src/main/res/values-zh-rCN/chat_viewer.xml @@ -108,7 +108,6 @@ 显示的存档聊天记录 隐藏的存档聊天记录 此聊天的通知 - 您正在使用的服务器不支持文件传输。您可以尝试 xabber.org 服务器。 加入群聊 向右滑动打开最近的聊天记录 向左滑动以打开联系人信息 diff --git a/xabber/src/main/res/values/chat_viewer.xml b/xabber/src/main/res/values/chat_viewer.xml index dc6a529d46..a33394dbe0 100644 --- a/xabber/src/main/res/values/chat_viewer.xml +++ b/xabber/src/main/res/values/chat_viewer.xml @@ -116,7 +116,7 @@ Archive chats hidden Notification for this chat - The server you are using does not support file transfer. You can try the xabber.org server. + %1$s server does not seem to support file transfer. This may happen because Xabber didn\'t yet receive server capabilities, or because of some glitch.\n\nRefresh server info in Account settings → Server info. If that does not help, consider using a server that definitely does support file transfer. One such server is xabber.org Join conference Swipe right to open recent chats From deab7f9d93575da8786d9035da81240ed84cf29b Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Mon, 8 Jul 2019 18:30:42 +0500 Subject: [PATCH 234/237] Up version to 633 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index c5f9082b2f..157ca5a104 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 632 - versionName '2.6.4(632)' + versionCode 633 + versionName '2.6.4(633)' manifestPlaceholders = [crashlytics:getLocalProperty("crashlytics.key")] } From 3b8047889aabb99b6ff7517a7939a48ef9b3ba88 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 9 Jul 2019 11:58:23 +0500 Subject: [PATCH 235/237] Changed jid validation in add contact and add account --- .../com/xabber/android/data/account/AccountManager.java | 4 ++++ .../com/xabber/android/ui/fragment/AccountAddFragment.java | 2 +- .../com/xabber/android/ui/fragment/ContactAddFragment.java | 7 ++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java index ccb48323f5..30ea450311 100644 --- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java +++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java @@ -423,6 +423,10 @@ public AccountJid addAccount(String user, String password, String token, boolean throw new NetworkException(R.string.EMPTY_USER_NAME); } + if (user.contains(" ")) { + throw new NetworkException(R.string.INCORRECT_USER_NAME); + } + DomainBareJid serverName; try { serverName = JidCreate.domainBareFrom(user); diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/AccountAddFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/AccountAddFragment.java index 796ec08880..3322b697b4 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/AccountAddFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/AccountAddFragment.java @@ -97,7 +97,7 @@ public void addAccount() { AccountJid account; try { account = AccountManager.getInstance().addAccount( - userView.getText().toString().replace(" ", ""), + userView.getText().toString().trim(), passwordView.getText().toString(), "", false, diff --git a/xabber/src/main/java/com/xabber/android/ui/fragment/ContactAddFragment.java b/xabber/src/main/java/com/xabber/android/ui/fragment/ContactAddFragment.java index 40defa04bc..e3b0852bb1 100644 --- a/xabber/src/main/java/com/xabber/android/ui/fragment/ContactAddFragment.java +++ b/xabber/src/main/java/com/xabber/android/ui/fragment/ContactAddFragment.java @@ -175,7 +175,12 @@ public void addContact() { } String contactString = userView.getText().toString(); - contactString = contactString.replace(" ", ""); + contactString = contactString.trim(); + + if (contactString.contains(" ")) { + userView.setError(getString(R.string.INCORRECT_USER_NAME)); + return; + } if (TextUtils.isEmpty(contactString)) { userView.setError(getString(R.string.EMPTY_USER_NAME)); From 2e38f016ff271d1133b9d80d0eca2a2569247156 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 9 Jul 2019 17:56:01 +0500 Subject: [PATCH 236/237] Enabled quotes references --- .../references/ReferencesManager.java | 11 ++++++----- .../references/ReferencesManagerTest.java | 18 +++++++++--------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java index a96eb77deb..4fb32d397b 100644 --- a/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java +++ b/xabber/src/main/java/com/xabber/android/data/extension/references/ReferencesManager.java @@ -95,7 +95,7 @@ public static Pair modifyBodyWithReferences(Message message, Str // modify chars with references except markup and mention for (ReferenceElement reference : references) { - if (!(reference instanceof Markup) && !(reference instanceof Mention)) + if (!(reference instanceof Markup) && !(reference instanceof Mention) && !(reference instanceof Quote)) chars = modifyBodyWithReferences(chars, reference); } @@ -105,7 +105,7 @@ public static Pair modifyBodyWithReferences(Message message, Str // modify chars with markup and mention references for (ReferenceElement reference : references) { - if (reference instanceof Markup || reference instanceof Mention) + if (reference instanceof Markup || reference instanceof Mention || reference instanceof Quote) chars = modifyBodyWithReferences(chars, reference); } markupBody = charsToString(chars); @@ -163,7 +163,7 @@ private static String[] modifyBodyWithReferences(String[] chars, ReferenceElemen chars = markup(begin, end, chars, (Markup) reference); break; case quote: - //chars = removeInLine(begin, end, chars, (Quote) reference); + chars = quote(begin, end, chars, (Quote) reference); break; case mention: chars = mention(begin, end, chars, (Mention) reference); @@ -179,12 +179,13 @@ private static String[] remove(int begin, int end, String[] source) { return source; } - private static String[] removeInLine(int begin, int end, String[] source, Quote reference) { + private static String[] quote(int begin, int end, String[] source, Quote reference) { int del = reference.getMarker().length(); int removed = 0; for (int i = begin; i <= end; i++) { if (removed < del) { - source[i] = String.valueOf(Character.MIN_VALUE); + if (removed == 0) source[i] = "\u2503 "; + else source[i] = String.valueOf(Character.MIN_VALUE); removed++; } if (source[i].equals("\n")) removed = 0; diff --git a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java index ae982c4521..3c22df8ad9 100644 --- a/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java +++ b/xabber/src/test/java/com/xabber/android/data/extension/references/ReferencesManagerTest.java @@ -105,15 +105,15 @@ public void modifyBodyWithReferences3() { "Использование нескольких стилей.", result.second); } -// @Test -// public void modifyBodyWithReferences4() { -// String expected = "This is a quote\n" + -// "of two lines\n" + -// "Hello world!"; -// Pair result = ReferencesManager.modifyBodyWithReferences(message4, body4); -// assertEquals(expected, result.first); -// assertNull(result.second); -// } + @Test + public void modifyBodyWithReferences4() { + String expected = "\u2503 This is a quote\n" + + "\u2503 of two lines\n" + + "Hello world!"; + Pair result = ReferencesManager.modifyBodyWithReferences(message4, body4); + assertEquals(body4, result.first); + assertEquals(expected, result.second); + } @Test public void modifyBodyWithReferences5() { From f5fe2c95e78a09d049676cb17a0ffdf4d87fefe3 Mon Sep 17 00:00:00 2001 From: Valery Miller Date: Tue, 9 Jul 2019 18:07:19 +0500 Subject: [PATCH 237/237] Up version to 634 --- xabber/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xabber/build.gradle b/xabber/build.gradle index 157ca5a104..53b172ee52 100644 --- a/xabber/build.gradle +++ b/xabber/build.gradle @@ -10,8 +10,8 @@ android { defaultConfig { minSdkVersion 15 targetSdkVersion 28 - versionCode 633 - versionName '2.6.4(633)' + versionCode 634 + versionName '2.6.4(634)' manifestPlaceholders = [crashlytics:getLocalProperty("crashlytics.key")] }