From 170cd930e94901d6e2d6eff8cf19ed030406015f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Tue, 20 Jan 2026 02:02:24 +0100 Subject: [PATCH] Add ability to import otpauth uri from clipboard --- .../aegis/ui/MainActivity.java | 33 ++++++++++++++++-- .../aegis/util/ClipboardUtils.java | 34 +++++++++++++++++++ app/src/main/res/values/strings.xml | 4 +++ 3 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/beemdevelopment/aegis/util/ClipboardUtils.java diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java index a553fc5d..7ff23b25 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -17,6 +17,7 @@ import android.provider.Settings; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.style.StyleSpan; +import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; @@ -63,6 +64,7 @@ import com.beemdevelopment.aegis.ui.models.VaultGroupModel; import com.beemdevelopment.aegis.ui.tasks.IconOptimizationTask; import com.beemdevelopment.aegis.ui.tasks.QrDecodeTask; import com.beemdevelopment.aegis.ui.views.EntryListView; +import com.beemdevelopment.aegis.util.ClipboardUtils; import com.beemdevelopment.aegis.util.TimeUtils; import com.beemdevelopment.aegis.util.UUIDMap; import com.beemdevelopment.aegis.vault.VaultEntry; @@ -89,7 +91,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.SequencedMap; import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; @@ -252,7 +253,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene LinkedHashMap actions = new LinkedHashMap<>(); actions.put(fabMenuLayout.findViewById(R.id.fab_menu_item_scan), this::startScanActivity); actions.put(fabMenuLayout.findViewById(R.id.fab_menu_item_scan_image), this::startScanImageActivity); - actions.put(fabMenuLayout.findViewById(R.id.fab_menu_item_enter), this::startEditEntryActivityForManual); + actions.put(fabMenuLayout.findViewById(R.id.fab_menu_item_enter), this::startEditEntryActivity); _fabMenuHelper = new FabMenuHelper(scrimOverlay, menuItemsContainer, fab, actions); _fabMenuHelper.setOnFabMenuStateChangeListener(_fabMenuBackPressHandler::setEnabled); @@ -470,6 +471,34 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene } } + private void startEditEntryActivity() { + String clip = ClipboardUtils.readText(this); + if (clip != null) { + GoogleAuthInfo parsed; + try { + parsed = GoogleAuthInfo.parseUri(clip.trim()); + String message = getString( + R.string.import_from_clipboard_message, + parsed.getAccountName(), + parsed.getIssuer() + ); + + Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(this) + .setTitle(R.string.import_from_clipboard_title) + .setMessage(message) + .setPositiveButton(R.string.yes, (dialog, which) -> startEditEntryActivityForNew(new VaultEntry(parsed))) + .setNegativeButton(R.string.no, (dialog, which) -> startEditEntryActivityForManual()) + .create()); + + return; + } catch (GoogleAuthInfoException e) { + Log.i("EntryActivity", "Clipboard did not contain a valid otpauth URI", e); + } + } + + startEditEntryActivityForManual(); + } + private void startEditEntryActivityForNew(VaultEntry entry) { Intent intent = new Intent(this, EditEntryActivity.class); intent.putExtra("newEntry", entry); diff --git a/app/src/main/java/com/beemdevelopment/aegis/util/ClipboardUtils.java b/app/src/main/java/com/beemdevelopment/aegis/util/ClipboardUtils.java new file mode 100644 index 00000000..03b30be3 --- /dev/null +++ b/app/src/main/java/com/beemdevelopment/aegis/util/ClipboardUtils.java @@ -0,0 +1,34 @@ +package com.beemdevelopment.aegis.util; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; + +public final class ClipboardUtils { + public static String readText(Context context) { + ClipboardManager clipboard = + (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + + if (clipboard == null) { + return null; + } + + ClipData clip = clipboard.getPrimaryClip(); + if (clip == null || clip.getItemCount() == 0) { + return null; + } + + ClipData.Item item = clip.getItemAt(0); + CharSequence cs = item.coerceToText(context); + if (cs == null) { + return null; + } + + String text = cs.toString().trim(); + if (text.isEmpty()) { + return null; + } + + return text; + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9014aa46..c29a1911 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -539,6 +539,10 @@ Your vault already contains entries. Do you want to remove these entries before importing this file?\n\nIn doing so, you will permanently lose access to the existing entries in the vault. Wipe vault contents + Import from clipboard + + We found a valid otpauth uri on your clipboard.\n\nName: %1$s\nIssuer: %2$s\n\nDo you want to use it to prefill this entry? + Aegis received panic trigger but setting is disabled, ignoring Delete vault on panic trigger Delete vault when a panic trigger is received from Ripple