Merge remote-tracking branch 'upstream/main'

This commit is contained in:
adbenitez
2026-02-24 01:30:11 +01:00
12 changed files with 221 additions and 193 deletions
@@ -22,6 +22,8 @@ import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
@@ -89,18 +91,6 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == ScreenLockUtil.REQUEST_CODE_CONFIRM_CREDENTIALS) {
showBackupProvider();
return;
}
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment);
fragment.onActivityResult(requestCode, resultCode, data);
}
@Override
public boolean onSupportNavigateUp() {
FragmentManager fragmentManager = getSupportFragmentManager();
@@ -132,11 +122,21 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
}
public static class ApplicationPreferenceFragment extends CorrectedPreferenceFragment implements DcEventCenter.DcEventDelegate {
private ActivityResultLauncher<Intent> screenLockLauncher;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
screenLockLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
((ApplicationPreferencesActivity)getActivity()).showBackupProvider();
}
}
);
this.findPreference(PREFERENCE_CATEGORY_PROFILE)
.setOnPreferenceClickListener(new ProfileClickListener());
this.findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS)
@@ -247,7 +247,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
case PREFERENCE_CATEGORY_MULTIDEVICE:
if (!ScreenLockUtil.applyScreenLock(getActivity(), getString(R.string.multidevice_title),
getString(R.string.multidevice_this_creates_a_qr_code) + "\n\n" + getString(R.string.enter_system_secret_to_continue),
ScreenLockUtil.REQUEST_CODE_CONFIRM_CREDENTIALS)) {
screenLockLauncher)) {
new AlertDialog.Builder(getActivity())
.setTitle(R.string.multidevice_title)
.setMessage(R.string.multidevice_this_creates_a_qr_code)
@@ -32,6 +32,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
@@ -79,7 +81,6 @@ public class ContactSelectionListFragment extends Fragment
public static final String SELECT_UNENCRYPTED_EXTRA = "select_unencrypted_extra";
public static final String ALLOW_CREATION = "allow_creation";
public static final String PRESELECTED_CONTACTS = "preselected_contacts";
public static final int CONTACT_ADDR_RESULT_CODE = 61123;
private DcContext dcContext;
@@ -91,14 +92,26 @@ public class ContactSelectionListFragment extends Fragment
private TextView emptyView;
private ActionMode actionMode;
private ActionMode.Callback actionModeCallback;
private ActivityResultLauncher<Intent> newContactLauncher;
@Override
public void onActivityCreated(Bundle icicle) {
super.onActivityCreated(icicle);
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
dcContext = DcHelper.getContext(getActivity());
DcHelper.getEventCenter(getActivity()).addObserver(DcContext.DC_EVENT_CONTACTS_CHANGED, this);
initializeCursor();
dcContext = DcHelper.getContext(requireContext());
newContactLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
int contactId = result.getData().getIntExtra(NewContactActivity.CONTACT_ID_EXTRA, 0);
if (contactId != 0) {
selectedContacts.add(contactId);
deselectedContacts.remove(contactId);
}
LoaderManager.getInstance(this).restartLoader(0, null, ContactSelectionListFragment.this);
}
}
);
}
@Override
@@ -162,6 +175,9 @@ public class ContactSelectionListFragment extends Fragment
}
};
DcHelper.getEventCenter(requireActivity()).addObserver(DcContext.DC_EVENT_CONTACTS_CHANGED, this);
initializeCursor();
return view;
}
@@ -314,7 +330,7 @@ public class ContactSelectionListFragment extends Fragment
intent.putExtra(NewContactActivity.ADDR_EXTRA, cursorFilter);
}
if (isMulti()) {
startActivityForResult(intent, CONTACT_ADDR_RESULT_CODE);
newContactLauncher.launch(intent);
} else {
requireContext().startActivity(intent);
}
@@ -363,16 +379,4 @@ public class ContactSelectionListFragment extends Fragment
}
}
@Override
public void onActivityResult(int reqCode, int resultCode, final Intent data) {
super.onActivityResult(reqCode, resultCode, data);
if (resultCode == Activity.RESULT_OK && reqCode == CONTACT_ADDR_RESULT_CODE) {
int contactId = data.getIntExtra(NewContactActivity.CONTACT_ID_EXTRA, 0);
if (contactId != 0) {
selectedContacts.add(contactId);
deselectedContacts.remove(contactId);
}
getLoaderManager().restartLoader(0, null, ContactSelectionListFragment.this);
}
}
}
@@ -87,7 +87,6 @@ public class ConversationFragment extends MessageSelectorFragment
private static final String TAG = ConversationFragment.class.getSimpleName();
private static final int SCROLL_ANIMATION_THRESHOLD = 50;
private static final int CODE_ADD_EDIT_CONTACT = 77;
private final ActionModeCallback actionModeCallback = new ActionModeCallback();
private final ItemClickListener selectionClickListener = new ConversationFragmentItemClickListener();
@@ -954,17 +953,6 @@ public class ConversationFragment extends MessageSelectorFragment
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CODE_ADD_EDIT_CONTACT && getContext() != null) {
// ApplicationContext.getInstance(getContext().getApplicationContext())
// .getJobManager()
// .add(new DirectoryRefreshJob(getContext().getApplicationContext(), false));
}
}
private class ActionModeCallback implements ActionMode.Callback {
@Override
@@ -47,6 +47,8 @@ import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.OnBackPressedCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
@@ -100,7 +102,6 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
public static final String ACCOUNT_ID_EXTRA = "account_id";
public static final String FROM_WELCOME = "from_welcome";
public static final String FROM_WELCOME_RAW_QR = "from_welcome_raw_qr";
private static final int REQUEST_CODE_CONFIRM_CREDENTIALS_DELETE_PROFILE = ScreenLockUtil.REQUEST_CODE_CONFIRM_CREDENTIALS+1;
private ConversationListFragment conversationListFragment;
public TextView title;
@@ -114,8 +115,12 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
/** used to store temporarily scanned QR to pass it back to QrCodeHandler when ScreenLockUtil is used */
private String qrData = null;
private ActivityResultLauncher<Intent> relayLockLauncher;
private ActivityResultLauncher<Intent> qrScannerLauncher;
/** used to store temporarily profile ID to delete after authorization is granted via ScreenLockUtil */
private int deleteProfileId = 0;
private ActivityResultLauncher<Intent> deleteProfileLockLauncher;
@Override
protected void onPreCreate() {
@@ -125,6 +130,41 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
@Override
protected void onCreate(Bundle icicle, boolean ready) {
relayLockLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
// QrCodeHandler requested user authorization before adding a relay
// and it was granted, so proceed to add the relay
if (qrData != null) {
new QrCodeHandler(this).addRelay(qrData);
qrData = null;
}
}
}
);
deleteProfileLockLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
if (deleteProfileId != 0) {
deleteProfile(deleteProfileId);
deleteProfileId = 0;
}
}
}
);
qrScannerLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
IntentResult scanResult = IntentIntegrator.parseActivityResult(result.getResultCode(), result.getData());
qrData = scanResult.getContents();
new QrCodeHandler(this).handleQrData(qrData, SecurejoinSource.Scan, SecurejoinUiPath.QrIcon, relayLockLauncher);
}
}
);
addDeviceMessages(getIntent().getBooleanExtra(FROM_WELCOME, false));
if (getIntent().getIntExtra(ACCOUNT_ID_EXTRA, -1) <= 0) {
getIntent().putExtra(ACCOUNT_ID_EXTRA, DcHelper.getContext(this).getAccountId());
@@ -458,7 +498,10 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
startActivity(new Intent(this, ApplicationPreferencesActivity.class));
return true;
} else if (itemId == R.id.menu_qr) {
new IntentIntegrator(this).setCaptureActivity(QrActivity.class).initiateScan();
Intent intent = new IntentIntegrator(this)
.setCaptureActivity(QrActivity.class)
.createScanIntent();
qrScannerLauncher.launch(intent);
return true;
} else if (itemId == R.id.menu_global_map) {
WebxdcActivity.openMaps(this, 0);
@@ -634,7 +677,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
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);
boolean result = ScreenLockUtil.applyScreenLock(this, getString(R.string.delete_account), getString(R.string.enter_system_secret_to_continue), deleteProfileLockLauncher);
if (!result) {
deleteProfile(profileId);
}
@@ -661,37 +704,6 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
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(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;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
@@ -4,6 +4,7 @@ import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -11,6 +12,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
@@ -39,11 +42,11 @@ import java.util.List;
public class ProfileFragment extends Fragment
implements ProfileAdapter.ItemClickListener, DcEventCenter.DcEventDelegate {
private static final String TAG = ProfileFragment.class.getSimpleName();
public static final String CHAT_ID_EXTRA = "chat_id";
public static final String CONTACT_ID_EXTRA = "contact_id";
private static final int REQUEST_CODE_PICK_CONTACT = 2;
private ActivityResultLauncher<Intent> pickContactLauncher;
private ProfileAdapter adapter;
private ActionMode actionMode;
private final ActionModeCallback actionModeCallback = new ActionModeCallback();
@@ -60,6 +63,40 @@ public class ProfileFragment extends Fragment
chatId = getArguments() != null ? getArguments().getInt(CHAT_ID_EXTRA, -1) : -1;
contactId = getArguments().getInt(CONTACT_ID_EXTRA, -1);
dcContext = DcHelper.getContext(requireContext());
pickContactLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
Intent data = result.getData();
Log.i(TAG, "Received result from activity, resultCode=" + result.getResultCode() + ", data=" + data);
if (result.getResultCode() == Activity.RESULT_OK && data != null) {
List<Integer> selected = data.getIntegerArrayListExtra(ContactMultiSelectionActivity.CONTACTS_EXTRA);
List<Integer> deselected = data.getIntegerArrayListExtra(ContactMultiSelectionActivity.DESELECTED_CONTACTS_EXTRA);
Util.runOnAnyBackgroundThread(() -> {
if (deselected != null) { // Remove members that were deselected
Log.i(TAG, deselected.size() + " members removed");
int[] members = dcContext.getChatContacts(chatId);
for (int contactId : deselected) {
for (int memberId : members) {
if (memberId == contactId) {
dcContext.removeContactFromChat(chatId, memberId);
break;
}
}
}
}
if (selected != null) { // Add new members
Log.i(TAG, selected.size() + " members added");
for (Integer contactId : selected) {
if (contactId != null) {
dcContext.addContactToChat(chatId, contactId);
}
}
}
});
}
}
);
}
@Override
@@ -210,7 +247,7 @@ public class ProfileFragment extends Fragment
preselectedContacts.add(memberId);
}
intent.putExtra(ContactSelectionListFragment.PRESELECTED_CONTACTS, preselectedContacts);
startActivityForResult(intent, REQUEST_CODE_PICK_CONTACT);
pickContactLauncher.launch(intent);
}
public void onQrInvite() {
@@ -304,36 +341,4 @@ public class ProfileFragment extends Fragment
adapter.clearSelection();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode==REQUEST_CODE_PICK_CONTACT && resultCode==Activity.RESULT_OK && data!=null) {
List<Integer> selected = data.getIntegerArrayListExtra(ContactMultiSelectionActivity.CONTACTS_EXTRA);
List<Integer> deselected = data.getIntegerArrayListExtra(ContactMultiSelectionActivity.DESELECTED_CONTACTS_EXTRA);
Util.runOnAnyBackgroundThread(() -> {
if (deselected != null) {
// Remove members that were deselected
int[] members = dcContext.getChatContacts(chatId);
for (int contactId : deselected) {
for (int memberId : members) {
if (memberId == contactId) {
dcContext.removeContactFromChat(chatId, memberId);
break;
}
}
}
}
if (selected != null) {
// Add new members
for (Integer contactId : selected) {
if (contactId != null) {
dcContext.addContactToChat(chatId, contactId);
}
}
}
});
}
}
}
@@ -18,6 +18,8 @@ import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
@@ -55,11 +57,21 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
CheckBoxPreference multiDeviceCheckbox;
CheckBoxPreference mvboxMoveCheckbox;
CheckBoxPreference onlyFetchMvboxCheckbox;
private ActivityResultLauncher<Intent> screenLockLauncher;
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
screenLockLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
openRelayListActivity();
}
}
);
showEmails = (ListPreference) this.findPreference("pref_show_emails");
if (showEmails != null) {
showEmails.setOnPreferenceChangeListener((preference, newValue) -> {
@@ -158,7 +170,7 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
Preference relayListBtn = this.findPreference("pref_relay_list_button");
if (relayListBtn != null) {
relayListBtn.setOnPreferenceClickListener(((preference) -> {
boolean result = ScreenLockUtil.applyScreenLock(requireActivity(), getString(R.string.transports), getString(R.string.enter_system_secret_to_continue), REQUEST_CODE_CONFIRM_CREDENTIALS_ACCOUNT);
boolean result = ScreenLockUtil.applyScreenLock(requireActivity(), getString(R.string.transports), getString(R.string.enter_system_secret_to_continue), screenLockLauncher);
if (!result) {
openRelayListActivity();
}
@@ -191,14 +203,6 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
onlyFetchMvboxCheckbox.setChecked(0!=dcContext.getConfigInt(CONFIG_ONLY_FETCH_MVBOX));
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == REQUEST_CODE_CONFIRM_CREDENTIALS_ACCOUNT) {
openRelayListActivity();
}
}
protected File copyToCacheDir(Uri uri) throws IOException {
try (InputStream inputStream = requireActivity().getContentResolver().openInputStream(uri)) {
File file = File.createTempFile("tmp-keys-file", ".tmp", requireActivity().getCacheDir());
@@ -10,6 +10,8 @@ import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
@@ -28,6 +30,8 @@ import org.thoughtcrime.securesms.util.ScreenLockUtil;
import org.thoughtcrime.securesms.util.Util;
public class ChatsPreferenceFragment extends ListSummaryPreferenceFragment {
private ActivityResultLauncher<Intent> screenLockLauncher;
private ListPreference mediaQuality;
private ListPreference autoDownload;
@@ -35,6 +39,15 @@ public class ChatsPreferenceFragment extends ListSummaryPreferenceFragment {
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
screenLockLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
performBackup();
}
}
);
mediaQuality = (ListPreference) this.findPreference("pref_compression");
if (mediaQuality != null) {
mediaQuality.setOnPreferenceChangeListener((preference, newValue) -> {
@@ -113,14 +126,6 @@ public class ChatsPreferenceFragment extends ListSummaryPreferenceFragment {
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == REQUEST_CODE_CONFIRM_CREDENTIALS_BACKUP) {
performBackup();
}
}
public static CharSequence getSummary(Context context) {
final String quality;
if (Prefs.isHardCompressionEnabled(context)) {
@@ -138,7 +143,7 @@ public class ChatsPreferenceFragment extends ListSummaryPreferenceFragment {
private class BackupListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(@NonNull Preference preference) {
boolean result = ScreenLockUtil.applyScreenLock(requireActivity(), getString(R.string.pref_backup), getString(R.string.enter_system_secret_to_continue), REQUEST_CODE_CONFIRM_CREDENTIALS_BACKUP);
boolean result = ScreenLockUtil.applyScreenLock(requireActivity(), getString(R.string.pref_backup), getString(R.string.enter_system_secret_to_continue), screenLockLauncher);
if (!result) {
performBackup();
}
@@ -19,7 +19,6 @@ import org.thoughtcrime.securesms.connect.DcEventCenter;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.service.GenericForegroundService;
import org.thoughtcrime.securesms.service.NotificationController;
import org.thoughtcrime.securesms.util.ScreenLockUtil;
import org.thoughtcrime.securesms.util.views.ProgressDialog;
import java.util.Arrays;
@@ -27,9 +26,6 @@ import java.util.HashMap;
import java.util.Map;
public abstract class ListSummaryPreferenceFragment extends CorrectedPreferenceFragment implements DcEventCenter.DcEventDelegate {
protected static final int REQUEST_CODE_CONFIRM_CREDENTIALS_BACKUP = ScreenLockUtil.REQUEST_CODE_CONFIRM_CREDENTIALS + 1;
protected static final int REQUEST_CODE_CONFIRM_CREDENTIALS_KEYS = REQUEST_CODE_CONFIRM_CREDENTIALS_BACKUP + 1;
protected static final int REQUEST_CODE_CONFIRM_CREDENTIALS_ACCOUNT = REQUEST_CODE_CONFIRM_CREDENTIALS_KEYS + 1;
protected DcContext dcContext;
private NotificationController notificationController;
@@ -16,6 +16,8 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationManagerCompat;
@@ -34,17 +36,34 @@ import org.thoughtcrime.securesms.util.Prefs;
public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragment implements Preference.OnPreferenceChangeListener {
private static final String TAG = NotificationsPreferenceFragment.class.getSimpleName();
private static final int REQUEST_CODE_NOTIFICATION_SELECTED = 1;
private CheckBoxPreference ignoreBattery;
private CheckBoxPreference notificationsEnabled;
private CheckBoxPreference mentionNotifEnabled;
private CheckBoxPreference reliableService;
private ActivityResultLauncher<Intent> ringtonePickerLauncher;
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
ringtonePickerLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK && result.getData() != null) {
Uri uri = result.getData().getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
if (Settings.System.DEFAULT_NOTIFICATION_URI.equals(uri)) {
Prefs.removeNotificationRingtone(getContext());
} else {
Prefs.setNotificationRingtone(getContext(), uri != null ? uri : Uri.EMPTY);
}
initializeRingtoneSummary(findPreference(Prefs.RINGTONE_PREF));
}
}
);
this.findPreference(Prefs.LED_COLOR_PREF)
.setOnPreferenceChangeListener(new ListSummaryListener());
this.findPreference(Prefs.RINGTONE_PREF)
@@ -65,8 +84,7 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, Settings.System.DEFAULT_NOTIFICATION_URI);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, current);
startActivityForResult(intent, REQUEST_CODE_NOTIFICATION_SELECTED);
ringtonePickerLauncher.launch(intent);
return true;
});
@@ -137,22 +155,6 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
reliableService.setOnPreferenceChangeListener(this);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_NOTIFICATION_SELECTED && resultCode == RESULT_OK && data != null) {
Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
if (Settings.System.DEFAULT_NOTIFICATION_URI.equals(uri)) {
Prefs.removeNotificationRingtone(getContext());
} else {
Prefs.setNotificationRingtone(getContext(), uri != null ? uri : Uri.EMPTY);
}
initializeRingtoneSummary(findPreference(Prefs.RINGTONE_PREF));
}
}
@Override
public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) {
Context context = getContext();
@@ -6,6 +6,8 @@ import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog;
@@ -121,16 +123,16 @@ public class QrCodeHandler {
}
/** Process only QR about adding relays/profiles (DCACCOUNT: / DCLOGIN:) */
public void handleOnlyAddRelayQr(String rawString) {
public void handleOnlyAddRelayQr(String rawString, @Nullable ActivityResultLauncher<Intent> screenLockLauncher) {
final DcLot qrParsed = dcContext.checkQr(rawString);
if (!handleAddRelayQr(qrParsed, rawString)) {
if (!handleAddRelayQr(qrParsed, rawString, screenLockLauncher)) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
handleDefault(builder, rawString, qrParsed);
builder.create().show();
}
}
private boolean handleAddRelayQr(DcLot qrParsed, String rawString) {
private boolean handleAddRelayQr(DcLot qrParsed, String rawString, @Nullable ActivityResultLauncher<Intent> screenLockLauncher) {
switch (qrParsed.getState()) {
case DcContext.DC_QR_ACCOUNT:
case DcContext.DC_QR_LOGIN:
@@ -138,14 +140,13 @@ public class QrCodeHandler {
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 (screenLockLauncher != null) {
boolean result = ScreenLockUtil.applyScreenLock(activity, activity.getString(R.string.add_transport), activity.getString(R.string.enter_system_secret_to_continue), screenLockLauncher);
if (!result) {
addRelay(rawString);
}
} else { // Screen lock not needed
addRelay(rawString);
}
});
builder.setNegativeButton(R.string.cancel, null);
@@ -219,10 +220,10 @@ public class QrCodeHandler {
}
/** Handle any kind of QR showing an AlertDialog adapted to the QR type. */
public void handleQrData(String rawString, SecurejoinSource source, SecurejoinUiPath uiPath) {
public void handleQrData(String rawString, SecurejoinSource source, SecurejoinUiPath uiPath, ActivityResultLauncher<Intent> relayLockLauncher) {
final DcLot qrParsed = dcContext.checkQr(rawString);
if (handleSecureJoinQr(qrParsed, rawString, source, uiPath)
|| handleAddRelayQr(qrParsed, rawString)
|| handleAddRelayQr(qrParsed, rawString, relayLockLauncher)
|| handleProxyQr(qrParsed, rawString)
|| handleBackupQr(qrParsed, rawString)) return;
@@ -7,6 +7,8 @@ import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
@@ -48,6 +50,8 @@ public class RelayListActivity extends BaseActionBarActivity
/** QR provided via Intent extras needs to be saved to pass it to QrCodeHandler when authorization finishes */
private String qrData = null;
private ActivityResultLauncher<Intent> screenLockLauncher;
private ActivityResultLauncher<Intent> qrScannerLauncher;
/** Relay selected for context menu via onRelayLongClick() */
private EnteredLoginParam contextMenuRelay = null;
@@ -57,6 +61,31 @@ public class RelayListActivity extends BaseActionBarActivity
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_relay_list);
qrScannerLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
IntentResult scanResult = IntentIntegrator.parseActivityResult(result.getResultCode(), result.getData());
new QrCodeHandler(this).handleOnlyAddRelayQr(scanResult.getContents(), null);
}
}
);
screenLockLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() != RESULT_OK) {
// if user canceled unlocking, then finish
finish();
return;
}
// user authorized, then proceed to handle the QR data
if (qrData != null) {
new QrCodeHandler(this).handleOnlyAddRelayQr(qrData, null);
qrData = null;
}
}
);
rpc = DcHelper.getRpc(this);
accId = DcHelper.getContext(this).getAccountId();
@@ -77,14 +106,18 @@ public class RelayListActivity extends BaseActionBarActivity
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);
boolean result = ScreenLockUtil.applyScreenLock(this, getString(R.string.add_transport), getString(R.string.enter_system_secret_to_continue), screenLockLauncher);
if (!result) {
new QrCodeHandler(this).handleOnlyAddRelayQr(qrData);
new QrCodeHandler(this).handleOnlyAddRelayQr(qrData, null);
}
}
fabAdd.setOnClickListener(v -> {
new IntentIntegrator(this).setCaptureActivity(QrActivity.class).addExtra(QrActivity.EXTRA_SCAN_RELAY, true).initiateScan();
Intent intent = new IntentIntegrator(this)
.setCaptureActivity(QrActivity.class)
.addExtra(QrActivity.EXTRA_SCAN_RELAY, true)
.createScanIntent();
qrScannerLauncher.launch(intent);
});
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
@@ -220,28 +253,6 @@ public class RelayListActivity extends BaseActionBarActivity
return super.onOptionsItemSelected(item);
}
@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(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;
}
}
}
@Override
public void handleEvent(@NonNull DcEvent event) {
int eventId = event.getId();
@@ -5,17 +5,17 @@ import android.app.KeyguardManager;
import android.content.Context;
import android.content.Intent;
import androidx.activity.result.ActivityResultLauncher;
public class ScreenLockUtil {
public static final int REQUEST_CODE_CONFIRM_CREDENTIALS = 1001;
public static boolean applyScreenLock(Activity activity, String title, String descr, int requestCode) {
public static boolean applyScreenLock(Activity activity, String title, String descr, ActivityResultLauncher<Intent> launcher) {
KeyguardManager keyguardManager = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE);
Intent intent;
if (keyguardManager != null) {
intent = keyguardManager.createConfirmDeviceCredentialIntent(title, descr);
if (intent != null) {
activity.startActivityForResult(intent, requestCode);
launcher.launch(intent);
return true;
}
}