From 7d2a7d536d5030b7cd9e10b1fcd41692d05bc6b5 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 5 Aug 2020 21:31:54 +0200 Subject: [PATCH 01/29] fix attachments getting lost when switching to chat during call fixes #3854 --- .../eu/siacs/conversations/ui/ConversationFragment.java | 7 +++++-- .../eu/siacs/conversations/ui/ConversationsActivity.java | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index a8fecc6f7..c195fb13b 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -2034,9 +2034,12 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke toggleInputMethod(); } - public void reInit(Conversation conversation, Bundle extras) { + public void reInit(final Conversation conversation, final Bundle extras) { QuickLoader.set(conversation.getUuid()); - this.saveMessageDraftStopAudioPlayer(); + final boolean changedConversation = this.conversation != conversation; + if (changedConversation) { + this.saveMessageDraftStopAudioPlayer(); + } this.clearPending(); if (this.reInit(conversation, extras != null)) { if (extras != null) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java index 261907d5b..451f4d105 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java @@ -266,8 +266,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio } private boolean processViewIntent(Intent intent) { - String uuid = intent.getStringExtra(EXTRA_CONVERSATION); - Conversation conversation = uuid != null ? xmppConnectionService.findConversationByUuid(uuid) : null; + final String uuid = intent.getStringExtra(EXTRA_CONVERSATION); + final Conversation conversation = uuid != null ? xmppConnectionService.findConversationByUuid(uuid) : null; if (conversation == null) { Log.d(Config.LOGTAG, "unable to view conversation with uuid:" + uuid); return false; From 1958cded2390906aae99b0fd07175b91047da3af Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 19 Aug 2020 13:18:27 +0200 Subject: [PATCH 02/29] improve logging for app server failures. change wording to include 'push' --- .../eu/siacs/conversations/services/PushManagementService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playstore/java/eu/siacs/conversations/services/PushManagementService.java b/src/playstore/java/eu/siacs/conversations/services/PushManagementService.java index 57b9b1c61..ae883f524 100644 --- a/src/playstore/java/eu/siacs/conversations/services/PushManagementService.java +++ b/src/playstore/java/eu/siacs/conversations/services/PushManagementService.java @@ -55,7 +55,7 @@ public class PushManagementService { e.printStackTrace(); } } else { - Log.d(Config.LOGTAG, a.getJid().asBareJid() + ": invalid response from app server"); + Log.d(Config.LOGTAG, a.getJid().asBareJid() + ": failed to enable push. invalid response from app server "+response); } }); }); From 70c10fd0de14fd2dc042d60bdc98ad10c3108d1c Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 19 Aug 2020 13:57:33 +0200 Subject: [PATCH 03/29] listen to orbot events instead of using intent result to reconnect account --- .../conversations/services/EventReceiver.java | 18 ++++++------- .../services/XmppConnectionService.java | 27 +++++++++++++++---- .../conversations/ui/EditAccountActivity.java | 13 --------- .../conversations/utils/TorServiceUtils.java | 3 +++ 4 files changed, 33 insertions(+), 28 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/EventReceiver.java b/src/main/java/eu/siacs/conversations/services/EventReceiver.java index 985effc3a..500eb25e5 100644 --- a/src/main/java/eu/siacs/conversations/services/EventReceiver.java +++ b/src/main/java/eu/siacs/conversations/services/EventReceiver.java @@ -8,6 +8,8 @@ import android.preference.PreferenceManager; import android.support.v4.content.ContextCompat; import android.util.Log; +import com.google.common.base.Strings; + import eu.siacs.conversations.Config; import eu.siacs.conversations.utils.Compatibility; @@ -19,17 +21,13 @@ public class EventReceiver extends BroadcastReceiver { @Override public void onReceive(final Context context, final Intent originalIntent) { final Intent intentForService = new Intent(context, XmppConnectionService.class); - if (originalIntent.getAction() != null) { - intentForService.setAction(originalIntent.getAction()); - final Bundle extras = originalIntent.getExtras(); - if (extras != null) { - intentForService.putExtras(extras); - } - } else { - intentForService.setAction("other"); - } final String action = originalIntent.getAction(); - if (action.equals("ui") || hasEnabledAccounts(context)) { + intentForService.setAction(Strings.isNullOrEmpty(action) ? "other" : action); + final Bundle extras = originalIntent.getExtras(); + if (extras != null) { + intentForService.putExtras(extras); + } + if ("ui".equals(action) || hasEnabledAccounts(context)) { Compatibility.startService(context, intentForService); } else { Log.d(Config.LOGTAG, "EventReceiver ignored action " + intentForService.getAction()); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 8bc43c99f..240c64ac3 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -127,6 +127,7 @@ import eu.siacs.conversations.utils.ReplacingTaskManager; import eu.siacs.conversations.utils.Resolver; import eu.siacs.conversations.utils.SerialSingleThreadExecutor; import eu.siacs.conversations.utils.StringUtils; +import eu.siacs.conversations.utils.TorServiceUtils; import eu.siacs.conversations.utils.WakeLockHelper; import eu.siacs.conversations.utils.XmppUri; import eu.siacs.conversations.xml.Element; @@ -652,8 +653,15 @@ public class XmppConnectionService extends Service { final String sessionId = intent.getStringExtra(RtpSessionActivity.EXTRA_SESSION_ID); Log.d(Config.LOGTAG, "received intent to dismiss call with session id " + sessionId); mJingleConnectionManager.rejectRtpSession(sessionId); + break; } - break; + case TorServiceUtils.ACTION_STATUS: + final String status = intent.getStringExtra(TorServiceUtils.EXTRA_STATUS); + if ("ON".equals(status)) { + handleOrbotStartedEvent(); + return START_STICKY; + } + break; case ACTION_END_CALL: { final String sessionId = intent.getStringExtra(RtpSessionActivity.EXTRA_SESSION_ID); Log.d(Config.LOGTAG, "received intent to end call with session id " + sessionId); @@ -787,6 +795,14 @@ public class XmppConnectionService extends Service { return START_STICKY; } + private void handleOrbotStartedEvent() { + for (final Account account : accounts) { + if (account.getStatus() == Account.State.TOR_NOT_AVAILABLE) { + reconnectAccount(account, true, false); + } + } + } + private boolean processAccountState(Account account, boolean interactive, boolean isUiAction, boolean isAccountPushed, HashSet pingCandidates) { boolean pingNow = false; if (account.getStatus().isAttemptReconnect()) { @@ -1128,15 +1144,16 @@ public class XmppConnectionService extends Service { toggleForegroundService(); updateUnreadCountBadge(); toggleScreenEventReceiver(); + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(TorServiceUtils.ACTION_STATUS); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { scheduleNextIdlePing(); - IntentFilter intentFilter = new IntentFilter(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); } intentFilter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED); - registerReceiver(this.mInternalEventReceiver, intentFilter); } + registerReceiver(this.mInternalEventReceiver, intentFilter); mForceDuringOnCreate.set(false); toggleForegroundService(); } @@ -1192,7 +1209,7 @@ public class XmppConnectionService extends Service { public void onDestroy() { try { unregisterReceiver(this.mInternalEventReceiver); - } catch (IllegalArgumentException e) { + } catch (final IllegalArgumentException e) { //ignored } destroyed = false; @@ -2193,7 +2210,7 @@ public class XmppConnectionService extends Service { final Jid jid = Jid.ofEscaped(address); final Account account = new Account(jid, password); account.setOption(Account.OPTION_DISABLED, true); - Log.d(Config.LOGTAG,jid.asBareJid().toEscapedString()+": provisioning account"); + Log.d(Config.LOGTAG, jid.asBareJid().toEscapedString() + ": provisioning account"); createAccount(account); } diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 92d6f2093..dcccec104 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -89,7 +89,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat private static final int REQUEST_CHANGE_STATUS = 0xee11; private static final int REQUEST_ORBOT = 0xff22; private final PendingItem mPendingPresenceTemplate = new PendingItem<>(); - private final AtomicBoolean mPendingReconnect = new AtomicBoolean(false); private AlertDialog mCaptchaDialog = null; private Jid jidToEdit; private boolean mInitMode = false; @@ -475,13 +474,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat Log.d(Config.LOGTAG, "pgp result not ok"); } } - if (requestCode == REQUEST_ORBOT) { - if (xmppConnectionService != null && mAccount != null) { - xmppConnectionService.reconnectAccountInBackground(mAccount); - } else { - mPendingReconnect.set(true); - } - } } @Override @@ -781,11 +773,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat } if (mAccount != null) { - - if (mPendingReconnect.compareAndSet(true, false)) { - xmppConnectionService.reconnectAccountInBackground(mAccount); - } - this.mInitMode |= this.mAccount.isOptionSet(Account.OPTION_REGISTER); this.mUsernameMode |= mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) && mAccount.isOptionSet(Account.OPTION_REGISTER); if (mPendingFingerprintVerificationUri != null) { diff --git a/src/main/java/eu/siacs/conversations/utils/TorServiceUtils.java b/src/main/java/eu/siacs/conversations/utils/TorServiceUtils.java index 3e333483b..c3f6fd3c6 100644 --- a/src/main/java/eu/siacs/conversations/utils/TorServiceUtils.java +++ b/src/main/java/eu/siacs/conversations/utils/TorServiceUtils.java @@ -16,6 +16,9 @@ public class TorServiceUtils { private static final Uri ORBOT_PLAYSTORE_URI = Uri.parse("market://details?id=" + URI_ORBOT); private final static String ACTION_START_TOR = "org.torproject.android.START_TOR"; + public final static String ACTION_STATUS = "org.torproject.android.intent.action.STATUS"; + public final static String EXTRA_STATUS = "org.torproject.android.intent.extra.STATUS"; + public static boolean isOrbotInstalled(Context context) { try { context.getPackageManager().getPackageInfo(URI_ORBOT, PackageManager.GET_ACTIVITIES); From f3362ebde51ba85082c2a006ca25484889f1ef61 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 19 Aug 2020 15:29:25 +0200 Subject: [PATCH 04/29] add start/install orbot to error notification if applicable. fixes #3846 --- .../services/NotificationService.java | 21 +++++++++++++++++- .../conversations/utils/TorServiceUtils.java | 10 ++++----- .../ic_play_circle_filled_white_48dp.png | Bin 0 -> 666 bytes .../ic_play_circle_filled_white_48dp.png | Bin 0 -> 464 bytes .../ic_play_circle_filled_white_48dp.png | Bin 0 -> 883 bytes .../ic_play_circle_filled_white_48dp.png | Bin 0 -> 1331 bytes .../ic_play_circle_filled_white_48dp.png | Bin 0 -> 1826 bytes 7 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 src/main/res/drawable-hdpi/ic_play_circle_filled_white_48dp.png create mode 100644 src/main/res/drawable-mdpi/ic_play_circle_filled_white_48dp.png create mode 100644 src/main/res/drawable-xhdpi/ic_play_circle_filled_white_48dp.png create mode 100644 src/main/res/drawable-xxhdpi/ic_play_circle_filled_white_48dp.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_play_circle_filled_white_48dp.png diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index 2e64815f5..a77b923f2 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -61,6 +61,7 @@ import eu.siacs.conversations.ui.TimePreference; import eu.siacs.conversations.utils.AccountUtils; import eu.siacs.conversations.utils.Compatibility; import eu.siacs.conversations.utils.GeoHelper; +import eu.siacs.conversations.utils.TorServiceUtils; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection; @@ -1092,9 +1093,11 @@ public class NotificationService { } final boolean showAllErrors = QuickConversationsService.isConversations(); final List errors = new ArrayList<>(); + boolean torNotAvailable = false; for (final Account account : mXmppConnectionService.getAccounts()) { if (account.hasErrorStatus() && account.showErrorNotification() && (showAllErrors || account.getLastErrorStatus() == Account.State.UNAUTHORIZED)) { errors.add(account); + torNotAvailable |= account.getStatus() == Account.State.TOR_NOT_AVAILABLE; } } if (mXmppConnectionService.foregroundNotificationNeedsUpdatingWhenErrorStateChanges()) { @@ -1113,7 +1116,23 @@ public class NotificationService { } mBuilder.addAction(R.drawable.ic_autorenew_white_24dp, mXmppConnectionService.getString(R.string.try_again), - createTryAgainIntent()); + createTryAgainIntent() + ); + if (torNotAvailable) { + if (TorServiceUtils.isOrbotInstalled(mXmppConnectionService)) { + mBuilder.addAction( + R.drawable.ic_play_circle_filled_white_48dp, + mXmppConnectionService.getString(R.string.start_orbot), + PendingIntent.getActivity(mXmppConnectionService, 147, TorServiceUtils.LAUNCH_INTENT, 0) + ); + } else { + mBuilder.addAction( + R.drawable.ic_file_download_white_24dp, + mXmppConnectionService.getString(R.string.install_orbot), + PendingIntent.getActivity(mXmppConnectionService, 146, TorServiceUtils.INSTALL_INTENT, 0) + ); + } + } mBuilder.setDeleteIntent(createDismissErrorIntent()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { mBuilder.setVisibility(Notification.VISIBILITY_PRIVATE); diff --git a/src/main/java/eu/siacs/conversations/utils/TorServiceUtils.java b/src/main/java/eu/siacs/conversations/utils/TorServiceUtils.java index c3f6fd3c6..9fc9f5082 100644 --- a/src/main/java/eu/siacs/conversations/utils/TorServiceUtils.java +++ b/src/main/java/eu/siacs/conversations/utils/TorServiceUtils.java @@ -16,6 +16,9 @@ public class TorServiceUtils { private static final Uri ORBOT_PLAYSTORE_URI = Uri.parse("market://details?id=" + URI_ORBOT); private final static String ACTION_START_TOR = "org.torproject.android.START_TOR"; + public static final Intent INSTALL_INTENT = new Intent(Intent.ACTION_VIEW, ORBOT_PLAYSTORE_URI); + public static final Intent LAUNCH_INTENT = new Intent(ACTION_START_TOR); + public final static String ACTION_STATUS = "org.torproject.android.intent.action.STATUS"; public final static String EXTRA_STATUS = "org.torproject.android.intent.extra.STATUS"; @@ -30,17 +33,14 @@ public class TorServiceUtils { public static void downloadOrbot(Activity activity, int requestCode) { - final Intent intent = new Intent(Intent.ACTION_VIEW, ORBOT_PLAYSTORE_URI); try { - activity.startActivityForResult(intent, requestCode); + activity.startActivityForResult(INSTALL_INTENT, requestCode); } catch (ActivityNotFoundException e) { ToastCompat.makeText(activity, R.string.no_market_app_installed, ToastCompat.LENGTH_SHORT).show(); } } public static void startOrbot(Activity activity, int requestCode) { - final Intent launchIntent = new Intent(URI_ORBOT); - launchIntent.setAction(ACTION_START_TOR); - activity.startActivityForResult(launchIntent, requestCode); + activity.startActivityForResult(LAUNCH_INTENT, requestCode); } } diff --git a/src/main/res/drawable-hdpi/ic_play_circle_filled_white_48dp.png b/src/main/res/drawable-hdpi/ic_play_circle_filled_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..30330cfad6fc31d88d473c30deb4f1b101e70b23 GIT binary patch literal 666 zcmV;L0%iS)P)KoJ$#a2BE&B1G5KtV4`9-@U>Xiu8Z3hhnNLqTEHU_CFi{b5EA+5lUSV03GGP|Y4B7~O#$)UXE$ zMt7_Swe3NI(Y5rTdwY;zbX`5DZx0fTuBQh@b|B&Ch7$_%Ke9#n$R_TWdgA`<8zjnL zR3;rw+N)z<4_f~(FV|Ok(5&eAvFQHzp}0-`fEJEFG47^*gx!uiHcc`SG9GCd&J5$L)iUJ*c^n<+pYN6wSQ0WbcEP)8qwL)}Di@L#=vc2@L4ggOYl3qLMETUUz&Y@xg0B7)Z;_5v!psA;D{ljZ5) zc#?BoPeMz<=Us&de(}5?&XfNETsn+db08ohBH+N95p7%?Q<;9yV8)pwPJEzlFQ~F4 z!bFHq#YWKQ2T}rhj|mEV;Zb}%si4RX8@3cBf&x2i+2WZ6pGkvn67)&SJDs4)PttOu zoGe(91&bs>L;I}W^9vavFY$sIIvn2c4H?rofy)^k_ZRXN2}g3Opo1RgUc#tas$eV= z2%{RRg0)N_jB2F{4l;o-s=X=*WCCGSS5*+n1j4AozbLSe=q>Vyvj52c;BPuYixQ2V zfhuTc+A5l=z~z)#v-=*`>>NI#;~tHSN&GyhXEbnrQ%f3|K3OnNp2-yg(sH4sTU&ah zrE6NeeA4jAyxDndv1LPEw*1;DHoTIq?;gHIIQhp8kRCUrTVtW-#)^unfcGG6`1cl!3TbBCbQR4az#Z&MMXt1K#o;*Iio^@SKfK& zl?D|~*ndW&kOE z<`WV$Xn z5mr^ck_L=(N0{9*CJ7kj4j^R0h!o&UYM7`>p9CPm1*SSD?jP_QCfoK4Sip4iegMNX zG2Js6?|>6*sN@wehb`s308-pwOLda&0Y70=Kez>S^B>;&o)+?bB<&7Rz-x+cC?nsJ z8^9OTd;k9y{0}cfM@>AN^1*G{b0Fa;33rRh|EQkQ)r!=hx z*b)NBPiaFBP!$5mPw8(RzyOE=JFu=%`1 z-tU2@ZA|tH$}b?!Ii~uPPX7Q!A5~0rNsrXA%Moq~yBji+2VciRCj86S(npU+xC(JR znIH~-_j4Z7pKec3$M56p5Of=K273Wwo@avUk$f0eP%@MPdgmDo?-Ed+I+9)UA?#~d zNq*!b5;Z80Fmn+u%@SAmsmdZL(^nC*?DK-#n(Xl{9kyHsO)|{}|DaQab*8jOBM)$R z@ta_UBFB`ur^Op@w793t5t|gq(rf-YuK6bdM1Tko0V06Z^FN`6oF-LpM=}5a002ov JPDHLkV1l`OfX)B_ literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxhdpi/ic_play_circle_filled_white_48dp.png b/src/main/res/drawable-xxhdpi/ic_play_circle_filled_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..1d73fb5f49686ad8aa5535da4db8ecb0e9267b15 GIT binary patch literal 1331 zcmV-31DT6gOANX9Tzo7>imQ=8r z~zxRBUuaffld_JGg z=kxh|K5FQopR3$qnnhN~@_{mCK9FUFMILdREA(@e8kE#gBz>wl%n*~T5Ts=$8KRvk zmx1;$z@HR|Ql3dJ@}+A)yBOdxW#X#LG#99L1LzR9c#n>XjM8c|P?`+S(A`tMA#EQ} zif-PJRIka9vI*!IuSmKVbl3s3pZiEPPMz66AMqpI&^0jg&K6Z@N56M&j|hpDa7Bn{L_5tA!$QWB_}O-yftj1*80Wo)R# zSqY$S%GgqgOwvG|Y+_RzoJbO=nIg7TpeZS!dfs7UtJEd|w1Wj~ZJurVfo@`R*L4G( z!}fY~0v(`$?d53D1(fDFE;LJ856~~T(oZ^o_EW@_^3=r-bRU=cEpDJ=xYm(4fl|D} zwdP612h@#=b;Sjg<_+=pBSmCeBoz-(1|2EB<{xA`9S_hmO+bo|8AY-uaR40xZ9obo zJZde`fo|yq5+1c1QGs^xUN4aFs1?{54QK%L0*Q~>`Dj3obpwfy+Ef&vJ(P6=iH}-| z&%*-^fOa7HQR@#6^hW|f@}qVyEKn7N1c2m6Ez8z$K!-s9NMh7l!vPHm0LhHnU^t*j z0U()Cn+ONAA^;>aYHz~;eFg$RQlnNK9H>J8NN&{Hg9G);0SSy+Z*ZWiazFy3HXI!2 zjvSD{sEq{&nwA3+7`3V3K#Ouf0;9GN9B4%jNMO{Kf&*pcfCNTuEjZ8zIUs>iD+UKD z%K-_DTFCymf;Pr(E`l=#c;@lk`Nay22`OyM^2dF4O7o2~Qye}G1 zHASbtije1%Xh4cl^dvo605F1z3e@WK*P)uD11X+5`-Qq0R2)Fxq9fVS0)WnVfYQ8n z@=LuhNyP)C$lzk9;=EYk1+Fz0@6{9?xK>-dK#Fl(>Mkm7pgQunQkH%311WySl`iSJ zqH7ixnjxhJNYOwJ+gqnz=QV*n*xni47fp^}bJtM1fwnV`t<6!TA4pNlDmJ#v-lVQe zZlZu~i#EGf8F#TrQoZDqjmxl8oaPC-o1v4G z&Fj=#xIqye6&Rt}jfMO>InNX&;;O_0`uJ2}A-~r11^wJ3OO)0br;pvJq>du#vz1l` znP7<^y=8(yTG)b0_9*1eF52m3m@%eUV2L$~lqgYTjU^U%$QZ-)(nd8(>L~n48ps2A pAb&iN2l7B3$OCyG59ERT`48zT_|5F4XSo0X002ovPDHLkV1hwJYjywt literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_play_circle_filled_white_48dp.png b/src/main/res/drawable-xxxhdpi/ic_play_circle_filled_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..166f5c5ce313a782e713ff9a5704902fb6a639bf GIT binary patch literal 1826 zcmZ{lX*?A8AIE<)gBjP1V+flWwY3@#ie4cr6$^DyD>OcC(KTIj(>~Nc`$cKIMVpcZN6lVXh$|tWX zqf1PpZBDiTV@=RDdu23*KR-b{a)zR^DNW6C#X$bF z53Cj-Z9}OA`O{sl-;AE6uz`q9Mo+_7DV)}|OMjL0E+>MfC+Yb&)YJp=WWz9S$&RN9 zC3Gppg?Vsy>938k*JK(!ZV z@qxr|WanZcuf&nD`sf(~9yr%2SzADLinTj$WP0*XE=OfzCj7cA<8)AT#TU5KSStrnYBc8Bzk#0wlK>6D?ZbmX8$Y zIa=#wK9XbZEWp&WI#CT98G-BQS)CmNwKOwY5sr6Z9jJeSh&YUftb+|6NU2#0ehFHM zSk5?FR8@Gb#*Fq5XY#uy=Sm_7bQ>p2_zBDZN5O%YfpQtj?;-=K0@rCk`9(6gHb_4o zEN2!yV=v^VpKC^YhWj{jM}!l7s9k2HQ{d*Mry-`%TB zfSi?df2?ahSi5+DIB8>$Ec@|5{QeX#ds5SO`<(cG@cCV{Y}A_hMery7?X8B&;$(&B z0?+L;dHdzp3XLDh-9kBkc~IRQGSYFonv$`)1v*cLNGHc{7L)Qov;FSwV9WlOm|wyM z0O4nmvSJoCB)suJQnk=zmmmxLhxfBL(NC|d@ULOwdrC3&!>aH#_8vA&WAn{BfZwSU zn()rxz612oM~u^^Cf=kxKBKwp`;?y^2SKj#V0R`csua-nTg8A=_M+X03<%sGY2SjO z;eH(Kxt3eJe7IOcxpU_7=!&q4DD7+};i+fGk(ZETO+mABGrYa*)fhl$^|NKhDu0x> z5iWDuMj3gAWYsT25cy%ro!z#Q^!Se+oxkh6#S*d|v2VP0RMy`B}92j!($T>M}-=@Fol&}~P=9l)Fux+PXTf`)0Y zsC}`fp9spc`5B)1^<)I-^zp!XX%MpLP=!n}mntQsf+7TA$Qb{D90DxvR&1V9u>^Aj ztEC7PcbfLTJ-3yJI}ggcut9d3!V?HRspg^Q%?L6E&_y#F z8Py&}y~=4A;`&KTn1=TSV7|_;P(UsG8_}kgic{o)}yQ-3h#oSLp8NnB}u zW}HMiA;A??^gYpa^aE)zw2A9Aq-&GqAD xvTn~sYhPw4i|CV22F&rDhDU<`pZ=Xa>~1M5TK-gy$6@yY8!Jc41`EF%{{q_ZDF^@n literal 0 HcmV?d00001 From 15b323ee694e1bd112de88ef8435cbb80e5d487b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 22 Aug 2020 08:11:21 +0200 Subject: [PATCH 05/29] fix crash after session-accept failed and session-accept contained candidates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Conversations would attempt to feed any candidates found in the session-accept into WebRTC; even if the session wasn’t setup correctly. this commit processes the candidates only if the session was setup correctly fixes #3867 --- .../conversations/xmpp/jingle/JingleRtpConnection.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java index bc3487ad6..eb28444a7 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java @@ -371,8 +371,6 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web if (transition(State.SESSION_ACCEPTED)) { respondOk(jinglePacket); receiveSessionAccept(contentMap); - final List identificationTags = contentMap.group == null ? contentMap.getNames() : contentMap.group.getIdentificationTags(); - processCandidates(identificationTags, contentMap.contents.entrySet()); } else { Log.d(Config.LOGTAG, String.format("%s: received session-accept while in state %s", id.account.getJid().asBareJid(), state)); respondOk(jinglePacket); @@ -390,7 +388,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web sendSessionTerminate(Reason.FAILED_APPLICATION, e.getMessage()); return; } - org.webrtc.SessionDescription answer = new org.webrtc.SessionDescription( + final org.webrtc.SessionDescription answer = new org.webrtc.SessionDescription( org.webrtc.SessionDescription.Type.ANSWER, sessionDescription.toString() ); @@ -400,7 +398,10 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable to set remote description after receiving session-accept", Throwables.getRootCause(e)); webRTCWrapper.close(); sendSessionTerminate(Reason.FAILED_APPLICATION); + return; } + final List identificationTags = contentMap.group == null ? contentMap.getNames() : contentMap.group.getIdentificationTags(); + processCandidates(identificationTags, contentMap.contents.entrySet()); } private void sendSessionAccept() { From 91e94db747792746487155b94d7c2caca94e5c9a Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 24 Aug 2020 09:51:26 +0200 Subject: [PATCH 06/29] extend isBusyState to check phone state as well --- src/main/AndroidManifest.xml | 5 +---- .../services/XmppConnectionService.java | 22 +++++++++++++++++++ .../xmpp/jingle/JingleConnectionManager.java | 11 ++++++---- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index c78d32a98..ffd06ec0f 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ + @@ -36,10 +37,6 @@ - - d instanceof RtpDescription), input -> (RtpDescription) input ); - if (rtpDescriptions.size() > 0 && rtpDescriptions.size() == descriptions.size() && !usesTor(account)) { + if (rtpDescriptions.size() > 0 && rtpDescriptions.size() == descriptions.size() && isUsingClearNet(account)) { final Collection media = Collections2.transform(rtpDescriptions, RtpDescription::getMedia); if (media.contains(Media.UNKNOWN)) { Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": encountered unknown media in session proposal. " + propose); From d158eeaf723002a7aab1833f9eb4dc5a66f32a24 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 24 Aug 2020 12:47:54 +0200 Subject: [PATCH 07/29] terminate jingle call when regular call starts --- .../services/XmppConnectionService.java | 5 ++++- .../xmpp/jingle/JingleConnectionManager.java | 13 +++++++++++++ .../xmpp/jingle/JingleRtpConnection.java | 10 ++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 0c46e3657..dc371fec6 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -268,7 +268,10 @@ public class XmppConnectionService extends Service { private final PhoneStateListener phoneStateListener = new PhoneStateListener() { @Override public void onCallStateChanged(final int state, final String phoneNumber) { - isPhoneInCall.set(state != 0); + isPhoneInCall.set(state != TelephonyManager.CALL_STATE_IDLE); + if (state == TelephonyManager.CALL_STATE_OFFHOOK) { + mJingleConnectionManager.notifyPhoneCallStarted(); + } } }; diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java index c82a8474a..178ac659c 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java @@ -14,6 +14,7 @@ import com.google.common.collect.ImmutableSet; import java.lang.ref.WeakReference; import java.security.SecureRandom; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -137,6 +138,18 @@ public class JingleConnectionManager extends AbstractConnectionManager { } } + public void notifyPhoneCallStarted() { + for (AbstractJingleConnection connection : connections.values()) { + if (connection instanceof JingleRtpConnection) { + final JingleRtpConnection rtpConnection = (JingleRtpConnection) connection; + if (rtpConnection.isTerminated()) { + continue; + } + rtpConnection.notifyPhoneCall(); + } + } + } + private Optional findMatchingSessionProposal(final Account account, final Jid with, final Set media) { synchronized (this.rtpSessionProposals) { for (Map.Entry entry : this.rtpSessionProposals.entrySet()) { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java index eb28444a7..d2c340639 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java @@ -901,6 +901,16 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web } } + + public void notifyPhoneCall() { + Log.d(Config.LOGTAG, "a phone call has just been started. killing jingle rtp connections"); + if (Arrays.asList(State.PROPOSED, State.SESSION_INITIALIZED).contains(this.state)) { + rejectCall(); + } else { + endCall(); + } + } + public synchronized void rejectCall() { if (isTerminated()) { Log.w(Config.LOGTAG, id.account.getJid().asBareJid() + ": received rejectCall() when session has already been terminated. nothing to do"); From 35af8894d2dedfda8a4b66e8e3fb6a2d5a8346a0 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 29 Aug 2020 08:16:08 +0200 Subject: [PATCH 08/29] search individual conversations. fixes #3243 --- .../persistance/DatabaseBackend.java | 17 ++++++++--- .../services/MessageSearchTask.java | 10 ++++--- .../services/XmppConnectionService.java | 4 +-- .../ui/ConversationFragment.java | 11 ++++++- .../ui/ConversationsActivity.java | 12 ++++++++ .../conversations/ui/SearchActivity.java | 15 +++++++--- src/main/res/menu/activity_conversations.xml | 29 ++++++++++++++----- src/main/res/menu/fragment_conversation.xml | 8 ++++- .../menu/fragment_conversations_overview.xml | 1 + src/main/res/values-w945dp/defaults.xml | 2 ++ src/main/res/values/defaults.xml | 2 ++ src/main/res/values/strings.xml | 2 ++ 12 files changed, 90 insertions(+), 23 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 86662f530..4d8e8d22d 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -776,11 +776,20 @@ public class DatabaseBackend extends SQLiteOpenHelper { return list; } - public Cursor getMessageSearchCursor(List term) { - SQLiteDatabase db = this.getReadableDatabase(); - String SQL = "SELECT " + Message.TABLENAME + ".*," + Conversation.TABLENAME + '.' + Conversation.CONTACTJID + ',' + Conversation.TABLENAME + '.' + Conversation.ACCOUNT + ',' + Conversation.TABLENAME + '.' + Conversation.MODE + " FROM " + Message.TABLENAME + " join " + Conversation.TABLENAME + " on " + Message.TABLENAME + '.' + Message.CONVERSATION + '=' + Conversation.TABLENAME + '.' + Conversation.UUID + " join messages_index ON messages_index.uuid=messages.uuid where " + Message.ENCRYPTION + " NOT IN(" + Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE + ',' + Message.ENCRYPTION_PGP + ',' + Message.ENCRYPTION_DECRYPTION_FAILED + ',' + Message.ENCRYPTION_AXOLOTL_FAILED + ") AND " + Message.TYPE + " IN(" + Message.TYPE_TEXT + ',' + Message.TYPE_PRIVATE + ") AND messages_index.body MATCH ? ORDER BY " + Message.TIME_SENT + " DESC limit " + Config.MAX_SEARCH_RESULTS; + public Cursor getMessageSearchCursor(final List term, final String uuid) { + final SQLiteDatabase db = this.getReadableDatabase(); + final StringBuilder SQL = new StringBuilder(); + final String[] selectionArgs; + SQL.append("SELECT " + Message.TABLENAME + ".*," + Conversation.TABLENAME + '.' + Conversation.CONTACTJID + ',' + Conversation.TABLENAME + '.' + Conversation.ACCOUNT + ',' + Conversation.TABLENAME + '.' + Conversation.MODE + " FROM " + Message.TABLENAME + " join " + Conversation.TABLENAME + " on " + Message.TABLENAME + '.' + Message.CONVERSATION + '=' + Conversation.TABLENAME + '.' + Conversation.UUID + " join messages_index ON messages_index.uuid=messages.uuid where " + Message.ENCRYPTION + " NOT IN(" + Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE + ',' + Message.ENCRYPTION_PGP + ',' + Message.ENCRYPTION_DECRYPTION_FAILED + ',' + Message.ENCRYPTION_AXOLOTL_FAILED + ") AND " + Message.TYPE + " IN(" + Message.TYPE_TEXT + ',' + Message.TYPE_PRIVATE + ") AND messages_index.body MATCH ?"); + if (uuid == null) { + selectionArgs = new String[]{FtsUtils.toMatchString(term)}; + } else { + selectionArgs = new String[]{FtsUtils.toMatchString(term), uuid}; + SQL.append(" AND "+Conversation.TABLENAME+'.'+Conversation.UUID+"=?"); + } + SQL.append(" ORDER BY " + Message.TIME_SENT + " DESC limit " + Config.MAX_SEARCH_RESULTS); Log.d(Config.LOGTAG, "search term: " + FtsUtils.toMatchString(term)); - return db.rawQuery(SQL, new String[]{FtsUtils.toMatchString(term)}); + return db.rawQuery(SQL.toString(), selectionArgs); } public List markFileAsDeleted(final File file, final boolean internal) { diff --git a/src/main/java/eu/siacs/conversations/services/MessageSearchTask.java b/src/main/java/eu/siacs/conversations/services/MessageSearchTask.java index 6fd2413f8..c18c94cf2 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageSearchTask.java +++ b/src/main/java/eu/siacs/conversations/services/MessageSearchTask.java @@ -56,18 +56,20 @@ public class MessageSearchTask implements Runnable, Cancellable { private final XmppConnectionService xmppConnectionService; private final List term; + private final String uuid; private final OnSearchResultsAvailable onSearchResultsAvailable; private boolean isCancelled = false; - private MessageSearchTask(XmppConnectionService xmppConnectionService, List term, OnSearchResultsAvailable onSearchResultsAvailable) { + private MessageSearchTask(XmppConnectionService xmppConnectionService, List term, final String uuid, OnSearchResultsAvailable onSearchResultsAvailable) { this.xmppConnectionService = xmppConnectionService; this.term = term; + this.uuid = uuid; this.onSearchResultsAvailable = onSearchResultsAvailable; } - public static void search(XmppConnectionService xmppConnectionService, List term, OnSearchResultsAvailable onSearchResultsAvailable) { - new MessageSearchTask(xmppConnectionService, term, onSearchResultsAvailable).executeInBackground(); + public static void search(XmppConnectionService xmppConnectionService, List term, final String uuid, OnSearchResultsAvailable onSearchResultsAvailable) { + new MessageSearchTask(xmppConnectionService, term, uuid, onSearchResultsAvailable).executeInBackground(); } public static void cancelRunningTasks() { @@ -86,7 +88,7 @@ public class MessageSearchTask implements Runnable, Cancellable { try { final HashMap conversationCache = new HashMap<>(); final List result = new ArrayList<>(); - cursor = xmppConnectionService.databaseBackend.getMessageSearchCursor(term); + cursor = xmppConnectionService.databaseBackend.getMessageSearchCursor(term, uuid); long dbTimer = SystemClock.elapsedRealtime(); if (isCancelled) { Log.d(Config.LOGTAG, "canceled search task"); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index dc371fec6..d539ff30f 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -615,8 +615,8 @@ public class XmppConnectionService extends Service { return c != null && c.getMode() == Conversational.MODE_MULTI; } - public void search(List term, OnSearchResultsAvailable onSearchResultsAvailable) { - MessageSearchTask.search(this, term, onSearchResultsAvailable); + public void search(final List term, final String uuid, final OnSearchResultsAvailable onSearchResultsAvailable) { + MessageSearchTask.search(this, term, uuid, onSearchResultsAvailable); } @Override diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index c195fb13b..7b231f7bf 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -1240,6 +1240,9 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke case R.id.attach_location: handleAttachmentSelection(item); break; + case R.id.action_search: + startSearch(); + break; case R.id.action_archive: activity.xmppConnectionService.archiveConversation(conversation); break; @@ -1289,6 +1292,12 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke return super.onOptionsItemSelected(item); } + private void startSearch() { + final Intent intent = new Intent(getActivity(), SearchActivity.class); + intent.putExtra(SearchActivity.EXTRA_CONVERSATION_UUID, conversation.getUuid()); + startActivity(intent); + } + private void returnToOngoingCall() { final Optional ongoingRtpSession = activity.xmppConnectionService.getJingleConnectionManager().getOngoingRtpConnection(conversation.getContact()); if (ongoingRtpSession.isPresent()) { @@ -2757,7 +2766,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke correctMessage(lastEditableMessage); return true; } else { - Toast.makeText(getActivity(),R.string.could_not_correct_message, Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity(), R.string.could_not_correct_message, Toast.LENGTH_LONG).show(); return false; } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java index 451f4d105..967c2fd3d 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java @@ -489,6 +489,18 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio case R.id.action_scan_qr_code: UriHandlerActivity.scan(this); return true; + case R.id.action_search_all_conversations: + startActivity(new Intent(this, SearchActivity.class)); + return true; + case R.id.action_search_this_conversation: + final Conversation conversation = ConversationFragment.getConversation(this); + if (conversation == null) { + return true; + } + final Intent intent = new Intent(this, SearchActivity.class); + intent.putExtra(SearchActivity.EXTRA_CONVERSATION_UUID, conversation.getUuid()); + startActivity(intent); + return true; } return super.onOptionsItemSelected(item); } diff --git a/src/main/java/eu/siacs/conversations/ui/SearchActivity.java b/src/main/java/eu/siacs/conversations/ui/SearchActivity.java index 3b337e0c2..f1979828c 100644 --- a/src/main/java/eu/siacs/conversations/ui/SearchActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/SearchActivity.java @@ -29,6 +29,7 @@ package eu.siacs.conversations.ui; +import android.content.Intent; import android.databinding.DataBindingUtil; import android.os.Bundle; import android.support.v7.widget.Toolbar; @@ -42,6 +43,8 @@ import android.view.View; import android.widget.AdapterView; import android.widget.EditText; +import com.google.common.base.Strings; + import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -70,17 +73,21 @@ import static eu.siacs.conversations.ui.util.SoftKeyboardUtils.showKeyboard; public class SearchActivity extends XmppActivity implements TextWatcher, OnSearchResultsAvailable, MessageAdapter.OnContactPictureClicked { private static final String EXTRA_SEARCH_TERM = "search-term"; + public static final String EXTRA_CONVERSATION_UUID = "uuid"; private ActivitySearchBinding binding; private MessageAdapter messageListAdapter; private final List messages = new ArrayList<>(); private WeakReference selectedMessageReference = new WeakReference<>(null); + private String uuid; private final ChangeWatcher> currentSearch = new ChangeWatcher<>(); private final PendingItem pendingSearchTerm = new PendingItem<>(); private final PendingItem> pendingSearch = new PendingItem<>(); @Override public void onCreate(final Bundle bundle) { + final Intent intent = getIntent(); + this.uuid = intent == null ? null : Strings.emptyToNull(intent.getStringExtra(EXTRA_CONVERSATION_UUID)); final String searchTerm = bundle == null ? null : bundle.getString(EXTRA_SEARCH_TERM); if (searchTerm != null) { pendingSearchTerm.push(searchTerm); @@ -103,10 +110,10 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc final String term = pendingSearchTerm.pop(); if (term != null) { searchField.append(term); - List searchTerm = FtsUtils.parse(term); + final List searchTerm = FtsUtils.parse(term); if (xmppConnectionService != null) { if (currentSearch.watch(searchTerm)) { - xmppConnectionService.search(searchTerm, this); + xmppConnectionService.search(searchTerm, uuid, this); } } else { pendingSearch.push(searchTerm); @@ -206,7 +213,7 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc void onBackendConnected() { final List searchTerm = pendingSearch.pop(); if (searchTerm != null && currentSearch.watch(searchTerm)) { - xmppConnectionService.search(searchTerm, this); + xmppConnectionService.search(searchTerm, uuid,this); } } @@ -239,7 +246,7 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc return; } if (term.size() > 0) { - xmppConnectionService.search(term, this); + xmppConnectionService.search(term, uuid,this); } else { MessageSearchTask.cancelRunningTasks(); this.messages.clear(); diff --git a/src/main/res/menu/activity_conversations.xml b/src/main/res/menu/activity_conversations.xml index 3275fdc6d..bb399a68a 100644 --- a/src/main/res/menu/activity_conversations.xml +++ b/src/main/res/menu/activity_conversations.xml @@ -1,26 +1,41 @@ + xmlns:app="http://schemas.android.com/apk/res-auto"> + app:showAsAction="always" /> + + + + + + + app:showAsAction="never" /> + app:showAsAction="never" /> + app:showAsAction="never" /> \ No newline at end of file diff --git a/src/main/res/menu/fragment_conversation.xml b/src/main/res/menu/fragment_conversation.xml index 5eb0b313b..294807bea 100644 --- a/src/main/res/menu/fragment_conversation.xml +++ b/src/main/res/menu/fragment_conversation.xml @@ -99,6 +99,12 @@ android:orderInCategory="45" android:title="@string/invite_contact" app:showAsAction="never" /> + + app:showAsAction="never" /> \ No newline at end of file diff --git a/src/main/res/menu/fragment_conversations_overview.xml b/src/main/res/menu/fragment_conversations_overview.xml index 39daf7d8c..3e2865493 100644 --- a/src/main/res/menu/fragment_conversations_overview.xml +++ b/src/main/res/menu/fragment_conversations_overview.xml @@ -32,6 +32,7 @@ \ No newline at end of file diff --git a/src/main/res/values-w945dp/defaults.xml b/src/main/res/values-w945dp/defaults.xml index 855f5b520..f17a59a91 100644 --- a/src/main/res/values-w945dp/defaults.xml +++ b/src/main/res/values-w945dp/defaults.xml @@ -1,5 +1,7 @@ false + false + true diff --git a/src/main/res/values/defaults.xml b/src/main/res/values/defaults.xml index 4ea78ef51..a031a9149 100644 --- a/src/main/res/values/defaults.xml +++ b/src/main/res/values/defaults.xml @@ -35,6 +35,8 @@ false false true + true + false true default_on small diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index c6a77aaa9..409039203 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -927,6 +927,8 @@ Remove from favorites GPX track Could not correct message + All conversations + This conversation View %1$d Participant View %1$d Participants From 3dcb36a417ebc4b0d3e5deedf35a333376ff61a9 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 31 Aug 2020 09:03:54 +0200 Subject: [PATCH 09/29] persist presence name (pep, nick in subscribe) to DB. fixes #3856 --- .../java/eu/siacs/conversations/entities/Contact.java | 10 +++++++++- .../eu/siacs/conversations/parser/MessageParser.java | 4 +++- .../eu/siacs/conversations/parser/PresenceParser.java | 1 + .../conversations/persistance/DatabaseBackend.java | 10 +++++++--- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java index 7789a6686..07ffbc89c 100644 --- a/src/main/java/eu/siacs/conversations/entities/Contact.java +++ b/src/main/java/eu/siacs/conversations/entities/Contact.java @@ -33,6 +33,7 @@ public class Contact implements ListItem, Blockable { public static final String SYSTEMNAME = "systemname"; public static final String SERVERNAME = "servername"; + public static final String PRESENCE_NAME = "presence_name"; public static final String JID = "jid"; public static final String OPTIONS = "options"; public static final String SYSTEMACCOUNT = "systemaccount"; @@ -62,13 +63,14 @@ public class Contact implements ListItem, Blockable { private long mLastseen = 0; private String mLastPresence = null; - public Contact(final String account, final String systemName, final String serverName, + public Contact(final String account, final String systemName, final String serverName, final String presenceName, final Jid jid, final int subscription, final String photoUri, final Uri systemAccount, final String keys, final String avatar, final long lastseen, final String presence, final String groups) { this.accountUuid = account; this.systemName = systemName; this.serverName = serverName; + this.presenceName = presenceName; this.jid = jid; this.subscription = subscription; this.photoUri = photoUri; @@ -116,6 +118,7 @@ public class Contact implements ListItem, Blockable { return new Contact(cursor.getString(cursor.getColumnIndex(ACCOUNT)), cursor.getString(cursor.getColumnIndex(SYSTEMNAME)), cursor.getString(cursor.getColumnIndex(SERVERNAME)), + cursor.getString(cursor.getColumnIndex(PRESENCE_NAME)), jid, cursor.getInt(cursor.getColumnIndex(OPTIONS)), cursor.getString(cursor.getColumnIndex(PHOTOURI)), @@ -213,6 +216,7 @@ public class Contact implements ListItem, Blockable { values.put(ACCOUNT, accountUuid); values.put(SYSTEMNAME, systemName); values.put(SERVERNAME, serverName); + values.put(PRESENCE_NAME, presenceName); values.put(JID, jid.toString()); values.put(OPTIONS, subscription); values.put(SYSTEMACCOUNT, systemAccount != null ? systemAccount.toString() : null); @@ -554,6 +558,10 @@ public class Contact implements ListItem, Blockable { return UIHelper.getColorForName(jid != null ? jid.asBareJid().toString() : getDisplayName()); } + public boolean hasAvatarOrPresenceName() { + return (avatar != null && avatar.getFilename() != null) || presenceName != null; + } + public final class Options { public static final int TO = 0; public static final int FROM = 1; diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 7622d3071..7a82b092d 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -300,6 +300,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece } else { Contact contact = account.getRoster().getContact(user); if (contact.setPresenceName(nick)) { + mXmppConnectionService.syncRoster(account); mXmppConnectionService.getAvatarService().clear(contact); } } @@ -1011,8 +1012,9 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece final String nick = packet.findChildContent("nick", Namespace.NICK); if (nick != null && InvalidJid.hasValidFrom(original)) { - Contact contact = account.getRoster().getContact(from); + final Contact contact = account.getRoster().getContact(from); if (contact.setPresenceName(nick)) { + mXmppConnectionService.syncRoster(account); mXmppConnectionService.getAvatarService().clear(contact); } } diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index 4e862ddf6..7f57ef733 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -337,6 +337,7 @@ public class PresenceParser extends AbstractParser implements mXmppConnectionService.onContactStatusChanged.onContactStatusChanged(contact, false); } else if (type.equals("subscribe")) { if (contact.setPresenceName(packet.findChildContent("nick", Namespace.NICK))) { + mXmppConnectionService.syncRoster(account); mXmppConnectionService.getAvatarService().clear(contact); } if (contact.getOption(Contact.Options.PREEMPTIVE_GRANT)) { diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 4d8e8d22d..789b07c42 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -63,11 +63,12 @@ import eu.siacs.conversations.xmpp.Jid; public class DatabaseBackend extends SQLiteOpenHelper { private static final String DATABASE_NAME = "history"; - private static final int DATABASE_VERSION = 46; + private static final int DATABASE_VERSION = 47; private static DatabaseBackend instance = null; private static String CREATE_CONTATCS_STATEMENT = "create table " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " + Contact.SERVERNAME + " TEXT, " + Contact.SYSTEMNAME + " TEXT," + + Contact.PRESENCE_NAME + " TEXT," + Contact.JID + " TEXT," + Contact.KEYS + " TEXT," + Contact.PHOTOURI + " TEXT," + Contact.OPTIONS + " NUMBER," + Contact.SYSTEMACCOUNT + " NUMBER, " + Contact.AVATAR + " TEXT, " @@ -555,6 +556,9 @@ public class DatabaseBackend extends SQLiteOpenHelper { final long diff = SystemClock.elapsedRealtime() - start; Log.d(Config.LOGTAG,"deleted old edit information in "+diff+"ms"); } + if (oldVersion < 47 && newVersion >= 47) { + db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN " + Contact.PRESENCE_NAME + " TEXT"); + } } private void canonicalizeJids(SQLiteDatabase db) { @@ -573,7 +577,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { continue; } - String updateArgs[] = { + final String[] updateArgs = { newJid, cursor.getString(cursor.getColumnIndex(Conversation.UUID)), }; @@ -1011,7 +1015,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { final SQLiteDatabase db = this.getWritableDatabase(); db.beginTransaction(); for (Contact contact : roster.getContacts()) { - if (contact.getOption(Contact.Options.IN_ROSTER) || contact.getAvatarFilename() != null || contact.getOption(Contact.Options.SYNCED_VIA_OTHER)) { + if (contact.getOption(Contact.Options.IN_ROSTER) || contact.hasAvatarOrPresenceName() || contact.getOption(Contact.Options.SYNCED_VIA_OTHER)) { db.insert(Contact.TABLENAME, null, contact.getContentValues()); } else { String where = Contact.ACCOUNT + "=? AND " + Contact.JID + "=?"; From 064264c20b6a371ebdb46813fc8af62adfb9f500 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 31 Aug 2020 11:06:26 +0200 Subject: [PATCH 10/29] parse 'received' carbon-copied error messages. fixes #3803 --- .../generator/PresenceGenerator.java | 136 +++++++++--------- .../conversations/parser/MessageParser.java | 8 +- 2 files changed, 75 insertions(+), 69 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java b/src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java index d3143f01e..0701afcfe 100644 --- a/src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java @@ -13,81 +13,81 @@ import eu.siacs.conversations.xmpp.stanzas.PresencePacket; public class PresenceGenerator extends AbstractGenerator { - public PresenceGenerator(XmppConnectionService service) { - super(service); - } + public PresenceGenerator(XmppConnectionService service) { + super(service); + } - private PresencePacket subscription(String type, Contact contact) { - PresencePacket packet = new PresencePacket(); - packet.setAttribute("type", type); - packet.setTo(contact.getJid()); - packet.setFrom(contact.getAccount().getJid().asBareJid()); - return packet; - } + private PresencePacket subscription(String type, Contact contact) { + PresencePacket packet = new PresencePacket(); + packet.setAttribute("type", type); + packet.setTo(contact.getJid()); + packet.setFrom(contact.getAccount().getJid().asBareJid()); + return packet; + } - public PresencePacket requestPresenceUpdatesFrom(Contact contact) { - PresencePacket packet = subscription("subscribe", contact); - String displayName = contact.getAccount().getDisplayName(); - if (!TextUtils.isEmpty(displayName)) { - packet.addChild("nick",Namespace.NICK).setContent(displayName); - } - return packet; - } + public PresencePacket requestPresenceUpdatesFrom(Contact contact) { + PresencePacket packet = subscription("subscribe", contact); + String displayName = contact.getAccount().getDisplayName(); + if (!TextUtils.isEmpty(displayName)) { + packet.addChild("nick", Namespace.NICK).setContent(displayName); + } + return packet; + } - public PresencePacket stopPresenceUpdatesFrom(Contact contact) { - return subscription("unsubscribe", contact); - } + public PresencePacket stopPresenceUpdatesFrom(Contact contact) { + return subscription("unsubscribe", contact); + } - public PresencePacket stopPresenceUpdatesTo(Contact contact) { - return subscription("unsubscribed", contact); - } + public PresencePacket stopPresenceUpdatesTo(Contact contact) { + return subscription("unsubscribed", contact); + } - public PresencePacket sendPresenceUpdatesTo(Contact contact) { - return subscription("subscribed", contact); - } + public PresencePacket sendPresenceUpdatesTo(Contact contact) { + return subscription("subscribed", contact); + } - public PresencePacket selfPresence(Account account, Presence.Status status) { - return selfPresence(account, status, true); - } + public PresencePacket selfPresence(Account account, Presence.Status status) { + return selfPresence(account, status, true); + } - public PresencePacket selfPresence(final Account account, final Presence.Status status, final boolean personal) { - final PresencePacket packet = new PresencePacket(); - if (personal) { - final String sig = account.getPgpSignature(); - final String message = account.getPresenceStatusMessage(); - if(status.toShowString() != null) { - packet.addChild("show").setContent(status.toShowString()); - } - if (!TextUtils.isEmpty(message)) { - packet.addChild(new Element("status").setContent(message)); - } - if (sig != null && mXmppConnectionService.getPgpEngine() != null) { - packet.addChild("x", "jabber:x:signed").setContent(sig); - } - } - final String capHash = getCapHash(account); - if (capHash != null) { - Element cap = packet.addChild("c", - "http://jabber.org/protocol/caps"); - cap.setAttribute("hash", "sha-1"); - cap.setAttribute("node", "http://conversations.im"); - cap.setAttribute("ver", capHash); - } - return packet; - } + public PresencePacket selfPresence(final Account account, final Presence.Status status, final boolean personal) { + final PresencePacket packet = new PresencePacket(); + if (personal) { + final String sig = account.getPgpSignature(); + final String message = account.getPresenceStatusMessage(); + if (status.toShowString() != null) { + packet.addChild("show").setContent(status.toShowString()); + } + if (!TextUtils.isEmpty(message)) { + packet.addChild(new Element("status").setContent(message)); + } + if (sig != null && mXmppConnectionService.getPgpEngine() != null) { + packet.addChild("x", "jabber:x:signed").setContent(sig); + } + } + final String capHash = getCapHash(account); + if (capHash != null) { + Element cap = packet.addChild("c", + "http://jabber.org/protocol/caps"); + cap.setAttribute("hash", "sha-1"); + cap.setAttribute("node", "http://conversations.im"); + cap.setAttribute("ver", capHash); + } + return packet; + } - public PresencePacket leave(final MucOptions mucOptions) { - PresencePacket presencePacket = new PresencePacket(); - presencePacket.setTo(mucOptions.getSelf().getFullJid()); - presencePacket.setFrom(mucOptions.getAccount().getJid()); - presencePacket.setAttribute("type", "unavailable"); - return presencePacket; - } + public PresencePacket leave(final MucOptions mucOptions) { + PresencePacket presencePacket = new PresencePacket(); + presencePacket.setTo(mucOptions.getSelf().getFullJid()); + presencePacket.setFrom(mucOptions.getAccount().getJid()); + presencePacket.setAttribute("type", "unavailable"); + return presencePacket; + } - public PresencePacket sendOfflinePresence(Account account) { - PresencePacket packet = new PresencePacket(); - packet.setFrom(account.getJid()); - packet.setAttribute("type","unavailable"); - return packet; - } + public PresencePacket sendOfflinePresence(Account account) { + PresencePacket packet = new PresencePacket(); + packet.setFrom(account.getJid()); + packet.setAttribute("type", "unavailable"); + return packet; + } } diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 7a82b092d..588af4c1e 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -308,8 +308,14 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece mXmppConnectionService.updateAccountUi(); } - private boolean handleErrorMessage(Account account, MessagePacket packet) { + private boolean handleErrorMessage(final Account account, final MessagePacket packet) { if (packet.getType() == MessagePacket.TYPE_ERROR) { + if (packet.fromServer(account)) { + final Pair forwarded = packet.getForwardedMessagePacket("received", "urn:xmpp:carbons:2"); + if (forwarded != null) { + return handleErrorMessage(account, forwarded.first); + } + } final Jid from = packet.getFrom(); final String id = packet.getId(); if (from != null && id != null) { From 3c0773c6e71398a0e4de5440b009cfeedd758b85 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 31 Aug 2020 11:19:27 +0200 Subject: [PATCH 11/29] use darker accent color in light theme --- src/main/java/eu/siacs/conversations/utils/StylingHelper.java | 2 +- src/main/res/values/colors.xml | 2 ++ src/main/res/values/themes.xml | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/utils/StylingHelper.java b/src/main/java/eu/siacs/conversations/utils/StylingHelper.java index c26a86ea4..4d4339a42 100644 --- a/src/main/java/eu/siacs/conversations/utils/StylingHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/StylingHelper.java @@ -129,7 +129,7 @@ public class StylingHelper { int start = indexOfIgnoreCase(string, needle, 0); while (start != -1) { int end = start + length; - editable.setSpan(new BackgroundColorSpan(ContextCompat.getColor(context, dark ? R.color.blue_a100 : R.color.blue_a200)), start, end, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); + editable.setSpan(new BackgroundColorSpan(ContextCompat.getColor(context, dark ? R.color.blue_a100 : R.color.blue_a400)), start, end, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); editable.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, dark ? R.color.black87 : R.color.white)), start, end, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); start = indexOfIgnoreCase(string, needle, start + length); } diff --git a/src/main/res/values/colors.xml b/src/main/res/values/colors.xml index 4332d1907..a61aa0e46 100644 --- a/src/main/res/values/colors.xml +++ b/src/main/res/values/colors.xml @@ -26,6 +26,8 @@ #ffff9800 #ff82B1FF #ff448AFF + #ff2979FF + #ff2962FF #ff4CAF50 #ff43A047 #ff388E3C diff --git a/src/main/res/values/themes.xml b/src/main/res/values/themes.xml index c9d20fcd8..78341bcfd 100644 --- a/src/main/res/values/themes.xml +++ b/src/main/res/values/themes.xml @@ -4,7 +4,7 @@