From 9c3281e182da0ad966ccebb81b25f52f5ead1a61 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 15 Dec 2025 15:25:24 +0100 Subject: [PATCH 1/4] chats preferences is called just 'Chats' it was renamed first on iOS from 'Chats and Media' to 'Chats' to not confuse with 'All Apps and Media' - however, that point is also valid for android, but even if not, it is good for inner consistency and simpler documentation. moreover, the settings are in reality also about contacts and more, so just a broad chats is fine. but also for outer consistency, this seems better - also in quite some other apps, it is just called 'chats' --- .../securesms/preferences/ChatsPreferenceFragment.java | 2 +- src/main/res/values/strings.xml | 1 + src/main/res/xml/preferences.xml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java b/src/main/java/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java index 4360d0ed4..0c5140bbf 100644 --- a/src/main/java/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java +++ b/src/main/java/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java @@ -93,7 +93,7 @@ public class ChatsPreferenceFragment extends ListSummaryPreferenceFragment { @Override public void onResume() { super.onResume(); - ((ApplicationPreferencesActivity)getActivity()).getSupportActionBar().setTitle(R.string.pref_chats_and_media); + ((ApplicationPreferencesActivity)getActivity()).getSupportActionBar().setTitle(R.string.pref_chats); String value = Integer.toString(dcContext.getConfigInt(DcHelper.CONFIG_MEDIA_QUALITY)); mediaQuality.setValue(value); diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 17ffd8c43..fd0327911 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -749,6 +749,7 @@ Sound Silent Privacy + Chats and Media System default diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml index e09faabed..be94c2100 100644 --- a/src/main/res/xml/preferences.xml +++ b/src/main/res/xml/preferences.xml @@ -6,7 +6,7 @@ android:key="preference_category_profile"/> From 4a73ac19c2ba52478487a14fe7dd3a3bf35a582f Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 15 Dec 2025 17:17:14 +0100 Subject: [PATCH 2/4] tweak another occurance of 'Chats and Media' --- src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index fd0327911..bd0a5ad77 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -954,7 +954,7 @@ You deleted the \"Saved messages\" chat.\n\nℹ️ To use the \"Saved messages\" feature again, create a new chat with yourself. - ⚠️ Your provider\'s storage is about to run out: %1$s%% are already used.\n\nYou may not be able to receive messages if storage is full.\n\n👉 Please check if you can delete old data in the provider\'s web interface and consider enabling \"Settings / Chats and Media / Delete Old Messages\". You can check your current storage usage anytime at \"Settings / Connectivity\". + ⚠️ Your provider\'s storage is about to run out: %1$s%% are already used.\n\nYou may not be able to receive messages if storage is full.\n\n👉 Please check if you can delete old data in the provider\'s web interface and consider enabling \"Settings / Chats / Delete Old Messages\". You can check your current storage usage anytime at \"Settings / Connectivity\". ⚠️ Date or time on your device seems to be inaccurate (%1$s).\n\nAdjust your clock ⏰🔧 to ensure your messages are received correctly. ⚠️ Your Delta Chat version might be outdated.\n\nThis may cause problems because your chat partners use newer versions - and you are missing the latest features 😳\nPlease check https://get.delta.chat or your app store for updates. From 2a7025ef1704f2182e02e8ab1bcd5f53fd445b61 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 15 Dec 2025 15:04:29 +0100 Subject: [PATCH 3/4] stop using deprecated ask_delete_messages_simple --- .../java/org/thoughtcrime/securesms/MediaPreviewActivity.java | 4 +--- .../org/thoughtcrime/securesms/MessageSelectorFragment.java | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java b/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java index c8d46085a..8c451f7c4 100644 --- a/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java +++ b/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java @@ -344,9 +344,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity DcMsg dcMsg = dcContext.getMsg(mediaItem.msgId); DcChat dcChat = dcContext.getChat(dcMsg.getChatId()); - String text = getResources().getQuantityString( - dcChat.isDeviceTalk() ? R.plurals.ask_delete_messages_simple : R.plurals.ask_delete_messages, - 1, 1); + String text = getResources().getQuantityString(R.plurals.ask_delete_messages,1, 1); int positiveBtnLabel = dcChat.isSelfTalk() ? R.string.delete : R.string.delete_for_me; final int[] messageIds = new int[]{mediaItem.msgId}; diff --git a/src/main/java/org/thoughtcrime/securesms/MessageSelectorFragment.java b/src/main/java/org/thoughtcrime/securesms/MessageSelectorFragment.java index d8513f89f..9f86ecf76 100644 --- a/src/main/java/org/thoughtcrime/securesms/MessageSelectorFragment.java +++ b/src/main/java/org/thoughtcrime/securesms/MessageSelectorFragment.java @@ -76,9 +76,7 @@ public abstract class MessageSelectorFragment canDeleteForAll = false; } - String text = getActivity().getResources().getQuantityString( - dcChat.isDeviceTalk() ? R.plurals.ask_delete_messages_simple : R.plurals.ask_delete_messages, - messageIds.length, messageIds.length); + String text = getActivity().getResources().getQuantityString(R.plurals.ask_delete_messages, messageIds.length, messageIds.length); int positiveBtnLabel = dcChat.isSelfTalk() ? R.string.delete : R.string.delete_for_me; AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity()) From 114731f7229bb6b1dccfb21659dbce2d063f1649 Mon Sep 17 00:00:00 2001 From: Hocuri Date: Tue, 16 Dec 2025 13:10:51 +0100 Subject: [PATCH 4/4] Make sending of statistics into a setting (#3794) Counterpart of https://github.com/chatmail/core/pull/6851 * Make sending of statistics into a setting * feat: Count securejoin sources and UI paths * feat: Rename self_reporting to send_statistics * Adapt core's API change * WIP, untested: Adapt to a rename on the core side * Adapt to generated jsonrpc * New strings and a new dialog * Adapt to the API change * Rewording: `...and support research` * "More Info" button rather than link * Small fixes * Open the correct survey (though it doesn't work yet) * Changelog * Update help * Fix compile error * Fix compilation * Revert submodule change * Don't show a device message yet * Move "Send Statistics" setting * Fix compilation error * Remove unused constant --------- Co-authored-by: adb --- CHANGELOG.md | 1 + .../securesms/ConversationFragment.java | 3 + .../securesms/ConversationListActivity.java | 6 +- .../securesms/NewConversationActivity.java | 4 +- .../thoughtcrime/securesms/StatsSending.java | 100 ++++++++++++++++++ .../securesms/WebViewActivity.java | 4 +- .../securesms/connect/DcHelper.java | 2 + .../contacts/NewContactActivity.java | 4 +- .../AdvancedPreferenceFragment.java | 22 ++++ .../thoughtcrime/securesms/qr/QrActivity.java | 25 ++++- .../securesms/qr/QrCodeHandler.java | 42 +++++--- .../securesms/relay/RelayListActivity.java | 6 +- .../securesms/util/LongClickCopySpan.java | 6 +- .../thoughtcrime/securesms/util/Prefs.java | 11 +- src/main/res/values/strings.xml | 9 +- src/main/res/xml/preferences_advanced.xml | 4 + 16 files changed, 222 insertions(+), 27 deletions(-) create mode 100644 src/main/java/org/thoughtcrime/securesms/StatsSending.java diff --git a/CHANGELOG.md b/CHANGELOG.md index f4d9dd544..318d24e9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ * Target Android 16 * Change color of links in text messages * Improve edge-to-edge support +* Add the option (opt-in) to send anonymous statistics to Delta Chat's developers * Metadata protection: protect message recipients * Allow to withdraw channel invite links and QR codes * Allow to open externally links clicked inside in-chat apps diff --git a/src/main/java/org/thoughtcrime/securesms/ConversationFragment.java b/src/main/java/org/thoughtcrime/securesms/ConversationFragment.java index 02f2f1271..3929de365 100644 --- a/src/main/java/org/thoughtcrime/securesms/ConversationFragment.java +++ b/src/main/java/org/thoughtcrime/securesms/ConversationFragment.java @@ -744,6 +744,9 @@ public class ConversationFragment extends MessageSelectorFragment else if(DozeReminder.isDozeReminderMsg(getContext(), messageRecord)) { DozeReminder.dozeReminderTapped(getContext()); } + else if(StatsSending.isStatsSendingDeviceMsg(getContext(), messageRecord)) { + StatsSending.statsDeviceMsgTapped(getActivity()); + } else if(messageRecord.getInfoType() == DcMsg.DC_INFO_WEBXDC_INFO_MESSAGE) { if (messageRecord.getParent() != null) { // if the parent webxdc message still exists diff --git a/src/main/java/org/thoughtcrime/securesms/ConversationListActivity.java b/src/main/java/org/thoughtcrime/securesms/ConversationListActivity.java index 1076889db..f0fa56c83 100644 --- a/src/main/java/org/thoughtcrime/securesms/ConversationListActivity.java +++ b/src/main/java/org/thoughtcrime/securesms/ConversationListActivity.java @@ -80,6 +80,8 @@ import org.thoughtcrime.securesms.util.SendRelayedMessageUtil; import org.thoughtcrime.securesms.util.StorageUtil; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.ViewUtil; +import chat.delta.rpc.types.SecurejoinSource; +import chat.delta.rpc.types.SecurejoinUiPath; import java.util.ArrayList; import java.util.Date; @@ -489,7 +491,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit if (uri.getScheme().equalsIgnoreCase(OPENPGP4FPR) || Util.isInviteURL(uri)) { QrCodeHandler qrCodeHandler = new QrCodeHandler(this); - qrCodeHandler.handleQrData(uri.toString()); + qrCodeHandler.handleQrData(uri.toString(), SecurejoinSource.ExternalLink, null); } } } @@ -571,7 +573,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit case IntentIntegrator.REQUEST_CODE: IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data); QrCodeHandler qrCodeHandler = new QrCodeHandler(this); - qrCodeHandler.onScanPerformed(scanResult); + qrCodeHandler.onScanPerformed(scanResult, SecurejoinUiPath.QrIcon); break; default: break; diff --git a/src/main/java/org/thoughtcrime/securesms/NewConversationActivity.java b/src/main/java/org/thoughtcrime/securesms/NewConversationActivity.java index 2421ef92d..628525e37 100644 --- a/src/main/java/org/thoughtcrime/securesms/NewConversationActivity.java +++ b/src/main/java/org/thoughtcrime/securesms/NewConversationActivity.java @@ -39,6 +39,8 @@ import org.thoughtcrime.securesms.qr.QrActivity; import org.thoughtcrime.securesms.qr.QrCodeHandler; import org.thoughtcrime.securesms.util.MailtoUtil; +import chat.delta.rpc.types.SecurejoinUiPath; + /** * Activity container for starting a new conversation. * @@ -137,7 +139,7 @@ public class NewConversationActivity extends ContactSelectionActivity { case IntentIntegrator.REQUEST_CODE: IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data); QrCodeHandler qrCodeHandler = new QrCodeHandler(this); - qrCodeHandler.onScanPerformed(scanResult); + qrCodeHandler.onScanPerformed(scanResult, SecurejoinUiPath.NewContact); break; default: break; diff --git a/src/main/java/org/thoughtcrime/securesms/StatsSending.java b/src/main/java/org/thoughtcrime/securesms/StatsSending.java new file mode 100644 index 000000000..4b98dfbc0 --- /dev/null +++ b/src/main/java/org/thoughtcrime/securesms/StatsSending.java @@ -0,0 +1,100 @@ +package org.thoughtcrime.securesms; + +import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_STATS_SENDING; +import static org.thoughtcrime.securesms.connect.DcHelper.openHelp; + +import android.app.Activity; +import android.content.Context; +import android.text.util.Linkify; +import android.widget.TextView; + +import androidx.appcompat.app.AlertDialog; + +import com.b44t.messenger.DcContact; +import com.b44t.messenger.DcContext; +import com.b44t.messenger.DcMsg; + +import org.thoughtcrime.securesms.connect.DcHelper; +import org.thoughtcrime.securesms.util.IntentUtils; +import org.thoughtcrime.securesms.util.Prefs; + +import java.util.Locale; + +public class StatsSending { + /** @noinspection unused: We will start adding a device message once stats-sending is tested a bit */ + public static void maybeAddStatsSendingDeviceMsg(Context context) { + if (Prefs.getStatsDeviceMsgId(context) != 0) { + return; + } + if (DcHelper.getInt(context, CONFIG_STATS_SENDING) != 0) { + return; // Stats-sending is already enabled + } + DcContext dcContext = DcHelper.getContext(context); + DcMsg msg = new DcMsg(dcContext, DcMsg.DC_MSG_TEXT); + msg.setText(context.getString(R.string.stats_device_message)); + int msgId = dcContext.addDeviceMsg("stats_device_message", msg); + if (msgId!=0) { + Prefs.setStatsDeviceMsgId(context, msgId); + } + } + + public static boolean isStatsSendingDeviceMsg(Context context, DcMsg msg) { + return msg != null + && msg.getFromId() == DcContact.DC_CONTACT_ID_DEVICE + && msg.getId() == Prefs.getStatsDeviceMsgId(context); + } + + public static void statsDeviceMsgTapped(Activity activity) { + if (DcHelper.getInt(activity, CONFIG_STATS_SENDING) != 0) { + showStatsDisableDialog(activity); + } else { + showStatsConfirmationDialog(activity, () -> {}); + } + } + + public static void showStatsConfirmationDialog(Activity activity, Runnable onConfigChangedListener) { + AlertDialog d = new AlertDialog.Builder(activity) + .setMessage(R.string.stats_confirmation_dialog) + .setNegativeButton(R.string.cancel, (_d, i) -> {}) + .setPositiveButton(R.string.yes, (_d, i) -> { + DcHelper.set(activity, DcHelper.CONFIG_STATS_SENDING, "1"); + onConfigChangedListener.run(); + showStatsThanksDialog(activity); + }) + .setNeutralButton(R.string.more_info_desktop, (_d, i) -> openHelp(activity, "#statssending")) + .create(); + d.show(); + try { + //noinspection DataFlowIssue + Linkify.addLinks((TextView) d.findViewById(android.R.id.message), Linkify.WEB_URLS); + } catch (NullPointerException e) { + //noinspection CallToPrintStackTrace + e.printStackTrace(); + } + } + + private static void showStatsThanksDialog(Activity activity) { + String stats_id = DcHelper.get(activity, DcHelper.CONFIG_STATS_ID); + new AlertDialog.Builder(activity) + .setMessage(R.string.stats_thanks) + .setNeutralButton(R.string.no, (d, i) -> {}) + .setPositiveButton(R.string.yes, (d, i) -> { + String ln = Locale.getDefault().getLanguage(); + IntentUtils.showInBrowser(activity, "https://cispa.qualtrics.com/jfe/form/SV_9YmhkpGa48KxfLg?id=" + stats_id + "&ln=" + ln); + }) + .show(); + } + + public static void showStatsDisableDialog(Activity activity) { + AlertDialog d = new AlertDialog.Builder(activity) + .setMessage(R.string.stats_disable_dialog) + .setNegativeButton(R.string.disable, (_d, i) -> { + DcHelper.set(activity, DcHelper.CONFIG_STATS_SENDING, "0"); + }) + .setPositiveButton(R.string.stats_keep_sending, (_d, i) -> { + }) + .setNeutralButton(R.string.more_info_desktop, (_d, i) -> openHelp(activity, "#statssending")) + .create(); + d.show(); + } +} diff --git a/src/main/java/org/thoughtcrime/securesms/WebViewActivity.java b/src/main/java/org/thoughtcrime/securesms/WebViewActivity.java index b092e3c62..2d97e16c0 100644 --- a/src/main/java/org/thoughtcrime/securesms/WebViewActivity.java +++ b/src/main/java/org/thoughtcrime/securesms/WebViewActivity.java @@ -28,6 +28,8 @@ import org.thoughtcrime.securesms.util.IntentUtils; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.ViewUtil; +import chat.delta.rpc.types.SecurejoinSource; + import java.net.IDN; public class WebViewActivity extends PassphraseRequiredActionBarActivity @@ -302,7 +304,7 @@ public class WebViewActivity extends PassphraseRequiredActionBarActivity // invite-links should be handled directly String schema = url.split(":")[0].toLowerCase(); if (schema.equals("openpgp4fpr") || url.startsWith("https://" + Util.INVITE_DOMAIN + "/")) { - new QrCodeHandler(this).handleQrData(url); + new QrCodeHandler(this).handleQrData(url, SecurejoinSource.InternalLink, null); return true; // abort internal loading } diff --git a/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java b/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java index 2f0b6163e..824cd1f84 100644 --- a/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java +++ b/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java @@ -62,6 +62,8 @@ public class DcHelper { public static final String CONFIG_PROXY_URL = "proxy_url"; public static final String CONFIG_WEBXDC_REALTIME_ENABLED = "webxdc_realtime_enabled"; public static final String CONFIG_PRIVATE_TAG = "private_tag"; + public static final String CONFIG_STATS_SENDING = "stats_sending"; + public static final String CONFIG_STATS_ID = "stats_id"; public static DcContext getContext(@NonNull Context context) { return ApplicationContext.getInstance(context).dcContext; diff --git a/src/main/java/org/thoughtcrime/securesms/contacts/NewContactActivity.java b/src/main/java/org/thoughtcrime/securesms/contacts/NewContactActivity.java index a9b11e960..494c8655a 100644 --- a/src/main/java/org/thoughtcrime/securesms/contacts/NewContactActivity.java +++ b/src/main/java/org/thoughtcrime/securesms/contacts/NewContactActivity.java @@ -22,6 +22,8 @@ import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.qr.QrCodeHandler; import org.thoughtcrime.securesms.util.ViewUtil; +import chat.delta.rpc.types.SecurejoinUiPath; + public class NewContactActivity extends PassphraseRequiredActionBarActivity { @@ -105,7 +107,7 @@ public class NewContactActivity extends PassphraseRequiredActionBarActivity if (requestCode == IntentIntegrator.REQUEST_CODE) { IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data); QrCodeHandler qrCodeHandler = new QrCodeHandler(this); - qrCodeHandler.onScanPerformed(scanResult); + qrCodeHandler.onScanPerformed(scanResult, SecurejoinUiPath.NewContact); } } } diff --git a/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java b/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java index 1b8de05a4..8fe732761 100644 --- a/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java +++ b/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java @@ -5,6 +5,7 @@ import static android.text.InputType.TYPE_TEXT_VARIATION_URI; import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_BCC_SELF; import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_MVBOX_MOVE; import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_ONLY_FETCH_MVBOX; +import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_STATS_SENDING; import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SHOW_EMAILS; import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_WEBXDC_REALTIME_ENABLED; @@ -16,6 +17,7 @@ import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.EditText; +import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; @@ -29,8 +31,10 @@ import org.thoughtcrime.securesms.ApplicationPreferencesActivity; import org.thoughtcrime.securesms.LogViewActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.relay.RelayListActivity; +import org.thoughtcrime.securesms.StatsSending; import org.thoughtcrime.securesms.connect.DcEventCenter; import org.thoughtcrime.securesms.proxy.ProxySettingsActivity; +import org.thoughtcrime.securesms.util.IntentUtils; import org.thoughtcrime.securesms.util.Prefs; import org.thoughtcrime.securesms.util.StreamUtil; import org.thoughtcrime.securesms.util.Util; @@ -49,6 +53,7 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment private static final String TAG = AdvancedPreferenceFragment.class.getSimpleName(); private ListPreference showEmails; + CheckBoxPreference selfReportingCheckbox; CheckBoxPreference multiDeviceCheckbox; CheckBoxPreference mvboxMoveCheckbox; CheckBoxPreference onlyFetchMvboxCheckbox; @@ -191,6 +196,22 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment }); } + selfReportingCheckbox = this.findPreference("pref_stats_sending"); + if (selfReportingCheckbox != null) { + selfReportingCheckbox.setOnPreferenceChangeListener((preference, newValue) -> { + boolean enabled = (Boolean) newValue; + if (enabled) { + StatsSending.showStatsConfirmationDialog(requireActivity(), () -> { + ((CheckBoxPreference)preference).setChecked(true); + }); + return false; + } else { + dcContext.setConfigInt(CONFIG_STATS_SENDING, 0); + return true; + } + }); + } + Preference proxySettings = this.findPreference("proxy_settings_button"); if (proxySettings != null) { proxySettings.setOnPreferenceClickListener((preference) -> { @@ -226,6 +247,7 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment showEmails.setValue(value); updateListSummary(showEmails, value); + selfReportingCheckbox.setChecked(0!=dcContext.getConfigInt(CONFIG_STATS_SENDING)); multiDeviceCheckbox.setChecked(0!=dcContext.getConfigInt(CONFIG_BCC_SELF)); mvboxMoveCheckbox.setChecked(0!=dcContext.getConfigInt(CONFIG_MVBOX_MOVE)); onlyFetchMvboxCheckbox.setChecked(0!=dcContext.getConfigInt(CONFIG_ONLY_FETCH_MVBOX)); diff --git a/src/main/java/org/thoughtcrime/securesms/qr/QrActivity.java b/src/main/java/org/thoughtcrime/securesms/qr/QrActivity.java index 6be2b363e..1b62f61e1 100644 --- a/src/main/java/org/thoughtcrime/securesms/qr/QrActivity.java +++ b/src/main/java/org/thoughtcrime/securesms/qr/QrActivity.java @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.qr; import android.Manifest; import android.app.Activity; +import android.content.ComponentName; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; @@ -29,6 +30,8 @@ import com.google.zxing.Result; import com.google.zxing.common.HybridBinarizer; import org.thoughtcrime.securesms.BaseActionBarActivity; +import org.thoughtcrime.securesms.ConversationListActivity; +import org.thoughtcrime.securesms.NewConversationActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.contacts.NewContactActivity; @@ -41,6 +44,9 @@ import org.thoughtcrime.securesms.util.ViewUtil; import java.io.FileNotFoundException; import java.io.InputStream; +import chat.delta.rpc.types.SecurejoinSource; +import chat.delta.rpc.types.SecurejoinUiPath; + public class QrActivity extends BaseActionBarActivity implements View.OnClickListener { private final static String TAG = QrActivity.class.getSimpleName(); @@ -149,7 +155,7 @@ public class QrActivity extends BaseActionBarActivity implements View.OnClickLis AttachmentManager.selectImage(this, REQUEST_CODE_IMAGE); } else if (itemId == R.id.paste) { QrCodeHandler qrCodeHandler = new QrCodeHandler(this); - qrCodeHandler.handleQrData(Util.getTextFromClipboard(this)); + qrCodeHandler.handleQrData(Util.getTextFromClipboard(this), SecurejoinSource.Clipboard, getUiPath()); } return false; @@ -200,7 +206,7 @@ public class QrActivity extends BaseActionBarActivity implements View.OnClickLis try { Result result = reader.decode(bBitmap); QrCodeHandler qrCodeHandler = new QrCodeHandler(this); - qrCodeHandler.handleQrData(result.getText()); + qrCodeHandler.handleQrData(result.getText(), SecurejoinSource.ImageLoaded, getUiPath()); } catch (NotFoundException e) { Log.e(TAG, "decode exception", e); Toast.makeText(this, getString(R.string.qrscan_failed), Toast.LENGTH_LONG).show(); @@ -213,6 +219,21 @@ public class QrActivity extends BaseActionBarActivity implements View.OnClickLis } } + private SecurejoinUiPath getUiPath() { + SecurejoinUiPath uiPath = null; + ComponentName caller = this.getCallingActivity(); + if (caller != null) { + if (caller.getClassName().equals(NewConversationActivity.class.getName())) { + uiPath = SecurejoinUiPath.NewContact; + } else if (caller.getClassName().equals(ConversationListActivity.class.getName()) + // RoutingActivity is an alias for ConversationListActivity + || caller.getClassName().endsWith(".RoutingActivity")) { + uiPath = SecurejoinUiPath.QrIcon; + } + } + return uiPath; + } + @Override public void onClick(View v) { viewPager.setCurrentItem(TAB_SCAN); diff --git a/src/main/java/org/thoughtcrime/securesms/qr/QrCodeHandler.java b/src/main/java/org/thoughtcrime/securesms/qr/QrCodeHandler.java index 46d9e942b..84f3c9fd6 100644 --- a/src/main/java/org/thoughtcrime/securesms/qr/QrCodeHandler.java +++ b/src/main/java/org/thoughtcrime/securesms/qr/QrCodeHandler.java @@ -25,10 +25,22 @@ import org.thoughtcrime.securesms.util.views.ProgressDialog; import chat.delta.rpc.Rpc; import chat.delta.rpc.RpcException; -public class QrCodeHandler { +import chat.delta.rpc.types.SecurejoinSource; +import chat.delta.rpc.types.SecurejoinUiPath; +public class QrCodeHandler { private static final String TAG = QrCodeHandler.class.getSimpleName(); + public static int SECUREJOIN_SOURCE_EXTERNAL_LINK = 1; + public static int SECUREJOIN_SOURCE_INTERNAL_LINK = 2; + public static int SECUREJOIN_SOURCE_CLIPBOARD = 3; + public static int SECUREJOIN_SOURCE_IMAGE_LOADED = 4; + public static int SECUREJOIN_SOURCE_SCAN = 5; + + public static int SECUREJOIN_UIPATH_QR_ICON = 1; + public static int SECUREJOIN_UIPATH_NEW_CONTACT = 2; + + private final Activity activity; private final DcContext dcContext; private final Rpc rpc; @@ -41,15 +53,15 @@ public class QrCodeHandler { accId = dcContext.getAccountId(); } - public void onScanPerformed(IntentResult scanResult) { + public void onScanPerformed(IntentResult scanResult, SecurejoinUiPath uipath) { if (scanResult == null || scanResult.getFormatName() == null) { return; // aborted } - handleQrData(scanResult.getContents()); + handleQrData(scanResult.getContents(), SecurejoinSource.Scan, uipath); } - public void handleQrData(String rawString) { + public void handleQrData(String rawString, SecurejoinSource source, SecurejoinUiPath uiPath) { AlertDialog.Builder builder = new AlertDialog.Builder(activity); final DcLot qrParsed = dcContext.checkQr(rawString); String name = dcContext.getContact(qrParsed.getId()).getDisplayName(); @@ -57,7 +69,7 @@ public class QrCodeHandler { case DcContext.DC_QR_ASK_VERIFYCONTACT: case DcContext.DC_QR_ASK_VERIFYGROUP: case DcContext.DC_QR_ASK_JOIN_BROADCAST: - showVerifyContactOrGroup(activity, builder, rawString, qrParsed, name); + showVerifyContactOrGroup(activity, builder, rawString, qrParsed, name, source, uiPath); break; case DcContext.DC_QR_FPR_WITHOUT_ADDR: @@ -224,7 +236,13 @@ public class QrCodeHandler { }); } - private void showVerifyContactOrGroup(Activity activity, AlertDialog.Builder builder, String qrRawString, DcLot qrParsed, String name) { + private void showVerifyContactOrGroup(Activity activity, + AlertDialog.Builder builder, + String qrRawString, + DcLot qrParsed, + String name, + SecurejoinSource source, + SecurejoinUiPath uipath) { String msg; switch (qrParsed.getState()) { case DcContext.DC_QR_ASK_VERIFYGROUP: @@ -239,17 +257,17 @@ public class QrCodeHandler { } builder.setMessage(msg); builder.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> { - DcHelper.getEventCenter(activity).captureNextError(); - int newChatId = dcContext.joinSecurejoin(qrRawString); - DcHelper.getEventCenter(activity).endCaptureNextError(); + try { + int newChatId = DcHelper.getRpc(activity).secureJoinWithUxInfo(dcContext.getAccountId(), qrRawString, source, uipath); + if (newChatId == 0) throw new Exception("Securejoin failed to create a chat"); - if (newChatId != 0) { Intent intent = new Intent(activity, ConversationActivity.class); intent.putExtra(ConversationActivity.CHAT_ID_EXTRA, newChatId); activity.startActivity(intent); - } else { + } catch (Exception e) { + e.printStackTrace(); AlertDialog.Builder builder1 = new AlertDialog.Builder(activity); - builder1.setMessage(dcContext.getLastError()); + builder1.setMessage(e.getMessage()); builder1.setPositiveButton(android.R.string.ok, null); builder1.create().show(); } diff --git a/src/main/java/org/thoughtcrime/securesms/relay/RelayListActivity.java b/src/main/java/org/thoughtcrime/securesms/relay/RelayListActivity.java index d0ae1859d..bb15e4dfc 100644 --- a/src/main/java/org/thoughtcrime/securesms/relay/RelayListActivity.java +++ b/src/main/java/org/thoughtcrime/securesms/relay/RelayListActivity.java @@ -32,6 +32,8 @@ import java.util.List; import chat.delta.rpc.Rpc; import chat.delta.rpc.RpcException; import chat.delta.rpc.types.EnteredLoginParam; +import chat.delta.rpc.types.SecurejoinSource; +import chat.delta.rpc.types.SecurejoinUiPath; public class RelayListActivity extends BaseActionBarActivity implements RelayListAdapter.OnRelayClickListener, DcEventCenter.DcEventDelegate { @@ -88,7 +90,7 @@ public class RelayListActivity extends BaseActionBarActivity String qrdata = getIntent().getStringExtra(EXTRA_QR_DATA); if (qrdata != null) { QrCodeHandler qrCodeHandler = new QrCodeHandler(this); - qrCodeHandler.handleQrData(qrdata); + qrCodeHandler.handleQrData(qrdata, SecurejoinSource.Unknown, SecurejoinUiPath.Unknown); } } @@ -173,7 +175,7 @@ public class RelayListActivity extends BaseActionBarActivity if (requestCode == IntentIntegrator.REQUEST_CODE) { IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data); QrCodeHandler qrCodeHandler = new QrCodeHandler(this); - qrCodeHandler.onScanPerformed(scanResult); + qrCodeHandler.onScanPerformed(scanResult, SecurejoinUiPath.Unknown); } } diff --git a/src/main/java/org/thoughtcrime/securesms/util/LongClickCopySpan.java b/src/main/java/org/thoughtcrime/securesms/util/LongClickCopySpan.java index 7f64ca54f..606bedbeb 100644 --- a/src/main/java/org/thoughtcrime/securesms/util/LongClickCopySpan.java +++ b/src/main/java/org/thoughtcrime/securesms/util/LongClickCopySpan.java @@ -19,6 +19,8 @@ import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.qr.QrCodeHandler; +import chat.delta.rpc.types.SecurejoinSource; + public class LongClickCopySpan extends ClickableSpan { private static final String PREFIX_MAILTO = "mailto:"; private static final String PREFIX_TEL = "tel:"; @@ -80,13 +82,13 @@ public class LongClickCopySpan extends ClickableSpan { } } else if (Util.isInviteURL(url)) { QrCodeHandler qrCodeHandler = new QrCodeHandler((Activity) widget.getContext()); - qrCodeHandler.handleQrData(url); + qrCodeHandler.handleQrData(url, SecurejoinSource.InternalLink, null); } else { Activity activity = (Activity) widget.getContext(); DcContext dcContext = DcHelper.getContext(activity); if (dcContext.checkQr(url).getState() == DcContext.DC_QR_PROXY) { QrCodeHandler qrCodeHandler = new QrCodeHandler(activity); - qrCodeHandler.handleQrData(url); + qrCodeHandler.handleQrData(url, null, null); } else { IntentUtils.showInBrowser(widget.getContext(), url); } diff --git a/src/main/java/org/thoughtcrime/securesms/util/Prefs.java b/src/main/java/org/thoughtcrime/securesms/util/Prefs.java index 4e257d843..52d0d2e3e 100644 --- a/src/main/java/org/thoughtcrime/securesms/util/Prefs.java +++ b/src/main/java/org/thoughtcrime/securesms/util/Prefs.java @@ -12,12 +12,10 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.app.NotificationCompat; -import com.b44t.messenger.DcAccounts; import com.b44t.messenger.DcContext; import org.thoughtcrime.securesms.BuildConfig; import org.thoughtcrime.securesms.connect.DcHelper; -import org.thoughtcrime.securesms.notifications.FcmReceiveService; import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference; import java.util.ArrayList; @@ -46,6 +44,7 @@ public class Prefs { public static final String SCREEN_SECURITY_PREF = "pref_screen_security"; private static final String ENTER_SENDS_PREF = "pref_enter_sends"; private static final String PROMPTED_DOZE_MSG_ID_PREF = "pref_prompted_doze_msg_id"; + private static final String STATS_DEVICE_MSG_ID_PREF = "pref_stats_device_msg_id"; public static final String DOZE_ASKED_DIRECTLY = "pref_doze_asked_directly"; public static final String ASKED_FOR_NOTIFICATION_PERMISSION= "pref_asked_for_notification_permission"; private static final String IN_THREAD_NOTIFICATION_PREF = "pref_key_inthread_notifications"; @@ -154,6 +153,14 @@ public class Prefs { return getIntegerPreference(context, PROMPTED_DOZE_MSG_ID_PREF, 0); } + public static void setStatsDeviceMsgId(Context context, int msg_id) { + setIntegerPreference(context, STATS_DEVICE_MSG_ID_PREF, msg_id); + } + + public static int getStatsDeviceMsgId(Context context) { + return getIntegerPreference(context, STATS_DEVICE_MSG_ID_PREF, 0); + } + public static boolean isPushEnabled(Context context) { return BuildConfig.USE_PLAY_SERVICES; } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index bd0a5ad77..d4251d01c 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -824,8 +824,13 @@ Disable IMAP IDLE Do not use IMAP IDLE extension even if the server supports it. Enabling this option will delay message retrieval, enable it only for testing. Send statistics to Delta Chat\'s developers - The attachment contains anonymous usage statistics, which help us improve Delta Chat. Thank you! - + Do you want to help improve Delta Chat and support research by sending weekly anonymous usage statistics?\n\n👉 Tap here… 👈 + Do you want to help improve Delta Chat and support research by sending weekly anonymous usage statistics? + Thank you! You can always disable the sending at \"Settings -> Advanced\".\n\nDo you additionally have 5 minutes to take part in a scientific study on the security of Delta Chat? + Sending of statistics is already enabled.\n\nDo you want to disable it? + Disable + Keep sending + The attachment contains anonymous usage statistics, which helps us improve Delta Chat. See https://delta.chat/help#statssending for more information. Thank you! Search Results diff --git a/src/main/res/xml/preferences_advanced.xml b/src/main/res/xml/preferences_advanced.xml index dc540cb4f..dde838992 100644 --- a/src/main/res/xml/preferences_advanced.xml +++ b/src/main/res/xml/preferences_advanced.xml @@ -49,6 +49,10 @@ +