diff --git a/CHANGELOG.md b/CHANGELOG.md
index dd468564e..08b11223f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
* Remove deprecated "real-time apps" switch
* Fix: Remove address from profile switcher
+* Protect profile deletion and relays management with system lock/pin
## v2.34.0
2025-12
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 77c5f6e3e..5daa74438 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -209,16 +209,7 @@
-
-
-
-
-
-
-
-
+ android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
+ android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
+ android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode">
+ android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode">
{
Log.i(TAG, "Starting event loop");
DcEventEmitter emitter = dcAccounts.getEventEmitter();
diff --git a/src/main/java/org/thoughtcrime/securesms/ConversationListActivity.java b/src/main/java/org/thoughtcrime/securesms/ConversationListActivity.java
index f0fa56c83..dd202b3ad 100644
--- a/src/main/java/org/thoughtcrime/securesms/ConversationListActivity.java
+++ b/src/main/java/org/thoughtcrime/securesms/ConversationListActivity.java
@@ -74,6 +74,7 @@ import org.thoughtcrime.securesms.search.SearchFragment;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.Prefs;
+import org.thoughtcrime.securesms.util.ScreenLockUtil;
import org.thoughtcrime.securesms.util.ShareUtil;
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
import org.thoughtcrime.securesms.util.SendRelayedMessageUtil;
@@ -95,6 +96,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
public static final String CLEAR_NOTIFICATIONS = "clear_notifications";
public static final String ACCOUNT_ID_EXTRA = "account_id";
public static final String FROM_WELCOME = "from_welcome";
+ private static final int REQUEST_CODE_CONFIRM_CREDENTIALS_DELETE_PROFILE = ScreenLockUtil.REQUEST_CODE_CONFIRM_CREDENTIALS+1;
private ConversationListFragment conversationListFragment;
public TextView title;
@@ -106,6 +108,11 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
private ViewGroup fragmentContainer;
private ViewGroup selfAvatarContainer;
+ /** used to store temporarily scanned QR to pass it back to QrCodeHandler when ScreenLockUtil is used */
+ private String qrData = null;
+ /** used to store temporarily profile ID to delete after authorization is granted via ScreenLockUtil */
+ private int deleteProfileId = 0;
+
@Override
protected void onPreCreate() {
dynamicTheme = new DynamicNoActionBarTheme();
@@ -491,7 +498,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
if (uri.getScheme().equalsIgnoreCase(OPENPGP4FPR) || Util.isInviteURL(uri)) {
QrCodeHandler qrCodeHandler = new QrCodeHandler(this);
- qrCodeHandler.handleQrData(uri.toString(), SecurejoinSource.ExternalLink, null);
+ qrCodeHandler.handleOnlySecureJoinQr(uri.toString(), SecurejoinSource.ExternalLink, null);
}
}
}
@@ -566,14 +573,55 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
startActivity(Intent.createChooser(intent, getString(R.string.chat_share_with_title)));
}
+ public void onDeleteProfile(int profileId) {
+ deleteProfileId = profileId;
+ boolean result = ScreenLockUtil.applyScreenLock(this, getString(R.string.delete_account), getString(R.string.enter_system_secret_to_continue), REQUEST_CODE_CONFIRM_CREDENTIALS_DELETE_PROFILE);
+ if (!result) {
+ deleteProfile(profileId);
+ }
+ }
+
+ private void deleteProfile(int profileId) {
+ DcAccounts accounts = DcHelper.getAccounts(this);
+ boolean selected = profileId == accounts.getSelectedAccount().getAccountId();
+ DcHelper.getNotificationCenter(this).removeAllNotifications(profileId);
+ accounts.removeAccount(profileId);
+ if (selected) {
+ DcContext selAcc = accounts.getSelectedAccount();
+ AccountManager.getInstance().switchAccountAndStartActivity(this, selAcc.isOk()? selAcc.getAccountId() : 0);
+ } else {
+ AccountManager.getInstance().showSwitchAccountMenu(this);
+ }
+
+ // title update needed to show "Delta Chat" in case there is only one profile left
+ refreshTitle();
+ }
+
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
+ if (resultCode != RESULT_OK) return;
+
+ QrCodeHandler qrCodeHandler = new QrCodeHandler(this);
switch (requestCode) {
case IntentIntegrator.REQUEST_CODE:
- IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
- QrCodeHandler qrCodeHandler = new QrCodeHandler(this);
- qrCodeHandler.onScanPerformed(scanResult, SecurejoinUiPath.QrIcon);
+ IntentResult scanResult = IntentIntegrator.parseActivityResult(resultCode, data);
+ qrData = scanResult.getContents();
+ qrCodeHandler.handleQrData(qrData, SecurejoinSource.Scan, SecurejoinUiPath.QrIcon);
+ break;
+ case ScreenLockUtil.REQUEST_CODE_CONFIRM_CREDENTIALS:
+ // QrCodeHandler requested user authorization before adding a relay
+ // and it was granted, so proceed to add the relay
+ if (qrData != null) {
+ qrCodeHandler.addRelay(qrData);
+ qrData = null;
+ }
+ break;
+ case REQUEST_CODE_CONFIRM_CREDENTIALS_DELETE_PROFILE:
+ if (deleteProfileId != 0) {
+ deleteProfile(deleteProfileId);
+ deleteProfileId = 0;
+ }
break;
default:
break;
diff --git a/src/main/java/org/thoughtcrime/securesms/InstantOnboardingActivity.java b/src/main/java/org/thoughtcrime/securesms/InstantOnboardingActivity.java
index 4f664af8d..614a997aa 100644
--- a/src/main/java/org/thoughtcrime/securesms/InstantOnboardingActivity.java
+++ b/src/main/java/org/thoughtcrime/securesms/InstantOnboardingActivity.java
@@ -208,10 +208,8 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
case IntentIntegrator.REQUEST_CODE:
String qrRaw = data.getStringExtra(RegistrationQrActivity.QRDATA_EXTRA);
if (qrRaw == null) {
- IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
- if (scanResult != null && scanResult.getFormatName() != null) {
- qrRaw = scanResult.getContents();
- }
+ IntentResult scanResult = IntentIntegrator.parseActivityResult(resultCode, data);
+ qrRaw = scanResult.getContents();
}
if (qrRaw != null) {
setProviderFromQr(qrRaw);
diff --git a/src/main/java/org/thoughtcrime/securesms/NewConversationActivity.java b/src/main/java/org/thoughtcrime/securesms/NewConversationActivity.java
index 628525e37..b8180cb98 100644
--- a/src/main/java/org/thoughtcrime/securesms/NewConversationActivity.java
+++ b/src/main/java/org/thoughtcrime/securesms/NewConversationActivity.java
@@ -39,6 +39,7 @@ import org.thoughtcrime.securesms.qr.QrActivity;
import org.thoughtcrime.securesms.qr.QrCodeHandler;
import org.thoughtcrime.securesms.util.MailtoUtil;
+import chat.delta.rpc.types.SecurejoinSource;
import chat.delta.rpc.types.SecurejoinUiPath;
/**
@@ -135,11 +136,13 @@ public class NewConversationActivity extends ContactSelectionActivity {
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
+ if (resultCode != RESULT_OK) return;
+
switch (requestCode) {
case IntentIntegrator.REQUEST_CODE:
- IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
+ IntentResult scanResult = IntentIntegrator.parseActivityResult(resultCode, data);
QrCodeHandler qrCodeHandler = new QrCodeHandler(this);
- qrCodeHandler.onScanPerformed(scanResult, SecurejoinUiPath.NewContact);
+ qrCodeHandler.handleOnlySecureJoinQr(scanResult.getContents(), SecurejoinSource.Scan, SecurejoinUiPath.NewContact);
break;
default:
break;
diff --git a/src/main/java/org/thoughtcrime/securesms/WebViewActivity.java b/src/main/java/org/thoughtcrime/securesms/WebViewActivity.java
index 2d97e16c0..42d1fc410 100644
--- a/src/main/java/org/thoughtcrime/securesms/WebViewActivity.java
+++ b/src/main/java/org/thoughtcrime/securesms/WebViewActivity.java
@@ -304,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, SecurejoinSource.InternalLink, null);
+ new QrCodeHandler(this).handleOnlySecureJoinQr(url, SecurejoinSource.InternalLink, null);
return true; // abort internal loading
}
diff --git a/src/main/java/org/thoughtcrime/securesms/WelcomeActivity.java b/src/main/java/org/thoughtcrime/securesms/WelcomeActivity.java
index 83282eb58..53e4a1961 100644
--- a/src/main/java/org/thoughtcrime/securesms/WelcomeActivity.java
+++ b/src/main/java/org/thoughtcrime/securesms/WelcomeActivity.java
@@ -22,7 +22,6 @@ import androidx.appcompat.app.AlertDialog;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEvent;
-import com.b44t.messenger.DcLot;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
@@ -32,6 +31,7 @@ import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.mms.AttachmentManager;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.qr.BackupTransferActivity;
+import org.thoughtcrime.securesms.qr.QrCodeHandler;
import org.thoughtcrime.securesms.qr.RegistrationQrActivity;
import org.thoughtcrime.securesms.service.GenericForegroundService;
import org.thoughtcrime.securesms.service.NotificationController;
@@ -336,39 +336,14 @@ public class WelcomeActivity extends BaseActionBarActivity implements DcEventCen
if (requestCode==IntentIntegrator.REQUEST_CODE) {
String qrRaw = data.getStringExtra(RegistrationQrActivity.QRDATA_EXTRA);
if (qrRaw == null) {
- IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
- if (scanResult == null || scanResult.getFormatName() == null) {
- return; // aborted
- }
+ IntentResult scanResult = IntentIntegrator.parseActivityResult(resultCode, data);
qrRaw = scanResult.getContents();
}
- DcLot qrParsed = dcContext.checkQr(qrRaw);
- switch (qrParsed.getState()) {
- case DcContext.DC_QR_BACKUP2:
- final String finalQrRaw = qrRaw;
- new AlertDialog.Builder(this)
- .setTitle(R.string.multidevice_receiver_title)
- .setMessage(R.string.multidevice_receiver_scanning_ask)
- .setPositiveButton(R.string.perm_continue, (dialog, which) -> startBackupTransfer(finalQrRaw))
- .setNegativeButton(R.string.cancel, null)
- .setCancelable(false)
- .show();
- break;
-
- case DcContext.DC_QR_BACKUP_TOO_NEW:
- new AlertDialog.Builder(this)
- .setTitle(R.string.multidevice_receiver_title)
- .setMessage(R.string.multidevice_receiver_needs_update)
- .setPositiveButton(R.string.ok, null)
- .show();
- break;
-
- default:
- new AlertDialog.Builder(this)
- .setMessage(R.string.qraccount_qr_code_cannot_be_used)
- .setPositiveButton(R.string.ok, null)
- .show();
- break;
+ if (!new QrCodeHandler(this).handleBackupQr(qrRaw)) {
+ new AlertDialog.Builder(this)
+ .setMessage(R.string.qraccount_qr_code_cannot_be_used)
+ .setPositiveButton(R.string.ok, null)
+ .show();
}
} else if (requestCode == PICK_BACKUP) {
Uri uri = (data != null ? data.getData() : null);
diff --git a/src/main/java/org/thoughtcrime/securesms/accounts/AccountSelectionListFragment.java b/src/main/java/org/thoughtcrime/securesms/accounts/AccountSelectionListFragment.java
index 012807a31..c5e4bcf0b 100644
--- a/src/main/java/org/thoughtcrime/securesms/accounts/AccountSelectionListFragment.java
+++ b/src/main/java/org/thoughtcrime/securesms/accounts/AccountSelectionListFragment.java
@@ -47,9 +47,15 @@ import chat.delta.rpc.RpcException;
public class AccountSelectionListFragment extends DialogFragment implements DcEventCenter.DcEventDelegate
{
private static final String TAG = AccountSelectionListFragment.class.getSimpleName();
+ private final ConversationListActivity activity;
private RecyclerView recyclerView;
private AccountSelectionListAdapter adapter;
+ public AccountSelectionListFragment(ConversationListActivity activity) {
+ super();
+ this.activity = activity;
+ }
+
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
@@ -132,7 +138,7 @@ public class AccountSelectionListFragment extends DialogFragment implements DcEv
private void onContextItemSelected(MenuItem item, int accountId) {
int itemId = item.getItemId();
if (itemId == R.id.delete) {
- onDeleteAccount(accountId);
+ onDeleteProfile(accountId);
} else if (itemId == R.id.menu_mute_notifications) {
onToggleMute(accountId);
} else if (itemId == R.id.menu_set_tag) {
@@ -167,8 +173,6 @@ public class AccountSelectionListFragment extends DialogFragment implements DcEv
}
private void onSetTag(int accountId) {
- Activity activity = getActivity();
- if (activity == null) return;
AccountSelectionListFragment.this.dismiss();
DcContext dcContext = DcHelper.getAccounts(activity).getAccount(accountId);
@@ -190,10 +194,8 @@ public class AccountSelectionListFragment extends DialogFragment implements DcEv
.show();
}
- private void onDeleteAccount(int accountId) {
- Activity activity = getActivity();
+ private void onDeleteProfile(int accountId) {
AccountSelectionListFragment.this.dismiss();
- if (activity == null) return;
DcAccounts accounts = DcHelper.getAccounts(activity);
Rpc rpc = DcHelper.getRpc(activity);
@@ -229,22 +231,7 @@ public class AccountSelectionListFragment extends DialogFragment implements DcEv
.setTitle(R.string.delete_account)
.setView(dialogView)
.setNegativeButton(R.string.cancel, (d, which) -> AccountManager.getInstance().showSwitchAccountMenu(activity))
- .setPositiveButton(R.string.delete, (d2, which2) -> {
- boolean selected = accountId == accounts.getSelectedAccount().getAccountId();
- DcHelper.getNotificationCenter(activity).removeAllNotifications(accountId);
- accounts.removeAccount(accountId);
- if (selected) {
- DcContext selAcc = accounts.getSelectedAccount();
- AccountManager.getInstance().switchAccountAndStartActivity(activity, selAcc.isOk()? selAcc.getAccountId() : 0);
- } else {
- AccountManager.getInstance().showSwitchAccountMenu(activity);
- }
-
- // title update needed to show "Delta Chat" in case there is only one profile left
- if (activity instanceof ConversationListActivity) {
- ((ConversationListActivity)activity).refreshTitle();
- }
- })
+ .setPositiveButton(R.string.delete, (d2, w2) -> activity.onDeleteProfile(accountId))
.show();
Util.redPositiveButton(dialog);
}
diff --git a/src/main/java/org/thoughtcrime/securesms/connect/AccountManager.java b/src/main/java/org/thoughtcrime/securesms/connect/AccountManager.java
index 7c5268dcb..5763089d6 100644
--- a/src/main/java/org/thoughtcrime/securesms/connect/AccountManager.java
+++ b/src/main/java/org/thoughtcrime/securesms/connect/AccountManager.java
@@ -147,8 +147,8 @@ public class AccountManager {
// ui
- public void showSwitchAccountMenu(Activity activity) {
- AccountSelectionListFragment dialog = new AccountSelectionListFragment();
+ public void showSwitchAccountMenu(ConversationListActivity activity) {
+ AccountSelectionListFragment dialog = new AccountSelectionListFragment(activity);
dialog.show(((FragmentActivity) activity).getSupportFragmentManager(), null);
}
diff --git a/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java b/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java
index 72b3edc44..6eadb77f8 100644
--- a/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java
+++ b/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java
@@ -77,11 +77,11 @@ public class DcHelper {
}
public static DcEventCenter getEventCenter(@NonNull Context context) {
- return ApplicationContext.getInstance(context).eventCenter;
+ return ApplicationContext.getInstance(context).getEventCenter();
}
public static NotificationCenter getNotificationCenter(@NonNull Context context) {
- return ApplicationContext.getInstance(context).notificationCenter;
+ return ApplicationContext.getInstance(context).getNotificationCenter();
}
public static boolean isConfigured(Context context) {
diff --git a/src/main/java/org/thoughtcrime/securesms/contacts/NewContactActivity.java b/src/main/java/org/thoughtcrime/securesms/contacts/NewContactActivity.java
index 494c8655a..c3459619a 100644
--- a/src/main/java/org/thoughtcrime/securesms/contacts/NewContactActivity.java
+++ b/src/main/java/org/thoughtcrime/securesms/contacts/NewContactActivity.java
@@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.qr.QrCodeHandler;
import org.thoughtcrime.securesms.util.ViewUtil;
+import chat.delta.rpc.types.SecurejoinSource;
import chat.delta.rpc.types.SecurejoinUiPath;
public class NewContactActivity extends PassphraseRequiredActionBarActivity
@@ -104,10 +105,10 @@ public class NewContactActivity extends PassphraseRequiredActionBarActivity
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
- if (requestCode == IntentIntegrator.REQUEST_CODE) {
- IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
+ if (resultCode == RESULT_OK && requestCode == IntentIntegrator.REQUEST_CODE) {
+ IntentResult scanResult = IntentIntegrator.parseActivityResult(resultCode, data);
QrCodeHandler qrCodeHandler = new QrCodeHandler(this);
- qrCodeHandler.onScanPerformed(scanResult, SecurejoinUiPath.NewContact);
+ qrCodeHandler.handleOnlySecureJoinQr(scanResult.getContents(), SecurejoinSource.Scan, SecurejoinUiPath.NewContact);
}
}
}
diff --git a/src/main/java/org/thoughtcrime/securesms/geolocation/DcLocationManager.java b/src/main/java/org/thoughtcrime/securesms/geolocation/DcLocationManager.java
index 1876caa2c..c54e81455 100644
--- a/src/main/java/org/thoughtcrime/securesms/geolocation/DcLocationManager.java
+++ b/src/main/java/org/thoughtcrime/securesms/geolocation/DcLocationManager.java
@@ -16,6 +16,8 @@ import java.util.Observer;
import static android.content.Context.BIND_AUTO_CREATE;
+import com.b44t.messenger.DcContext;
+
public class DcLocationManager implements Observer {
private static final String TAG = DcLocationManager.class.getSimpleName();
@@ -40,10 +42,10 @@ public class DcLocationManager implements Observer {
}
};
- public DcLocationManager(Context context) {
+ public DcLocationManager(Context context, DcContext dcContext) {
this.context = context.getApplicationContext();
DcLocation.getInstance().addObserver(this);
- if (DcHelper.getContext(context).isSendingLocationsToChat(0)) {
+ if (dcContext.isSendingLocationsToChat(0)) {
startLocationEngine();
}
}
diff --git a/src/main/java/org/thoughtcrime/securesms/mms/AttachmentManager.java b/src/main/java/org/thoughtcrime/securesms/mms/AttachmentManager.java
index 53589981d..c2902b63e 100644
--- a/src/main/java/org/thoughtcrime/securesms/mms/AttachmentManager.java
+++ b/src/main/java/org/thoughtcrime/securesms/mms/AttachmentManager.java
@@ -473,7 +473,7 @@ public class AttachmentManager {
public static void selectLocation(Activity activity, int chatId) {
ApplicationContext applicationContext = ApplicationContext.getInstance(activity);
- DcLocationManager dcLocationManager = applicationContext.dcLocationManager;
+ DcLocationManager dcLocationManager = applicationContext.getLocationManager();
if (DcHelper.getContext(applicationContext).isSendingLocationsToChat(chatId)) {
dcLocationManager.stopSharingLocation(chatId);
diff --git a/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java b/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
index d6abb1244..ae870df8c 100644
--- a/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
+++ b/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
@@ -16,7 +16,6 @@ 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;
@@ -33,8 +32,8 @@ 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.ScreenLockUtil;
import org.thoughtcrime.securesms.util.StreamUtil;
import org.thoughtcrime.securesms.util.Util;
@@ -212,7 +211,10 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
Preference relayListBtn = this.findPreference("pref_relay_list_button");
if (relayListBtn != null) {
relayListBtn.setOnPreferenceClickListener(((preference) -> {
- openRelayListActivity();
+ boolean result = ScreenLockUtil.applyScreenLock(requireActivity(), getString(R.string.transports), getString(R.string.enter_system_secret_to_continue), REQUEST_CODE_CONFIRM_CREDENTIALS_ACCOUNT);
+ if (!result) {
+ openRelayListActivity();
+ }
return true;
}));
}
diff --git a/src/main/java/org/thoughtcrime/securesms/qr/QrActivity.java b/src/main/java/org/thoughtcrime/securesms/qr/QrActivity.java
index 1b62f61e1..a9f08134c 100644
--- a/src/main/java/org/thoughtcrime/securesms/qr/QrActivity.java
+++ b/src/main/java/org/thoughtcrime/securesms/qr/QrActivity.java
@@ -2,7 +2,6 @@ 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;
@@ -27,11 +26,10 @@ import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Result;
+import com.google.zxing.client.android.Intents;
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;
@@ -44,9 +42,6 @@ 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();
@@ -154,8 +149,7 @@ public class QrActivity extends BaseActionBarActivity implements View.OnClickLis
} else if (itemId == R.id.load_from_image) {
AttachmentManager.selectImage(this, REQUEST_CODE_IMAGE);
} else if (itemId == R.id.paste) {
- QrCodeHandler qrCodeHandler = new QrCodeHandler(this);
- qrCodeHandler.handleQrData(Util.getTextFromClipboard(this), SecurejoinSource.Clipboard, getUiPath());
+ setQrResult(Util.getTextFromClipboard(this));
}
return false;
@@ -203,10 +197,10 @@ public class QrActivity extends BaseActionBarActivity implements View.OnClickLis
RGBLuminanceSource source = new RGBLuminanceSource(width, height, pixels);
BinaryBitmap bBitmap = new BinaryBitmap(new HybridBinarizer(source));
MultiFormatReader reader = new MultiFormatReader();
+
try {
Result result = reader.decode(bBitmap);
- QrCodeHandler qrCodeHandler = new QrCodeHandler(this);
- qrCodeHandler.handleQrData(result.getText(), SecurejoinSource.ImageLoaded, getUiPath());
+ setQrResult(result.getText());
} catch (NotFoundException e) {
Log.e(TAG, "decode exception", e);
Toast.makeText(this, getString(R.string.qrscan_failed), Toast.LENGTH_LONG).show();
@@ -219,19 +213,11 @@ 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;
+ private void setQrResult(String qrData) {
+ Intent intent = new Intent();
+ intent.putExtra(Intents.Scan.RESULT, qrData);
+ setResult(RESULT_OK, intent);
+ finish();
}
@Override
diff --git a/src/main/java/org/thoughtcrime/securesms/qr/QrCodeHandler.java b/src/main/java/org/thoughtcrime/securesms/qr/QrCodeHandler.java
index 84f3c9fd6..8e5900386 100644
--- a/src/main/java/org/thoughtcrime/securesms/qr/QrCodeHandler.java
+++ b/src/main/java/org/thoughtcrime/securesms/qr/QrCodeHandler.java
@@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.connect.AccountManager;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.relay.RelayListActivity;
import org.thoughtcrime.securesms.util.IntentUtils;
+import org.thoughtcrime.securesms.util.ScreenLockUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.views.ProgressDialog;
@@ -53,118 +54,182 @@ public class QrCodeHandler {
accId = dcContext.getAccountId();
}
- public void onScanPerformed(IntentResult scanResult, SecurejoinUiPath uipath) {
- if (scanResult == null || scanResult.getFormatName() == null) {
- return; // aborted
- }
-
- handleQrData(scanResult.getContents(), SecurejoinSource.Scan, uipath);
+ /** Process only QR about getting in contact or joining chats */
+ public void handleOnlySecureJoinQr(String rawString, SecurejoinSource source, SecurejoinUiPath uiPath) {
+ final DcLot qrParsed = dcContext.checkQr(rawString);
+ if (!handleSecureJoinQr(qrParsed, rawString, source, uiPath)) {
+ handleDefault(new AlertDialog.Builder(activity), rawString, qrParsed);
}
+ }
- public void handleQrData(String rawString, SecurejoinSource source, SecurejoinUiPath uiPath) {
+ private boolean handleSecureJoinQr(DcLot qrParsed, String rawString, SecurejoinSource source, SecurejoinUiPath uiPath) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ String name = dcContext.getContact(qrParsed.getId()).getDisplayName();
+ switch (qrParsed.getState()) {
+ case DcContext.DC_QR_ASK_VERIFYCONTACT:
+ case DcContext.DC_QR_ASK_VERIFYGROUP:
+ case DcContext.DC_QR_ASK_JOIN_BROADCAST:
+ showVerifyContactOrGroup(builder, rawString, qrParsed, name, source, uiPath);
+ break;
+
+ case DcContext.DC_QR_WITHDRAW_VERIFYCONTACT:
+ case DcContext.DC_QR_WITHDRAW_VERIFYGROUP:
+ case DcContext.DC_QR_WITHDRAW_JOINBROADCAST:
+ String message = qrParsed.getState() == DcContext.DC_QR_WITHDRAW_VERIFYCONTACT ? activity.getString(R.string.withdraw_verifycontact_explain)
+ : qrParsed.getState() == DcContext.DC_QR_WITHDRAW_VERIFYCONTACT ? activity.getString(R.string.withdraw_verifygroup_explain, qrParsed.getText1())
+ : activity.getString(R.string.withdraw_joinbroadcast_explain, qrParsed.getText1());
+ builder.setTitle(R.string.qrshow_title);
+ builder.setMessage(message);
+ builder.setNeutralButton(R.string.reset, (dialog, which) -> {
+ dcContext.setConfigFromQr(rawString);
+ });
+ builder.setPositiveButton(R.string.ok, null);
+ Util.redButton(builder.show(), AlertDialog.BUTTON_NEUTRAL);
+ return true;
+
+ case DcContext.DC_QR_REVIVE_VERIFYCONTACT:
+ case DcContext.DC_QR_REVIVE_VERIFYGROUP:
+ case DcContext.DC_QR_REVIVE_JOINBROADCAST:
+ builder.setTitle(R.string.qrshow_title);
+ builder.setMessage(activity.getString(R.string.revive_verifycontact_explain));
+ builder.setNeutralButton(R.string.revive_qr_code, (dialog, which) -> {
+ dcContext.setConfigFromQr(rawString);
+ });
+ builder.setPositiveButton(R.string.ok, null);
+ break;
+
+ case DcContext.DC_QR_FPR_WITHOUT_ADDR:
+ showVerifyFingerprintWithoutAddress(builder, qrParsed);
+ break;
+
+ case DcContext.DC_QR_FPR_MISMATCH:
+ showFingerPrintError(builder, name);
+ break;
+
+ case DcContext.DC_QR_FPR_OK:
+ case DcContext.DC_QR_ADDR:
+ showFingerprintOrQrSuccess(builder, qrParsed, name);
+ break;
+
+ default:
+ return false;
+ }
+ builder.create().show();
+ return true;
+ }
+
+ /** Process only QR about adding relays/profiles (DCACCOUNT: / DCLOGIN:) */
+ public void handleOnlyAddRelayQr(String rawString) {
+ final DcLot qrParsed = dcContext.checkQr(rawString);
+ if (!handleAddRelayQr(qrParsed, rawString)) {
+ handleDefault(new AlertDialog.Builder(activity), rawString, qrParsed);
+ }
+ }
+
+ private boolean handleAddRelayQr(DcLot qrParsed, String rawString) {
+ switch (qrParsed.getState()) {
+ case DcContext.DC_QR_ACCOUNT:
+ case DcContext.DC_QR_LOGIN:
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- final DcLot qrParsed = dcContext.checkQr(rawString);
- String name = dcContext.getContact(qrParsed.getId()).getDisplayName();
- switch (qrParsed.getState()) {
- 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, source, uiPath);
- break;
-
- case DcContext.DC_QR_FPR_WITHOUT_ADDR:
- showVerifyFingerprintWithoutAddress(builder, qrParsed);
- break;
-
- case DcContext.DC_QR_FPR_MISMATCH:
- showFingerPrintError(builder, name);
- break;
-
- case DcContext.DC_QR_FPR_OK:
- case DcContext.DC_QR_ADDR:
- showFingerprintOrQrSuccess(builder, qrParsed, name);
- break;
-
- case DcContext.DC_QR_URL:
- showQrUrl(builder, qrParsed);
- break;
-
- case DcContext.DC_QR_ACCOUNT:
- case DcContext.DC_QR_LOGIN:
- final String scope = qrParsed.getText1();
- setAddTransportDialog(activity, builder, rawString, scope);
- builder.setNegativeButton(R.string.cancel, null);
- builder.setCancelable(false);
- break;
-
- case DcContext.DC_QR_BACKUP2:
- builder.setTitle(R.string.multidevice_receiver_title);
- builder.setMessage(activity.getString(R.string.multidevice_receiver_scanning_ask) + "\n\n" + activity.getString(R.string.multidevice_same_network_hint));
- builder.setPositiveButton(R.string.perm_continue, (dialog, which) -> {
- AccountManager.getInstance().addAccountFromSecondDevice(activity, rawString);
- });
- builder.setNegativeButton(R.string.cancel, null);
- builder.setCancelable(false);
-
- AlertDialog alertDialog = builder.create();
- alertDialog.show();
- BackupTransferActivity.appendSSID(activity, alertDialog.findViewById(android.R.id.message));
- return;
-
- case DcContext.DC_QR_BACKUP_TOO_NEW:
- builder.setTitle(R.string.multidevice_receiver_title);
- builder.setMessage(activity.getString(R.string.multidevice_receiver_needs_update));
- builder.setNegativeButton(R.string.ok, null);
- break;
-
- case DcContext.DC_QR_PROXY:
- builder.setTitle(R.string.proxy_use_proxy);
- builder.setMessage(activity.getString(R.string.proxy_use_proxy_confirm, qrParsed.getText1()));
- builder.setPositiveButton(R.string.proxy_use_proxy, (dlg, btn) -> {
- dcContext.setConfigFromQr(rawString);
- dcContext.restartIo();
- showDoneToast(activity);
- });
- if (rawString.toLowerCase().startsWith("http")) {
- builder.setNeutralButton(R.string.open, (d, b) -> IntentUtils.showInBrowser(activity, rawString));
- }
- builder.setNegativeButton(R.string.cancel, null);
- builder.setCancelable(false);
- break;
-
- case DcContext.DC_QR_WITHDRAW_VERIFYCONTACT:
- case DcContext.DC_QR_WITHDRAW_VERIFYGROUP:
- case DcContext.DC_QR_WITHDRAW_JOINBROADCAST:
- String message = qrParsed.getState() == DcContext.DC_QR_WITHDRAW_VERIFYCONTACT ? activity.getString(R.string.withdraw_verifycontact_explain)
- : qrParsed.getState() == DcContext.DC_QR_WITHDRAW_VERIFYCONTACT ? activity.getString(R.string.withdraw_verifygroup_explain, qrParsed.getText1())
- : activity.getString(R.string.withdraw_joinbroadcast_explain, qrParsed.getText1());
- builder.setTitle(R.string.qrshow_title);
- builder.setMessage(message);
- builder.setNeutralButton(R.string.reset, (dialog, which) -> {
- dcContext.setConfigFromQr(rawString);
- });
- builder.setPositiveButton(R.string.ok, null);
- AlertDialog withdrawDialog = builder.show();
- Util.redButton(withdrawDialog, AlertDialog.BUTTON_NEUTRAL);
- return;
-
- case DcContext.DC_QR_REVIVE_VERIFYCONTACT:
- case DcContext.DC_QR_REVIVE_VERIFYGROUP:
- case DcContext.DC_QR_REVIVE_JOINBROADCAST:
- builder.setTitle(R.string.qrshow_title);
- builder.setMessage(activity.getString(R.string.revive_verifycontact_explain));
- builder.setNeutralButton(R.string.revive_qr_code, (dialog, which) -> {
- dcContext.setConfigFromQr(rawString);
- });
- builder.setPositiveButton(R.string.ok, null);
- break;
-
- default:
- handleDefault(builder, rawString, qrParsed);
- break;
- }
+ builder.setTitle(R.string.confirm_add_transport);
+ builder.setMessage(qrParsed.getText1());
+ builder.setPositiveButton(R.string.ok, (d, w) -> {
+ if (activity instanceof RelayListActivity) {
+ // no need to protect with lock, RelayListActivity is already protected
+ addRelay(rawString);
+ } else {
+ boolean result = ScreenLockUtil.applyScreenLock(activity, activity.getString(R.string.add_transport), activity.getString(R.string.enter_system_secret_to_continue), ScreenLockUtil.REQUEST_CODE_CONFIRM_CREDENTIALS);
+ if (!result) {
+ addRelay(rawString);
+ }
+ }
+ });
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setCancelable(false);
builder.create().show();
+ return true;
+ default:
+ return false;
}
+ }
+
+ /** Process a proxy QR, returns true if a dialog was shown, false if the QR is not a proxy QR */
+ public boolean handleProxyQr(String rawString) {
+ return handleProxyQr(dcContext.checkQr(rawString), rawString);
+ }
+
+ private boolean handleProxyQr(DcLot qrParsed, String rawString) {
+ if (qrParsed.getState() == DcContext.DC_QR_PROXY) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setTitle(R.string.proxy_use_proxy);
+ builder.setMessage(activity.getString(R.string.proxy_use_proxy_confirm, qrParsed.getText1()));
+ builder.setPositiveButton(R.string.proxy_use_proxy, (dlg, btn) -> {
+ dcContext.setConfigFromQr(rawString);
+ dcContext.restartIo();
+ showDoneToast();
+ });
+ if (rawString.toLowerCase().startsWith("http")) {
+ builder.setNeutralButton(R.string.open, (d, b) -> IntentUtils.showInBrowser(activity, rawString));
+ }
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setCancelable(false);
+ builder.create().show();
+ return true;
+ }
+ return false;
+ }
+
+ /** Process a backup QR, returns true if a dialog was shown, false if the QR is not a backup QR */
+ public boolean handleBackupQr(String rawString) {
+ return handleBackupQr(dcContext.checkQr(rawString), rawString);
+ }
+
+ private boolean handleBackupQr(DcLot qrParsed, String rawString) {
+ switch (qrParsed.getState()) {
+ case DcContext.DC_QR_BACKUP2:
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setTitle(R.string.multidevice_receiver_title);
+ builder.setMessage(activity.getString(R.string.multidevice_receiver_scanning_ask) + "\n\n" + activity.getString(R.string.multidevice_same_network_hint));
+ builder.setPositiveButton(R.string.perm_continue, (dialog, which) -> {
+ AccountManager.getInstance().addAccountFromSecondDevice(activity, rawString);
+ });
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setCancelable(false);
+
+ AlertDialog alertDialog = builder.create();
+ alertDialog.show();
+ BackupTransferActivity.appendSSID(activity, alertDialog.findViewById(android.R.id.message));
+ return true;
+
+ case DcContext.DC_QR_BACKUP_TOO_NEW:
+ new AlertDialog.Builder(activity)
+ .setTitle(R.string.multidevice_receiver_title)
+ .setMessage(activity.getString(R.string.multidevice_receiver_needs_update))
+ .setNegativeButton(R.string.ok, null)
+ .create().show();
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ /** Handle any kind of QR showing an AlertDialog adapted to the QR type. */
+ public void handleQrData(String rawString, SecurejoinSource source, SecurejoinUiPath uiPath) {
+ final DcLot qrParsed = dcContext.checkQr(rawString);
+ if (handleSecureJoinQr(qrParsed, rawString, source, uiPath)
+ || handleAddRelayQr(qrParsed, rawString)
+ || handleProxyQr(qrParsed, rawString)
+ || handleBackupQr(qrParsed, rawString)) return;
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ if (qrParsed.getState() == DcContext.DC_QR_URL) {
+ showQrUrl(builder, qrParsed);
+ } else {
+ handleDefault(builder, rawString, qrParsed);
+ }
+ builder.create().show();
+ }
private void handleDefault(AlertDialog.Builder builder, String qrRawString, DcLot qrParsed) {
String msg;
@@ -187,7 +252,7 @@ public class QrCodeHandler {
builder.setPositiveButton(android.R.string.ok, null);
builder.setNeutralButton(R.string.menu_copy_to_clipboard, (dialog, which) -> {
Util.writeTextToClipboard(activity, scannedText);
- showDoneToast(activity);
+ showDoneToast();
});
}
@@ -199,11 +264,11 @@ public class QrCodeHandler {
builder.setNegativeButton(android.R.string.cancel, null);
builder.setNeutralButton(R.string.menu_copy_to_clipboard, (dialog, which) -> {
Util.writeTextToClipboard(activity, url);
- showDoneToast(activity);
+ showDoneToast();
});
}
- private void showDoneToast(Activity activity) {
+ private void showDoneToast() {
Toast.makeText(activity, activity.getString(R.string.done), Toast.LENGTH_SHORT).show();
}
@@ -232,12 +297,11 @@ public class QrCodeHandler {
builder.setPositiveButton(android.R.string.ok, null);
builder.setNeutralButton(R.string.menu_copy_to_clipboard, (dialog, which) -> {
Util.writeTextToClipboard(activity, qrParsed.getText1());
- showDoneToast(activity);
+ showDoneToast();
});
}
- private void showVerifyContactOrGroup(Activity activity,
- AlertDialog.Builder builder,
+ private void showVerifyContactOrGroup(AlertDialog.Builder builder,
String qrRawString,
DcLot qrParsed,
String name,
@@ -275,51 +339,47 @@ public class QrCodeHandler {
builder.setNegativeButton(android.R.string.cancel, null);
}
- private void setAddTransportDialog(Activity activity, AlertDialog.Builder builder, String qrData, String transportName) {
- builder.setTitle(R.string.confirm_add_transport);
- builder.setMessage(transportName);
- builder.setPositiveButton(R.string.ok, (d, w) -> {
- ProgressDialog progressDialog = new ProgressDialog(activity);
- progressDialog.setMessage(activity.getResources().getString(R.string.one_moment));
- progressDialog.setCanceledOnTouchOutside(false);
- progressDialog.setCancelable(false);
- String cancel = activity.getResources().getString(android.R.string.cancel);
- progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, cancel, (d2, w2) -> {
- dcContext.stopOngoingProcess();
- });
- progressDialog.show();
+ public void addRelay(String qrData) {
+ ProgressDialog progressDialog = new ProgressDialog(activity);
+ progressDialog.setMessage(activity.getResources().getString(R.string.one_moment));
+ progressDialog.setCanceledOnTouchOutside(false);
+ progressDialog.setCancelable(false);
+ String cancel = activity.getResources().getString(android.R.string.cancel);
+ progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, cancel, (d, w) -> {
+ dcContext.stopOngoingProcess();
+ });
+ progressDialog.show();
- Util.runOnAnyBackgroundThread(() -> {
- String error = null;
- try {
- rpc.addTransportFromQr(accId, qrData);
- } catch (RpcException e) {
- Log.w(TAG, e);
- error = e.getMessage();
- }
- final String finalError = error;
- Util.runOnMain(() -> {
- if (!progressDialog.isShowing()) return; // canceled dialog, nothing to do
- if (finalError != null) {
- new AlertDialog.Builder(activity)
- .setTitle(R.string.error)
- .setMessage(finalError)
- .setPositiveButton(R.string.ok, null)
- .show();
- } else {
- showDoneToast(activity);
- if (!(activity instanceof RelayListActivity)) {
- activity.startActivity(new Intent(activity, RelayListActivity.class));
- }
- }
- try {
- progressDialog.dismiss();
- } catch (IllegalArgumentException e) {
- // see https://stackoverflow.com/a/5102572/4557005
- Log.w(TAG, e);
- }
- });
- });
+ Util.runOnAnyBackgroundThread(() -> {
+ String error = null;
+ try {
+ rpc.addTransportFromQr(accId, qrData);
+ } catch (RpcException e) {
+ Log.w(TAG, e);
+ error = e.getMessage();
+ }
+ final String finalError = error;
+ Util.runOnMain(() -> {
+ if (!progressDialog.isShowing()) return; // canceled dialog, nothing to do
+ if (finalError != null) {
+ new AlertDialog.Builder(activity)
+ .setTitle(R.string.error)
+ .setMessage(finalError)
+ .setPositiveButton(R.string.ok, null)
+ .show();
+ } else {
+ showDoneToast();
+ if (!(activity instanceof RelayListActivity)) {
+ activity.startActivity(new Intent(activity, RelayListActivity.class));
+ }
+ }
+ try {
+ progressDialog.dismiss();
+ } catch (IllegalArgumentException e) {
+ // see https://stackoverflow.com/a/5102572/4557005
+ Log.w(TAG, e);
+ }
});
+ });
}
}
diff --git a/src/main/java/org/thoughtcrime/securesms/relay/RelayListActivity.java b/src/main/java/org/thoughtcrime/securesms/relay/RelayListActivity.java
index bb15e4dfc..a5b45990d 100644
--- a/src/main/java/org/thoughtcrime/securesms/relay/RelayListActivity.java
+++ b/src/main/java/org/thoughtcrime/securesms/relay/RelayListActivity.java
@@ -24,6 +24,7 @@ import org.thoughtcrime.securesms.connect.DcEventCenter;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.qr.QrActivity;
import org.thoughtcrime.securesms.qr.QrCodeHandler;
+import org.thoughtcrime.securesms.util.ScreenLockUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
@@ -32,8 +33,6 @@ 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 {
@@ -45,6 +44,9 @@ public class RelayListActivity extends BaseActionBarActivity
private Rpc rpc;
private int accId;
+ /** QR provided via Intent extras needs to be saved to pass it to QrCodeHandler when authorization finishes */
+ private String qrData = null;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -67,6 +69,15 @@ public class RelayListActivity extends BaseActionBarActivity
// Apply insets to prevent fab from being covered by system bars
ViewUtil.applyWindowInsetsAsMargin(fabAdd);
+ qrData = getIntent().getStringExtra(EXTRA_QR_DATA);
+ if (qrData != null) {
+ // when the activity is opened with a QR data, we need to ask for authorization first
+ boolean result = ScreenLockUtil.applyScreenLock(this, getString(R.string.add_transport), getString(R.string.enter_system_secret_to_continue), ScreenLockUtil.REQUEST_CODE_CONFIRM_CREDENTIALS);
+ if (!result) {
+ new QrCodeHandler(this).handleOnlyAddRelayQr(qrData);
+ }
+ }
+
fabAdd.setOnClickListener(v -> {
new IntentIntegrator(this).setCaptureActivity(QrActivity.class).addExtra(QrActivity.EXTRA_SCAN_RELAY, true).initiateScan();
});
@@ -86,12 +97,6 @@ public class RelayListActivity extends BaseActionBarActivity
DcEventCenter eventCenter = DcHelper.getEventCenter(this);
eventCenter.addObserver(DcContext.DC_EVENT_CONFIGURE_PROGRESS, this);
-
- String qrdata = getIntent().getStringExtra(EXTRA_QR_DATA);
- if (qrdata != null) {
- QrCodeHandler qrCodeHandler = new QrCodeHandler(this);
- qrCodeHandler.handleQrData(qrdata, SecurejoinSource.Unknown, SecurejoinUiPath.Unknown);
- }
}
@Override
@@ -172,10 +177,22 @@ public class RelayListActivity extends BaseActionBarActivity
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
+ if (resultCode != RESULT_OK) {
+ // if user canceled unlocking, then finish
+ if (requestCode == ScreenLockUtil.REQUEST_CODE_CONFIRM_CREDENTIALS) finish();
+ return;
+ }
+
+ QrCodeHandler qrCodeHandler = new QrCodeHandler(this);
if (requestCode == IntentIntegrator.REQUEST_CODE) {
- IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
- QrCodeHandler qrCodeHandler = new QrCodeHandler(this);
- qrCodeHandler.onScanPerformed(scanResult, SecurejoinUiPath.Unknown);
+ IntentResult scanResult = IntentIntegrator.parseActivityResult(resultCode, data);
+ qrCodeHandler.handleOnlyAddRelayQr(scanResult.getContents());
+ } else if (requestCode == ScreenLockUtil.REQUEST_CODE_CONFIRM_CREDENTIALS) {
+ // user authorized, then proceed to handle the QR data
+ if (qrData != null) {
+ qrCodeHandler.handleOnlyAddRelayQr(qrData);
+ qrData = null;
+ }
}
}
diff --git a/src/main/java/org/thoughtcrime/securesms/util/LongClickCopySpan.java b/src/main/java/org/thoughtcrime/securesms/util/LongClickCopySpan.java
index 606bedbeb..594081204 100644
--- a/src/main/java/org/thoughtcrime/securesms/util/LongClickCopySpan.java
+++ b/src/main/java/org/thoughtcrime/securesms/util/LongClickCopySpan.java
@@ -82,15 +82,11 @@ public class LongClickCopySpan extends ClickableSpan {
}
} else if (Util.isInviteURL(url)) {
QrCodeHandler qrCodeHandler = new QrCodeHandler((Activity) widget.getContext());
- qrCodeHandler.handleQrData(url, SecurejoinSource.InternalLink, null);
+ qrCodeHandler.handleOnlySecureJoinQr(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, null, null);
- } else {
- IntentUtils.showInBrowser(widget.getContext(), url);
+ if (!new QrCodeHandler(activity).handleProxyQr(url)) {
+ IntentUtils.showInBrowser(activity, url);
}
}
}