From 327f97c51deac94252bd91e33fbe355a211c1d94 Mon Sep 17 00:00:00 2001 From: Jules Kerssemakers Date: Tue, 2 Jul 2024 11:52:12 +0200 Subject: [PATCH 001/113] DatabaseImporter: add overlooked FreeOTP "1.x"-only Include the '(1.x)' qualifier directly in the import-source selection dropdown to avoid raising false expectations. See also: - #1204, where the 1.x-hint was introduced - #1084: tracking issue for 2.x support - https://github.com/freeotp/freeotp-android/issues/381 FreeOTP-issue to reconsider the brittle serialised java format used by 2.x --- .../com/beemdevelopment/aegis/importers/DatabaseImporter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/importers/DatabaseImporter.java b/app/src/main/java/com/beemdevelopment/aegis/importers/DatabaseImporter.java index fcf8e8d4..fee6d3f8 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/importers/DatabaseImporter.java +++ b/app/src/main/java/com/beemdevelopment/aegis/importers/DatabaseImporter.java @@ -39,7 +39,7 @@ public abstract class DatabaseImporter { _importers.add(new Definition("Battle.net Authenticator", BattleNetImporter.class, R.string.importer_help_battle_net_authenticator, true)); _importers.add(new Definition("Bitwarden", BitwardenImporter.class, R.string.importer_help_bitwarden, false)); _importers.add(new Definition("Duo", DuoImporter.class, R.string.importer_help_duo, true)); - _importers.add(new Definition("FreeOTP", FreeOtpImporter.class, R.string.importer_help_freeotp, true)); + _importers.add(new Definition("FreeOTP (1.x)", FreeOtpImporter.class, R.string.importer_help_freeotp, true)); _importers.add(new Definition("FreeOTP+", FreeOtpPlusImporter.class, R.string.importer_help_freeotp_plus, true)); _importers.add(new Definition("Google Authenticator", GoogleAuthImporter.class, R.string.importer_help_google_authenticator, true)); _importers.add(new Definition("Microsoft Authenticator", MicrosoftAuthImporter.class, R.string.importer_help_microsoft_authenticator, true)); From edf2201fb3ae710812ad0ea5fb53876b7566205a Mon Sep 17 00:00:00 2001 From: Jules Kerssemakers Date: Mon, 15 Jul 2024 10:34:34 +0200 Subject: [PATCH 002/113] Clarify FreeOTP+ import needs JSON, not URI-format --- .../com/beemdevelopment/aegis/importers/DatabaseImporter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/importers/DatabaseImporter.java b/app/src/main/java/com/beemdevelopment/aegis/importers/DatabaseImporter.java index fee6d3f8..62d846fe 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/importers/DatabaseImporter.java +++ b/app/src/main/java/com/beemdevelopment/aegis/importers/DatabaseImporter.java @@ -40,7 +40,7 @@ public abstract class DatabaseImporter { _importers.add(new Definition("Bitwarden", BitwardenImporter.class, R.string.importer_help_bitwarden, false)); _importers.add(new Definition("Duo", DuoImporter.class, R.string.importer_help_duo, true)); _importers.add(new Definition("FreeOTP (1.x)", FreeOtpImporter.class, R.string.importer_help_freeotp, true)); - _importers.add(new Definition("FreeOTP+", FreeOtpPlusImporter.class, R.string.importer_help_freeotp_plus, true)); + _importers.add(new Definition("FreeOTP+ (JSON)", FreeOtpPlusImporter.class, R.string.importer_help_freeotp_plus, true)); _importers.add(new Definition("Google Authenticator", GoogleAuthImporter.class, R.string.importer_help_google_authenticator, true)); _importers.add(new Definition("Microsoft Authenticator", MicrosoftAuthImporter.class, R.string.importer_help_microsoft_authenticator, true)); _importers.add(new Definition("Plain text", GoogleAuthUriImporter.class, R.string.importer_help_plain_text, false)); From 46e1421c28857034c135f3c3facbe8b9b5c6483d Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Wed, 17 Jul 2024 19:18:09 +0200 Subject: [PATCH 003/113] Start auth/intro activities from onStart to work around an Android bug --- .../main/java/com/beemdevelopment/aegis/ui/MainActivity.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 24bf91c5..820dd3ee 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -657,8 +657,8 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene } @Override - protected void onResume() { - super.onResume(); + protected void onStart() { + super.onStart(); if (_vaultManager.isVaultInitNeeded()) { if (_prefs.isIntroDone()) { From f1ff402db48db421803444f2a58ebea1469cbf24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Wed, 17 Jul 2024 22:17:35 +0200 Subject: [PATCH 004/113] Release v3.1.1-beta1 --- app/build.gradle | 4 ++-- app/src/main/assets/changelog.html | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 92d6ccfa..bf7f2e85 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -28,8 +28,8 @@ android { applicationId "${packageName}" minSdkVersion 21 targetSdkVersion 34 - versionCode 67 - versionName "3.1" + versionCode 68 + versionName "3.1.1-beta1" multiDexEnabled true buildConfigField "String", "GIT_HASH", "\"${getGitHash()}\"" buildConfigField "String", "GIT_BRANCH", "\"${getGitBranch()}\"" diff --git a/app/src/main/assets/changelog.html b/app/src/main/assets/changelog.html index 48b89761..221bcd89 100644 --- a/app/src/main/assets/changelog.html +++ b/app/src/main/assets/changelog.html @@ -31,6 +31,12 @@
+

Version 3.1.1-beta1

+

+ A recent Android Pixel update introduced a bug causing Aegis to sometimes show a black screen after unlocking the vault. + We have reported this issue to the Google Issue Tracker (link) and + are awaiting a response from Google. In the meantime, we have implemented a workaround to eliminates this bug. +

Version 3.1

New

    From d1695aa7127c9d7e3aa28bcec9997e0521f3ab49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Wed, 17 Jul 2024 22:29:45 +0200 Subject: [PATCH 005/113] Bump versioncode because play store --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index bf7f2e85..404bfb17 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -28,7 +28,7 @@ android { applicationId "${packageName}" minSdkVersion 21 targetSdkVersion 34 - versionCode 68 + versionCode 69 versionName "3.1.1-beta1" multiDexEnabled true buildConfigField "String", "GIT_HASH", "\"${getGitHash()}\"" From f7862dcdf030704107ac81653b16a2205b698cf5 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Fri, 19 Jul 2024 20:28:48 +0200 Subject: [PATCH 006/113] Initialize the group chip properly after unlocking Aegis This fixes an issue introduced by 46e1421c28857034c135f3c3facbe8b9b5c6483d where the group chip would not show after unlocking Aegis. This happened because the activity result is received *after* ``onStart``. When we were using ``onResume``, it was the other way around. --- app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java | 1 + 1 file changed, 1 insertion(+) 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 820dd3ee..0915f055 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -857,6 +857,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene private void loadEntries() { if (!_loaded) { + _entryListView.setGroups(_vaultManager.getVault().getUsedGroups()); _entryListView.setUsageCounts(_prefs.getUsageCounts()); _entryListView.setLastUsedTimestamps(_prefs.getLastUsedTimestamps()); _entryListView.addEntries(_vaultManager.getVault().getEntries()); From 94d1cc66082517451c7ed41ef011c1ad41266bb1 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Fri, 19 Jul 2024 20:57:23 +0200 Subject: [PATCH 007/113] Simplify approach for animating advanced entry settings This slightly simplifies the approach we use to animate the advanced entry settings into view, by defaulting its alpha to 0 and setting it to VISIBLE before the animation starts. That way, we're not dependent on "animation ended" callbacks that apparently don't fire in all cases. The XML diff looks a bit scary, but it basically just removes a wrapping ``RelativeLayout`` that appears to not be necessary. --- .../aegis/ui/EditEntryActivity.java | 18 +- .../main/res/layout/activity_edit_entry.xml | 224 +++++++++--------- 2 files changed, 116 insertions(+), 126 deletions(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java index c2280cc5..55ff2642 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java @@ -127,7 +127,7 @@ public class EditEntryActivity extends AegisActivity { private KropView _kropView; private RelativeLayout _advancedSettingsHeader; - private RelativeLayout _advancedSettings; + private LinearLayout _advancedSettingsLayout; private BackPressHandler _backPressHandler; private IconBackPressHandler _iconBackPressHandler; @@ -241,7 +241,7 @@ public class EditEntryActivity extends AegisActivity { _advancedSettingsHeader = findViewById(R.id.accordian_header); _advancedSettingsHeader.setOnClickListener(v -> openAdvancedSettings()); - _advancedSettings = findViewById(R.id.expandableLayout); + _advancedSettingsLayout = findViewById(R.id.layout_advanced); // fill the fields with values if possible GlideHelper.loadEntryIcon(Glide.with(this), _origEntry, _iconView); @@ -411,17 +411,13 @@ public class EditEntryActivity extends AegisActivity { fadeOut.setDuration((long) (220 * AnimationsHelper.Scale.ANIMATOR.getValue(this))); _advancedSettingsHeader.startAnimation(fadeOut); - Animation fadeIn = new AlphaAnimation(0, 1); - fadeIn.setInterpolator(new AccelerateInterpolator()); - fadeIn.setDuration((long) (250 * AnimationsHelper.Scale.ANIMATOR.getValue(this))); - fadeOut.setAnimationListener(new SimpleAnimationEndListener((a) -> { _advancedSettingsHeader.setVisibility(View.GONE); - _advancedSettings.startAnimation(fadeIn); - })); - - fadeIn.setAnimationListener(new SimpleAnimationEndListener((a) -> { - _advancedSettings.setVisibility(View.VISIBLE); + _advancedSettingsLayout.setVisibility(View.VISIBLE); + _advancedSettingsLayout.animate() + .setInterpolator(new AccelerateInterpolator()) + .setDuration((long) (250 * AnimationsHelper.Scale.ANIMATOR.getValue(this))) + .alpha(1); })); } diff --git a/app/src/main/res/layout/activity_edit_entry.xml b/app/src/main/res/layout/activity_edit_entry.xml index 509d927e..2b06060e 100644 --- a/app/src/main/res/layout/activity_edit_entry.xml +++ b/app/src/main/res/layout/activity_edit_entry.xml @@ -251,149 +251,143 @@ android:textStyle="bold" /> - + android:orientation="vertical" + android:visibility="gone" + android:alpha="0" + android:layout_marginHorizontal="10dp"> - + + + - - - - - - - - - - - - - + + android:inputType="none"/> - + + android:inputType="none" /> - + + - + - - + + + - - - - - - - + + + + + android:src="@drawable/ic_counter_black_24" + app:tint="?attr/colorOnSurface" + android:layout_marginStart="5dp" + android:layout_marginEnd="15dp" + android:layout_gravity="center_vertical"/> + + + + + + + - - - + + From c1ffe4a23ea02a5c769fb177f41d39f386f84c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Thu, 13 Jun 2024 21:28:52 +0200 Subject: [PATCH 008/113] Hide keyboard on scroll when search field is focused --- .../com/beemdevelopment/aegis/ui/MainActivity.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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 24bf91c5..50c45aa1 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -23,6 +23,7 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.CheckBox; import android.widget.Toast; @@ -34,6 +35,8 @@ import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.view.ActionMode; import androidx.appcompat.widget.SearchView; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import com.beemdevelopment.aegis.AccountNamePosition; import com.beemdevelopment.aegis.CopyBehavior; @@ -285,6 +288,15 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene @Override public void onEntryListTouch() { _isDPadPressed = false; + + if (_searchView != null && !_searchView.isIconified()) { + if (ViewCompat.getRootWindowInsets(findViewById(android.R.id.content).getRootView()).isVisible(WindowInsetsCompat.Type.ime())) { + InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + if (inputMethodManager != null && getCurrentFocus() != null) { + inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); + } + } + } } private void onPreferencesResult(Intent data) { From 2e9efa0617b7f67595d5e4fcef27fa09f0caebe0 Mon Sep 17 00:00:00 2001 From: Praveen Kumar Date: Wed, 10 Apr 2024 10:24:56 +0530 Subject: [PATCH 009/113] Support for Adding Multiple Groups --- .../beemdevelopment/aegis/OverallTest.java | 10 +- .../aegis/ui/EditEntryActivity.java | 168 ++++++++++++------ .../aegis/ui/dialogs/Dialogs.java | 4 +- .../main/res/drawable/ic_outline_group_24.xml | 10 ++ .../main/res/layout/activity_edit_entry.xml | 29 ++- .../main/res/layout/dialog_select_groups.xml | 43 ++++- app/src/main/res/values/strings.xml | 1 + 7 files changed, 198 insertions(+), 67 deletions(-) create mode 100644 app/src/main/res/drawable/ic_outline_group_24.xml diff --git a/app/src/androidTest/java/com/beemdevelopment/aegis/OverallTest.java b/app/src/androidTest/java/com/beemdevelopment/aegis/OverallTest.java index 6c12809e..cc921be7 100644 --- a/app/src/androidTest/java/com/beemdevelopment/aegis/OverallTest.java +++ b/app/src/androidTest/java/com/beemdevelopment/aegis/OverallTest.java @@ -7,6 +7,7 @@ import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard; import static androidx.test.espresso.action.ViewActions.longClick; import static androidx.test.espresso.action.ViewActions.pressBack; +import static androidx.test.espresso.action.ViewActions.scrollTo; import static androidx.test.espresso.action.ViewActions.typeText; import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant; import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA; @@ -118,10 +119,11 @@ public class OverallTest extends AegisTest { onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(entryPosOffset + 1, longClick())); onView(withId(R.id.action_edit)).perform(click()); onView(withId(R.id.text_name)).perform(clearText(), typeText("Bob"), closeSoftKeyboard()); - onView(withId(R.id.dropdown_group)).perform(click()); - onView(withText(R.string.new_group)).inRoot(RootMatchers.isPlatformPopup()).perform(click()); + onView(withId(R.id.text_group)).perform(click()); + onView(withId(R.id.addGroup)).inRoot(RootMatchers.isDialog()).perform(click()); onView(withId(R.id.text_input)).perform(typeText(_groupName), closeSoftKeyboard()); onView(withId(android.R.id.button1)).perform(click()); + onView(withText(R.string.save)).perform(click()); onView(isRoot()).perform(pressBack()); onView(withId(android.R.id.button1)).perform(click()); @@ -188,7 +190,7 @@ public class OverallTest extends AegisTest { onView(withId(R.id.fab)).perform(click()); onView(withId(R.id.fab_enter)).perform(click()); - onView(withId(R.id.accordian_header)).perform(click()); + onView(withId(R.id.accordian_header)).perform(scrollTo(), click()); onView(withId(R.id.text_name)).perform(typeText(entry.getName()), closeSoftKeyboard()); onView(withId(R.id.text_issuer)).perform(typeText(entry.getIssuer()), closeSoftKeyboard()); @@ -208,7 +210,7 @@ public class OverallTest extends AegisTest { throw new RuntimeException(String.format("Unexpected entry type: %s", entry.getInfo().getClass().getSimpleName())); } - onView(withId(R.id.dropdown_type)).perform(click()); + onView(withId(R.id.dropdown_type)).perform(scrollTo(), click()); onView(withText(otpType)).inRoot(RootMatchers.isPlatformPopup()).perform(click()); } diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java index c2280cc5..5c690e6a 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java @@ -1,6 +1,5 @@ package com.beemdevelopment.aegis.ui; -import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; @@ -16,6 +15,7 @@ import android.view.animation.AccelerateInterpolator; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.widget.AutoCompleteTextView; +import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; @@ -68,6 +68,8 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.target.CustomTarget; import com.bumptech.glide.request.transition.Transition; import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.google.android.material.chip.Chip; +import com.google.android.material.chip.ChipGroup; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.textfield.TextInputEditText; import com.google.android.material.textfield.TextInputLayout; @@ -85,7 +87,6 @@ import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Locale; -import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; @@ -107,6 +108,8 @@ public class EditEntryActivity extends AegisActivity { private TextInputEditText _textName; private TextInputEditText _textIssuer; + private TextInputLayout _textGroupLayout; + private TextInputEditText _textGroup; private TextInputEditText _textPeriodCounter; private TextInputLayout _textPeriodCounterLayout; private TextInputEditText _textDigits; @@ -121,8 +124,7 @@ public class EditEntryActivity extends AegisActivity { private AutoCompleteTextView _dropdownType; private AutoCompleteTextView _dropdownAlgo; private TextInputLayout _dropdownAlgoLayout; - private AutoCompleteTextView _dropdownGroup; - private List _dropdownGroupList = new ArrayList<>(); + private List _selectedGroups = new ArrayList<>(); private KropView _kropView; @@ -195,6 +197,8 @@ public class EditEntryActivity extends AegisActivity { _saveImageButton = findViewById(R.id.iv_saveImage); _textName = findViewById(R.id.text_name); _textIssuer = findViewById(R.id.text_issuer); + _textGroup = findViewById(R.id.text_group); + _textGroupLayout = findViewById(R.id.text_group_layout); _textPeriodCounter = findViewById(R.id.text_period_counter); _textPeriodCounterLayout = findViewById(R.id.text_period_counter_layout); _textDigits = findViewById(R.id.text_digits); @@ -210,9 +214,6 @@ public class EditEntryActivity extends AegisActivity { _dropdownAlgoLayout = findViewById(R.id.dropdown_algo_layout); _dropdownAlgo = findViewById(R.id.dropdown_algo); DropdownHelper.fillDropdown(this, _dropdownAlgo, R.array.otp_algo_array); - _dropdownGroup = findViewById(R.id.dropdown_group); - updateGroupDropdownList(); - DropdownHelper.fillDropdown(this, _dropdownGroup, _dropdownGroupList); // if this is NOT a manually entered entry, move the "Secret" field from basic to advanced settings if (!_isNew || !_isManual) { @@ -286,10 +287,15 @@ public class EditEntryActivity extends AegisActivity { Set groups = _origEntry.getGroups(); if (groups.isEmpty()) { - setGroup(new VaultGroupModel(getString(R.string.no_group))); + _textGroup.setText(getString(R.string.no_group)); } else { - VaultGroup group = _vaultManager.getVault().getGroupByUUID(groups.iterator().next()); - setGroup(new VaultGroupModel(group)); + String text = groups.stream().map(uuid -> { + VaultGroup group = _vaultManager.getVault().getGroupByUUID(uuid); + return group.getName(); + }) + .collect(Collectors.joining(", ")); + _selectedGroups.addAll(groups); + _textGroup.setText(text); } // Update the icon if the issuer or name has changed @@ -298,11 +304,11 @@ public class EditEntryActivity extends AegisActivity { // Register listeners to trigger validation _textIssuer.addTextChangedListener(_validationListener); + _textGroup.addTextChangedListener(_validationListener); _textName.addTextChangedListener(_validationListener); _textNote.addTextChangedListener(_validationListener); _textSecret.addTextChangedListener(_validationListener); _dropdownType.addTextChangedListener(_validationListener); - _dropdownGroup.addTextChangedListener(_validationListener); _dropdownAlgo.addTextChangedListener(_validationListener); _textPeriodCounter.addTextChangedListener(_validationListener); _textDigits.addTextChangedListener(_validationListener); @@ -354,38 +360,109 @@ public class EditEntryActivity extends AegisActivity { startIconSelection(); }); - _dropdownGroup.setOnItemClickListener((parent, view, position, id) -> { - VaultGroupModel selectedGroup = _dropdownGroupList.get(position); - if (selectedGroup.isPlaceholder() && Objects.equals(selectedGroup.getName(), getString(R.string.new_group))) { - Dialogs.TextInputListener onAddGroup = text -> { - String groupName = new String(text).trim(); - if (!groupName.isEmpty()) { - VaultGroup group = _vaultManager.getVault().findGroupByName(groupName); - if (group == null) { - group = new VaultGroup(groupName); - _vaultManager.getVault().addGroup(group); - } - - updateGroupDropdownList(); - setGroup(new VaultGroupModel(group)); - } - }; - - DialogInterface.OnCancelListener onCancel = dialogInterface -> { - VaultGroupModel previous = (VaultGroupModel) _dropdownGroup.getTag(); - _dropdownGroup.setText(previous.getName(), false); - }; - - Dialogs.showTextInputDialog(EditEntryActivity.this, R.string.set_group, R.string.group_name_hint, onAddGroup, onCancel); - } else { - setGroup(_dropdownGroupList.get(position)); + _textGroup.setShowSoftInputOnFocus(false); + _textGroup.setOnClickListener(v -> showGroupSelectionDialog()); + _textGroup.setOnFocusChangeListener((v, hasFocus) -> { + if (hasFocus) { + showGroupSelectionDialog(); } }); + _textGroupLayout.setOnClickListener(v -> { + showGroupSelectionDialog(); + }); + _textUsageCount.setText(_prefs.getUsageCount(entryUUID).toString()); setLastUsedTimestamp(_prefs.getLastUsedTimestamp(entryUUID)); } + private void showGroupSelectionDialog() { + BottomSheetDialog dialog = new BottomSheetDialog(this); + View view = getLayoutInflater().inflate(R.layout.dialog_select_groups, null); + dialog.setContentView(view); + + ChipGroup chipGroup = view.findViewById(R.id.groupChipGroup); + TextView addGroupInfo = view.findViewById(R.id.addGroupInfo); + LinearLayout addGroup = view.findViewById(R.id.addGroup); + Button clearButton = view.findViewById(R.id.btnClear); + Button saveButton = view.findViewById(R.id.btnSave); + + chipGroup.removeAllViews(); + addGroupInfo.setVisibility(View.VISIBLE); + addGroup.setVisibility(View.VISIBLE); + + for (VaultGroup group : _groups) { + addChipTo(chipGroup, new VaultGroupModel(group), false); + } + + addGroup.setOnClickListener(v1 -> { + Dialogs.TextInputListener onAddGroup = text -> { + String groupName = new String(text).trim(); + if (!groupName.isEmpty()) { + VaultGroup group = _vaultManager.getVault().findGroupByName(groupName); + if (group == null) { + group = new VaultGroup(groupName); + _vaultManager.getVault().addGroup(group); + } + + _selectedGroups.add(group.getUUID()); + addChipTo(chipGroup, new VaultGroupModel(group), true); + } + }; + + Dialogs.showTextInputDialog(EditEntryActivity.this, R.string.set_group, R.string.group_name_hint, onAddGroup); + }); + + saveButton.setOnClickListener(v1 -> { + if(getCheckedUUID(chipGroup).isEmpty()) { + _selectedGroups.clear(); + _textGroup.setText(getString(R.string.no_group)); + } else { + _selectedGroups.clear(); + _selectedGroups.addAll(getCheckedUUID(chipGroup)); + _textGroup.setText(getCheckedNames(chipGroup)); + } + dialog.dismiss(); + }); + + clearButton.setOnClickListener(v1 -> { + chipGroup.clearCheck(); + }); + + Dialogs.showSecureDialog(dialog); + } + + private void addChipTo(ChipGroup chipGroup, VaultGroupModel group, Boolean isNew) { + Chip chip = (Chip) getLayoutInflater().inflate(R.layout.chip_group_filter, null, false); + chip.setText(group.getName()); + chip.setCheckable(true); + + chip.setChecked((!_selectedGroups.isEmpty() && _selectedGroups.contains(group.getUUID())) || isNew); + chip.setCheckedIconVisible(true); + chip.setTag(group); + chipGroup.addView(chip); + } + + private static Set getCheckedUUID(ChipGroup chipGroup) { + return chipGroup.getCheckedChipIds().stream() + .map(i -> { + Chip chip = chipGroup.findViewById(i); + VaultGroupModel group = (VaultGroupModel) chip.getTag(); + return group.getUUID(); + }) + .collect(Collectors.toSet()); + } + + private static String getCheckedNames(ChipGroup chipGroup) { + return chipGroup.getCheckedChipIds().stream() + .map(i -> { + Chip chip = chipGroup.findViewById(i); + VaultGroupModel group = (VaultGroupModel) chip.getTag(); + return group.getName(); + }) + .collect(Collectors.joining(", ")); + } + private void updateAdvancedFieldStatus(String otpType) { boolean enabled = !otpType.equals(SteamInfo.ID) && !otpType.equals(YandexInfo.ID) && !otpType.equals(MotpInfo.ID) && (!_isNew || _isManual); @@ -400,11 +477,6 @@ public class EditEntryActivity extends AegisActivity { _textPin.setHint(otpType.equals(MotpInfo.ID) ? R.string.motp_pin : R.string.yandex_pin); } - private void setGroup(VaultGroupModel group) { - _dropdownGroup.setText(group.getName(), false); - _dropdownGroup.setTag(group); - } - private void openAdvancedSettings() { Animation fadeOut = new AlphaAnimation(1, 0); fadeOut.setInterpolator(new AccelerateInterpolator()); @@ -425,13 +497,6 @@ public class EditEntryActivity extends AegisActivity { })); } - private void updateGroupDropdownList() { - _dropdownGroupList.clear(); - _dropdownGroupList.add(new VaultGroupModel(getString(R.string.new_group))); - _dropdownGroupList.addAll(_groups.stream().map(VaultGroupModel::new).collect(Collectors.toList())); - _dropdownGroupList.add(new VaultGroupModel(getString(R.string.no_group))); - } - private boolean hasUnsavedChanges(VaultEntry newEntry) { return _hasChangedIcon || !_origEntry.equals(newEntry); } @@ -731,13 +796,10 @@ public class EditEntryActivity extends AegisActivity { entry.setName(_textName.getText().toString()); entry.setNote(_textNote.getText().toString()); - VaultGroupModel group = (VaultGroupModel) _dropdownGroup.getTag(); - if (group.isPlaceholder()) { + if (_selectedGroups.isEmpty()) { entry.setGroups(new HashSet<>()); } else { - Set groups = new HashSet<>(); - groups.add(group.getUUID()); - entry.setGroups(groups); + entry.setGroups(new HashSet<>(_selectedGroups)); } if (_hasChangedIcon) { diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java b/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java index 4d14908d..273fb2f3 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java @@ -244,8 +244,8 @@ public class Dialogs { showTextInputDialog(context, titleId, 0, hintId, listener, null, isSecret, null); } - public static void showTextInputDialog(Context context, @StringRes int titleId, @StringRes int hintId, TextInputListener listener, @Nullable DialogInterface.OnCancelListener onCancel) { - showTextInputDialog(context, titleId, 0, hintId, listener, onCancel, false, null); + public static void showTextInputDialog(Context context, @StringRes int titleId, @StringRes int hintId, TextInputListener listener) { + showTextInputDialog(context, titleId, 0, hintId, listener, null, false, null); } public static void showPasswordInputDialog(Context context, TextInputListener listener) { diff --git a/app/src/main/res/drawable/ic_outline_group_24.xml b/app/src/main/res/drawable/ic_outline_group_24.xml new file mode 100644 index 00000000..5c60ea3e --- /dev/null +++ b/app/src/main/res/drawable/ic_outline_group_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/activity_edit_entry.xml b/app/src/main/res/layout/activity_edit_entry.xml index 509d927e..87ec7b8f 100644 --- a/app/src/main/res/layout/activity_edit_entry.xml +++ b/app/src/main/res/layout/activity_edit_entry.xml @@ -110,7 +110,6 @@ android:hint="@string/issuer" android:layout_width="0dp" android:layout_height="match_parent" - android:layout_marginEnd="5dp" android:layout_weight="1"> + + + + - + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9998e88e..ff77446c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -311,6 +311,7 @@ No tokens can be imported as a result Unlocking the vault Rename Group + If an entry is not part of any group, it can be found under \"No group\". Remove group Are you sure you want to remove this group? Entries in this group will automatically switch to \'No group\'. Delete unused groups From 8960ffffb4251fbb1b202a6bb210e21c2a5a4234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Mon, 22 Jul 2024 00:17:19 +0200 Subject: [PATCH 010/113] Release v3.1.1 --- app/build.gradle | 4 ++-- app/src/main/assets/changelog.html | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 404bfb17..d85b6982 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -28,8 +28,8 @@ android { applicationId "${packageName}" minSdkVersion 21 targetSdkVersion 34 - versionCode 69 - versionName "3.1.1-beta1" + versionCode 70 + versionName "3.1.1" multiDexEnabled true buildConfigField "String", "GIT_HASH", "\"${getGitHash()}\"" buildConfigField "String", "GIT_BRANCH", "\"${getGitBranch()}\"" diff --git a/app/src/main/assets/changelog.html b/app/src/main/assets/changelog.html index 221bcd89..1f97ffee 100644 --- a/app/src/main/assets/changelog.html +++ b/app/src/main/assets/changelog.html @@ -31,12 +31,18 @@
    -

    Version 3.1.1-beta1

    +

    Version 3.1.1

    +

    Fixes

    A recent Android Pixel update introduced a bug causing Aegis to sometimes show a black screen after unlocking the vault. We have reported this issue to the Google Issue Tracker (link) and - are awaiting a response from Google. In the meantime, we have implemented a workaround to eliminates this bug. + are awaiting a response from Google. In the meantime, we have implemented a workaround that eliminates this bug.

    +
      +
    • Group filter now gets applied properly upon unlocking the vault
    • +
    • Advanced entry settings now gets shown correctly
    • +
    • Keyboard when searching for entries now gets hidden when the user starts scrolling through the list
    • +

    Version 3.1

    New

      From e53688d30d83c1fe4da05593f389edcc56fef4be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Mon, 22 Jul 2024 19:04:34 +0200 Subject: [PATCH 011/113] Fix datetime parsing in Audit Log --- .../com/beemdevelopment/aegis/ui/views/AuditLogHolder.java | 3 ++- app/src/main/res/values-ar-rSA/strings.xml | 1 - app/src/main/res/values-bg-rBG/strings.xml | 1 - app/src/main/res/values-ca-rES/strings.xml | 1 - app/src/main/res/values-cs-rCZ/strings.xml | 1 - app/src/main/res/values-da-rDK/strings.xml | 1 - app/src/main/res/values-de-rDE/strings.xml | 1 - app/src/main/res/values-el-rGR/strings.xml | 1 - app/src/main/res/values-es-rES/strings.xml | 1 - app/src/main/res/values-fi-rFI/strings.xml | 1 - app/src/main/res/values-fr-rFR/strings.xml | 1 - app/src/main/res/values-fy-rNL/strings.xml | 1 - app/src/main/res/values-hu-rHU/strings.xml | 1 - app/src/main/res/values-lv-rLV/strings.xml | 1 - app/src/main/res/values-nl-rNL/strings.xml | 1 - app/src/main/res/values-pl-rPL/strings.xml | 1 - app/src/main/res/values-pt-rBR/strings.xml | 1 - app/src/main/res/values-ro-rRO/strings.xml | 1 - app/src/main/res/values-ru-rRU/strings.xml | 1 - app/src/main/res/values-sk-rSK/strings.xml | 1 - app/src/main/res/values-vi-rVN/strings.xml | 1 - app/src/main/res/values-zh-rCN/strings.xml | 1 - app/src/main/res/values/strings.xml | 1 - 23 files changed, 2 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/AuditLogHolder.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/AuditLogHolder.java index 8ff088a2..9dd1a82c 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/AuditLogHolder.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/AuditLogHolder.java @@ -20,6 +20,7 @@ import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; import java.time.temporal.ChronoUnit; public class AuditLogHolder extends RecyclerView.ViewHolder { @@ -133,7 +134,7 @@ public class AuditLogHolder extends RecyclerView.ViewHolder { String formattedTime = timestamp.format(timeFormatter); return context.getString(R.string.day_of_week_at_time, dayOfWeek, formattedTime); } else { - DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(context.getString(R.string.date_format)); + DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM); return timestamp.format(dateFormatter); } } diff --git a/app/src/main/res/values-ar-rSA/strings.xml b/app/src/main/res/values-ar-rSA/strings.xml index 7328eae2..c732e62a 100644 --- a/app/src/main/res/values-ar-rSA/strings.xml +++ b/app/src/main/res/values-ar-rSA/strings.xml @@ -131,7 +131,6 @@ نوع الحدث غير معروف اليوم على %1$s %1$s في %2$s - dd/MM/yyyy تشفير المخزن هذا الإجراء سيصدر المخزن خارج ذاكرة تخزين Aegis الداخلية. حدد الصيغة التي ترغب بأن يكون التصدير عليها: أنت على وشك تصدير نسخة غير مشفرة من مخزن Aegis. لا يُنصح بهذا. diff --git a/app/src/main/res/values-bg-rBG/strings.xml b/app/src/main/res/values-bg-rBG/strings.xml index 6949ab8a..966960b9 100644 --- a/app/src/main/res/values-bg-rBG/strings.xml +++ b/app/src/main/res/values-bg-rBG/strings.xml @@ -123,7 +123,6 @@ Неизвестен вид събитие Днес в %1$s %1$s в %2$s - dd.MM.yyyy Шифровайте трезора По този начин ще бъде изнесен трезора на Aegis от вътрешното хранилище. Изберете формата на данните, в който искате да бъдат изнесени: На път сте да изнесете нешифровано копие на трезора на Aegis. Това е силно непрепоръчително. diff --git a/app/src/main/res/values-ca-rES/strings.xml b/app/src/main/res/values-ca-rES/strings.xml index 9f465e42..4dd6d845 100644 --- a/app/src/main/res/values-ca-rES/strings.xml +++ b/app/src/main/res/values-ca-rES/strings.xml @@ -123,7 +123,6 @@ Tipus d\'esdeveniment desconegut Avui a les %1$s %1$s a les %2$s - dd/MM/yyyy Xifra la caixa forta Això exportarà la caixa forta fora d\'Aegis. Tria el format en el que s\'ha d\'exportar: Això exportarà una còpia sense xifrar de la caixa forta d\'Aegis. No recomanat. diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 9312a30a..bf110758 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -127,7 +127,6 @@ Neznámý typ události Dnes v %1$s %1$s v %2$s - dd. MM. yyyy Šifrovat trezor Trezor bude exportován mimo vnitřní úložiště Aegis. Zvolte formát, ve kterém chcete trezor exportovat: Chystáte se exportovat nešifrovanou kopii vašeho Aegis trezoru. Toto není doporučeno. diff --git a/app/src/main/res/values-da-rDK/strings.xml b/app/src/main/res/values-da-rDK/strings.xml index a9dfe457..40d41544 100644 --- a/app/src/main/res/values-da-rDK/strings.xml +++ b/app/src/main/res/values-da-rDK/strings.xml @@ -123,7 +123,6 @@ Ukendt hændelsestype I dag kl. %1$s %1$s kl. %2$s - dd-MM-yyyy Kryptér boksen Denne handling eksporterer Boksen ud af Aegis\' interne lager. Vælg det format Boksen skal eksportere som: Du er ved at eksportere en ukrypteret kopi af din Aegis-boks. Dette er ikke anbefalet. diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index 790f1a7f..f69d5b55 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -123,7 +123,6 @@ Unbekanntes Ereignis Heute um %1$s %1$s um %2$s - dd/MM/yyyy Datenbank verschlüsseln Mit dieser Aktion wird die Datenbank aus dem internen Speicher von Aegis exportiert. Wähle das Format aus, in dem der Export erfolgen soll: Du bist dabei, eine unverschlüsselte Kopie deiner Aegis-Datenbank zu exportieren. Dies wird nicht empfohlen. diff --git a/app/src/main/res/values-el-rGR/strings.xml b/app/src/main/res/values-el-rGR/strings.xml index 445ee8af..a488564f 100644 --- a/app/src/main/res/values-el-rGR/strings.xml +++ b/app/src/main/res/values-el-rGR/strings.xml @@ -123,7 +123,6 @@ Άγνωστος τύπος συμβάντος Σήμερα στις %1$s %1$s στις %2$s - ηη/ΜΜ/εεεε Κρυπτογράφηση κρύπτης Αυτή η ενέργεια θα εξάγει την κρύπτη έξω από τον εσωτερικό χώρο αποθήκευσης του Aegis. Επιλέξτε τη μορφή στην οποία θέλετε να είναι η εξαγωγή σας: Πρόκειται να εξαγάγετε ένα μη κρυπτογραφημένο αντίγραφο της Aegis κρύπτης σας. Αυτό δεν συνιστάται . diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index 209b719c..f4648457 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -123,7 +123,6 @@ Tipo de evento desconocido Hoy a las %1$s %1$s a las %2$s - día/mes/año Cifrar la bóveda Esta acción exportará la bóveda fuera del almacenamiento interno de Aegis. Seleccione el formato al que desea exportar: Estás a punto de exportar una copia sin cifrar de tu bóveda de Aegis. No se recomienda en absoluto. diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index 5936bbd0..28292499 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -123,7 +123,6 @@ Tuntematon tapahtumatyyppi Tänään klo %1$s %1$s klo %2$s - dd/MM/yyyy Salaa holvi Tämä toiminto vie holvin ulos Aegisin sisäisestä tallennustilasta. Valitse viennin tiedostomuoto: Olet viemässä salaamattoman kopion Aegis-holvistasi. Tätä ei suositella. diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml index 415ea1d9..62db5d2b 100644 --- a/app/src/main/res/values-fr-rFR/strings.xml +++ b/app/src/main/res/values-fr-rFR/strings.xml @@ -123,7 +123,6 @@ Type d\'événement inconnu Ajourd\'hui à %1$s %1$s à %2$s - dd/MM/yyyy Chiffrer le coffre-fort Cette action exportera le coffre-fort à partir du stockage interne d\'Aegis. Sélectionnez le format vers lequel vous souhaitez faire votre export : Vous êtes sur le point d\'exporter une copie non chiffrée de votre coffre-fort Aegis. Ce n\'est pas recommandé. diff --git a/app/src/main/res/values-fy-rNL/strings.xml b/app/src/main/res/values-fy-rNL/strings.xml index 97100aad..0b2c8648 100644 --- a/app/src/main/res/values-fy-rNL/strings.xml +++ b/app/src/main/res/values-fy-rNL/strings.xml @@ -123,7 +123,6 @@ Unbekend barrenstype Hjoed om %1$s %1$s om %2$s - dd/mm/jjjj Fersiferje de klûs Dizze aksje sil de klûs eksportearje út it ynterne ûnthâld fan Aegis. Selektearje it formaat wêryn’tsto de eksport wolst: Do stiest op it punt in ûnfersifere kopy fan de Aegis-klûs te eksportearjen. Dit wurdt net oanrekommandearre. diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index 733e57cf..b11acae9 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -123,7 +123,6 @@ Ismeretlen eseménytípus Ma %1$s-kor %1$s %2$s-kor - yyyy. MM. dd. A széf titkosítása Ez a művelet exportálja a széfet az Aegis belső tárolójából. Válassza ki az exportálás formátumát: Arra készül, hogy egy titkosítatlan Aegis széfet exportáljon. Ez nem ajánlott. diff --git a/app/src/main/res/values-lv-rLV/strings.xml b/app/src/main/res/values-lv-rLV/strings.xml index 3dcc8f6b..b625f5ab 100644 --- a/app/src/main/res/values-lv-rLV/strings.xml +++ b/app/src/main/res/values-lv-rLV/strings.xml @@ -125,7 +125,6 @@ Nezināms notikuma veids Šodien %1$s %1$s %2$s - dd.MM.yyyy. Šifrēt glabātavu Šī darbība izgūs glabātavas saturu no Aegis iekšējās krātuves. Jāatlasa veidols, kurā izgūt datus: Tiks izgūts nešifrēts Aegis glabātavas atveidojums. Tas nav ieteicams. diff --git a/app/src/main/res/values-nl-rNL/strings.xml b/app/src/main/res/values-nl-rNL/strings.xml index 2219fcd4..1903ccef 100644 --- a/app/src/main/res/values-nl-rNL/strings.xml +++ b/app/src/main/res/values-nl-rNL/strings.xml @@ -123,7 +123,6 @@ Onbekende gebeurtenis Vandaag om %1$s %1$s om %2$s - dd-mm-jjjj Kluis versleutelen Deze actie zal de kluis exporteren uit de interne opslag van Aegis. Selecteer het formaat waarin je de export wilt: Je staat op het punt een onversleutelde kopie van de Aegis-kluis te exporteren. Dit wordt niet aanbevolen. diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml index a81c7146..5c4ee6ea 100644 --- a/app/src/main/res/values-pl-rPL/strings.xml +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -127,7 +127,6 @@ Nieznany typ zdarzenia Dzisiaj o %1$s %1$s o %2$s - dd/MM/yyyy Zaszyfruj sejf Ta czynność wyeksportuje sejf z wewnętrznej przestrzeni dyskowej aplikacji Aegis. Wybierz format eksportowanego pliku: Wyeksportujesz sejf aplikacji Aegis w niezaszyfrowanym formacie. Ta opcja nie jest zalecana. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index a916e995..b414f490 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -123,7 +123,6 @@ Tipo de evento desconhecido Hoje às %1$s %1$s em %2$s - dd/MM/yyyy Criptografar o cofre Esta ação irá exportar o cofre para fora do armazenamento interno do Aegis. Selecione o formato em que você gostaria que sua exportação esteja: Você está prestes a exportar uma cópia não criptografada de seu cofre Aegis. Isso não é recomendado. diff --git a/app/src/main/res/values-ro-rRO/strings.xml b/app/src/main/res/values-ro-rRO/strings.xml index d6941355..1a7b9af0 100644 --- a/app/src/main/res/values-ro-rRO/strings.xml +++ b/app/src/main/res/values-ro-rRO/strings.xml @@ -125,7 +125,6 @@ Tipul evenimentului este necunoscut Astăzi, la %1$s %1$s la %2$s - zz/ll/aaaa Criptează seiful Această acțiune va exporta seiful din spațiul de stocare al aplicaţiei. Selectează formatul în care dorești exportul: Ești pe cale să exportezi o copie necriptată a seifului Aegis. Acest lucru nu este recomandat. diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index affd6312..9ac692b1 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -127,7 +127,6 @@ Неизвестный тип события Сегодня в %1$s %1$s в %2$s - dd.MM.yyyy Шифровать хранилище Экспорт внутреннего хранилища Aegis. Выберите формат: Вы собираетесь экспортировать незашифрованную копию хранилища Aegis. Не рекомендуется. diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index 8651c50e..8fa87bf6 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -121,7 +121,6 @@ Neznámy typ udalosti Dnes o %1$s %1$s o %2$s - dd. mm. yyyy Šifrovať trezor Touto akciou sa exportuje trezor z interného úložiska Aegis. Vyberte formát, v ktorom chcete mať export: Chystáte sa exportovať nezašifrovanú kópiu svojho trezoru Aegis. Toto sa neodporúča . diff --git a/app/src/main/res/values-vi-rVN/strings.xml b/app/src/main/res/values-vi-rVN/strings.xml index dfb09103..b9effb74 100644 --- a/app/src/main/res/values-vi-rVN/strings.xml +++ b/app/src/main/res/values-vi-rVN/strings.xml @@ -121,7 +121,6 @@ Sự kiện chưa rõ %1$s hôm nay %2$s lúc %1$s - dd/MM/yyyy Mã hoá kho Hành động này sẽ xuất kho ra ngoài bộ nhớ trong của Aegis. Hãy chọn định dạng bản xuất: Bạn sắp xuất một bản sao chưa được mã khóa của kho Aegis. Việc này không được khuyến khích. diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 9cf8ce6d..eb5eeb9a 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -121,7 +121,6 @@ 未知事件类型 今天 %1$s %2$s 的 %1$s - 日/月/年 加密数据库 此操作将从 Aegis 的内部存储中导出数据库。选择您想要的导出格式: 您将导出一个未加密的 Aegis 数据库副本。不建议这么做 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ff77446c..1d9cdcea 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -128,7 +128,6 @@ Today at %1$s %1$s at %2$s - dd/MM/yyyy Encrypt the vault This action will export the vault out of Aegis\' internal storage. Select the format you\'d like your export to be in: From 62f25d9ae9d169c7b2ca943aa019edaefa2b4c58 Mon Sep 17 00:00:00 2001 From: r3dh3ck Date: Mon, 22 Jul 2024 17:53:04 +0000 Subject: [PATCH 012/113] Strip a biometric slot when a backup is made --- .../aegis/vault/slots/SlotList.java | 15 +++++----- .../aegis/vault/slots/SlotTest.java | 28 +++++++++---------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/vault/slots/SlotList.java b/app/src/main/java/com/beemdevelopment/aegis/vault/slots/SlotList.java index 99037c52..f479b593 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/vault/slots/SlotList.java +++ b/app/src/main/java/com/beemdevelopment/aegis/vault/slots/SlotList.java @@ -75,6 +75,7 @@ public class SlotList extends UUIDMap { /** * Returns a copy of this SlotList that is suitable for exporting. + * Strips biometric slots. * In case there's a backup password slot, any regular password slots are stripped. */ public SlotList exportable() { @@ -85,18 +86,16 @@ public class SlotList extends UUIDMap { break; } } - - if (!hasBackupSlots) { - return this; - } - SlotList slots = new SlotList(); for (Slot slot : this) { - if (!(slot instanceof PasswordSlot) || ((PasswordSlot) slot).isBackup()) { - slots.add(slot); + if (slot instanceof BiometricSlot) { + continue; } + if (hasBackupSlots && slot instanceof PasswordSlot && !((PasswordSlot) slot).isBackup()) { + continue; + } + slots.add(slot); } - return slots; } } diff --git a/app/src/test/java/com/beemdevelopment/aegis/vault/slots/SlotTest.java b/app/src/test/java/com/beemdevelopment/aegis/vault/slots/SlotTest.java index 345c8f1d..dbee9f54 100644 --- a/app/src/test/java/com/beemdevelopment/aegis/vault/slots/SlotTest.java +++ b/app/src/test/java/com/beemdevelopment/aegis/vault/slots/SlotTest.java @@ -1,7 +1,6 @@ package com.beemdevelopment.aegis.vault.slots; import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThrows; import com.beemdevelopment.aegis.crypto.CryptoUtils; @@ -96,22 +95,21 @@ public class SlotTest { } @Test - public void testPasswordSlotExclusion() { - SlotList slots = new SlotList(); - PasswordSlot passSlot = new PasswordSlot(); - PasswordSlot passSlot2 = new PasswordSlot(); - slots.add(passSlot); - slots.add(passSlot2); - - assertArrayEquals(slots.getValues().toArray(), slots.exportable().getValues().toArray()); - - SlotList backupSlots = new SlotList(); + public void testNonExportableSlotsExclusion() { + Slot rawSlot = new RawSlot(); + Slot passwordSlot = new PasswordSlot(); + Slot biometricSlot = new BiometricSlot(); PasswordSlot backupSlot = new PasswordSlot(); backupSlot.setIsBackup(true); + SlotList slots = new SlotList(); + slots.add(rawSlot); + slots.add(passwordSlot); + slots.add(biometricSlot); slots.add(backupSlot); - backupSlots.add(backupSlot); - - assertArrayEquals(backupSlots.getValues().toArray(), slots.exportable().getValues().toArray()); - assertNotEquals(slots.getValues().toArray(), slots.exportable().getValues().toArray()); + SlotList actual = slots.exportable(); + SlotList expected = new SlotList(); + expected.add(rawSlot); + expected.add(backupSlot); + assertArrayEquals(expected.getValues().toArray(), actual.getValues().toArray()); } } From 7d76be577d3328815fee10a894995adcf3c2ac99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Mon, 22 Jul 2024 20:08:48 +0200 Subject: [PATCH 013/113] Fix showing duplicate time sync dialogs --- .../main/java/com/beemdevelopment/aegis/ui/MainActivity.java | 2 -- 1 file changed, 2 deletions(-) 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 81a7c5bf..b8528cba 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -520,7 +520,6 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene private void onIntroResult() { loadEntries(); - checkTimeSyncSetting(); } private void checkTimeSyncSetting() { @@ -537,7 +536,6 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene _auditLogRepository.addVaultUnlockedEvent(); loadEntries(); - checkTimeSyncSetting(); } private void startScanActivity() { From fc8cdc65022cbcfb50d69931054c90dfbfb3a0dc Mon Sep 17 00:00:00 2001 From: r3dh3ck Date: Tue, 23 Jul 2024 06:08:52 +0000 Subject: [PATCH 014/113] Implement infinite backups --- .../beemdevelopment/aegis/Preferences.java | 1 + .../aegis/ui/dialogs/Dialogs.java | 25 ++++++++++++------- .../BackupsPreferencesFragment.java | 15 ++++++++--- .../aegis/vault/VaultBackupManager.java | 4 +++ app/src/main/res/values/strings.xml | 2 ++ 5 files changed, 35 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/Preferences.java b/app/src/main/java/com/beemdevelopment/aegis/Preferences.java index d94668b1..0ccf77ee 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/Preferences.java +++ b/app/src/main/java/com/beemdevelopment/aegis/Preferences.java @@ -33,6 +33,7 @@ public class Preferences { public static final int AUTO_LOCK_ON_BACK_BUTTON = 1 << 1; public static final int AUTO_LOCK_ON_MINIMIZE = 1 << 2; public static final int AUTO_LOCK_ON_DEVICE_LOCK = 1 << 3; + public static final int BACKUPS_VERSIONS_INFINITE = -1; public static final int[] AUTO_LOCK_SETTINGS = { AUTO_LOCK_ON_BACK_BUTTON, diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java b/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java index 4d14908d..5a427494 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java @@ -318,25 +318,32 @@ public class Dialogs { } public static void showBackupVersionsPickerDialog(Context context, int currentVersionCount, NumberInputListener listener) { - final int max = 30; - String[] numbers = new String[max / 5]; - for (int i = 0; i < numbers.length; i++) { - numbers[i] = Integer.toString(i * 5 + 5); + String infinite = context.getString(R.string.pref_backups_versions_infinite); + String[] values = {"5", "10", "15", "20", "25", "30", infinite}; + int[] numbers = {5, 10, 15, 20, 25, 30, Preferences.BACKUPS_VERSIONS_INFINITE}; + int selectedIndex; + if (currentVersionCount == Preferences.BACKUPS_VERSIONS_INFINITE) { + selectedIndex = numbers.length - 1; + } else { + selectedIndex = currentVersionCount / 5 - 1; } View view = LayoutInflater.from(context).inflate(R.layout.dialog_number_picker, null); NumberPicker numberPicker = view.findViewById(R.id.numberPicker); - numberPicker.setDisplayedValues(numbers); - numberPicker.setMaxValue(numbers.length - 1); + numberPicker.setDisplayedValues(values); + numberPicker.setMaxValue(values.length - 1); numberPicker.setMinValue(0); - numberPicker.setValue(currentVersionCount / 5 - 1); + numberPicker.setValue(selectedIndex); numberPicker.setWrapSelectorWheel(false); AlertDialog dialog = new MaterialAlertDialogBuilder(context) .setTitle(R.string.set_number) .setView(view) - .setPositiveButton(android.R.string.ok, (dialog1, which) -> - listener.onNumberInputResult(numberPicker.getValue())) + .setPositiveButton(android.R.string.ok, (dialog1, which) -> { + int index = numberPicker.getValue(); + int number = numbers[index]; + listener.onNumberInputResult(number); + }) .create(); showSecureDialog(dialog); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/BackupsPreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/BackupsPreferencesFragment.java index a2ec4fd5..cb9c6658 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/BackupsPreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/BackupsPreferencesFragment.java @@ -131,12 +131,11 @@ public class BackupsPreferencesFragment extends PreferencesFragment { }); _backupsVersionsPreference = requirePreference("pref_backups_versions"); - _backupsVersionsPreference.setSummary(getResources().getQuantityString(R.plurals.pref_backups_versions_summary, _prefs.getBackupsVersionCount(), _prefs.getBackupsVersionCount())); + updateBackupsVersionsSummary(); _backupsVersionsPreference.setOnPreferenceClickListener(preference -> { Dialogs.showBackupVersionsPickerDialog(requireContext(), _prefs.getBackupsVersionCount(), number -> { - number = number * 5 + 5; _prefs.setBackupsVersionCount(number); - _backupsVersionsPreference.setSummary(getResources().getQuantityString(R.plurals.pref_backups_versions_summary, _prefs.getBackupsVersionCount(), _prefs.getBackupsVersionCount())); + updateBackupsVersionsSummary(); }); return false; }); @@ -242,4 +241,14 @@ public class BackupsPreferencesFragment extends PreferencesFragment { Dialogs.showErrorDialog(requireContext(), R.string.backup_error, e); } } + + private void updateBackupsVersionsSummary() { + int count = _prefs.getBackupsVersionCount(); + if (count == Preferences.BACKUPS_VERSIONS_INFINITE) { + _backupsVersionsPreference.setSummary(R.string.pref_backups_versions_infinite_summary); + } else { + String summary = getResources().getQuantityString(R.plurals.pref_backups_versions_summary, count, count); + _backupsVersionsPreference.setSummary(summary); + } + } } diff --git a/app/src/main/java/com/beemdevelopment/aegis/vault/VaultBackupManager.java b/app/src/main/java/com/beemdevelopment/aegis/vault/VaultBackupManager.java index 46d515c1..e235337d 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/vault/VaultBackupManager.java +++ b/app/src/main/java/com/beemdevelopment/aegis/vault/VaultBackupManager.java @@ -118,6 +118,10 @@ public class VaultBackupManager { } private void enforceVersioning(DocumentFile dir, int versionsToKeep) { + if (versionsToKeep < 0) { + return; + } + Log.i(TAG, String.format("Scanning directory %s for backup files", Uri.decode(dir.getUri().toString()))); List files = new ArrayList<>(); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9998e88e..6cc0ae54 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -66,10 +66,12 @@ Trigger backup Manually trigger a backup Number of versions to keep + \u221E Keep %1$d version of the backup Keep %1$d versions of the backup + Keep an infinite number of versions of the backup Import from app Import tokens from an app (requires root access) Export From 4ea19a2b7a955c357fcec0657358d33801066315 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Tue, 23 Jul 2024 20:12:07 +0200 Subject: [PATCH 015/113] Don't enforce backup versioning if versionsToKeep <= 0 --- .../com/beemdevelopment/aegis/vault/VaultBackupManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/vault/VaultBackupManager.java b/app/src/main/java/com/beemdevelopment/aegis/vault/VaultBackupManager.java index e235337d..6ce60b49 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/vault/VaultBackupManager.java +++ b/app/src/main/java/com/beemdevelopment/aegis/vault/VaultBackupManager.java @@ -118,7 +118,7 @@ public class VaultBackupManager { } private void enforceVersioning(DocumentFile dir, int versionsToKeep) { - if (versionsToKeep < 0) { + if (versionsToKeep <= 0) { return; } From a10693e79e612701ecc461d6e1933b0cd5845e24 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Tue, 23 Jul 2024 20:26:45 +0200 Subject: [PATCH 016/113] Expand the number of cases covered under the slot exclusion tests --- .../aegis/vault/slots/SlotTest.java | 70 ++++++++++++++++++- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/app/src/test/java/com/beemdevelopment/aegis/vault/slots/SlotTest.java b/app/src/test/java/com/beemdevelopment/aegis/vault/slots/SlotTest.java index dbee9f54..56a939b2 100644 --- a/app/src/test/java/com/beemdevelopment/aegis/vault/slots/SlotTest.java +++ b/app/src/test/java/com/beemdevelopment/aegis/vault/slots/SlotTest.java @@ -96,20 +96,84 @@ public class SlotTest { @Test public void testNonExportableSlotsExclusion() { - Slot rawSlot = new RawSlot(); + // If a backup password slot, multiple regular password slots and a biometric slot are present: + // -> The Regular password slots and the biometric slot get stripped Slot passwordSlot = new PasswordSlot(); + Slot passwordSlot2 = new PasswordSlot(); Slot biometricSlot = new BiometricSlot(); PasswordSlot backupSlot = new PasswordSlot(); backupSlot.setIsBackup(true); SlotList slots = new SlotList(); - slots.add(rawSlot); slots.add(passwordSlot); + slots.add(passwordSlot2); slots.add(biometricSlot); slots.add(backupSlot); SlotList actual = slots.exportable(); SlotList expected = new SlotList(); - expected.add(rawSlot); expected.add(backupSlot); assertArrayEquals(expected.getValues().toArray(), actual.getValues().toArray()); + + // If a backup password slot, a regular password slot and a biometric slot are present: + // -> The Regular password slot and the biometric slot get stripped + slots = new SlotList(); + slots.add(passwordSlot); + slots.add(biometricSlot); + slots.add(backupSlot); + actual = slots.exportable(); + expected = new SlotList(); + expected.add(backupSlot); + assertArrayEquals(expected.getValues().toArray(), actual.getValues().toArray()); + + // If a backup password slot and a regular password slot are present: + // -> The regular password slot get stripped + slots = new SlotList(); + slots.add(passwordSlot); + slots.add(backupSlot); + actual = slots.exportable(); + expected = new SlotList(); + expected.add(backupSlot); + assertArrayEquals(expected.getValues().toArray(), actual.getValues().toArray()); + + // If a backup password slot and multiple regular password slot are present: + // -> The regular password slots get stripped + slots = new SlotList(); + slots.add(passwordSlot); + slots.add(passwordSlot2); + slots.add(backupSlot); + actual = slots.exportable(); + expected = new SlotList(); + expected.add(backupSlot); + assertArrayEquals(expected.getValues().toArray(), actual.getValues().toArray()); + + // If multiple regular password slots and a biometric slot are present: + // -> The biometric slot gets stripped + slots = new SlotList(); + slots.add(passwordSlot); + slots.add(passwordSlot2); + slots.add(biometricSlot); + actual = slots.exportable(); + expected = new SlotList(); + expected.add(passwordSlot); + expected.add(passwordSlot2); + assertArrayEquals(expected.getValues().toArray(), actual.getValues().toArray()); + + // If a regular password slot and a biometric slot are present + // -> The biometric slot gets stripped + slots = new SlotList(); + slots.add(passwordSlot); + slots.add(biometricSlot); + actual = slots.exportable(); + expected = new SlotList(); + expected.add(passwordSlot); + assertArrayEquals(expected.getValues().toArray(), actual.getValues().toArray()); + + // If a regular password slot is present + // -> No slots get stripped + slots = new SlotList(); + slots.add(passwordSlot); + actual = slots.exportable(); + expected = new SlotList(); + expected.add(passwordSlot); + assertArrayEquals(expected.getValues().toArray(), actual.getValues().toArray()); } } From f796e4542a59b4dbcd9958bf87fe1fe99449899a Mon Sep 17 00:00:00 2001 From: r3dh3ck Date: Tue, 23 Jul 2024 13:33:52 +0000 Subject: [PATCH 017/113] Remove preferences result --- .../aegis/ui/MainActivity.java | 42 +++---------------- .../aegis/ui/PreferencesActivity.java | 16 ------- .../AppearancePreferencesFragment.java | 19 --------- .../BackupsPreferencesFragment.java | 1 - .../BehaviorPreferencesFragment.java | 16 ++----- .../ImportExportPreferencesFragment.java | 10 +---- .../preferences/MainPreferencesFragment.java | 1 - .../preferences/PreferencesFragment.java | 19 --------- .../SecurityPreferencesFragment.java | 9 ---- 9 files changed, 11 insertions(+), 122 deletions(-) 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 24bf91c5..0f6a01dd 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -35,12 +35,9 @@ import androidx.appcompat.app.AlertDialog; import androidx.appcompat.view.ActionMode; import androidx.appcompat.widget.SearchView; -import com.beemdevelopment.aegis.AccountNamePosition; -import com.beemdevelopment.aegis.CopyBehavior; import com.beemdevelopment.aegis.Preferences; import com.beemdevelopment.aegis.R; import com.beemdevelopment.aegis.SortCategory; -import com.beemdevelopment.aegis.ViewMode; import com.beemdevelopment.aegis.helpers.FabScrollHelper; import com.beemdevelopment.aegis.helpers.PermissionHelper; import com.beemdevelopment.aegis.otp.GoogleAuthInfo; @@ -133,12 +130,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene }); private final ActivityResultLauncher preferenceResultLauncher = - registerForActivityResult(new StartActivityForResult(), activityResult -> { - if (activityResult.getResultCode() != RESULT_OK || activityResult.getData() == null) { - return; - } - onPreferencesResult(activityResult.getData()); - }); + registerForActivityResult(new StartActivityForResult(), activityResult -> onPreferencesResult()); private final ActivityResultLauncher editEntryResultLauncher = registerForActivityResult(new StartActivityForResult(), activityResult -> { @@ -287,34 +279,10 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene _isDPadPressed = false; } - private void onPreferencesResult(Intent data) { + private void onPreferencesResult() { // refresh the entire entry list if needed if (_loaded) { - if (data.getBooleanExtra("needsRecreate", false)) { - recreate(); - } else if (data.getBooleanExtra("needsRefresh", false)) { - AccountNamePosition accountNamePosition = _prefs.getAccountNamePosition(); - boolean showIcons = _prefs.isIconVisible(); - boolean onlyShowNecessaryAccountNames = _prefs.onlyShowNecessaryAccountNames(); - Preferences.CodeGrouping codeGroupSize = _prefs.getCodeGroupSize(); - boolean highlightEntry = _prefs.isEntryHighlightEnabled(); - boolean pauseFocused = _prefs.isPauseFocusedEnabled(); - boolean tapToReveal = _prefs.isTapToRevealEnabled(); - int tapToRevealTime = _prefs.getTapToRevealTime(); - ViewMode viewMode = _prefs.getCurrentViewMode(); - CopyBehavior copyBehavior = _prefs.getCopyBehavior(); - _entryListView.setAccountNamePosition(accountNamePosition); - _entryListView.setOnlyShowNecessaryAccountNames(onlyShowNecessaryAccountNames); - _entryListView.setShowIcon(showIcons); - _entryListView.setCodeGroupSize(codeGroupSize); - _entryListView.setHighlightEntry(highlightEntry); - _entryListView.setPauseFocused(pauseFocused); - _entryListView.setTapToReveal(tapToReveal); - _entryListView.setTapToRevealTime(tapToRevealTime); - _entryListView.setViewMode(viewMode); - _entryListView.setCopyBehavior(copyBehavior); - _entryListView.refresh(true); - } + recreate(); } } @@ -860,7 +828,9 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene _entryListView.setUsageCounts(_prefs.getUsageCounts()); _entryListView.setLastUsedTimestamps(_prefs.getLastUsedTimestamps()); _entryListView.addEntries(_vaultManager.getVault().getEntries()); - _entryListView.runEntriesAnimation(); + if (!_isRecreated) { + _entryListView.runEntriesAnimation(); + } _loaded = true; } } diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesActivity.java index 120c1311..e4d55919 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesActivity.java @@ -57,24 +57,8 @@ public class PreferencesActivity extends AegisActivity implements } } - @Override - protected void onRestoreInstanceState(@NonNull final Bundle inState) { - if (_fragment instanceof PreferencesFragment) { - // pass the stored result intent back to the fragment - if (inState.containsKey("result")) { - ((PreferencesFragment) _fragment).setResult(inState.getParcelable("result")); - } - } - super.onRestoreInstanceState(inState); - } - @Override protected void onSaveInstanceState(@NonNull final Bundle outState) { - if (_fragment instanceof PreferencesFragment) { - // save the result intent of the fragment - // this is done so we don't lose anything if the fragment calls recreate on this activity - outState.putParcelable("result", ((PreferencesFragment) _fragment).getResult()); - } outState.putCharSequence("prefTitle", _prefTitle); super.onSaveInstanceState(outState); } diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AppearancePreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AppearancePreferencesFragment.java index 8abdd841..a0b39a33 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AppearancePreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AppearancePreferencesFragment.java @@ -27,7 +27,6 @@ public class AppearancePreferencesFragment extends PreferencesFragment { @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - super.onCreatePreferences(savedInstanceState, rootKey); addPreferencesFromResource(R.xml.preferences_appearance); _groupsPreference = requirePreference("pref_groups"); @@ -62,7 +61,6 @@ public class AppearancePreferencesFragment extends PreferencesFragment { dialog.dismiss(); - getResult().putExtra("needsRecreate", true); requireActivity().recreate(); }) .setNegativeButton(android.R.string.cancel, null) @@ -74,7 +72,6 @@ public class AppearancePreferencesFragment extends PreferencesFragment { Preference dynamicColorsPreference = requirePreference("pref_dynamic_colors"); dynamicColorsPreference.setEnabled(DynamicColors.isDynamicColorAvailable()); dynamicColorsPreference.setOnPreferenceChangeListener((preference, newValue) -> { - getResult().putExtra("needsRecreate", true); requireActivity().recreate(); return true; }); @@ -96,7 +93,6 @@ public class AppearancePreferencesFragment extends PreferencesFragment { dialog.dismiss(); - getResult().putExtra("needsRecreate", true); requireActivity().recreate(); }) .setNegativeButton(android.R.string.cancel, null) @@ -120,7 +116,6 @@ public class AppearancePreferencesFragment extends PreferencesFragment { int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition(); _prefs.setCurrentViewMode(ViewMode.fromInteger(i)); viewModePreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.view_mode_titles)[i])); - getResult().putExtra("needsRefresh", true); overrideAccountNamePosition(ViewMode.fromInteger(i) == ViewMode.TILES); dialog.dismiss(); }) @@ -143,19 +138,12 @@ public class AppearancePreferencesFragment extends PreferencesFragment { _prefs.setCodeGroupSize(Preferences.CodeGrouping.valueOf(codeGroupings[newCodeGroupingIndex])); dialog.dismiss(); - getResult().putExtra("needsRefresh", true); }) .setNegativeButton(android.R.string.cancel, null) .create()); return true; }); - Preference onlyShowNecessaryAccountNames = requirePreference("pref_shared_issuer_account_name"); - onlyShowNecessaryAccountNames.setOnPreferenceChangeListener((preference, newValue) -> { - getResult().putExtra("needsRefresh", true); - return true; - }); - int currentAccountNamePosition = _prefs.getAccountNamePosition().ordinal(); _currentAccountNamePositionPreference = requirePreference("pref_account_name_position"); _currentAccountNamePositionPreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.account_name_position_titles)[currentAccountNamePosition])); @@ -168,7 +156,6 @@ public class AppearancePreferencesFragment extends PreferencesFragment { int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition(); _prefs.setAccountNamePosition(AccountNamePosition.fromInteger(i)); _currentAccountNamePositionPreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.account_name_position_titles)[i])); - getResult().putExtra("needsRefresh", true); dialog.dismiss(); }) .setNegativeButton(android.R.string.cancel, null) @@ -177,12 +164,6 @@ public class AppearancePreferencesFragment extends PreferencesFragment { return true; }); - Preference showIconsPreference = requirePreference("pref_show_icons"); - showIconsPreference.setOnPreferenceChangeListener((preference, newValue) -> { - getResult().putExtra("needsRefresh", true); - return true; - }); - overrideAccountNamePosition(_prefs.getCurrentViewMode() == ViewMode.TILES); } diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/BackupsPreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/BackupsPreferencesFragment.java index a2ec4fd5..e1157fa9 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/BackupsPreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/BackupsPreferencesFragment.java @@ -52,7 +52,6 @@ public class BackupsPreferencesFragment extends PreferencesFragment { @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - super.onCreatePreferences(savedInstanceState, rootKey); addPreferencesFromResource(R.xml.preferences_backups); _backupsPasswordWarningPreference = requirePreference("pref_backups_warning_password"); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/BehaviorPreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/BehaviorPreferencesFragment.java index 278f53dd..679021e7 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/BehaviorPreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/BehaviorPreferencesFragment.java @@ -11,11 +11,9 @@ import com.beemdevelopment.aegis.ui.dialogs.Dialogs; import com.google.android.material.dialog.MaterialAlertDialogBuilder; public class BehaviorPreferencesFragment extends PreferencesFragment { - private Preference _entryPausePreference; @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - super.onCreatePreferences(savedInstanceState, rootKey); addPreferencesFromResource(R.xml.preferences_behavior); int currentCopyBehavior = _prefs.getCopyBehavior().ordinal(); @@ -30,7 +28,6 @@ public class BehaviorPreferencesFragment extends PreferencesFragment { int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition(); _prefs.setCopyBehavior(CopyBehavior.fromInteger(i)); copyBehaviorPreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.copy_behavior_titles)[i])); - getResult().putExtra("needsRefresh", true); dialog.dismiss(); }) .setNegativeButton(android.R.string.cancel, null) @@ -39,18 +36,13 @@ public class BehaviorPreferencesFragment extends PreferencesFragment { return true; }); + Preference entryPausePreference = requirePreference("pref_pause_entry"); + entryPausePreference.setEnabled(_prefs.isTapToRevealEnabled() || _prefs.isEntryHighlightEnabled()); + Preference entryHighlightPreference = requirePreference("pref_highlight_entry"); entryHighlightPreference.setOnPreferenceChangeListener((preference, newValue) -> { - getResult().putExtra("needsRefresh", true); - _entryPausePreference.setEnabled(_prefs.isTapToRevealEnabled() || (boolean) newValue); + entryPausePreference.setEnabled(_prefs.isTapToRevealEnabled() || (boolean) newValue); return true; }); - - _entryPausePreference = requirePreference("pref_pause_entry"); - _entryPausePreference.setOnPreferenceChangeListener((preference, newValue) -> { - getResult().putExtra("needsRefresh", true); - return true; - }); - _entryPausePreference.setEnabled(_prefs.isTapToRevealEnabled() || _prefs.isEntryHighlightEnabled()); } } diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/ImportExportPreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/ImportExportPreferencesFragment.java index fb507840..0b8cee53 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/ImportExportPreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/ImportExportPreferencesFragment.java @@ -23,7 +23,6 @@ import androidx.preference.Preference; import com.beemdevelopment.aegis.BuildConfig; import com.beemdevelopment.aegis.R; -import com.beemdevelopment.aegis.database.AuditLogRepository; import com.beemdevelopment.aegis.helpers.DropdownHelper; import com.beemdevelopment.aegis.importers.DatabaseImporter; import com.beemdevelopment.aegis.otp.GoogleAuthInfo; @@ -64,18 +63,12 @@ import java.util.UUID; import java.util.stream.Collectors; import javax.crypto.Cipher; -import javax.inject.Inject; public class ImportExportPreferencesFragment extends PreferencesFragment { // keep a reference to the type of database converter that was selected private DatabaseImporter.Definition _importerDef; private Vault.EntryFilter _exportFilter; - private final ActivityResultLauncher importResultLauncher = - registerForActivityResult(new StartActivityForResult(), activityResult -> { - getResult().putExtra("needsRecreate", true); - }); - private final ActivityResultLauncher importSelectResultLauncher = registerForActivityResult(new StartActivityForResult(), activityResult -> { Intent data = activityResult.getData(); @@ -102,7 +95,6 @@ public class ImportExportPreferencesFragment extends PreferencesFragment { @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - super.onCreatePreferences(savedInstanceState, rootKey); addPreferencesFromResource(R.xml.preferences_import_export); if (savedInstanceState != null) { @@ -169,7 +161,7 @@ public class ImportExportPreferencesFragment extends PreferencesFragment { Intent intent = new Intent(requireContext(), ImportEntriesActivity.class); intent.putExtra("importerDef", importerDef); intent.putExtra("file", file); - importResultLauncher.launch(intent); + startActivity(intent); } private void startExport() { diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/MainPreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/MainPreferencesFragment.java index 3172fd85..980c7f02 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/MainPreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/MainPreferencesFragment.java @@ -7,7 +7,6 @@ import com.beemdevelopment.aegis.R; public class MainPreferencesFragment extends PreferencesFragment { @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - super.onCreatePreferences(savedInstanceState, rootKey); addPreferencesFromResource(R.xml.preferences); } } diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/PreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/PreferencesFragment.java index 7968ff1e..367c32e1 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/PreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/PreferencesFragment.java @@ -1,8 +1,6 @@ package com.beemdevelopment.aegis.ui.fragments.preferences; -import android.app.Activity; import android.content.Intent; -import android.os.Bundle; import android.view.animation.Animation; import androidx.annotation.CallSuper; @@ -31,8 +29,6 @@ public abstract class PreferencesFragment extends PreferenceFragmentCompat { public static final int CODE_EXPORT_GOOGLE_URI = 7; public static final int CODE_EXPORT_HTML = 8; - private Intent _result; - @Inject Preferences _prefs; @@ -42,12 +38,6 @@ public abstract class PreferencesFragment extends PreferenceFragmentCompat { @Inject protected AuditLogRepository _auditLogRepository; - @Override - @CallSuper - public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - setResult(new Intent()); - } - @Override @CallSuper public void onResume() { @@ -61,10 +51,6 @@ public abstract class PreferencesFragment extends PreferenceFragmentCompat { } } - public Intent getResult() { - return _result; - } - @Override @Nullable public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { @@ -75,11 +61,6 @@ public abstract class PreferencesFragment extends PreferenceFragmentCompat { return super.onCreateAnimation(transit, enter, nextAnim); } - public void setResult(Intent result) { - _result = result; - requireActivity().setResult(Activity.RESULT_OK, _result); - } - protected boolean saveAndBackupVault() { try { _vaultManager.saveAndBackup(); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/SecurityPreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/SecurityPreferencesFragment.java index 3ba3d59a..e1123ca2 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/SecurityPreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/SecurityPreferencesFragment.java @@ -55,18 +55,10 @@ public class SecurityPreferencesFragment extends PreferencesFragment { @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - super.onCreatePreferences(savedInstanceState, rootKey); addPreferencesFromResource(R.xml.preferences_security); - Preference tapToRevealPreference = requirePreference("pref_tap_to_reveal"); - tapToRevealPreference.setOnPreferenceChangeListener((preference, newValue) -> { - getResult().putExtra("needsRefresh", true); - return true; - }); - Preference screenPreference = requirePreference("pref_secure_screen"); screenPreference.setOnPreferenceChangeListener((preference, newValue) -> { - getResult().putExtra("needsRecreate", true); Window window = requireActivity().getWindow(); if ((boolean) newValue) { window.addFlags(WindowManager.LayoutParams.FLAG_SECURE); @@ -82,7 +74,6 @@ public class SecurityPreferencesFragment extends PreferencesFragment { Dialogs.showTapToRevealTimeoutPickerDialog(requireContext(), _prefs.getTapToRevealTime(), number -> { _prefs.setTapToRevealTime(number); tapToRevealTimePreference.setSummary(number + " seconds"); - getResult().putExtra("needsRefresh", true); }); return false; }); From 655881e8522623722d04dc3e2005c4a3d2e3a4e8 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Fri, 2 Aug 2024 19:43:39 +0200 Subject: [PATCH 018/113] Make the export dialog scrollable Reported by @valentinb102 on Matrix. --- app/src/main/res/layout/dialog_export.xml | 181 +++++++++++----------- 1 file changed, 93 insertions(+), 88 deletions(-) diff --git a/app/src/main/res/layout/dialog_export.xml b/app/src/main/res/layout/dialog_export.xml index 90c7f02a..ad98847d 100644 --- a/app/src/main/res/layout/dialog_export.xml +++ b/app/src/main/res/layout/dialog_export.xml @@ -1,96 +1,101 @@ - - + - - + - - - - - - - - - - - + - - + android:layout_marginStart="25dp" + android:layout_marginEnd="25dp" + android:layout_marginTop="15dp" + android:hint="@string/export_format_hint" + style="?attr/dropdownStyle"> + + + + + + + + + + + + + + + From db4c738c8f85dda512f5c1e48d74d4f76b03db50 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Fri, 9 Aug 2024 19:49:08 +0200 Subject: [PATCH 019/113] Update dependencies --- app/build.gradle | 70 +++++++++++-------- .../1.json | 52 ++++++++++++++ build.gradle | 6 +- gradle.properties | 1 - gradle/wrapper/gradle-wrapper.properties | 2 +- 5 files changed, 95 insertions(+), 36 deletions(-) create mode 100644 app/schemas/com.beemdevelopment.aegis.database.AppDatabase/1.json diff --git a/app/build.gradle b/app/build.gradle index d85b6982..0fb2de62 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -35,6 +35,12 @@ android { buildConfigField "String", "GIT_BRANCH", "\"${getGitBranch()}\"" buildConfigField "java.util.concurrent.atomic.AtomicBoolean", "TEST", "new java.util.concurrent.atomic.AtomicBoolean(false)" + javaCompileOptions { + annotationProcessorOptions { + arguments = ["room.schemaLocation": "$projectDir/schemas"] + } + } + testInstrumentationRunner "com.beemdevelopment.aegis.AegisTestRunner" testInstrumentationRunnerArguments clearPackageData: 'true' } @@ -104,6 +110,9 @@ android { checkDependencies true disable 'MissingQuantity', 'MissingTranslation' } + buildFeatures { + buildConfig true + } } protobuf { @@ -133,35 +142,34 @@ aboutLibraries { } dependencies { - def cameraxVersion = '1.3.1' + def cameraxVersion = '1.3.4' def glideVersion = '4.16.0' - def guavaVersion = '33.0.0' - def hiltVersion = '2.50' + def guavaVersion = '33.2.1' + def hiltVersion = '2.52' def junitVersion = '4.13.2' - def libsuVersion = '5.2.2' + def libsuVersion = '6.0.0' def roomVersion = "2.6.1" - - annotationProcessor 'androidx.annotation:annotation:1.7.1' + annotationProcessor 'androidx.annotation:annotation:1.8.2' + annotationProcessor "androidx.room:room-compiler:$roomVersion" annotationProcessor "com.google.dagger:hilt-compiler:$hiltVersion" annotationProcessor "com.github.bumptech.glide:compiler:${glideVersion}" - annotationProcessor "androidx.room:room-compiler:$roomVersion" implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.activity:activity:1.8.2' - implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'androidx.activity:activity:1.9.1' + implementation 'androidx.appcompat:appcompat:1.7.0' implementation "androidx.biometric:biometric:1.1.0" implementation "androidx.camera:camera-camera2:$cameraxVersion" implementation "androidx.camera:camera-lifecycle:$cameraxVersion" implementation "androidx.camera:camera-view:$cameraxVersion" - implementation "androidx.core:core:1.12.0" + implementation 'androidx.core:core:1.13.1' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.documentfile:documentfile:1.0.1' - implementation "androidx.lifecycle:lifecycle-process:2.6.2" + implementation 'androidx.lifecycle:lifecycle-process:2.8.4' implementation "androidx.preference:preference:1.2.1" implementation 'androidx.recyclerview:recyclerview:1.3.2' implementation "androidx.room:room-runtime:$roomVersion" - implementation "androidx.viewpager2:viewpager2:1.0.0" + implementation 'androidx.viewpager2:viewpager2:1.1.0' implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' implementation 'com.caverock:androidsvg-aar:1.4' implementation "com.google.dagger:hilt-android:$hiltVersion" @@ -174,37 +182,37 @@ dependencies { implementation "com.github.topjohnwu.libsu:core:${libsuVersion}" implementation "com.github.topjohnwu.libsu:io:${libsuVersion}" implementation "com.google.guava:guava:${guavaVersion}-android" - implementation 'com.google.android.material:material:1.11.0' - implementation 'com.google.protobuf:protobuf-javalite:3.25.1' - implementation 'com.google.zxing:core:3.5.2' - implementation("com.mikepenz:aboutlibraries:11.1.0") { + implementation 'com.google.android.material:material:1.12.0' + implementation 'com.google.protobuf:protobuf-javalite:4.27.3' + implementation 'com.google.zxing:core:3.5.3' + implementation('com.mikepenz:aboutlibraries:11.2.2') { exclude group: 'com.mikepenz', module: 'aboutlibraries-core' } - implementation "com.mikepenz:aboutlibraries-core-android:11.1.0" - implementation 'com.nulab-inc:zxcvbn:1.8.2' + implementation 'com.mikepenz:aboutlibraries-core-android:11.2.2' + implementation 'com.nulab-inc:zxcvbn:1.9.0' implementation 'de.hdodenhof:circleimageview:3.1.0' implementation 'net.lingala.zip4j:zip4j:2.11.5' implementation 'info.guardianproject.trustedintents:trustedintents:0.2' - implementation 'org.bouncycastle:bcprov-jdk18on:1.77' - implementation "org.simpleflatmapper:sfm-csv:8.2.3" + implementation 'org.bouncycastle:bcprov-jdk18on:1.78.1' + implementation 'org.simpleflatmapper:sfm-csv:8.2.3' androidTestAnnotationProcessor "com.google.dagger:hilt-android-compiler:$hiltVersion" androidTestImplementation "com.google.dagger:hilt-android-testing:$hiltVersion" - androidTestImplementation 'androidx.test:core:1.5.0' - androidTestImplementation 'androidx.test:runner:1.5.2' - androidTestImplementation 'androidx.test:rules:1.5.0' - androidTestImplementation 'androidx.test.ext:junit:1.1.5' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' - androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.5.1' - androidTestImplementation 'androidx.test.espresso:espresso-intents:3.5.1' + androidTestImplementation 'androidx.test:core:1.6.1' + androidTestImplementation 'androidx.test:runner:1.6.1' + androidTestImplementation 'androidx.test:rules:1.6.1' + androidTestImplementation 'androidx.test.ext:junit:1.2.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' + androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.6.1' + androidTestImplementation 'androidx.test.espresso:espresso-intents:3.6.1' androidTestImplementation "junit:junit:${junitVersion}" - androidTestUtil 'androidx.test:orchestrator:1.4.2' + androidTestUtil 'androidx.test:orchestrator:1.5.0' - testImplementation 'androidx.test:core:1.5.0' + testImplementation 'androidx.test:core:1.6.1' testImplementation "com.google.guava:guava:${guavaVersion}-jre" testImplementation "junit:junit:${junitVersion}" - testImplementation 'org.json:json:20231013' - testImplementation 'org.robolectric:robolectric:4.11.1' + testImplementation 'org.json:json:20240303' + testImplementation 'org.robolectric:robolectric:4.13' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' } diff --git a/app/schemas/com.beemdevelopment.aegis.database.AppDatabase/1.json b/app/schemas/com.beemdevelopment.aegis.database.AppDatabase/1.json new file mode 100644 index 00000000..811e430c --- /dev/null +++ b/app/schemas/com.beemdevelopment.aegis.database.AppDatabase/1.json @@ -0,0 +1,52 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "392278bdb797d013cb2ada67a3b1cc60", + "entities": [ + { + "tableName": "audit_logs", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `event_type` TEXT NOT NULL, `reference` TEXT, `timestamp` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "_eventType", + "columnName": "event_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "_reference", + "columnName": "reference", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "_timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '392278bdb797d013cb2ada67a3b1cc60')" + ] + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index 2272bfc5..3574bb41 100644 --- a/build.gradle +++ b/build.gradle @@ -6,8 +6,8 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:8.2.0' - classpath 'com.google.dagger:hilt-android-gradle-plugin:2.50' + classpath 'com.android.tools.build:gradle:8.5.2' + classpath 'com.google.dagger:hilt-android-gradle-plugin:2.52' classpath 'com.google.protobuf:protobuf-gradle-plugin:0.9.4' // NOTE: Do not place your application dependencies here; they belong @@ -16,7 +16,7 @@ buildscript { } plugins { - id 'com.mikepenz.aboutlibraries.plugin' version '11.1.0' + id 'com.mikepenz.aboutlibraries.plugin' version '11.2.2' } allprojects { diff --git a/gradle.properties b/gradle.properties index 5eacb8fe..09f93466 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,7 +17,6 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true -android.defaults.buildfeatures.buildconfig=true android.enableJetifier=false android.useAndroidX=true org.gradle.jvmargs=-Xmx8g diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 39c4f8b6..ef80139b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Tue Aug 15 23:01:16 CEST 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 010e2628e8bbe5ab6915b6c96d7de25620e1f7ac Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Sat, 10 Aug 2024 13:13:03 +0200 Subject: [PATCH 020/113] Add an extra check before showing the password reminder popup This is another attempt to fix a rare crash we're seeing in the developer console: ``` Exception android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running? at android.view.ViewRootImpl.setView (ViewRootImpl.java:1423) at android.view.WindowManagerGlobal.addView (WindowManagerGlobal.java:408) at android.view.WindowManagerImpl.addView (WindowManagerImpl.java:148) at android.widget.PopupWindow.invokePopup (PopupWindow.java:1583) at android.widget.PopupWindow.showAsDropDown (PopupWindow.java:1430) at android.widget.PopupWindow.showAsDropDown (PopupWindow.java:1386) at com.beemdevelopment.aegis.ui.AuthActivity.lambda$showPasswordReminder$5 (AuthActivity.java:253) at android.os.Handler.handleCallback (Handler.java:942) at android.os.Handler.dispatchMessage (Handler.java:99) at android.os.Looper.loopOnce (Looper.java:211) at android.os.Looper.loop (Looper.java:300) at android.app.ActivityThread.main (ActivityThread.java:8294) at java.lang.reflect.Method.invoke at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:580) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1028) ``` --- .../main/java/com/beemdevelopment/aegis/ui/AuthActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/AuthActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/AuthActivity.java index d711208c..57746cb1 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/AuthActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/AuthActivity.java @@ -241,7 +241,7 @@ public class AuthActivity extends AegisActivity { popup.setFocusable(false); popup.setOutsideTouchable(true); _textPassword.post(() -> { - if (isFinishing()) { + if (isFinishing() || !_textPassword.isAttachedToWindow()) { return; } From 71c0ad2a085babfb36ffe891f475e7b9d2d8e987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Tue, 6 Aug 2024 00:41:51 +0200 Subject: [PATCH 021/113] Add ability to hide account name in tiles mode --- .../AppearancePreferencesFragment.java | 13 +++--- .../aegis/ui/views/EntryAdapter.java | 4 +- .../aegis/ui/views/EntryHolder.java | 41 +++++++++++++------ app/src/main/res/layout/card_entry_tile.xml | 9 ++-- app/src/main/res/values/strings.xml | 2 +- 5 files changed, 42 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AppearancePreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AppearancePreferencesFragment.java index a0b39a33..b8cb7809 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AppearancePreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AppearancePreferencesFragment.java @@ -116,7 +116,7 @@ public class AppearancePreferencesFragment extends PreferencesFragment { int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition(); _prefs.setCurrentViewMode(ViewMode.fromInteger(i)); viewModePreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.view_mode_titles)[i])); - overrideAccountNamePosition(ViewMode.fromInteger(i) == ViewMode.TILES); + refreshAccountNamePositionText(); dialog.dismiss(); }) .setNegativeButton(android.R.string.cancel, null) @@ -156,6 +156,7 @@ public class AppearancePreferencesFragment extends PreferencesFragment { int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition(); _prefs.setAccountNamePosition(AccountNamePosition.fromInteger(i)); _currentAccountNamePositionPreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.account_name_position_titles)[i])); + refreshAccountNamePositionText(); dialog.dismiss(); }) .setNegativeButton(android.R.string.cancel, null) @@ -164,15 +165,15 @@ public class AppearancePreferencesFragment extends PreferencesFragment { return true; }); - overrideAccountNamePosition(_prefs.getCurrentViewMode() == ViewMode.TILES); + refreshAccountNamePositionText(); } - private void overrideAccountNamePosition(boolean override) { + private void refreshAccountNamePositionText() { + boolean override = (_prefs.getCurrentViewMode() == ViewMode.TILES && _prefs.getAccountNamePosition() == AccountNamePosition.END); + if (override) { - _currentAccountNamePositionPreference.setEnabled(false); - _currentAccountNamePositionPreference.setSummary(getString(R.string.pref_account_name_position_summary_override)); + _currentAccountNamePositionPreference.setSummary(String.format("%s: %s. %s", getString(R.string.selected), getResources().getStringArray(R.array.account_name_position_titles)[_prefs.getAccountNamePosition().ordinal()], getString(R.string.pref_account_name_position_summary_override))); } else { - _currentAccountNamePositionPreference.setEnabled(true); _currentAccountNamePositionPreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.account_name_position_titles)[_prefs.getAccountNamePosition().ordinal()])); } } diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java index 544c16d5..e503b7cf 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java @@ -550,7 +550,7 @@ public class EntryAdapter extends RecyclerView.Adapter case SINGLETAP: if (!handled) { _view.onEntryCopy(entry); - entryHolder.animateCopyText(_viewMode != ViewMode.TILES); + entryHolder.animateCopyText(); _clickedEntry = null; } break; @@ -559,7 +559,7 @@ public class EntryAdapter extends RecyclerView.Adapter if(entry == _clickedEntry) { _view.onEntryCopy(entry); - entryHolder.animateCopyText(_viewMode != ViewMode.TILES); + entryHolder.animateCopyText(); _clickedEntry = null; } else { _clickedEntry = entry; diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryHolder.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryHolder.java index a2fc82c0..b9ce5c18 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryHolder.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryHolder.java @@ -1,7 +1,9 @@ package com.beemdevelopment.aegis.ui.views; import android.os.Handler; +import android.view.Gravity; import android.view.View; +import android.view.ViewGroup; import android.view.animation.Animation; import android.widget.ImageView; import android.widget.RelativeLayout; @@ -108,6 +110,9 @@ public class EntryHolder extends RecyclerView.ViewHolder { _codeGrouping = groupSize; _viewMode = viewMode; _accountNamePosition = accountNamePosition; + if (viewMode.equals(ViewMode.TILES) && _accountNamePosition == AccountNamePosition.END) { + _accountNamePosition = AccountNamePosition.BELOW; + } _selected.clearAnimation(); _selected.setVisibility(View.GONE); @@ -143,15 +148,25 @@ public class EntryHolder extends RecyclerView.ViewHolder { } private void setAccountNameLayout(AccountNamePosition accountNamePosition, Boolean hasBothIssuerAndName) { - if (_viewMode == ViewMode.TILES) { - return; - } - RelativeLayout.LayoutParams profileNameLayoutParams; - RelativeLayout.LayoutParams copiedLayoutParams; + switch (accountNamePosition) { case HIDDEN: _profileName.setVisibility(View.GONE); + + if (_viewMode == ViewMode.TILES) { + _profileCopied.setGravity(Gravity.CENTER_VERTICAL); + ((RelativeLayout.LayoutParams)_profileCopied.getLayoutParams()).removeRule(RelativeLayout.BELOW); + _profileCopied.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT; + _profileCopied.setTextSize(14); + + _profileIssuer.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT; + _profileIssuer.setGravity(Gravity.CENTER_VERTICAL); + _profileIssuer.setTextSize(14); + + _profileName.setVisibility(View.GONE); + } + break; case BELOW: @@ -349,7 +364,7 @@ public class EntryHolder extends RecyclerView.ViewHolder { animateAlphaTo(DEFAULT_ALPHA); } - public void animateCopyText(boolean includeSlideAnimation) { + public void animateCopyText() { _animationHandler.removeCallbacksAndMessages(null); Animation slideDownFadeIn = AnimationsHelper.loadScaledAnimation(itemView.getContext(), R.anim.slide_down_fade_in); @@ -357,23 +372,25 @@ public class EntryHolder extends RecyclerView.ViewHolder { Animation fadeOut = AnimationsHelper.loadScaledAnimation(itemView.getContext(), R.anim.fade_out); Animation fadeIn = AnimationsHelper.loadScaledAnimation(itemView.getContext(), R.anim.fade_in); - if (includeSlideAnimation) { + // Use slideDown animation when user is not using Tiles mode + if (_viewMode != ViewMode.TILES) { _profileCopied.startAnimation(slideDownFadeIn); - View fadeOutView = (_accountNamePosition == AccountNamePosition.BELOW) ? _profileName : _description; - - fadeOutView.startAnimation(slideDownFadeOut); + View fadeOutView = (_accountNamePosition == AccountNamePosition.BELOW) ? _profileName : _description; + fadeOutView.startAnimation(slideDownFadeOut); _animationHandler.postDelayed(() -> { _profileCopied.startAnimation(fadeOut); fadeOutView.startAnimation(fadeIn); }, 3000); } else { + View visibleProfileText = _accountNamePosition == AccountNamePosition.BELOW ? _profileName : _profileIssuer; + _profileCopied.startAnimation(fadeIn); - _profileName.startAnimation(fadeOut); + visibleProfileText.startAnimation(fadeOut); _animationHandler.postDelayed(() -> { _profileCopied.startAnimation(fadeOut); - _profileName.startAnimation(fadeIn); + visibleProfileText.startAnimation(fadeIn); }, 3000); } } diff --git a/app/src/main/res/layout/card_entry_tile.xml b/app/src/main/res/layout/card_entry_tile.xml index d3351fbd..8a18a162 100644 --- a/app/src/main/res/layout/card_entry_tile.xml +++ b/app/src/main/res/layout/card_entry_tile.xml @@ -66,9 +66,9 @@ + android:layout_toEndOf="@id/layoutImage"> - - - Show the account name Only show account name when necessary Only show account names whenever they share the same issuer. Other account names will be hidden. - This setting is overridden by the tiles view mode. Account name will always be shown below the issuer. + This setting is overridden by the tiles view mode. Account name will be shown below the issuer. Import from file Import tokens from a file Android cloud backups From 4ddc42ea51d1ba0d8b0e5882058f6dd992e14821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Thu, 22 Aug 2024 01:05:35 +0200 Subject: [PATCH 022/113] Fix sizing inconsistency of the dots in hidden view --- .../aegis/helpers/CenterVerticalSpan.java | 30 ++++++++++ .../aegis/ui/views/EntryHolder.java | 59 +++++++++++++++++-- 2 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/com/beemdevelopment/aegis/helpers/CenterVerticalSpan.java diff --git a/app/src/main/java/com/beemdevelopment/aegis/helpers/CenterVerticalSpan.java b/app/src/main/java/com/beemdevelopment/aegis/helpers/CenterVerticalSpan.java new file mode 100644 index 00000000..bc94a21c --- /dev/null +++ b/app/src/main/java/com/beemdevelopment/aegis/helpers/CenterVerticalSpan.java @@ -0,0 +1,30 @@ +package com.beemdevelopment.aegis.helpers; + +import android.graphics.Rect; +import android.text.TextPaint; +import android.text.style.MetricAffectingSpan; + +import androidx.annotation.NonNull; + +public class CenterVerticalSpan extends MetricAffectingSpan { + Rect _substringBounds; + + public CenterVerticalSpan(Rect substringBounds) { + _substringBounds = substringBounds; + } + + @Override + public void updateMeasureState(@NonNull TextPaint textPaint) { + applyBaselineShift(textPaint); + } + + @Override + public void updateDrawState(@NonNull TextPaint textPaint) { + applyBaselineShift(textPaint); + } + + private void applyBaselineShift(TextPaint textPaint) { + float topDifference = textPaint.getFontMetrics().top - _substringBounds.top; + textPaint.baselineShift -= (topDifference / 2f); + } +} diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryHolder.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryHolder.java index b9ce5c18..ebfc9c29 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryHolder.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryHolder.java @@ -1,6 +1,11 @@ package com.beemdevelopment.aegis.ui.views; +import android.graphics.Paint; +import android.graphics.Rect; import android.os.Handler; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.RelativeSizeSpan; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -17,6 +22,7 @@ import com.beemdevelopment.aegis.Preferences; import com.beemdevelopment.aegis.R; import com.beemdevelopment.aegis.ViewMode; import com.beemdevelopment.aegis.helpers.AnimationsHelper; +import com.beemdevelopment.aegis.helpers.CenterVerticalSpan; import com.beemdevelopment.aegis.helpers.SimpleAnimationEndListener; import com.beemdevelopment.aegis.helpers.UiRefresher; import com.beemdevelopment.aegis.otp.HotpInfo; @@ -276,6 +282,10 @@ public class EntryHolder extends RecyclerView.ViewHolder { } private void updateCode() { + _profileCode.setText(getOtp()); + } + + private String getOtp() { OtpInfo info = _entry.getInfo(); // In previous versions of Aegis, it was possible to import entries with an empty @@ -292,7 +302,7 @@ public class EntryHolder extends RecyclerView.ViewHolder { otp = _view.getResources().getString(R.string.error_all_caps); } - _profileCode.setText(otp); + return otp; } private String formatCode(String code) { @@ -330,12 +340,53 @@ public class EntryHolder extends RecyclerView.ViewHolder { } public void hideCode() { - String hiddenText = new String(new char[_entry.getInfo().getDigits()]).replace("\0", Character.toString(HIDDEN_CHAR)); - hiddenText = formatCode(hiddenText); - _profileCode.setText(hiddenText); + String code = getOtp(); + String hiddenText = code.replaceAll("\\S", Character.toString(HIDDEN_CHAR)); + updateTextViewWithDots(_profileCode, hiddenText, code); + _hidden = true; } + private void updateTextViewWithDots(TextView textView, String hiddenCode, String code) { + Paint paint = new Paint(); + paint.setTextSize(_profileCode.getTextSize()); + + // Calculate the difference between the actual code width and the dots width + float codeWidth = paint.measureText(code); + float dotsWidth = paint.measureText(hiddenCode); + float scaleFactor = codeWidth / dotsWidth; + scaleFactor = (float)(Math.round(scaleFactor * 10.0) / 10.0); + + // If scale is higher or equal to 0.8, do nothing and proceed with the normal text rendering + if (scaleFactor >= 0.8) { + textView.setText(hiddenCode); + return; + } + + // We need to use an invisible character in order to get the height of the profileCode textview consistent + // Tokens without a space (ie Steam TOTP) will get misaligned without this + SpannableString dotsString = new SpannableString("\u200B" + hiddenCode); + + // Only scale the digits/characters, skip the spaces + int start = 1; + for (int i = 0; i <= dotsString.length(); i++) { + if (i == dotsString.length() || dotsString.charAt(i) == ' ') { + if (i > start) { + dotsString.setSpan(new RelativeSizeSpan(scaleFactor), start, i, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + start = i + 1; + } + } + + Rect dotsRectBounds = new Rect(); + paint.getTextBounds(hiddenCode, 1, hiddenCode.length(), dotsRectBounds); + + // Use custom CenterVerticalSpan to make sure the dots are vertically aligned + dotsString.setSpan(new CenterVerticalSpan(dotsRectBounds), 1, dotsString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + textView.setText(dotsString); + } + public void showIcon(boolean show) { if (show) { _profileDrawable.setVisibility(View.VISIBLE); From 991da65af0b3cf7e83a999e493c8612276f638da Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Mon, 26 Aug 2024 23:06:09 +0200 Subject: [PATCH 023/113] Vendor TextDrawable and TrustedIntents These were the only two libraries we were still getting from JCenter, which was permanently shut down recently: https://jfrog.com/blog/jcenter-sunset/ --- README.md | 5 + app/build.gradle | 2 - app/config/libraries/textdrawable.json | 9 + app/config/libraries/trustedintents.json | 23 + .../3ca920d1875f7ad7ab04a2a331958577.json | 5 + .../java/com/amulyakhare/textdrawable/LICENSE | 22 + .../textdrawable/TextDrawable.java | 316 +++++++++ .../textdrawable/util/ColorGenerator.java | 69 ++ .../GuardianProjectRSA4096.java | 117 ++++ .../trustedintents/ApkSignaturePin.java | 87 +++ .../trustedintents/LICENSE.txt | 502 +++++++++++++++ .../trustedintents/TrustedIntents.java | 271 ++++++++ app/src/main/res/raw/aboutlibraries.json | 603 +++++++++++------- build.gradle | 7 - 14 files changed, 1791 insertions(+), 247 deletions(-) create mode 100644 app/config/libraries/trustedintents.json create mode 100644 app/config/licenses/3ca920d1875f7ad7ab04a2a331958577.json create mode 100644 app/src/main/java/com/amulyakhare/textdrawable/LICENSE create mode 100644 app/src/main/java/com/amulyakhare/textdrawable/TextDrawable.java create mode 100644 app/src/main/java/com/amulyakhare/textdrawable/util/ColorGenerator.java create mode 100644 app/src/main/java/info/guardianproject/GuardianProjectRSA4096.java create mode 100644 app/src/main/java/info/guardianproject/trustedintents/ApkSignaturePin.java create mode 100644 app/src/main/java/info/guardianproject/trustedintents/LICENSE.txt create mode 100644 app/src/main/java/info/guardianproject/trustedintents/TrustedIntents.java diff --git a/README.md b/README.md index 2892a537..daf1b813 100644 --- a/README.md +++ b/README.md @@ -155,3 +155,8 @@ Swing by our Matrix room to interact with other contributors: This project is licensed under the GNU General Public License v3.0. See the [LICENSE](LICENSE) file for details. + +A couple of libraries vendored in Aegis' repository are licensed under a +different license: +- [TextDrawable](app/src/main/java/com/amulyakhare/textdrawable) +- [TrustedIntents](app/src/main/java/info/guardianproject/trustedintents) diff --git a/app/build.gradle b/app/build.gradle index 0fb2de62..10cdded4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -170,7 +170,6 @@ dependencies { implementation 'androidx.recyclerview:recyclerview:1.3.2' implementation "androidx.room:room-runtime:$roomVersion" implementation 'androidx.viewpager2:viewpager2:1.1.0' - implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' implementation 'com.caverock:androidsvg-aar:1.4' implementation "com.google.dagger:hilt-android:$hiltVersion" implementation 'com.github.avito-tech:krop:0.52' @@ -192,7 +191,6 @@ dependencies { implementation 'com.nulab-inc:zxcvbn:1.9.0' implementation 'de.hdodenhof:circleimageview:3.1.0' implementation 'net.lingala.zip4j:zip4j:2.11.5' - implementation 'info.guardianproject.trustedintents:trustedintents:0.2' implementation 'org.bouncycastle:bcprov-jdk18on:1.78.1' implementation 'org.simpleflatmapper:sfm-csv:8.2.3' diff --git a/app/config/libraries/textdrawable.json b/app/config/libraries/textdrawable.json index 529ea1bd..528a6354 100644 --- a/app/config/libraries/textdrawable.json +++ b/app/config/libraries/textdrawable.json @@ -1,5 +1,14 @@ { "uniqueId": "com.amulyakhare:com.amulyakhare.textdrawable", + "funding": [ + + ], + "developers": [ + + ], + "artifactVersion": "1.0.1", + "description": "This light-weight library provides images with letter/text like the Gmail app. It extends the Drawable class thus can be used with existing/custom/network ImageView classes. Also included is a fluent interface for creating drawables and a customizable ColorGenerator.", + "name": "textdrawable", "licenses": [ "MIT" ] diff --git a/app/config/libraries/trustedintents.json b/app/config/libraries/trustedintents.json new file mode 100644 index 00000000..5ba89066 --- /dev/null +++ b/app/config/libraries/trustedintents.json @@ -0,0 +1,23 @@ +{ + "uniqueId": "info.guardianproject.trustedintents:trustedintents", + "funding": [ + + ], + "developers": [ + { + "name": "Guardian Project" + } + ], + "artifactVersion": "0.2", + "description": "TrustedIntents is a library for flexible trusted interactions between Android apps. It is modeled after Android's `signature` protection level for permissions. The key difference is that the framework allows the trusted signature to be set, rather than requiring to match the current app's signature.", + "scm": { + "connection": "scm:https://github.com/guardianproject/TrustedIntents.git", + "url": "scm:https://github.com/guardianproject/TrustedIntents", + "developerConnection": "scm:git@github.com:guardianproject/TrustedIntents.git" + }, + "name": "TrustedIntents", + "website": "https://guardianproject.info/code/trustedintents", + "licenses": [ + "3ca920d1875f7ad7ab04a2a331958577" + ] +} \ No newline at end of file diff --git a/app/config/licenses/3ca920d1875f7ad7ab04a2a331958577.json b/app/config/licenses/3ca920d1875f7ad7ab04a2a331958577.json new file mode 100644 index 00000000..2f0d7c2a --- /dev/null +++ b/app/config/licenses/3ca920d1875f7ad7ab04a2a331958577.json @@ -0,0 +1,5 @@ +{ + "hash": "3ca920d1875f7ad7ab04a2a331958577", + "url": "https://github.com/guardianproject/TrustedIntents/blob/master/LICENSE.txt", + "name": "LGPLv2.1" +} \ No newline at end of file diff --git a/app/src/main/java/com/amulyakhare/textdrawable/LICENSE b/app/src/main/java/com/amulyakhare/textdrawable/LICENSE new file mode 100644 index 00000000..f8646616 --- /dev/null +++ b/app/src/main/java/com/amulyakhare/textdrawable/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014 Amulya Khare + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/app/src/main/java/com/amulyakhare/textdrawable/TextDrawable.java b/app/src/main/java/com/amulyakhare/textdrawable/TextDrawable.java new file mode 100644 index 00000000..f4105715 --- /dev/null +++ b/app/src/main/java/com/amulyakhare/textdrawable/TextDrawable.java @@ -0,0 +1,316 @@ +package com.amulyakhare.textdrawable; + +import android.graphics.*; +import android.graphics.drawable.ShapeDrawable; +import android.graphics.drawable.shapes.OvalShape; +import android.graphics.drawable.shapes.RectShape; +import android.graphics.drawable.shapes.RoundRectShape; + +/** + * @author amulya + * @datetime 14 Oct 2014, 3:53 PM + */ +public class TextDrawable extends ShapeDrawable { + + private final Paint textPaint; + private final Paint borderPaint; + private static final float SHADE_FACTOR = 0.9f; + private final String text; + private final int color; + private final RectShape shape; + private final int height; + private final int width; + private final int fontSize; + private final float radius; + private final int borderThickness; + + private TextDrawable(Builder builder) { + super(builder.shape); + + // shape properties + shape = builder.shape; + height = builder.height; + width = builder.width; + radius = builder.radius; + + // text and color + text = builder.toUpperCase ? builder.text.toUpperCase() : builder.text; + color = builder.color; + + // text paint settings + fontSize = builder.fontSize; + textPaint = new Paint(); + textPaint.setColor(builder.textColor); + textPaint.setAntiAlias(true); + textPaint.setFakeBoldText(builder.isBold); + textPaint.setStyle(Paint.Style.FILL); + textPaint.setTypeface(builder.font); + textPaint.setTextAlign(Paint.Align.CENTER); + textPaint.setStrokeWidth(builder.borderThickness); + + // border paint settings + borderThickness = builder.borderThickness; + borderPaint = new Paint(); + borderPaint.setColor(getDarkerShade(color)); + borderPaint.setStyle(Paint.Style.STROKE); + borderPaint.setStrokeWidth(borderThickness); + + // drawable paint color + Paint paint = getPaint(); + paint.setColor(color); + + } + + private int getDarkerShade(int color) { + return Color.rgb((int)(SHADE_FACTOR * Color.red(color)), + (int)(SHADE_FACTOR * Color.green(color)), + (int)(SHADE_FACTOR * Color.blue(color))); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + Rect r = getBounds(); + + + // draw border + if (borderThickness > 0) { + drawBorder(canvas); + } + + int count = canvas.save(); + canvas.translate(r.left, r.top); + + // draw text + int width = this.width < 0 ? r.width() : this.width; + int height = this.height < 0 ? r.height() : this.height; + int fontSize = this.fontSize < 0 ? (Math.min(width, height) / 2) : this.fontSize; + textPaint.setTextSize(fontSize); + canvas.drawText(text, width / 2, height / 2 - ((textPaint.descent() + textPaint.ascent()) / 2), textPaint); + + canvas.restoreToCount(count); + + } + + private void drawBorder(Canvas canvas) { + RectF rect = new RectF(getBounds()); + rect.inset(borderThickness/2, borderThickness/2); + + if (shape instanceof OvalShape) { + canvas.drawOval(rect, borderPaint); + } + else if (shape instanceof RoundRectShape) { + canvas.drawRoundRect(rect, radius, radius, borderPaint); + } + else { + canvas.drawRect(rect, borderPaint); + } + } + + @Override + public void setAlpha(int alpha) { + textPaint.setAlpha(alpha); + } + + @Override + public void setColorFilter(ColorFilter cf) { + textPaint.setColorFilter(cf); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + @Override + public int getIntrinsicWidth() { + return width; + } + + @Override + public int getIntrinsicHeight() { + return height; + } + + public static IShapeBuilder builder() { + return new Builder(); + } + + public static class Builder implements IConfigBuilder, IShapeBuilder, IBuilder { + + private String text; + + private int color; + + private int borderThickness; + + private int width; + + private int height; + + private Typeface font; + + private RectShape shape; + + public int textColor; + + private int fontSize; + + private boolean isBold; + + private boolean toUpperCase; + + public float radius; + + private Builder() { + text = ""; + color = Color.GRAY; + textColor = Color.WHITE; + borderThickness = 0; + width = -1; + height = -1; + shape = new RectShape(); + font = Typeface.create("sans-serif-light", Typeface.NORMAL); + fontSize = -1; + isBold = false; + toUpperCase = false; + } + + public IConfigBuilder width(int width) { + this.width = width; + return this; + } + + public IConfigBuilder height(int height) { + this.height = height; + return this; + } + + public IConfigBuilder textColor(int color) { + this.textColor = color; + return this; + } + + public IConfigBuilder withBorder(int thickness) { + this.borderThickness = thickness; + return this; + } + + public IConfigBuilder useFont(Typeface font) { + this.font = font; + return this; + } + + public IConfigBuilder fontSize(int size) { + this.fontSize = size; + return this; + } + + public IConfigBuilder bold() { + this.isBold = true; + return this; + } + + public IConfigBuilder toUpperCase() { + this.toUpperCase = true; + return this; + } + + @Override + public IConfigBuilder beginConfig() { + return this; + } + + @Override + public IShapeBuilder endConfig() { + return this; + } + + @Override + public IBuilder rect() { + this.shape = new RectShape(); + return this; + } + + @Override + public IBuilder round() { + this.shape = new OvalShape(); + return this; + } + + @Override + public IBuilder roundRect(int radius) { + this.radius = radius; + float[] radii = {radius, radius, radius, radius, radius, radius, radius, radius}; + this.shape = new RoundRectShape(radii, null, null); + return this; + } + + @Override + public TextDrawable buildRect(String text, int color) { + rect(); + return build(text, color); + } + + @Override + public TextDrawable buildRoundRect(String text, int color, int radius) { + roundRect(radius); + return build(text, color); + } + + @Override + public TextDrawable buildRound(String text, int color) { + round(); + return build(text, color); + } + + @Override + public TextDrawable build(String text, int color) { + this.color = color; + this.text = text; + return new TextDrawable(this); + } + } + + public interface IConfigBuilder { + public IConfigBuilder width(int width); + + public IConfigBuilder height(int height); + + public IConfigBuilder textColor(int color); + + public IConfigBuilder withBorder(int thickness); + + public IConfigBuilder useFont(Typeface font); + + public IConfigBuilder fontSize(int size); + + public IConfigBuilder bold(); + + public IConfigBuilder toUpperCase(); + + public IShapeBuilder endConfig(); + } + + public static interface IBuilder { + + public TextDrawable build(String text, int color); + } + + public static interface IShapeBuilder { + + public IConfigBuilder beginConfig(); + + public IBuilder rect(); + + public IBuilder round(); + + public IBuilder roundRect(int radius); + + public TextDrawable buildRect(String text, int color); + + public TextDrawable buildRoundRect(String text, int color, int radius); + + public TextDrawable buildRound(String text, int color); + } +} diff --git a/app/src/main/java/com/amulyakhare/textdrawable/util/ColorGenerator.java b/app/src/main/java/com/amulyakhare/textdrawable/util/ColorGenerator.java new file mode 100644 index 00000000..7efe7d5d --- /dev/null +++ b/app/src/main/java/com/amulyakhare/textdrawable/util/ColorGenerator.java @@ -0,0 +1,69 @@ +package com.amulyakhare.textdrawable.util; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +/** + * @author amulya + * @datetime 14 Oct 2014, 5:20 PM + */ +public class ColorGenerator { + + public static ColorGenerator DEFAULT; + + public static ColorGenerator MATERIAL; + + static { + DEFAULT = create(Arrays.asList( + 0xfff16364, + 0xfff58559, + 0xfff9a43e, + 0xffe4c62e, + 0xff67bf74, + 0xff59a2be, + 0xff2093cd, + 0xffad62a7, + 0xff805781 + )); + MATERIAL = create(Arrays.asList( + 0xffe57373, + 0xfff06292, + 0xffba68c8, + 0xff9575cd, + 0xff7986cb, + 0xff64b5f6, + 0xff4fc3f7, + 0xff4dd0e1, + 0xff4db6ac, + 0xff81c784, + 0xffaed581, + 0xffff8a65, + 0xffd4e157, + 0xffffd54f, + 0xffffb74d, + 0xffa1887f, + 0xff90a4ae + )); + } + + private final List mColors; + private final Random mRandom; + + public static ColorGenerator create(List colorList) { + return new ColorGenerator(colorList); + } + + private ColorGenerator(List colorList) { + mColors = colorList; + mRandom = new Random(System.currentTimeMillis()); + } + + public int getRandomColor() { + return mColors.get(mRandom.nextInt(mColors.size())); + } + + public int getColor(Object key) { + return mColors.get(Math.abs(key.hashCode()) % mColors.size()); + } +} \ No newline at end of file diff --git a/app/src/main/java/info/guardianproject/GuardianProjectRSA4096.java b/app/src/main/java/info/guardianproject/GuardianProjectRSA4096.java new file mode 100644 index 00000000..2d20f576 --- /dev/null +++ b/app/src/main/java/info/guardianproject/GuardianProjectRSA4096.java @@ -0,0 +1,117 @@ + +package info.guardianproject; + +import info.guardianproject.trustedintents.ApkSignaturePin; + +/** + * This is the second Guardian Project APK signing key. It was generated since + * RSA 1024-bit keys are deprecated. So any new Guardian Project app will be + * signed by this key. It is used to sign these apps: + *
        + *
      • Checkey
      • + *
      • Courier
      • + *
      + * + * @author hans + */ +public final class GuardianProjectRSA4096 extends ApkSignaturePin { + + public GuardianProjectRSA4096() { + fingerprints = new String[] { + "f006a20481c71a690de02e385ab0c9fa4ac1245240f68102682703ba0656867a", + }; + certificates = new byte[][] { + { + 48, -126, 5, -84, 48, -126, 3, -108, 2, 9, 0, -126, -20, 93, -43, 112, 34, + -87, 29, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 48, -127, + -105, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 17, 48, 15, 6, 3, + 85, 4, 8, 12, 8, 78, 101, 119, 32, 89, 111, 114, 107, 49, 17, 48, 15, 6, 3, + 85, 4, 7, 12, 8, 78, 101, 119, 32, 89, 111, 114, 107, 49, 25, 48, 23, 6, 3, + 85, 4, 10, 12, 16, 71, 117, 97, 114, 100, 105, 97, 110, 32, 80, 114, 111, + 106, 101, 99, 116, 49, 29, 48, 27, 6, 3, 85, 4, 3, 12, 20, 103, 117, 97, + 114, 100, 105, 97, 110, 112, 114, 111, 106, 101, 99, 116, 46, 105, 110, + 102, 111, 49, 40, 48, 38, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 1, 22, + 25, 114, 111, 111, 116, 64, 103, 117, 97, 114, 100, 105, 97, 110, 112, 114, + 111, 106, 101, 99, 116, 46, 105, 110, 102, 111, 48, 30, 23, 13, 49, 52, 48, + 53, 49, 52, 49, 55, 53, 55, 50, 57, 90, 23, 13, 52, 49, 48, 57, 50, 56, 49, + 55, 53, 55, 50, 57, 90, 48, -127, -105, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, + 2, 85, 83, 49, 17, 48, 15, 6, 3, 85, 4, 8, 12, 8, 78, 101, 119, 32, 89, + 111, 114, 107, 49, 17, 48, 15, 6, 3, 85, 4, 7, 12, 8, 78, 101, 119, 32, 89, + 111, 114, 107, 49, 25, 48, 23, 6, 3, 85, 4, 10, 12, 16, 71, 117, 97, 114, + 100, 105, 97, 110, 32, 80, 114, 111, 106, 101, 99, 116, 49, 29, 48, 27, 6, + 3, 85, 4, 3, 12, 20, 103, 117, 97, 114, 100, 105, 97, 110, 112, 114, 111, + 106, 101, 99, 116, 46, 105, 110, 102, 111, 49, 40, 48, 38, 6, 9, 42, -122, + 72, -122, -9, 13, 1, 9, 1, 22, 25, 114, 111, 111, 116, 64, 103, 117, 97, + 114, 100, 105, 97, 110, 112, 114, 111, 106, 101, 99, 116, 46, 105, 110, + 102, 111, 48, -126, 2, 34, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, + 1, 5, 0, 3, -126, 2, 15, 0, 48, -126, 2, 10, 2, -126, 2, 1, 0, -51, 108, + 83, -44, 61, 81, 46, 61, 2, -61, 46, 60, 2, -30, 44, 38, -70, -63, -93, + -66, -57, 1, 2, -32, -80, -82, 98, -26, -70, -34, 60, -65, -55, -43, 16, + -63, -89, -104, 50, 108, -26, -2, -3, -55, -77, 47, 75, 89, 99, 12, -32, + 32, 120, -26, -81, 54, 95, -57, -114, -100, -39, -110, -4, 120, 90, 90, + -40, -89, -53, 63, -122, -45, -80, 32, -6, -12, -29, -107, 45, 10, -23, 76, + 5, 112, -15, -63, 48, 35, -61, 0, -107, -110, 44, -46, -126, -30, -30, -33, + 86, 22, 30, 8, -72, 29, 75, 121, 31, -120, 119, 59, -57, 19, -64, 31, 84, + -94, -38, 91, 82, 92, -95, 66, 2, 120, -37, -113, 126, 54, -83, 83, -125, + 122, 110, -106, 80, 59, -127, -72, -23, 64, 105, 20, 25, -41, -3, -61, -44, + 51, -28, 17, 36, -90, -18, -25, 96, 37, -93, -48, 98, 47, 27, 49, 40, -31, + -62, -102, -49, 28, -55, 50, -38, -70, -83, 101, 97, 96, -122, -114, 18, + 47, 119, 117, -7, -55, -64, -1, 96, -120, 61, -89, -70, -7, -89, 113, -41, + 88, 27, 26, 95, -52, 53, 59, 7, 11, 79, 86, 31, -109, -21, 120, -15, 38, + 106, 33, -121, 82, 18, 45, 32, 49, 93, -26, -74, -104, 4, -122, 96, 39, + 126, -24, 16, 119, -45, -119, 110, -31, 55, -109, 53, 53, -11, -58, -124, + -84, 41, -42, 64, 17, -5, -78, -57, -100, 118, -105, -38, -94, 84, -16, + -53, -106, -11, 76, 81, 70, -83, -56, 73, -96, -100, -18, 55, -3, -3, 34, + -97, -62, 59, -17, -79, 91, -9, 122, 95, -108, -121, -76, -62, -72, 61, + -82, 105, -99, -59, 10, 51, 52, 77, -105, -127, 37, 79, 88, -127, 27, 39, + 44, 15, 123, -59, -118, -96, 61, -28, 23, -54, 124, 100, 57, 37, 123, -83, + -124, 11, 123, 73, -53, 18, 119, -39, -13, 46, 123, -55, 4, -91, 114, 93, + -116, -98, 21, 95, -30, -82, -108, 87, -65, -8, 30, 67, 14, 22, 79, -64, + 86, -128, -83, 74, 69, -42, 9, -18, -120, -52, 7, 62, 78, 88, -53, -125, + 41, -122, -91, -34, -110, 111, -118, -25, 25, -83, 90, -95, 84, -121, 95, + 72, -53, -14, -14, -48, 65, 4, 23, 99, 56, 23, -20, 9, 46, 63, 83, -26, + -86, 54, -104, 79, 9, 94, -91, -69, 10, -125, -17, -28, -32, -79, 5, -11, + 37, 103, -46, -75, 71, -119, 39, 48, -53, -51, 118, 43, 28, 68, 14, -33, + -82, -76, -98, 1, 41, 94, -128, -86, 51, -89, 17, -31, 38, -70, -2, -27, + -105, -87, 103, 93, 19, 73, -106, -82, -76, 110, -48, -124, -51, 92, -91, + -51, 22, 1, -48, 52, -127, -24, 26, -77, 4, 22, 33, 24, -128, -1, 9, -42, + 23, -53, 78, 10, -39, -115, -95, 17, 100, 90, 16, -23, -127, -38, 10, -62, + -64, 113, -115, -114, 78, -11, -124, 113, 113, -42, -66, 114, -98, -40, + -41, 2, 3, 1, 0, 1, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, + 0, 3, -126, 2, 1, 0, -54, 125, -113, -9, -45, 82, 2, -79, -87, 31, -17, + -10, 117, 16, 1, 67, -63, 57, -49, -81, -90, 48, 7, -58, 89, -29, 120, 84, + 116, 51, 54, -94, 74, -111, -11, 53, -13, 53, -125, -76, -64, 46, -35, 19, + -19, 25, 36, -82, 66, 113, -14, -6, -63, 83, 15, 8, -77, -74, -94, -53, + -35, -61, -75, 52, 13, -128, 9, 96, 66, 46, 46, -57, 24, -28, -39, -46, 96, + -115, -63, 92, -70, 51, 49, -94, 96, 77, 16, 108, -59, -28, 112, -2, -3, + -87, 27, 56, 118, 29, -95, -76, -70, 34, -105, -24, -104, 70, 24, -88, -29, + -28, -101, -98, 24, -48, -32, -111, 97, 61, -70, -21, -111, 70, -55, 68, + -76, 125, -61, 56, -122, 48, -118, 74, 61, -101, -46, -43, -12, -114, -116, + -57, -108, 91, -109, -62, -117, -76, -48, 109, 81, -22, -113, -73, 64, -61, + 102, 92, -117, -9, -100, 62, -90, 99, 102, -50, -41, -75, 31, 5, -76, -31, + -85, 118, -57, -21, 102, 71, 41, -34, -45, -92, 88, 82, -95, 65, -100, -31, + -28, -85, -37, 94, -52, 72, 39, 55, -42, 18, 29, 115, 23, -106, -2, -54, + -45, 61, 53, 62, 107, 109, -65, 69, 4, -123, 124, -30, -54, -44, 38, 119, + 49, -123, -27, -50, 77, -9, -40, -114, -50, -70, -123, 86, -115, 127, 45, + 42, 23, -25, -83, -81, -38, -84, -3, 99, -36, 12, -67, -39, -110, 21, -40, + -128, 6, -96, -24, -116, -62, 63, 127, 39, 57, -83, -63, 0, 127, -12, 73, + 85, -41, -101, -70, -48, -94, -94, -73, -38, -115, -62, -34, 62, -92, 96, + 16, 6, -19, -84, 38, -93, -117, -52, 32, 92, -21, 123, -117, 81, 50, -71, + 103, 121, 127, 4, -3, -40, 62, 100, 22, -123, -68, -69, -54, -127, -67, 50, + -114, 77, -30, 26, -102, 29, 106, 48, 83, 99, 73, 96, 124, -77, 51, 8, 15, + 40, 72, -108, 105, 62, 119, -113, -90, 57, -62, 127, -57, -21, -40, -109, + 96, 101, 71, -40, -101, 127, 69, 110, 43, 59, -102, -8, -42, -70, -24, 51, + -51, 54, 42, -110, -119, 41, -101, 45, -101, -124, 56, -75, -26, 86, -65, + 54, 21, -88, -30, 79, -26, -127, 121, -102, -48, -25, -62, 99, 76, -90, + -48, -37, 123, 9, 67, 51, -41, -116, 29, 69, 88, 93, -42, 23, 73, -112, 24, + -85, 60, 1, 3, -95, 12, -49, -55, 95, 109, -37, 10, -124, 119, -52, -31, + 91, 55, -67, 99, 87, -55, 97, 25, -9, -119, -41, -98, 100, -14, 70, -44, + -63, 60, -127, -99, 15, 49, 22, -118, -49, 66, -106, 36, -34, -5, 6, -48, + 123, -79, 115, 57, 30, -3, -34, -67, 91, 34, 3, -52, -106, 79, -63, 125, + 123, -16, -120, -53, -98, 34, 86, -60, 94, 78, -91, -34, 0, -8, 73, -119, + -87, 12, -101, -112, -10, -79, 10, 105, -82, 120, -106, -9, 99, 57, -63, + -26, 125, -80, 102, -106, -11, -91, -1, 37, 33 + }, + }; + } +} \ No newline at end of file diff --git a/app/src/main/java/info/guardianproject/trustedintents/ApkSignaturePin.java b/app/src/main/java/info/guardianproject/trustedintents/ApkSignaturePin.java new file mode 100644 index 00000000..ba72b3a2 --- /dev/null +++ b/app/src/main/java/info/guardianproject/trustedintents/ApkSignaturePin.java @@ -0,0 +1,87 @@ + +package info.guardianproject.trustedintents; + +import android.content.pm.Signature; + +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +public abstract class ApkSignaturePin { + + protected String[] fingerprints; // hex-encoded SHA-256 hashes of the certs + protected byte[][] certificates; // array of DER-encoded X.509 certificates + private Signature[] signatures; + + public Signature[] getSignatures() { + if (signatures == null) { + signatures = new Signature[certificates.length]; + for (int i = 0; i < certificates.length; i++) + signatures[i] = new Signature(certificates[i]); + } + return signatures; + } + + /** + * Gets the fingerprint of the first certificate in the signature. + * + * @param algorithm - Which hash to use (e.g. MD5, SHA1, SHA-256) + * @return the fingerprint as hex String + */ + public String getFingerprint(String algorithm) { + try { + MessageDigest md = MessageDigest.getInstance(algorithm); + byte[] hashBytes = md.digest(certificates[0]); + BigInteger bi = new BigInteger(1, hashBytes); + md.reset(); + return String.format("%0" + (hashBytes.length << 1) + "x", bi); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return null; + } + + /** + * Gets the MD5 fingerprint of the first certificate in the signature. + * + * @return the MD5 sum as hex String + */ + public String getMD5Fingerprint() { + return getFingerprint("MD5"); + } + + /** + * Gets the SHA1 fingerprint of the first certificate in the signature. + * + * @return the SHA1 sum as hex String + */ + public String getSHA1Fingerprint() { + return getFingerprint("SHA1"); + } + + /** + * Gets the SHA-256 fingerprint of the first certificate in the signature. + * + * @return the SHA-256 sum as hex String + */ + public String getSHA256Fingerprint() { + return getFingerprint("SHA-256"); + } + + /** + * Compares the calculated SHA-256 cert fingerprint to the stored one. + * + * @return the result of the comparison + */ + public boolean doFingerprintsMatchCertificates() { + if (fingerprints == null || certificates == null) + return false; + String[] calcedFingerprints = new String[certificates.length]; + for (int i = 0; i < calcedFingerprints.length; i++) + calcedFingerprints[i] = getSHA256Fingerprint(); + if (fingerprints.length == 0 || calcedFingerprints.length == 0) + return false; + return Arrays.equals(fingerprints, calcedFingerprints); + } +} \ No newline at end of file diff --git a/app/src/main/java/info/guardianproject/trustedintents/LICENSE.txt b/app/src/main/java/info/guardianproject/trustedintents/LICENSE.txt new file mode 100644 index 00000000..4362b491 --- /dev/null +++ b/app/src/main/java/info/guardianproject/trustedintents/LICENSE.txt @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/app/src/main/java/info/guardianproject/trustedintents/TrustedIntents.java b/app/src/main/java/info/guardianproject/trustedintents/TrustedIntents.java new file mode 100644 index 00000000..10f4b803 --- /dev/null +++ b/app/src/main/java/info/guardianproject/trustedintents/TrustedIntents.java @@ -0,0 +1,271 @@ + +package info.guardianproject.trustedintents; + +import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; +import android.content.pm.Signature; +import android.text.TextUtils; +import android.util.Log; + +import java.lang.reflect.Constructor; +import java.security.cert.CertificateException; +import java.util.LinkedHashSet; + +public class TrustedIntents { + + private static TrustedIntents instance; + + private static PackageManager pm; + + private final LinkedHashSet pinList; + + private TrustedIntents(Context context) { + pm = context.getPackageManager(); + this.pinList = new LinkedHashSet(); + } + + public static TrustedIntents get(Context context) { + if (instance == null) + instance = new TrustedIntents(context); + return instance; + } + + /** + * Check whether a resolved {@link Activity} is trusted. + * + * @param resolveInfo the one to check + * @return whether the {@code Intent}'s receiver is trusted + */ + public boolean isReceiverTrusted(ResolveInfo resolveInfo) { + return isPackageNameTrusted(resolveInfo.activityInfo.packageName); + } + + /** + * Check whether a resolved {@link Activity} is trusted. + * + * @param activityInfo the one to check + * @return whether the {@code Intent}'s receiver is trusted + */ + public boolean isReceiverTrusted(ActivityInfo activityInfo) { + return isPackageNameTrusted(activityInfo.packageName); + } + + /** + * Check an {@link Intent} is trusted based on the {@code packageName} set + * by {@link Intent#setPackage(String)} + * + * @param intent the one to check + * @return whether the {@code Intent}'s receiver is trusted + */ + public boolean isReceiverTrusted(Intent intent) { + if (!isIntentSane(intent)) + return false; + String packageName = intent.getPackage(); + if (TextUtils.isEmpty(packageName)) { + packageName = intent.getComponent().getPackageName(); + } + return isPackageNameTrusted(packageName); + } + + /** + * Check whether a {@code packageName} is trusted. + * + * @param packageName the one to check + * @return whether the {@code packageName} is trusted + */ + public boolean isPackageNameTrusted(String packageName) { + try { + checkTrustedSigner(packageName); + } catch (NameNotFoundException e) { + e.printStackTrace(); + return false; + } catch (CertificateException e) { + return false; + } + return true; + } + + /** + * Returns an {@link Intent} if the sending app is signed by one of + * the trusted signing keys as set in {@link #addTrustedSigner(Class)}. + * + * @returns {@code null} if there is no {@code Intent} or if the + * sender is not trusted. + * @see #addTrustedSigner(Class) + */ + public Intent getIntentFromTrustedSender(Activity activity) { + Intent intent = activity.getIntent(); + String packageName = getCallingPackageName(activity); + if (TextUtils.isEmpty(packageName)) { + return null; + } + if (isPackageNameTrusted(packageName)) { + return intent; + } + return null; + } + + /** + * Get the package name of the {@link Activity} that sent the + * {@link Intent} that started this {@code Activity}. + *

      + * WARNING: If the {@code Activity} has + * {@code android:launchMode="singleInstance"} or {@code "singleTask"}, then + * this method will not disconnect because it is not possible to get the + * calling {@code Activity}, as set by + * {@link Activity#startActivityForResult(Intent, int)} + * + * @param activity the {@code Activity} to check for the {@code Intent} + * @return the package of the sending app or {@code null} if it was not a + * {@code ACTION_CONNECT Intent} or the {@code Intent} was not sent + * with {@link Activity#startActivityForResult(Intent, int)} + */ + public static String getCallingPackageName(Activity activity) { + // getCallingPackage() was unstable until android-18, use this + ComponentName componentName = activity.getCallingActivity(); + if (componentName == null) + return null; + String packageName = componentName.getPackageName(); + if (TextUtils.isEmpty(packageName)) { + Log.e(activity.getClass().getSimpleName(), + "Received Intent without sender! The Intent must be sent using startActivityForResult() and received without launchMode singleTask or singleInstance!"); + } + return packageName; + } + + /** + * This is used to check whether an {@link Intent} that will be sent is + * complete. It should not be used with {@code Intent}s + * that have been received already. + */ + private boolean isIntentSane(Intent intent) { + if (intent == null) + return false; + if (TextUtils.isEmpty(intent.getPackage())) { + ComponentName componentName = intent.getComponent(); + if (componentName == null || TextUtils.isEmpty(componentName.getPackageName())) { + return false; + } + } + return true; + } + + /** + * Add an APK signature that is always trusted for any packageName. + * + * @param cls {@link Class} of the {@link ApkSignaturePin} to trust + * @return boolean + * @throws {@link IllegalArgumentException} the class cannot be instantiated + */ + public boolean addTrustedSigner(Class cls) { + try { + Constructor constructor = cls.getConstructor(); + return pinList.add((ApkSignaturePin) constructor.newInstance((Object[]) null)); + } catch (Exception e) { + e.printStackTrace(); + throw new IllegalArgumentException(e); + } + } + + /** + * Remove an APK signature from the trusted set. + * + * @param cls {@link Class} of the {@link ApkSignaturePin} to remove + */ + public boolean removeTrustedSigner(Class cls) { + for (ApkSignaturePin pin : pinList) { + if (pin.getClass().equals(cls)) { + return pinList.remove(pin); + } + } + return false; + } + + /** + * Remove all {@link ApkSignaturePin}s from the trusted set. + */ + public boolean removeAllTrustedSigners() { + pinList.clear(); + return pinList.isEmpty(); + } + + /** + * Check if a {@link ApkSignaturePin} is trusted. + * + * @param cls {@link Class} of the {@link ApkSignaturePin} to check + */ + public boolean isTrustedSigner(Class cls) { + for (ApkSignaturePin pin : pinList) { + if (pin.getClass().equals(cls)) { + return true; + } + } + return false; + } + + public void checkTrustedSigner(String packageName) + throws NameNotFoundException, CertificateException { + PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + checkTrustedSigner(packageInfo.signatures); + } + + public void checkTrustedSigner(PackageInfo packageInfo) + throws NameNotFoundException, CertificateException { + checkTrustedSigner(packageInfo.signatures); + } + + public void checkTrustedSigner(Signature[] signatures) + throws NameNotFoundException, CertificateException { + if (signatures == null || signatures.length == 0) + throw new CertificateException("signatures cannot be null or empty!"); + for (int i = 0; i < signatures.length; i++) + if (signatures[i] == null || signatures[i].toByteArray().length == 0) + throw new CertificateException("Certificates cannot be null or empty!"); + + // check whether the APK signer is trusted for all apps + for (ApkSignaturePin pin : pinList) + if (areSignaturesEqual(signatures, pin.getSignatures())) + return; // found a matching trusted APK signer + + throw new CertificateException("APK signatures did not match!"); + } + + public boolean areSignaturesEqual(Signature[] sigs0, Signature[] sigs1) { + // TODO where is Android's implementation of this that I can just call? + if (sigs0 == null || sigs1 == null) + return false; + if (sigs0.length == 0 || sigs1.length == 0) + return false; + if (sigs0.length != sigs1.length) + return false; + for (int i = 0; i < sigs0.length; i++) + if (!sigs0[i].equals(sigs1[i])) + return false; + return true; + } + + public void startActivity(Context context, Intent intent) throws CertificateException { + if (!isIntentSane(intent)) + throw new ActivityNotFoundException("The intent was null or empty!"); + String packageName = intent.getPackage(); + if (TextUtils.isEmpty(packageName)) { + packageName = intent.getComponent().getPackageName(); + intent.setPackage(packageName); + } + try { + checkTrustedSigner(packageName); + } catch (NameNotFoundException e) { + e.printStackTrace(); + throw new ActivityNotFoundException(e.getLocalizedMessage()); + } + context.startActivity(intent); + } +} diff --git a/app/src/main/res/raw/aboutlibraries.json b/app/src/main/res/raw/aboutlibraries.json index 22aa6dfb..914eeec3 100644 --- a/app/src/main/res/raw/aboutlibraries.json +++ b/app/src/main/res/raw/aboutlibraries.json @@ -1,6 +1,6 @@ { "metadata": { - "generated": "2024-03-23T12:05:55.114Z" + "generated": "2024-08-26T21:01:22.99Z" }, "libraries": [ { @@ -13,14 +13,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.8.2", + "artifactVersion": "1.9.1", "description": "Provides the base Activity subclass and the relevant hooks to build a composable structure on top.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Activity", - "website": "https://developer.android.com/jetpack/androidx/releases/activity#1.8.2", + "website": "https://developer.android.com/jetpack/androidx/releases/activity#1.9.1", "licenses": [ "Apache-2.0" ], @@ -38,14 +38,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.8.2", + "artifactVersion": "1.9.1", "description": "Kotlin extensions for 'activity' artifact", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Activity Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/activity#1.8.2", + "website": "https://developer.android.com/jetpack/androidx/releases/activity#1.9.1", "licenses": [ "Apache-2.0" ], @@ -63,17 +63,20 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.3.1", + "artifactVersion": "1.4.0", "description": "Java annotation for use on unstable Android API surfaces. When used in conjunction with the Experimental annotation lint checks, this annotation provides functional parity with Kotlin's Experimental annotation.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Experimental annotation", - "website": "https://developer.android.com/jetpack/androidx/releases/annotation#1.3.1", + "website": "https://developer.android.com/jetpack/androidx/releases/annotation#1.4.0", "licenses": [ "Apache-2.0" - ] + ], + "organization": { + "name": "The Android Open Source Project" + } }, { "uniqueId": "androidx.annotation:annotation-jvm", @@ -85,17 +88,20 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.6.0", - "description": "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs.", + "artifactVersion": "1.8.0", + "description": "Provides source annotations for tooling and readability.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, - "name": "Support Annotations", - "website": "https://developer.android.com/jetpack/androidx/releases/annotation#1.6.0", + "name": "Annotation", + "website": "https://developer.android.com/jetpack/androidx/releases/annotation#1.8.0", "licenses": [ "Apache-2.0" - ] + ], + "organization": { + "name": "The Android Open Source Project" + } }, { "uniqueId": "androidx.appcompat:appcompat", @@ -107,17 +113,20 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.6.1", - "description": "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.", + "artifactVersion": "1.7.0", + "description": "Provides backwards-compatible implementations of UI-related Android SDK functionality, including dark mode and Material theming.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, - "name": "Android AppCompat Library", - "website": "https://developer.android.com/jetpack/androidx/releases/appcompat#1.6.1", + "name": "AppCompat", + "website": "https://developer.android.com/jetpack/androidx/releases/appcompat#1.7.0", "licenses": [ "Apache-2.0" - ] + ], + "organization": { + "name": "The Android Open Source Project" + } }, { "uniqueId": "androidx.appcompat:appcompat-resources", @@ -129,17 +138,20 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.6.1", - "description": "The Resources Library is a static library that you can add to your Android application in order to use resource APIs that backport the latest APIs to older versions of the platform. Compatible on devices running API 14 or later.", + "artifactVersion": "1.7.0", + "description": "Provides backward-compatible implementations of resource-related Android SDKfunctionality, including color state list theming.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, - "name": "Android Resources Library", - "website": "https://developer.android.com/jetpack/androidx/releases/appcompat#1.6.1", + "name": "AppCompat Resources", + "website": "https://developer.android.com/jetpack/androidx/releases/appcompat#1.7.0", "licenses": [ "Apache-2.0" - ] + ], + "organization": { + "name": "The Android Open Source Project" + } }, { "uniqueId": "androidx.arch.core:core-common", @@ -217,14 +229,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.3.1", + "artifactVersion": "1.3.4", "description": "Camera2 implementation and extensions for the Jetpack Camera Library, a library providing a consistent and reliable camera foundation that enables great camera driven experiences across all of Android.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Camera2", - "website": "https://developer.android.com/jetpack/androidx/releases/camera#1.3.1", + "website": "https://developer.android.com/jetpack/androidx/releases/camera#1.3.4", "licenses": [ "Apache-2.0" ] @@ -239,14 +251,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.3.1", + "artifactVersion": "1.3.4", "description": "Core components for the Jetpack Camera Library, a library providing a consistent and reliable camera foundation that enables great camera driven experiences across all of Android.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Camera Core", - "website": "https://developer.android.com/jetpack/androidx/releases/camera#1.3.1", + "website": "https://developer.android.com/jetpack/androidx/releases/camera#1.3.4", "licenses": [ "Apache-2.0", "44d1a25c593283261968a15c8cc213cd" @@ -262,14 +274,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.3.1", + "artifactVersion": "1.3.4", "description": "Lifecycle components for the Jetpack Camera Library, a library providing a consistent and reliable camera foundation that enables great camera driven experiences across all of Android.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Camera Lifecycle", - "website": "https://developer.android.com/jetpack/androidx/releases/camera#1.3.1", + "website": "https://developer.android.com/jetpack/androidx/releases/camera#1.3.4", "licenses": [ "Apache-2.0" ] @@ -284,14 +296,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.3.1", + "artifactVersion": "1.3.4", "description": "Video components for the Jetpack Camera Library, a library providing a consistent and reliable camera foundation that enables great camera driven experiences across all of Android.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Camera Video", - "website": "https://developer.android.com/jetpack/androidx/releases/camera#1.3.1", + "website": "https://developer.android.com/jetpack/androidx/releases/camera#1.3.4", "licenses": [ "Apache-2.0" ] @@ -306,14 +318,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.3.1", + "artifactVersion": "1.3.4", "description": "UI tools for the Jetpack Camera Library, a library providing a consistent and reliable camera foundation that enables great camera driven experiences across all of Android.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Camera View", - "website": "https://developer.android.com/jetpack/androidx/releases/camera#1.3.1", + "website": "https://developer.android.com/jetpack/androidx/releases/camera#1.3.4", "licenses": [ "Apache-2.0" ] @@ -406,6 +418,28 @@ "Apache-2.0" ] }, + { + "uniqueId": "androidx.concurrent:concurrent-futures-ktx", + "funding": [ + + ], + "developers": [ + { + "name": "The Android Open Source Project" + } + ], + "artifactVersion": "1.1.0", + "description": "Kotlin Extensions for Androidx implementation of Guava's ListenableFuture", + "scm": { + "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", + "url": "http://source.android.com" + }, + "name": "AndroidX Futures Kotlin Extensions", + "website": "https://developer.android.com/topic/libraries/architecture/index.html", + "licenses": [ + "Apache-2.0" + ] + }, { "uniqueId": "androidx.constraintlayout:constraintlayout", "funding": [ @@ -482,17 +516,20 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.12.0", + "artifactVersion": "1.13.1", "description": "Provides backward-compatible implementations of Android platform APIs and features.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Core", - "website": "https://developer.android.com/jetpack/androidx/releases/core#1.12.0", + "website": "https://developer.android.com/jetpack/androidx/releases/core#1.13.1", "licenses": [ "Apache-2.0" - ] + ], + "organization": { + "name": "The Android Open Source Project" + } }, { "uniqueId": "androidx.core:core-ktx", @@ -504,17 +541,20 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.12.0", + "artifactVersion": "1.13.1", "description": "Kotlin extensions for 'core' artifact", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Core Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/core#1.12.0", + "website": "https://developer.android.com/jetpack/androidx/releases/core#1.13.1", "licenses": [ "Apache-2.0" - ] + ], + "organization": { + "name": "The Android Open Source Project" + } }, { "uniqueId": "androidx.cursoradapter:cursoradapter", @@ -590,7 +630,7 @@ "developers": [ ], - "artifactVersion": "8.2.2", + "artifactVersion": "8.5.0", "description": "", "name": "androidx.databinding:viewbinding", "licenses": [ @@ -673,14 +713,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.2.0", + "artifactVersion": "1.3.0", "description": "Core library to enable emoji compatibility in Kitkat and newer devices to avoid the empty emoji characters.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Android Emoji2 Compat", - "website": "https://developer.android.com/jetpack/androidx/releases/emoji2#1.2.0", + "website": "https://developer.android.com/jetpack/androidx/releases/emoji2#1.3.0", "licenses": [ "Apache-2.0" ] @@ -695,14 +735,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.2.0", + "artifactVersion": "1.3.0", "description": "View helpers for Emoji2", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Android Emoji2 Compat view helpers", - "website": "https://developer.android.com/jetpack/androidx/releases/emoji2#1.2.0", + "website": "https://developer.android.com/jetpack/androidx/releases/emoji2#1.3.0", "licenses": [ "Apache-2.0" ] @@ -818,7 +858,7 @@ ] }, { - "uniqueId": "androidx.lifecycle:lifecycle-common", + "uniqueId": "androidx.lifecycle:lifecycle-common-jvm", "funding": [ ], @@ -827,14 +867,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.7.0", + "artifactVersion": "2.8.4", "description": "Android Lifecycle-Common", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle-Common", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", "licenses": [ "Apache-2.0" ], @@ -852,14 +892,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.7.0", + "artifactVersion": "2.8.4", "description": "Android Lifecycle LiveData", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle LiveData", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", "licenses": [ "Apache-2.0" ], @@ -877,14 +917,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.7.0", + "artifactVersion": "2.8.4", "description": "Android Lifecycle LiveData Core", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle LiveData Core", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", "licenses": [ "Apache-2.0" ], @@ -902,14 +942,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.7.0", + "artifactVersion": "2.8.4", "description": "Kotlin extensions for 'livedata-core' artifact", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "LiveData Core Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", "licenses": [ "Apache-2.0" ], @@ -927,14 +967,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.7.0", + "artifactVersion": "2.8.4", "description": "Kotlin extensions for 'livedata' artifact", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "LiveData Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", "licenses": [ "Apache-2.0" ], @@ -952,14 +992,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.7.0", + "artifactVersion": "2.8.4", "description": "Android Lifecycle Process", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle Process", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", "licenses": [ "Apache-2.0" ], @@ -968,7 +1008,7 @@ } }, { - "uniqueId": "androidx.lifecycle:lifecycle-runtime", + "uniqueId": "androidx.lifecycle:lifecycle-runtime-android", "funding": [ ], @@ -977,14 +1017,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.7.0", + "artifactVersion": "2.8.4", "description": "Android Lifecycle Runtime", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle Runtime", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", "licenses": [ "Apache-2.0" ], @@ -993,7 +1033,7 @@ } }, { - "uniqueId": "androidx.lifecycle:lifecycle-runtime-ktx", + "uniqueId": "androidx.lifecycle:lifecycle-runtime-ktx-android", "funding": [ ], @@ -1002,14 +1042,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.7.0", + "artifactVersion": "2.8.4", "description": "Kotlin extensions for 'lifecycle' artifact", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", "licenses": [ "Apache-2.0" ], @@ -1027,14 +1067,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.7.0", + "artifactVersion": "2.8.4", "description": "Android Lifecycle ViewModel", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle ViewModel", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", "licenses": [ "Apache-2.0" ], @@ -1052,14 +1092,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.7.0", + "artifactVersion": "2.8.4", "description": "Kotlin extensions for 'viewmodel' artifact", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle ViewModel Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", "licenses": [ "Apache-2.0" ], @@ -1077,14 +1117,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.7.0", + "artifactVersion": "2.8.4", "description": "Android Lifecycle ViewModel", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle ViewModel with SavedState", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", "licenses": [ "Apache-2.0" ], @@ -1277,14 +1317,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.3.0", + "artifactVersion": "1.3.1", "description": "Allows libraries to prepopulate ahead of time compilation traces to be read by ART", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "androidx.profileinstaller:profileinstaller", - "website": "https://developer.android.com/jetpack/androidx/releases/profileinstaller#1.3.0", + "website": "https://developer.android.com/jetpack/androidx/releases/profileinstaller#1.3.1", "licenses": [ "Apache-2.0" ] @@ -1333,6 +1373,50 @@ "Apache-2.0" ] }, + { + "uniqueId": "androidx.room:room-common", + "funding": [ + + ], + "developers": [ + { + "name": "The Android Open Source Project" + } + ], + "artifactVersion": "2.6.1", + "description": "Android Room-Common", + "scm": { + "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", + "url": "https://cs.android.com/androidx/platform/frameworks/support" + }, + "name": "Room-Common", + "website": "https://developer.android.com/jetpack/androidx/releases/room#2.6.1", + "licenses": [ + "Apache-2.0" + ] + }, + { + "uniqueId": "androidx.room:room-runtime", + "funding": [ + + ], + "developers": [ + { + "name": "The Android Open Source Project" + } + ], + "artifactVersion": "2.6.1", + "description": "Android Room-Runtime", + "scm": { + "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", + "url": "https://cs.android.com/androidx/platform/frameworks/support" + }, + "name": "Room-Runtime", + "website": "https://developer.android.com/jetpack/androidx/releases/room#2.6.1", + "licenses": [ + "Apache-2.0" + ] + }, { "uniqueId": "androidx.savedstate:savedstate", "funding": [ @@ -1399,6 +1483,50 @@ "Apache-2.0" ] }, + { + "uniqueId": "androidx.sqlite:sqlite", + "funding": [ + + ], + "developers": [ + { + "name": "The Android Open Source Project" + } + ], + "artifactVersion": "2.4.0", + "description": "Android DB", + "scm": { + "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", + "url": "https://cs.android.com/androidx/platform/frameworks/support" + }, + "name": "SQLite", + "website": "https://developer.android.com/jetpack/androidx/releases/sqlite#2.4.0", + "licenses": [ + "Apache-2.0" + ] + }, + { + "uniqueId": "androidx.sqlite:sqlite-framework", + "funding": [ + + ], + "developers": [ + { + "name": "The Android Open Source Project" + } + ], + "artifactVersion": "2.4.0", + "description": "The implementation of Support SQLite library using the framework code.", + "scm": { + "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", + "url": "https://cs.android.com/androidx/platform/frameworks/support" + }, + "name": "SQLite Framework Integration", + "website": "https://developer.android.com/jetpack/androidx/releases/sqlite#2.4.0", + "licenses": [ + "Apache-2.0" + ] + }, { "uniqueId": "androidx.startup:startup-runtime", "funding": [ @@ -1431,7 +1559,7 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "3.5.1", + "artifactVersion": "3.6.1", "description": "The AndroidX Test Library provides an extensive framework for testing Android apps", "name": "AndroidX Test Library", "website": "https://developer.android.com/testing", @@ -1449,7 +1577,7 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.1.5", + "artifactVersion": "1.2.1", "description": "The AndroidX Test Library provides an extensive framework for testing Android apps", "name": "AndroidX Test Library", "website": "https://developer.android.com/testing", @@ -1467,7 +1595,7 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.4.2", + "artifactVersion": "1.5.0", "description": "The AndroidX Test Library provides an extensive framework for testing Android apps", "name": "AndroidX Test Library", "website": "https://developer.android.com/testing", @@ -1476,7 +1604,7 @@ ] }, { - "uniqueId": "androidx.test:annotation", + "uniqueId": "androidx.test:core", "funding": [ ], @@ -1485,7 +1613,7 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.0.1", + "artifactVersion": "1.6.1", "description": "The AndroidX Test Library provides an extensive framework for testing Android apps", "name": "AndroidX Test Library", "website": "https://developer.android.com/testing", @@ -1525,17 +1653,20 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.4.1", + "artifactVersion": "1.5.0", "description": "Android Transition Support Library", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, - "name": "Android Transition Support Library", - "website": "https://developer.android.com/jetpack/androidx/releases/transition#1.4.1", + "name": "Transition", + "website": "https://developer.android.com/jetpack/androidx/releases/transition#1.5.0", "licenses": [ "Apache-2.0" - ] + ], + "organization": { + "name": "The Android Open Source Project" + } }, { "uniqueId": "androidx.vectordrawable:vectordrawable", @@ -1613,17 +1744,20 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.1.0-beta02", + "artifactVersion": "1.1.0", "description": "AndroidX Widget ViewPager2", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "ViewPager2", - "website": "https://developer.android.com/jetpack/androidx/releases/viewpager2#1.1.0-beta02", + "website": "https://developer.android.com/jetpack/androidx/releases/viewpager2#1.1.0", "licenses": [ "Apache-2.0" - ] + ], + "organization": { + "name": "The Android Open Source Project" + } }, { "uniqueId": "androidx.viewpager:viewpager", @@ -1883,7 +2017,7 @@ "developers": [ ], - "artifactVersion": "5.2.2", + "artifactVersion": "6.0.0", "description": "", "name": "com.github.topjohnwu.libsu:core", "licenses": [ @@ -1898,7 +2032,7 @@ "developers": [ ], - "artifactVersion": "5.2.2", + "artifactVersion": "6.0.0", "description": "", "name": "com.github.topjohnwu.libsu:io", "licenses": [ @@ -1913,7 +2047,7 @@ "developers": [ ], - "artifactVersion": "5.2.2", + "artifactVersion": "6.0.0", "description": "", "name": "com.github.topjohnwu.libsu:nio", "licenses": [ @@ -1954,7 +2088,7 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.11.0", + "artifactVersion": "1.12.0", "description": "Material Components for Android is a static library that you can add to your Android application in order to use APIs that provide implementations of the Material Design specification. Compatible on devices running API 14 or later.", "scm": { "connection": "scm:git:https://github.com/material-components/material-components-android.git", @@ -2020,7 +2154,7 @@ "developers": [ ], - "artifactVersion": "2.50", + "artifactVersion": "2.52", "description": "A fast dependency injector for Android and Java.", "scm": { "connection": "scm:git:git://github.com/google/dagger.git", @@ -2045,7 +2179,7 @@ "developers": [ ], - "artifactVersion": "2.50", + "artifactVersion": "2.52", "description": "A fast dependency injector for Android and Java.", "scm": { "connection": "scm:git:git://github.com/google/dagger.git", @@ -2070,7 +2204,7 @@ "developers": [ ], - "artifactVersion": "2.50", + "artifactVersion": "2.52", "description": "A fast dependency injector for Android and Java.", "scm": { "connection": "scm:git:git://github.com/google/dagger.git", @@ -2095,7 +2229,7 @@ "developers": [ ], - "artifactVersion": "2.50", + "artifactVersion": "2.52", "description": "A fast dependency injector for Android and Java.", "scm": { "connection": "scm:git:git://github.com/google/dagger.git", @@ -2120,7 +2254,7 @@ "developers": [ ], - "artifactVersion": "2.50", + "artifactVersion": "2.52", "description": "A fast dependency injector for Android and Java.", "scm": { "connection": "scm:git:git://github.com/google/dagger.git", @@ -2170,7 +2304,7 @@ "developers": [ ], - "artifactVersion": "2.23.0", + "artifactVersion": "2.26.1", "description": "Error Prone is a static analysis tool for Java that catches common programming mistakes at compile-time.", "scm": { "connection": "scm:git:https://github.com/google/error-prone.git", @@ -2216,7 +2350,7 @@ "developers": [ ], - "artifactVersion": "33.0.0-android", + "artifactVersion": "33.2.1-android", "description": "Guava is a suite of core and expanded libraries that include\n utility classes, Google's collections, I/O classes, and\n much more.", "scm": { "connection": "scm:git:https://github.com/google/guava.git", @@ -2256,14 +2390,17 @@ ], "developers": [ - + { + "organisationUrl": "https://www.google.com", + "name": "Tom Ball" + } ], - "artifactVersion": "2.8", + "artifactVersion": "3.0.0", "description": "A set of annotations that provide additional information to the J2ObjC\n translator to modify the result of translation.", "scm": { - "connection": "scm:svn:http://svn.sonatype.org/spice/trunk/oss/oss-parenti-9", - "url": "http://svn.sonatype.org/spice/trunk/oss/oss-parent-9", - "developerConnection": "scm:svn:https://svn.sonatype.org/spice/trunk/oss/oss-parent-9" + "connection": "scm:git:git://github.com/google/j2objc.git", + "url": "http://github.com/google/j2objc", + "developerConnection": "scm:git:ssh://git@github.com/google/j2objc.git" }, "name": "J2ObjC Annotations", "website": "https://github.com/google/j2objc/", @@ -2279,7 +2416,7 @@ "developers": [ ], - "artifactVersion": "3.25.1", + "artifactVersion": "4.27.3", "description": "Lite version of Protocol Buffers library. This version is optimized for code size, but does\n not guarantee API/ABI stability.", "scm": { "connection": "scm:git:https://github.com/protocolbuffers/protobuf.git", @@ -2299,7 +2436,7 @@ "developers": [ ], - "artifactVersion": "3.5.2", + "artifactVersion": "3.5.3", "description": "Core barcode encoding/decoding library", "scm": { "connection": "scm:git:https://github.com/zxing/zxing.git", @@ -2318,46 +2455,27 @@ ], "developers": [ - { - "name": "Mark Davis" - }, - { - "name": "John Emmons" - }, - { - "name": "Doug Felt" - }, - { - "name": "Deborah Goldsmith" - }, - { - "name": "Steven Loomis" - }, - { - "name": "Markus Scherer" - }, - { - "name": "Peter Edberg" - }, - { - "name": "Yoshito Umaoka" - } + ], - "artifactVersion": "73.2", - "description": "International Component for Unicode for Java (ICU4J) is a mature, widely used Java library\n providing Unicode and Globalization support", + "artifactVersion": "75.1", + "description": "International Components for Unicode for Java (ICU4J) is a mature, widely used Java library\n providing Unicode and Globalization support", "scm": { "connection": "scm:git:git://github.com/unicode-org/icu.git", "url": "https://github.com/unicode-org/icu", "developerConnection": "scm:git:git@github.com:unicode-org/icu.git" }, - "name": "ICU4J", + "name": "${proj-title} (${project.artifactId})", "website": "https://icu.unicode.org/", "licenses": [ - "574a0735435695bc65f4863817e32536" - ] + "5be2dcb917a8d00d01258ff45d1f55b2" + ], + "organization": { + "url": "https://icu.unicode.org/", + "name": "Unicode, Inc." + } }, { - "uniqueId": "com.mikepenz:aboutlibraries-core-android-debug", + "uniqueId": "com.mikepenz:aboutlibraries-core-android", "funding": [ ], @@ -2366,7 +2484,7 @@ "name": "Mike Penz" } ], - "artifactVersion": "11.1.0", + "artifactVersion": "11.2.2", "description": "AboutLibraries automatically detects all dependencies of a project and collects their information including the license. Optionally visualising it via the provided ui components.", "scm": { "connection": "scm:git@github.com:mikepenz/AboutLibraries.git", @@ -2412,7 +2530,7 @@ "name": "Yuichi Watanabe" } ], - "artifactVersion": "1.8.2", + "artifactVersion": "1.9.0", "description": "This is a java port of zxcvbn, which is a JavaScript password strength generator.", "scm": { "connection": "https://github.com/nulab/zxcvbn4j.git", @@ -2425,31 +2543,6 @@ "MIT" ] }, - { - "uniqueId": "com.squareup:javawriter", - "funding": [ - - ], - "developers": [ - - ], - "artifactVersion": "2.1.1", - "description": "A utility class which aids in generating Java source files.", - "scm": { - "connection": "scm:git:git://github.com/square/javawriter.git", - "url": "http://github.com/square/javawriter/", - "developerConnection": "scm:git:ssh://git@github.com/square/javawriter.git" - }, - "name": "JavaWriter", - "website": "http://github.com/square/javawriter/", - "licenses": [ - "Apache-2.0" - ], - "organization": { - "url": "http://squareup.com", - "name": "Square, Inc." - } - }, { "uniqueId": "de.hdodenhof:circleimageview", "funding": [ @@ -2496,6 +2589,42 @@ "3ca920d1875f7ad7ab04a2a331958577" ] }, + { + "uniqueId": "jakarta.inject:jakarta.inject-api", + "funding": [ + + ], + "developers": [ + { + "name": "Antoine Sabot-Durand" + }, + { + "name": "Martin Kouba" + }, + { + "name": "Tomas Remes" + }, + { + "name": "Matej Novotny" + } + ], + "artifactVersion": "2.0.1", + "description": "Jakarta Dependency Injection", + "scm": { + "connection": "scm:git:ssh://git@github.com/eclipse-ee4j/injection-api.git", + "url": "https://github.com/eclipse-ee4j/injection-api", + "developerConnection": "scm:git:ssh://git@github.com/eclipse-ee4j/injection-api.git" + }, + "name": "Jakarta Dependency Injection", + "website": "https://github.com/eclipse-ee4j/injection-api", + "licenses": [ + "Apache-2.0" + ], + "organization": { + "url": "https://www.eclipse.org", + "name": "Eclipse Foundation" + } + }, { "uniqueId": "javax.inject:javax.inject", "funding": [ @@ -2582,7 +2711,7 @@ "name": "The Legion of the Bouncy Castle Inc." } ], - "artifactVersion": "1.77", + "artifactVersion": "1.78.1", "description": "The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for JDK 1.8 and up.", "scm": { "url": "https://github.com/bcgit/bc-java" @@ -2608,7 +2737,7 @@ "name": "Suzanne Millstein" } ], - "artifactVersion": "3.41.0", + "artifactVersion": "3.42.0", "description": "checker-qual contains annotations (type qualifiers) that a programmer\nwrites to specify Java code for type-checking by the Checker Framework.", "scm": { "connection": "scm:git:https://github.com/typetools/checker-framework.git", @@ -2701,26 +2830,6 @@ "BSD-3-Clause" ] }, - { - "uniqueId": "org.hamcrest:hamcrest-integration", - "funding": [ - - ], - "developers": [ - - ], - "artifactVersion": "1.3", - "description": "Provides integration between Hamcrest and other testing tools, including JUnit (3 and 4), TestNG, jMock and EasyMock.", - "scm": { - "connection": "scm:git:git@github.com:hamcrest/JavaHamcrest.git", - "url": "https://github.com/hamcrest/JavaHamcrest" - }, - "name": "Hamcrest Integration", - "website": "https://github.com/hamcrest/JavaHamcrest", - "licenses": [ - "BSD-3-Clause" - ] - }, { "uniqueId": "org.hamcrest:hamcrest-library", "funding": [ @@ -2784,7 +2893,7 @@ "name": "Kotlin Team" } ], - "artifactVersion": "1.9.22", + "artifactVersion": "2.0.0", "description": "Kotlin Standard Library", "scm": { "connection": "scm:git:https://github.com/JetBrains/kotlin.git", @@ -2797,6 +2906,54 @@ "Apache-2.0" ] }, + { + "uniqueId": "org.jetbrains.kotlin:kotlin-stdlib-jdk7", + "funding": [ + + ], + "developers": [ + { + "organisationUrl": "https://www.jetbrains.com", + "name": "Kotlin Team" + } + ], + "artifactVersion": "1.8.22", + "description": "Kotlin Standard Library JDK 7 extension", + "scm": { + "connection": "scm:git:https://github.com/JetBrains/kotlin.git", + "url": "https://github.com/JetBrains/kotlin", + "developerConnection": "scm:git:https://github.com/JetBrains/kotlin.git" + }, + "name": "Kotlin Stdlib Jdk7", + "website": "https://kotlinlang.org/", + "licenses": [ + "Apache-2.0" + ] + }, + { + "uniqueId": "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "funding": [ + + ], + "developers": [ + { + "organisationUrl": "https://www.jetbrains.com", + "name": "Kotlin Team" + } + ], + "artifactVersion": "1.8.22", + "description": "Kotlin Standard Library JDK 8 extension", + "scm": { + "connection": "scm:git:https://github.com/JetBrains/kotlin.git", + "url": "https://github.com/JetBrains/kotlin", + "developerConnection": "scm:git:https://github.com/JetBrains/kotlin.git" + }, + "name": "Kotlin Stdlib Jdk8", + "website": "https://kotlinlang.org/", + "licenses": [ + "Apache-2.0" + ] + }, { "uniqueId": "org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm", "funding": [ @@ -2830,7 +2987,7 @@ "name": "JetBrains Team" } ], - "artifactVersion": "1.8.0", + "artifactVersion": "1.8.1", "description": "Coroutines support libraries for Kotlin", "scm": { "url": "https://github.com/Kotlin/kotlinx.coroutines" @@ -2852,7 +3009,7 @@ "name": "JetBrains Team" } ], - "artifactVersion": "1.8.0", + "artifactVersion": "1.8.1", "description": "Coroutines support libraries for Kotlin", "scm": { "url": "https://github.com/Kotlin/kotlinx.coroutines" @@ -2874,7 +3031,7 @@ "name": "JetBrains Team" } ], - "artifactVersion": "1.8.0", + "artifactVersion": "1.8.1", "description": "Coroutines support libraries for Kotlin", "scm": { "url": "https://github.com/Kotlin/kotlinx.coroutines" @@ -2985,7 +3142,7 @@ "name": "Douglas Crockford" } ], - "artifactVersion": "20231013", + "artifactVersion": "20240303", "description": "JSON is a light-weight, language independent, data interchange format.\n See http://www.JSON.org/\n\n The files in this package implement JSON encoders/decoders in Java.\n It also includes the capability to convert between JSON and XML, HTTP\n headers, Cookies, and CDL.\n\n This is a reference implementation. There are a large number of JSON packages\n in Java. Perhaps someday the Java community will standardize on one. Until\n then, choose carefully.", "scm": { "connection": "scm:git:git://github.com/douglascrockford/JSON-java.git", @@ -3040,7 +3197,7 @@ "name": "Remi Forax" } ], - "artifactVersion": "9.6", + "artifactVersion": "9.7", "description": "ASM, a very small and fast Java bytecode manipulation framework", "scm": { "connection": "scm:git:https://gitlab.ow2.org/asm/asm/", @@ -3073,7 +3230,7 @@ "name": "Remi Forax" } ], - "artifactVersion": "9.6", + "artifactVersion": "9.7", "description": "Static code analysis API of ASM, a very small and fast Java bytecode manipulation framework", "scm": { "connection": "scm:git:https://gitlab.ow2.org/asm/asm/", @@ -3106,7 +3263,7 @@ "name": "Remi Forax" } ], - "artifactVersion": "9.6", + "artifactVersion": "9.7", "description": "Usefull class adapters based on ASM, a very small and fast Java bytecode manipulation framework", "scm": { "connection": "scm:git:https://gitlab.ow2.org/asm/asm/", @@ -3139,7 +3296,7 @@ "name": "Remi Forax" } ], - "artifactVersion": "9.6", + "artifactVersion": "9.7", "description": "Tree API of ASM, a very small and fast Java bytecode manipulation framework", "scm": { "connection": "scm:git:https://gitlab.ow2.org/asm/asm/", @@ -3172,7 +3329,7 @@ "name": "Remi Forax" } ], - "artifactVersion": "9.6", + "artifactVersion": "9.7", "description": "Utilities for ASM, a very small and fast Java bytecode manipulation framework", "scm": { "connection": "scm:git:https://gitlab.ow2.org/asm/asm/", @@ -3207,7 +3364,7 @@ "name": "Christian Williams" } ], - "artifactVersion": "4.11.1", + "artifactVersion": "4.13", "description": "An alternative Android testing framework.", "scm": { "connection": "scm:git:git://github.com/robolectric/robolectric.git", @@ -3238,7 +3395,7 @@ "name": "Christian Williams" } ], - "artifactVersion": "4.11.1", + "artifactVersion": "4.13", "description": "An alternative Android testing framework.", "scm": { "connection": "scm:git:git://github.com/robolectric/robolectric.git", @@ -3269,7 +3426,7 @@ "name": "Christian Williams" } ], - "artifactVersion": "4.11.1", + "artifactVersion": "4.13", "description": "An alternative Android testing framework.", "scm": { "connection": "scm:git:git://github.com/robolectric/robolectric.git", @@ -3292,7 +3449,7 @@ "name": "The Android Open Source Projects" } ], - "artifactVersion": "1.0.2", + "artifactVersion": "1.0.12", "description": "Robolectric Nativeruntime Distribution Compat", "scm": { "connection": "https://android.googlesource.com/platform/manifest.git", @@ -3322,7 +3479,7 @@ "name": "Christian Williams" } ], - "artifactVersion": "4.11.1", + "artifactVersion": "4.13", "description": "An alternative Android testing framework.", "scm": { "connection": "scm:git:git://github.com/robolectric/robolectric.git", @@ -3353,7 +3510,7 @@ "name": "Christian Williams" } ], - "artifactVersion": "4.11.1", + "artifactVersion": "4.13", "description": "An alternative Android testing framework.", "scm": { "connection": "scm:git:git://github.com/robolectric/robolectric.git", @@ -3384,7 +3541,7 @@ "name": "Christian Williams" } ], - "artifactVersion": "4.11.1", + "artifactVersion": "4.13", "description": "An alternative Android testing framework.", "scm": { "connection": "scm:git:git://github.com/robolectric/robolectric.git", @@ -3415,7 +3572,7 @@ "name": "Christian Williams" } ], - "artifactVersion": "4.11.1", + "artifactVersion": "4.13", "description": "An alternative Android testing framework.", "scm": { "connection": "scm:git:git://github.com/robolectric/robolectric.git", @@ -3446,7 +3603,7 @@ "name": "Christian Williams" } ], - "artifactVersion": "4.11.1", + "artifactVersion": "4.13", "description": "An alternative Android testing framework.", "scm": { "connection": "scm:git:git://github.com/robolectric/robolectric.git", @@ -3477,7 +3634,7 @@ "name": "Christian Williams" } ], - "artifactVersion": "4.11.1", + "artifactVersion": "4.13", "description": "An alternative Android testing framework.", "scm": { "connection": "scm:git:git://github.com/robolectric/robolectric.git", @@ -3508,7 +3665,7 @@ "name": "Christian Williams" } ], - "artifactVersion": "4.11.1", + "artifactVersion": "4.13", "description": "An alternative Android testing framework.", "scm": { "connection": "scm:git:git://github.com/robolectric/robolectric.git", @@ -3521,37 +3678,6 @@ "MIT" ] }, - { - "uniqueId": "org.robolectric:shadows-versioning", - "funding": [ - - ], - "developers": [ - { - "organisationUrl": "http://google.com", - "name": "Brett Chabot" - }, - { - "organisationUrl": "http://google.com", - "name": "Michael Hoisie" - }, - { - "name": "Christian Williams" - } - ], - "artifactVersion": "4.11.1", - "description": "An alternative Android testing framework.", - "scm": { - "connection": "scm:git:git://github.com/robolectric/robolectric.git", - "url": "git@github.com:robolectric/robolectric.git", - "developerConnection": "scm:git:https://github.com/robolectric/robolectric.git" - }, - "name": "versioning", - "website": "http://robolectric.org", - "licenses": [ - "MIT" - ] - }, { "uniqueId": "org.robolectric:utils", "funding": [ @@ -3570,7 +3696,7 @@ "name": "Christian Williams" } ], - "artifactVersion": "4.11.1", + "artifactVersion": "4.13", "description": "An alternative Android testing framework.", "scm": { "connection": "scm:git:git://github.com/robolectric/robolectric.git", @@ -3601,7 +3727,7 @@ "name": "Christian Williams" } ], - "artifactVersion": "4.11.1", + "artifactVersion": "4.13", "description": "An alternative Android testing framework.", "scm": { "connection": "scm:git:git://github.com/robolectric/robolectric.git", @@ -3805,6 +3931,7 @@ }, "3ca920d1875f7ad7ab04a2a331958577": { "hash": "3ca920d1875f7ad7ab04a2a331958577", + "internalHash": "3ca920d1875f7ad7ab04a2a331958577", "url": "https://github.com/guardianproject/TrustedIntents/blob/master/LICENSE.txt", "name": "LGPLv2.1" }, @@ -3813,10 +3940,10 @@ "url": "https://chromium.googlesource.com/libyuv/libyuv/+/refs/heads/main/README.chromium", "name": "BSD License" }, - "574a0735435695bc65f4863817e32536": { - "hash": "574a0735435695bc65f4863817e32536", - "url": "https://raw.githubusercontent.com/unicode-org/icu/main/icu4c/LICENSE", - "name": "Unicode/ICU License" + "5be2dcb917a8d00d01258ff45d1f55b2": { + "hash": "5be2dcb917a8d00d01258ff45d1f55b2", + "url": "https://raw.githubusercontent.com/unicode-org/icu/main/LICENSE", + "name": "Unicode-3.0" }, "73252b46f36df25ef51a7994de439aea": { "hash": "73252b46f36df25ef51a7994de439aea", diff --git a/build.gradle b/build.gradle index 3574bb41..c703f753 100644 --- a/build.gradle +++ b/build.gradle @@ -24,13 +24,6 @@ allprojects { mavenCentral() google() maven { url 'https://jitpack.io' } - maven { - url 'https://jcenter.bintray.com' - content { - includeModule('com.amulyakhare', 'com.amulyakhare.textdrawable') - includeModule('info.guardianproject.trustedintents', 'trustedintents') - } - } } } From 99e633d61a2e7f327601e4e046199d93594870ad Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Mon, 26 Aug 2024 22:02:30 +0200 Subject: [PATCH 024/113] Replace CircleImageView with ShapeableImageView --- app/build.gradle | 1 - .../aegis/ui/EditEntryActivity.java | 5 ++-- .../main/res/layout/activity_edit_entry.xml | 5 ++-- .../res/layout/card_assign_icon_entry.xml | 10 ++++---- app/src/main/res/layout/card_entry.xml | 10 ++++---- .../main/res/layout/card_entry_compact.xml | 10 ++++---- app/src/main/res/layout/card_entry_small.xml | 10 ++++---- app/src/main/res/layout/card_entry_tile.xml | 10 ++++---- app/src/main/res/raw/aboutlibraries.json | 23 ------------------- app/src/main/res/values/themes.xml | 5 ++++ 10 files changed, 40 insertions(+), 49 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 10cdded4..deff5c20 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -189,7 +189,6 @@ dependencies { } implementation 'com.mikepenz:aboutlibraries-core-android:11.2.2' implementation 'com.nulab-inc:zxcvbn:1.9.0' - implementation 'de.hdodenhof:circleimageview:3.1.0' implementation 'net.lingala.zip4j:zip4j:2.11.5' implementation 'org.bouncycastle:bcprov-jdk18on:1.78.1' implementation 'org.simpleflatmapper:sfm-csv:8.2.3' diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java index 45755b82..68f3db7a 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java @@ -71,6 +71,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog; import com.google.android.material.chip.Chip; import com.google.android.material.chip.ChipGroup; import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.android.material.imageview.ShapeableImageView; import com.google.android.material.textfield.TextInputEditText; import com.google.android.material.textfield.TextInputLayout; @@ -92,8 +93,6 @@ import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; -import de.hdodenhof.circleimageview.CircleImageView; - public class EditEntryActivity extends AegisActivity { private boolean _isNew = false; private boolean _isManual = false; @@ -103,7 +102,7 @@ public class EditEntryActivity extends AegisActivity { // keep track of icon changes separately as the generated jpeg's are not deterministic private boolean _hasChangedIcon = false; private IconPack.Icon _selectedIcon; - private CircleImageView _iconView; + private ShapeableImageView _iconView; private ImageView _saveImageButton; private TextInputEditText _textName; diff --git a/app/src/main/res/layout/activity_edit_entry.xml b/app/src/main/res/layout/activity_edit_entry.xml index f89c1275..6a63c26b 100644 --- a/app/src/main/res/layout/activity_edit_entry.xml +++ b/app/src/main/res/layout/activity_edit_entry.xml @@ -37,12 +37,13 @@ android:layout_width="match_parent" android:layout_height="250dp"> - + android:layout_centerVertical="true" + app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Aegis.ImageView.Circle" /> - + android:layout_gravity="center_vertical" + app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Aegis.ImageView.Circle" /> - + android:layout_gravity="center_vertical" + app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Aegis.ImageView.Circle" /> - + android:layout_alignParentStart="true" + app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Aegis.ImageView.Circle" /> - + android:background="?attr/colorPrimaryAlternative" + app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Aegis.ImageView.Circle" /> - + android:layout_centerVertical="true" + app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Aegis.ImageView.Circle" /> - + android:background="?attr/colorPrimaryAlternative" + app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Aegis.ImageView.Circle" /> - + android:layout_alignParentStart="true" + app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Aegis.ImageView.Circle" /> - + android:background="?attr/colorPrimaryAlternative" + app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Aegis.ImageView.Circle" /> - + android:layout_alignParentStart="true" + app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Aegis.ImageView.Circle" /> - + android:background="?attr/colorPrimaryAlternative" + app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Aegis.ImageView.Circle" /> rounded 8dp + + From 7e1daf731f406299cdeab416d1ca05caeaa39d79 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Tue, 27 Aug 2024 22:05:25 +0200 Subject: [PATCH 025/113] Trim spaces from the search filter --- .../java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java index e503b7cf..0ca0859b 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java @@ -362,7 +362,7 @@ public class EntryAdapter extends RecyclerView.Adapter } public void setSearchFilter(String search) { - _searchFilter = (search != null && !search.isEmpty()) ? search.toLowerCase() : null; + _searchFilter = (search != null && !search.isEmpty()) ? search.toLowerCase().trim() : null; updateShownEntries(); } From b92956deced757aac5d7c4395af1342e26cec805 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Tue, 27 Aug 2024 21:12:15 +0200 Subject: [PATCH 026/113] Account for audit log entries that reference deleted entries This fixes the following crash I noticed in the developer console: ``` Exception java.lang.AssertionError: at com.beemdevelopment.aegis.util.UUIDMap.getByUUID (UUIDMap.java:127) at com.beemdevelopment.aegis.vault.VaultRepository.getEntryByUUID (VaultRepository.java:229) at com.beemdevelopment.aegis.ui.fragments.preferences.AuditLogPreferencesFragment.lambda$onViewCreated$0 (AuditLogPreferencesFragment.java:70) at androidx.lifecycle.LiveData.considerNotify (LiveData.java:133) at androidx.lifecycle.LiveData.dispatchingValue (LiveData.java:151) at androidx.lifecycle.LiveData.setValue (LiveData.java:309) at androidx.lifecycle.LiveData$1.run (LiveData.java:93) at android.os.Handler.handleCallback (Handler.java:959) at android.os.Handler.dispatchMessage (Handler.java:100) at android.os.Looper.loopOnce (Looper.java:232) at android.os.Looper.loop (Looper.java:317) at android.app.ActivityThread.main (ActivityThread.java:8592) at java.lang.reflect.Method.invoke at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:580) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:878) ``` --- .../preferences/AuditLogPreferencesFragment.java | 8 ++++---- .../beemdevelopment/aegis/ui/views/AuditLogHolder.java | 4 ++++ .../com/beemdevelopment/aegis/vault/VaultRepository.java | 4 ++++ app/src/main/res/values/strings.xml | 1 + 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AuditLogPreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AuditLogPreferencesFragment.java index cabbbd61..daa722a8 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AuditLogPreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AuditLogPreferencesFragment.java @@ -6,10 +6,8 @@ import android.view.View; import android.widget.LinearLayout; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.lifecycle.LiveData; -import androidx.lifecycle.Observer; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -64,10 +62,12 @@ public class AuditLogPreferencesFragment extends Fragment { _noAuditLogsView.setVisibility(entries1.isEmpty() ? View.VISIBLE : View.GONE); for (AuditLogEntry entry : entries1) { - VaultEntry referencedEntry = null; if (entry.getReference() != null) { - referencedEntry = _vaultManager.getVault().getEntryByUUID(UUID.fromString(entry.getReference())); + UUID referencedEntryUUID = UUID.fromString(entry.getReference()); + if (_vaultManager.getVault().hasEntryByUUID(referencedEntryUUID)) { + referencedEntry = _vaultManager.getVault().getEntryByUUID(referencedEntryUUID); + } } AuditLogEntryModel auditLogEntryModel = new AuditLogEntryModel(entry, referencedEntry); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/AuditLogHolder.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/AuditLogHolder.java index 9dd1a82c..e0ae166c 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/AuditLogHolder.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/AuditLogHolder.java @@ -61,6 +61,10 @@ public class AuditLogHolder extends RecyclerView.ViewHolder { if (auditLogEntryModel.getReferencedVaultEntry() != null) { VaultEntry referencedVaultEntry = auditLogEntryModel.getReferencedVaultEntry(); _auditLogEntryReference.setText(String.format("%s (%s)", referencedVaultEntry.getIssuer(), referencedVaultEntry.getName())); + _auditLogEntryReference.setVisibility(View.VISIBLE); + } else if (auditLogEntryModel.getAuditLogEntry().getReference() != null) { + _auditLogEntryReference.setText(R.string.audit_log_entry_deleted); + _auditLogEntryReference.setVisibility(View.VISIBLE); } else { _auditLogEntryReference.setVisibility(View.GONE); } diff --git a/app/src/main/java/com/beemdevelopment/aegis/vault/VaultRepository.java b/app/src/main/java/com/beemdevelopment/aegis/vault/VaultRepository.java index 81e1e530..4044a6fe 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/vault/VaultRepository.java +++ b/app/src/main/java/com/beemdevelopment/aegis/vault/VaultRepository.java @@ -225,6 +225,10 @@ public class VaultRepository { _vault.getEntries().add(entry); } + public boolean hasEntryByUUID(UUID uuid) { + return _vault.getEntries().has(uuid); + } + public VaultEntry getEntryByUUID(UUID uuid) { return _vault.getEntries().getByUUID(uuid); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cc455a25..56772ec1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -127,6 +127,7 @@ Vault unlock failed (biometrics) An attempt to unlock the vault with biometrics failed Unknown event type + (deleted) Today at %1$s %1$s at %2$s From 3425256c29624791463da5b116b18a4f8f9ec081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Wed, 28 Aug 2024 00:20:08 +0200 Subject: [PATCH 027/113] Add preference to switch search behavior --- .../beemdevelopment/aegis/Preferences.java | 27 ++++++++ .../aegis/ui/MainActivity.java | 1 + .../BehaviorPreferencesFragment.java | 65 +++++++++++++++++++ .../aegis/ui/views/EntryAdapter.java | 20 +++++- .../aegis/ui/views/EntryListView.java | 5 ++ app/src/main/res/values/arrays.xml | 7 ++ app/src/main/res/values/strings.xml | 7 ++ app/src/main/res/xml/preferences_behavior.xml | 5 ++ 8 files changed, 136 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/Preferences.java b/app/src/main/java/com/beemdevelopment/aegis/Preferences.java index 0ccf77ee..c3077639 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/Preferences.java +++ b/app/src/main/java/com/beemdevelopment/aegis/Preferences.java @@ -33,6 +33,12 @@ public class Preferences { public static final int AUTO_LOCK_ON_BACK_BUTTON = 1 << 1; public static final int AUTO_LOCK_ON_MINIMIZE = 1 << 2; public static final int AUTO_LOCK_ON_DEVICE_LOCK = 1 << 3; + + public static final int SEARCH_IN_ISSUER = 1 << 0; + public static final int SEARCH_IN_NAME = 1 << 1; + public static final int SEARCH_IN_NOTE = 1 << 2; + public static final int SEARCH_IN_GROUPS = 1 << 3; + public static final int BACKUPS_VERSIONS_INFINITE = -1; public static final int[] AUTO_LOCK_SETTINGS = { @@ -41,6 +47,13 @@ public class Preferences { AUTO_LOCK_ON_DEVICE_LOCK }; + public static final int[] SEARCH_BEHAVIOR_SETTINGS = { + SEARCH_IN_ISSUER, + SEARCH_IN_NAME, + SEARCH_IN_NOTE, + SEARCH_IN_GROUPS + }; + private SharedPreferences _prefs; public Preferences(Context context) { @@ -163,6 +176,20 @@ public class Preferences { return _prefs.getInt("pref_auto_lock_mask", def); } + public int getSearchBehaviorMask() { + final int def = SEARCH_IN_ISSUER | SEARCH_IN_NAME; + + return _prefs.getInt("pref_search_behavior_mask", def); + } + + public boolean isSearchBehaviorTypeEnabled(int searchBehaviorType) { + return (getSearchBehaviorMask() & searchBehaviorType) == searchBehaviorType; + } + + public void setSearchBehaviorMask(int searchBehavior) { + _prefs.edit().putInt("pref_search_behavior_mask", searchBehavior).apply(); + } + public boolean isAutoLockEnabled() { return getAutoLockMask() != AUTO_LOCK_OFF; } 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 5411162d..82680e4f 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -195,6 +195,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene _entryListView.setSortCategory(_prefs.getCurrentSortCategory(), false); _entryListView.setViewMode(_prefs.getCurrentViewMode()); _entryListView.setCopyBehavior(_prefs.getCopyBehavior()); + _entryListView.setSearchBehaviorMask(_prefs.getSearchBehaviorMask()); _entryListView.setPrefGroupFilter(_prefs.getGroupFilter()); FloatingActionButton fab = findViewById(R.id.fab); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/BehaviorPreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/BehaviorPreferencesFragment.java index 679021e7..8fa73cda 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/BehaviorPreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/BehaviorPreferencesFragment.java @@ -1,11 +1,13 @@ package com.beemdevelopment.aegis.ui.fragments.preferences; import android.os.Bundle; +import android.widget.Button; import androidx.appcompat.app.AlertDialog; import androidx.preference.Preference; import com.beemdevelopment.aegis.CopyBehavior; +import com.beemdevelopment.aegis.Preferences; import com.beemdevelopment.aegis.R; import com.beemdevelopment.aegis.ui.dialogs.Dialogs; import com.google.android.material.dialog.MaterialAlertDialogBuilder; @@ -16,6 +18,51 @@ public class BehaviorPreferencesFragment extends PreferencesFragment { public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.preferences_behavior); + Preference currentSearchBehaviorPreference = requirePreference("pref_search_behavior"); + currentSearchBehaviorPreference.setSummary(getSearchBehaviorSummary()); + currentSearchBehaviorPreference.setOnPreferenceClickListener((preference) -> { + final int[] items = Preferences.SEARCH_BEHAVIOR_SETTINGS; + final String[] textItems = getResources().getStringArray(R.array.pref_search_behavior_types); + final boolean[] checkedItems = new boolean[items.length]; + for (int i = 0; i < items.length; i++) { + checkedItems[i] = _prefs.isSearchBehaviorTypeEnabled(items[i]); + } + + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.pref_search_behavior_prompt) + .setMultiChoiceItems(textItems, checkedItems, (dialog, index, isChecked) -> { + checkedItems[index] = isChecked; + + boolean containsAtLeastOneCheckedItem = false; + for(boolean b: checkedItems) { + if (b) { + containsAtLeastOneCheckedItem = true; + break; + } + } + + AlertDialog alertDialog = (AlertDialog) dialog; + Button positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); + + positiveButton.setEnabled(containsAtLeastOneCheckedItem); + }) + .setPositiveButton(android.R.string.ok, (dialog, which) -> { + int searchBehavior = 0; + for (int i = 0; i < checkedItems.length; i++) { + if (checkedItems[i]) { + searchBehavior |= items[i]; + } + } + + _prefs.setSearchBehaviorMask(searchBehavior); + currentSearchBehaviorPreference.setSummary(getSearchBehaviorSummary()); + }) + .setNegativeButton(android.R.string.cancel, null); + + Dialogs.showSecureDialog(builder.create()); + return true; + }); + int currentCopyBehavior = _prefs.getCopyBehavior().ordinal(); Preference copyBehaviorPreference = requirePreference("pref_copy_behavior"); copyBehaviorPreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.copy_behavior_titles)[currentCopyBehavior])); @@ -45,4 +92,22 @@ public class BehaviorPreferencesFragment extends PreferencesFragment { return true; }); } + + private String getSearchBehaviorSummary() { + final int[] settings = Preferences.SEARCH_BEHAVIOR_SETTINGS; + final String[] descriptions = getResources().getStringArray(R.array.pref_search_behavior_types); + + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < settings.length; i++) { + if (_prefs.isSearchBehaviorTypeEnabled(settings[i])) { + if (builder.length() != 0) { + builder.append(", "); + } + + builder.append(descriptions[i].toLowerCase()); + } + } + + return getString(R.string.pref_search_behavior_summary, builder.toString()); + } } diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java index 0ca0859b..56f521e2 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java @@ -32,6 +32,7 @@ import com.beemdevelopment.aegis.otp.TotpInfo; import com.beemdevelopment.aegis.ui.models.ErrorCardInfo; import com.beemdevelopment.aegis.util.CollectionUtils; import com.beemdevelopment.aegis.vault.VaultEntry; +import com.beemdevelopment.aegis.vault.VaultGroup; import java.util.ArrayList; import java.util.Collection; @@ -51,6 +52,7 @@ public class EntryAdapter extends RecyclerView.Adapter private List _entries; private List _shownEntries; private List _selectedEntries; + private Collection _groups; private Map _usageCounts; private Map _lastUsedTimestamps; private VaultEntry _focusedEntry; @@ -64,6 +66,7 @@ public class EntryAdapter extends RecyclerView.Adapter private boolean _tapToReveal; private int _tapToRevealTime; private CopyBehavior _copyBehavior; + private int _searchBehaviorMask; private Set _groupFilter; private SortCategory _sortCategory; private ViewMode _viewMode; @@ -130,6 +133,8 @@ public class EntryAdapter extends RecyclerView.Adapter public void setCopyBehavior(CopyBehavior copyBehavior) { _copyBehavior = copyBehavior; } + public void setSearchBehaviorMask(int searchBehaviorMask) { _searchBehaviorMask = searchBehaviorMask; } + public void setPauseFocused(boolean pauseFocused) { _pauseFocused = pauseFocused; } @@ -308,6 +313,7 @@ public class EntryAdapter extends RecyclerView.Adapter Set groups = entry.getGroups(); String issuer = entry.getIssuer().toLowerCase(); String name = entry.getName().toLowerCase(); + String note = entry.getNote().toLowerCase(); if (!_groupFilter.isEmpty()) { if (groups.isEmpty() && !_groupFilter.contains(null)) { @@ -322,7 +328,17 @@ public class EntryAdapter extends RecyclerView.Adapter return false; } - return !issuer.contains(_searchFilter) && !name.contains(_searchFilter); + return ((_searchBehaviorMask & Preferences.SEARCH_IN_ISSUER) == 0 || !issuer.contains(_searchFilter)) + && ((_searchBehaviorMask & Preferences.SEARCH_IN_NAME) == 0 || !name.contains(_searchFilter)) + && ((_searchBehaviorMask & Preferences.SEARCH_IN_NOTE) == 0 || !note.contains(_searchFilter)) + && ((_searchBehaviorMask & Preferences.SEARCH_IN_GROUPS) == 0 || !doesAnyGroupMatchSearchFilter(entry.getGroups(), _searchFilter)); + } + + private boolean doesAnyGroupMatchSearchFilter(Set entryGroupUUIDs, String searchFilter) { + return _groups.stream() + .filter(group -> entryGroupUUIDs.contains(group.getUUID())) + .map(VaultGroup::getName) + .anyMatch(groupName -> groupName.toLowerCase().contains(searchFilter.toLowerCase())); } public void refresh(boolean hard) { @@ -411,6 +427,8 @@ public class EntryAdapter extends RecyclerView.Adapter public Map getUsageCounts() { return _usageCounts; } + public void setGroups(Collection groups) { _groups = groups; } + public void setLastUsedTimestamps(Map lastUsedTimestamps) { _lastUsedTimestamps = lastUsedTimestamps; } public Map getLastUsedTimestamps() { return _lastUsedTimestamps; } diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java index f2ad7089..6bd4fb68 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java @@ -222,6 +222,10 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { _adapter.setCopyBehavior(copyBehavior); } + public void setSearchBehaviorMask(int searchBehaviorMask) { + _adapter.setSearchBehaviorMask(searchBehaviorMask); + } + public List selectAllEntries() { return _adapter.selectAllEntries(); } @@ -599,6 +603,7 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { public void setGroups(Collection groups) { _groups = groups; + _adapter.setGroups(groups); _groupChip.setVisibility(_groups.isEmpty() ? View.GONE : View.VISIBLE); updateDividerDecoration(); diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 2403d9f0..17ac962e 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -125,6 +125,13 @@ @string/pref_auto_lock_type_device_lock + + @string/pref_search_behavior_type_issuer + @string/pref_search_behavior_type_name + @string/pref_search_behavior_type_note + @string/pref_search_behavior_type_groups + + @string/export_format_aegis @string/export_format_html diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cc455a25..4e027399 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -107,6 +107,12 @@ Encrypt the vault and unlock it with a password or biometrics Biometric unlock Allow biometric authentication to unlock the vault + Search through: %s + Search in any of the following fields + Name + Issuer + Note + Groups Change password Set a new password which you will need to unlock your vault @@ -350,6 +356,7 @@ Minimize on copy Minimize the app after copying a token Copy tokens to the clipboard + Search behavior Freeze tokens when tapped Pause automatic refresh of tokens by tapping them. Tokens will not update as long as they are focused. Requires \"Highlight tokens when tapped\" or \"Tap to reveal\". diff --git a/app/src/main/res/xml/preferences_behavior.xml b/app/src/main/res/xml/preferences_behavior.xml index f5fd3535..ac2fa0d2 100644 --- a/app/src/main/res/xml/preferences_behavior.xml +++ b/app/src/main/res/xml/preferences_behavior.xml @@ -8,6 +8,11 @@ android:title="@string/pref_focus_search" android:summary="@string/pref_focus_search_summary" app:iconSpaceReserved="false"/> + Date: Sun, 8 Sep 2024 18:28:07 +0200 Subject: [PATCH 028/113] Update translations from Crowdin --- app/src/main/res/values-ar-rSA/strings.xml | 6 +- app/src/main/res/values-bg-rBG/strings.xml | 73 +++--- app/src/main/res/values-ca-rES/strings.xml | 13 +- app/src/main/res/values-cs-rCZ/strings.xml | 15 +- app/src/main/res/values-da-rDK/strings.xml | 11 + app/src/main/res/values-de-rDE/strings.xml | 51 +++-- app/src/main/res/values-el-rGR/strings.xml | 13 +- app/src/main/res/values-es-rES/strings.xml | 13 +- app/src/main/res/values-eu-rES/strings.xml | 34 +++ app/src/main/res/values-fi-rFI/strings.xml | 20 +- app/src/main/res/values-fr-rFR/strings.xml | 13 +- app/src/main/res/values-fy-rNL/strings.xml | 6 +- app/src/main/res/values-gl-rES/strings.xml | 29 ++- app/src/main/res/values-hu-rHU/strings.xml | 6 +- app/src/main/res/values-in-rID/strings.xml | 34 +++ app/src/main/res/values-it-rIT/strings.xml | 1 - app/src/main/res/values-ja-rJP/strings.xml | 1 - app/src/main/res/values-kn-rIN/strings.xml | 1 - app/src/main/res/values-lv-rLV/strings.xml | 13 +- app/src/main/res/values-nl-rNL/strings.xml | 13 +- app/src/main/res/values-pl-rPL/strings.xml | 2 +- app/src/main/res/values-pt-rBR/strings.xml | 25 +- app/src/main/res/values-pt-rPT/strings.xml | 252 ++++++++++++++++----- app/src/main/res/values-ro-rRO/strings.xml | 12 +- app/src/main/res/values-ru-rRU/strings.xml | 13 +- app/src/main/res/values-sk-rSK/strings.xml | 61 ++++- app/src/main/res/values-sv-rSE/strings.xml | 29 ++- app/src/main/res/values-tr-rTR/strings.xml | 1 - app/src/main/res/values-uk-rUA/strings.xml | 1 + app/src/main/res/values-vi-rVN/strings.xml | 106 +++++---- app/src/main/res/values-zh-rCN/strings.xml | 13 +- app/src/main/res/values-zh-rTW/strings.xml | 12 +- 32 files changed, 694 insertions(+), 199 deletions(-) diff --git a/app/src/main/res/values-ar-rSA/strings.xml b/app/src/main/res/values-ar-rSA/strings.xml index c732e62a..cdaaeff2 100644 --- a/app/src/main/res/values-ar-rSA/strings.xml +++ b/app/src/main/res/values-ar-rSA/strings.xml @@ -46,7 +46,6 @@ اضهِر اسم الحساب اضهِر اسم الحساب فقط عند الضرورة أضهِر أسماء الحسابات فقط عندما يشتركون نفس المصدر. سيتم إخفاء أسماء الحسابات الأخرى. - تجاوز هذا الإعداد عن طريق وضع عرض البلاط. سيتم عرض اسم الحساب دائمًا أسفل المصدر. استيراد من ملف استيراد الرموز من ملف النسخ الاحتياطية السحابية للأندرويد @@ -63,6 +62,7 @@ اصنع نسخة احتياطية قم بعمل نسخة احتياطية يدويًّا عدد الإصدارات المراد الاحتفاظ بها + \u221E احتفظ ب%1$d إصدارات من النسخ الاحتياطية احتفظ بإصدار واحد من النسخ الاحتياطية @@ -71,6 +71,7 @@ احتفظ ب%1$d إصدارات من النسخ الاحتياطية احتفظ ب%1$d إصدارات من النسخ الاحتياطية + الاحتفاظ بعدد غير محدود من النُسخ الاحتياطية استيراد من تطبيق استيراد الرموز من تطبيق (يتطلب الوصول إلى الجذر root) تصدير @@ -333,8 +334,9 @@ نتيجة لذلك، لا يمكن استيراد أي رموز يتم فتح قفل المخزن إعادة تسمية المجموعة + إذا لم يكن الإدخال جزءا من أي مجموعة، يمكن العثور عليه تحت \"بلا مجموعة\". إزالة المجموعة - هل ترغب حقًا في إزالة هذه المجموعة؟ ستتحول المدخلات في هذه المجموعة تلقائيًا إلى "غير مجمّعة" + هل ترغب حقًا في إزالة هذه المجموعة؟ ستتحول المدخلات في هذه المجموعة تلقائيًا إلى \'بلا مجموعة\'. حذف المجموعات غير المستخدمة هل أنت متأكد من أنك تريد حذف جميع المجموعات التي لم يتم تعيينها إلى إدخال؟ حذف حزمة الأيقونات diff --git a/app/src/main/res/values-bg-rBG/strings.xml b/app/src/main/res/values-bg-rBG/strings.xml index 966960b9..7689c3f8 100644 --- a/app/src/main/res/values-bg-rBG/strings.xml +++ b/app/src/main/res/values-bg-rBG/strings.xml @@ -27,7 +27,7 @@ Сигурност Настройки на шифроване, отключване с биометрични данни, автоматично заключване и други настройки за сигурност. Внасяне и изнасяне - Внасяне на резервни копия от Aegis или други приложения за удостоверяване. Ръчно изнасяне на трезора на Aegis. + Внасяне на резервни копия от Aegis или други приложения за удостоверяване. Ръчно изнасяне на хранилището на Aegis. Одитен дневник Списък с всички важни събития, докладвани от приложението. Резервни копия @@ -46,7 +46,7 @@ Име на профила Показване на името на профила при необходимост Показва имената на профилите само когато имат един и същ издател. Другите имена на профили ще бъдат скрити. - Тази настройка е заменена от режима на изглед на плочки. Името на профила винаги ще се показва под издателя. + Тази настройка е заменена от режима на изглед на плочки. Името на профила ще се показва под издателя. Внасяне от файл Внасяне на кодове за защита от файл Облачни резервни копия на Андроид @@ -63,14 +63,16 @@ Създаване на резервно копие Ръчно създава резервни копия Брой версии, които трябва да се запазят + \u221E Запазва се %1$d резервно копие Запазват се %1$d резервни копия - Импортиране от приложение - Импортиране на токени от приложение (изисква root достъп) + Пазене на неограничен брой архивни копия + Внасяне от приложение + Внасяне на кодове за защита от приложение (изисква суперпотребител) Изнасяне - Изнасяне на трезора + Изнасяне на хранилището Припомняне на паролата Изнасяне за Google Authenticator Създава кодове за QR, съвместими с Google Authenticator @@ -84,8 +86,8 @@ Сигурност на екрана Блокирайте екранни снимки и други опити за заснемане на екрана в приложението Показване при докосване - Токените ще бъдат скрити по подразбиране. Докоснете токените, за да разкриете кода. - Време за изчакване, за да се разкрие + Кодовете за защита ще бъдат скрити по подразбиране. Докоснете елемент от списъка, за да се покаже кода. + Период на показване при докосване Авт. заключване Когато %s Изключен @@ -99,14 +101,20 @@ Промяна на паролата за резервни копия и изнасяне Задава нова парола за шифроване на хранилището при създаване на резервни копия и изнасяне. Шифроване - Шифроване на хранилището, отключване с парола или биометрични нанни + Шифроване на хранилището, отключване с парола или биометрични данни Отключване с биометрични данни Разрешава удостоверяване с биометрични данни, за отключване на хранилището + Търсене в: %s + Търсене в следните полета + Име + Издател + Бележка + Групи Смяна на паролата - Задайте нова парола, която ще ви трябва, за да отключите трезора си + Задайте нова парола, с която да отключвате хранилището Не са докладвани събития Няма важни събития, докладвани от приложението - Отключено е хранилище + Хранилището е отключено Хранилището успешно е отключено Създадено е резервно копие Резервно копие на хранилището успешно е създадено @@ -116,16 +124,17 @@ Копие на хранилището е изнесено Споделен е запис Запис е споделен - Неуспешно отключване на хранилище (парола) + Неуспешно отключване на хранилището (парола) Опит за отключване на хранилището с парола е неуспешен - Неуспешно отключване на хранилище (биометрични данни) + Неуспешно отключване на хранилището (биометрични данни) Опит за отключване на хранилището с биометрични данни е неуспешен Неизвестен вид събитие + (премахнато) Днес в %1$s %1$s в %2$s - Шифровайте трезора - По този начин ще бъде изнесен трезора на Aegis от вътрешното хранилище. Изберете формата на данните, в който искате да бъдат изнесени: - На път сте да изнесете нешифровано копие на трезора на Aegis. Това е силно непрепоръчително. + Шифроване на хранилището + По този начин ще бъде изнесено хранилището на Aegis от вътрешната памет. Изберете формата на данните, в който искате да бъдат изнесени: + На път сте да изнесете нешифровано копие на хранилището на Aegis. Това е силно непрепоръчително. Изнасяните данни се шифроват с отделна парола, която се задава в раздел Сигурност. Разбирам риска Aegis (.JSON) @@ -141,26 +150,26 @@ Не са избрани групи, които да бъдат изнесени Изнесени данни от Aegis Authenticator Сигурност - Aegis е 2FA приложение, фокусирано върху сигурността. Токените се съхраняват в трезор, който по желание може да бъде шифрован с избрана от вас парола. Ако нападател получи вашия шифрован файл на трезора, той няма да може да осъществи достъп до съдържанието, без да знае паролата. \n\nПодбрахме опцията, която според нас най-добре пасва на вашето устройство. + Aegis е 2FA приложение, фокусирано върху сигурността. Кодовете за защита се пазят в хранилище, което по желание може да бъде шифровано с избрана от вас парола. Ако нападател получи шифрования файл на хранилището, той няма да може да осъществи достъп до съдържанието му, без паролата. \n\nПодбрахме стойността, която според нас най-добре пасва на устройството. Нищо - За отключване на трезора не е необходима парола, следователно той няма да бъде шифрован. Тази опция не се препоръчва. + За отключване на хранилището не е необходима парола и то няма да бъде шифровано. Това е силно непрепоръчително. Парола - За отключване на трезора е необходима парола. - Предупреждение: Ако забравите паролата си, ще загубите трайно достъп до вашите токени. Няма начин да ги възстановите без паролата. + Хранилището се отключва с парола. + Предупреждение: Ако забравите паролата си, ще загубите трайно достъп до кодовете за защита. Няма начин да ги възстановите без паролата. Биометрични данни - В допълнение към парола, биометрични данни, регистрирани на това устройство, като пръстов отпечатък или лицето Ви, могат да се използват за отключване на трезора. - Отключете трезора - Отключете\nтрезора + В допълнение към паролата, биометрични данни, регистрирани на това устройство, като пръстов отпечатък или лицето ви, могат да се използват за отключване на хранилището. + Отключване на хранилище + Отключете\nхранилището Или докоснете тук, за да използвате биометрични данни Моля въведете парола Моля, въведете име на групата - Моля въведете номер + Въведете число Моля, потвърдете паролата Паролата е неправилна Установена е промяна в настройките за защита на устройството. Посетете „Aegis -> Настройки -> Сигурност -> Биометрично отключване“, изключете и отново включете биометричното отключване. Въведете паролата си. Понякога искаме от вас да я въвеждате, за да не я забравите. Отключване с биометрични данни по подразбиране - Понякога искаме да въведете паролата си, за да не я забравите и така да останете без достъп до трезора. След като я въведете един път, Aegis отново ще използва биометрични данни при отключване, докато не дойде време отново да си припомните паролата. + Понякога искаме от вас да въвеждате паролата си, за да не я забравите и така да останете без достъп до хранилището. След като я въведете веднъж Aegis отново ще използва биометрични данни при отключване, докато не дойде време отново да си припомните паролата. Никога Веднъж седмично Веднъж на две седмици @@ -273,7 +282,7 @@ Грешка: Файлът не е намерен Грешка при прочитане на файла Грешка: Приложението не е инсталирано - Инсталираното издание на %s не се поддържа. В последните издания някои от файловете, необходимите при внасяне са шифровани и недостъпни за Aegis. Евентуален опит за внасяне би довел до грешка. Искате ли да продължите въпреки това? + Инсталираното издание на %s не се поддържа. В последните издания някои от файловете, необходими при внасяне са шифровани и недостъпни за Aegis. Евентуален опит за внасяне би довел до грешка. Желаете ли въпреки това да продължите? Грешка: неуспешнополучаване на достъп до правата на суперпотребителя %d запис е внесен @@ -293,14 +302,15 @@ Грешка при разчитане на QR кода Приложението Aegis е съвместимо със собственическия алгоритъм за 2FA на Microsoft. Не забравяйте да изберете „Настройка на приложение без известия“, когато настройвате 2FA в Office 365. Установени са частично изнасени данни за Google Authenticator - Няколко QR кода не са внесени. Следните кодове липсват:\n\n%s\n\nМожете да продължите с частично внесените данни, но е препоръчително да направите нов опит с всички QR кодове без да рискувате загуба на кодове за достъп. + Няколко QR кода не са внесени. Следните кодове липсват:\n\n%s\n\nМожете да продължите с частично внесените данни, но е препоръчително да направите нов опит с всички QR кодове без да рискувате загуба на кодове за защите. • QR код %d Внасяне на %d кода за достъп въпреки това Грешка при внасяне към Google Authenticator Изнесеното съдържа части от несвързана порция кодове. Внасяйте всяка порция поотделно. - Като резултат не са внесени кодове за достъп + Като резултат не са внесени кодове за защита Отключване на хранилището Преименуване на група + Ако запис не принадлежи към никоя група, може да бъде намерен в „Без група“. Премахване на група Наистина ли искате да премахнете тази група? Записите в нея ще бъдат преместени в групата „Без група“. Премахване на неизползваните групи @@ -336,9 +346,10 @@ Прави записите в списъка по-лесни за различаване един от друг, като при докосване временно ги осветява Свиване при копиране Приложението се свива при копиране на код за достъп - Копиране на кодове за достъп в междинната памет + Копиране на кодове за защита в междинната памет + Начин на търсене Замразяване на запис при докосване - Спира автоматичното опресняване на кодовете когато са избрани. Необходимо е да е включено или „Осветяване на запис при докосване“, или „Показване при докосване“. + Спира автоматичното опресняване на кодовете след докосване. Необходимо е да е включено или „Осветяване на запис при докосване“, или „Показване при докосване“. За да бъде показана цифровата клавиатура въведете паролата си. Имайте предвид, че това е удачно само ако вашата парола се състои само от цифри Грешка при задаване на цифрова клавиатура Не е възможно да зададете цифрова клавиатура. Паролата ви трябва да се състои само от цифри. @@ -415,7 +426,7 @@ Настройки на резервни копия Хранилището е било изнесено в чист текст Без повторно показване на предупреждението - Скоро е правено нешифровано резервно копие на хранилището. С оглед сигурността на кодовете за достъп е препоръчително да изтриете нешифрования файл след като вече не е необходим. + Скоро е правено нешифровано резервно копие на хранилището. С оглед сигурността на кодовете за защита е препоръчително да изтриете нешифрования файл след като вече не е необходим. Смяна на камера Няма кодове, които да бъдат показани. Добавете записи от бутона със знак плюс в долния десен ъгъл Не са открити записи @@ -460,7 +471,7 @@ Изпразване на хранилището Aegis получи сигнал за тревога, но настройката е изключена, пренебрегване на сигнала Изтриване на хранилището при сигнал за тревога - Изтрива хранилището, когато от Ripple се получи сигнал за тревога + Изтрива хранилището, когато от Ripple е получен сигнал за тревога Внасяне на хранилище на Aegis Искате да внесете от друго приложение за 2FA? Завършете помощника и посетете меню Настройки. diff --git a/app/src/main/res/values-ca-rES/strings.xml b/app/src/main/res/values-ca-rES/strings.xml index 4dd6d845..7c6ce971 100644 --- a/app/src/main/res/values-ca-rES/strings.xml +++ b/app/src/main/res/values-ca-rES/strings.xml @@ -46,7 +46,7 @@ Mostra el nom del compte Mostra el nom del compte només quan sigui necessari Mostra el nom de compte només quan es comparteixi el mateix emissor. Altres noms de compte estaran ocults. - S\'omet aquesta configuració en usar la visualització en mosaic. Els noms de compte es mostraran sempre a sota de l\'emissor. + S\'omet aquesta configuració en usar la visualització en mosaic. Els noms de compte es mostraran a sota de l\'emissor. Importa des d\'un fitxer Importar fitxes des d\'un fitxer Copies al núvol d\'Android @@ -63,10 +63,12 @@ Disparador de còpia Llançar còpia manualment Nombre de versions a mantenir + \u221E Mantindre %1$d versions a la còpia Mantindre %1$d versions a la còpia + Mantén un nombre infinit de versions de la còpia de seguretat Importar des d\'app Importar fitxes des d\'una aplicació (cal root) Exporta @@ -102,6 +104,12 @@ Xifra la caixa forta i desbloqueja-la amb contrasenya o biomètrics Desbloqueig biomètric Permet l\'autenticació biomètrica per a desbloquejar la caixa forta + Busca a: %s + Buscar en qualsevol d\'aquests camps + Nom + Emissor + Nota + Grups Canvia la contrasenya Defineix una nova contrasenya per a desbloquejar la caixa forta Cap esdeveniment registrat @@ -121,6 +129,7 @@ No s\'ha pogut desbloquejar la volta (dades biomètriques) Hi ha hagut un intent de desbloquejar la volta amb dades biomètriques incorrectes Tipus d\'esdeveniment desconegut + (esborrat) Avui a les %1$s %1$s a les %2$s Xifra la caixa forta @@ -301,6 +310,7 @@ Com a resultat, no es poden importar tokens Desbloquejant la caixa forta Canvia el nom del grup + Si una entrada no pertany a cap grup, es podrà trobar a \"Sense grup\". Elimina el grup Segur que vols eliminar aquest grup? Les entrades canviaran automàticament a \"Sense grup\". Esborrar grups no utilitzats @@ -337,6 +347,7 @@ Minimitzar al copiar Minimitzar l\'aplicació després de copiar una fitxa Copia les fitxes al porta-retalls + Comportament de la cerca Congela la fitxa al tocar Pausa l\'actualització automàtica de la fitxa al tocar-la. No s\'actualitzará mentre estigui marcada. Cal tenir \"Il·lumina les fitxes al tocar\" o \"Toca per a mostrar\". Introdueix la teva contrasenya per a activar el teclat PIN. Això només funcionarà si la contrasenya només té dígits diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index bf110758..486feae3 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -46,7 +46,7 @@ Zobrazit název účtu Název účtu zobrazit pouze v případě potřeby Názvy účtů zobrazit pouze, pokud mají stejného poskytovatele. Ostatní názvy účtů budou skryty. - Toto nastavení je přepsáno režimem zobrazení názvů. Název účtu bude vždy zobrazen pod poskytovatelem. + Toto nastavení je přepsáno režimem zobrazení dlaždic. Název účtu bude zobrazen pod poskytovatelem. Importovat ze souboru Importovat tokeny ze souboru Cloudové zálohování systému Android @@ -63,12 +63,14 @@ Spustit zálohování Ručně spustit zálohování Počet verzí k uchování + \u221E Uchovat %1$d verzi zálohy Uchovat %1$d verze zálohy Uchovat %1$d verzí zálohy Uchovat %1$d verzí zálohy + Ponechat nekonečný počet verzí zálohy Importovat z aplikace Importovat tokeny z aplikace (vyžaduje root přístup) Exportovat @@ -106,6 +108,12 @@ Šifrovat trezor a odemykat jej pomocí hesla, nebo biometrie Biometrické odemknutí Povolit biometrické ověření pro odemčení trezoru + Hledat v: %s + Hledat ve kterémkoli z následujících polí + Název + Vydavatel + Poznámka + Skupiny Změnit heslo Nastavení nového hesla potřebného pro odemčení trezoru Žádné nahlášené události @@ -125,6 +133,7 @@ Odemčení trezoru selhalo (biometrika) Pokus o odemknutí trezoru pomocí biometriky se nezdařil Neznámý typ události + (odstraněno) Dnes v %1$s %1$s v %2$s Šifrovat trezor @@ -317,6 +326,7 @@ Nebyly importovány žádné tokeny Odemykání trezoru Přejmenovat skupinu + Pokud není záznam součástí žádné skupiny, najdete jej v kategorii „Žádná skupina“. Odstranit skupinu Opravdu chcete odstranit tuto skupinu? Záznamy z ní budou automaticky přemístěny do „Žádná skupina“. Odstranit nepoužívané skupiny @@ -353,6 +363,7 @@ Minimalizovat při kopírování Minimalizovat aplikaci po zkopírování tokenu Zkopírovat tokeny do schránky + Chování vyhledávání Zmrazit tokeny po klepnutí Pozastavit automatické obnovování tokenů klepnutím na ně. Tokeny nebudou aktualizovány, dokud jsou zaměřeny. Vyžaduje \"Zvýraznit tokeny po klepnutí\" nebo \"Klepnutím zobrazit\". Zadejte své heslo pro povolení PIN klávesnice. Toto funguje jen pokud používáte číselné heslo. @@ -368,7 +379,7 @@ Normální Kompaktní Malý - Názvy + Dlaždice Neznámý poskytovatel Neznámý název účtu diff --git a/app/src/main/res/values-da-rDK/strings.xml b/app/src/main/res/values-da-rDK/strings.xml index 40d41544..c5d3479f 100644 --- a/app/src/main/res/values-da-rDK/strings.xml +++ b/app/src/main/res/values-da-rDK/strings.xml @@ -63,10 +63,12 @@ Udløs sikkerhedskopiering Udløs manuelt en sikkerhedskopiering Antal versioner at beholde + \u221E Behold %1$d version af sikkerhedskopien Behold %1$d versioner af sikkerhedskopien + Opbevar et uendeligt antal versioner af sikkerhedskopien Import fra app Importér tokens fra en app (kræver root-adgang) Export @@ -102,6 +104,12 @@ Kryptér og oplås Boksen med adgangskode/biometri Biometrisk oplåsning Tillad biometrisk godkendelse for at oplåse Boksen + Søg gennem: %s + Søg i ethvert af de flg. felter + Navn + Udsteder + Notat + Grupper Skift adgangskode Sæt ny adgangskode til brug for oplåsning af din Boks Ingen rapporterede hændelser @@ -121,6 +129,7 @@ Boksoplåsning mislykkedes (biometri) Et boksoplåsningsforsøg med biometri mislykkedes Ukendt hændelsestype + (slettet) I dag kl. %1$s %1$s kl. %2$s Kryptér boksen @@ -301,6 +310,7 @@ Som konsekvens, kan ingen tokener importeres Låser boksen op Omdøb gruppe + Er en post ikke en del af en gruppe, kan den findes under \"Ingen gruppe\". Fjern gruppe Sikker på, at denne gruppe skal fjernes? Poster heri vil automatisk skifte til \'Ingen gruppe\'. Slet ubrugte grupper @@ -337,6 +347,7 @@ Minimér under kopiering Minimér appen efter kopiering af et token Kopiér tokener til udklipsholder + Søgeadfærd Frys tokener ved tryk Pausér automatisk opdatering af tokener ved at trykke på dem. Tokener opdateres ikke, så længe de er fokuseret. Kræver \"Fremhæv tokener ved tryk\" eller \"Tryk for at vise\". Angiv adgangskoden for at aktivere PIN-tastaturet. Bemærk, at dette kun virker, såfremt adgangskoden alene består af cifre diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index f69d5b55..21c7d655 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -6,7 +6,7 @@ Übertragen Symbol bearbeiten Verwendungszähler zurücksetzen - Anzahl der Verwendungen dieses Eintrags auf 0 setzen? + Den Verwendungszähler dieses Eintrags auf 0 setzen? Standardsymbol wiederherstellen Verwerfen Speichern @@ -26,12 +26,12 @@ Das Design, die Sprache und andere Einstellungen anpassen, die das Erscheinungsbild der App betreffen. Sicherheit Verschlüsselung, biometrisches Entsperren, automatisches Sperren und andere Sicherheitseinstellungen konfigurieren. - Importieren & exportieren + Importieren und exportieren Sicherungskopien von Aegis oder anderen Authentifizierungs-Apps importieren und Exportdateien der Aegis-Datenbank erstellen. - Überwachungsprotokoll - Hier findest du eine Liste aller wichtigen Ereignisse, die innerhalb der App registriert wurden. + Audit-Log + Liste aller wichtigen Ereignisse, die innerhalb der App registriert wurden. Sicherungen - Automatisierte Sicherungen an einem Speicherort deiner Wahl oder das Verwenden des Cloud-Sicherungssystems von Android einrichten. + Automatisierte Sicherungen zu einem gewünschten Speicherort einrichten oder das Android-eigenen Cloud-Sicherungssystems aktivieren. Symbolpakete Symbolpakete verwalten und importieren. Design @@ -44,9 +44,9 @@ Zifferngruppierung Anzahl der Ziffern für das Gruppieren von Codes festlegen Kontonamen anzeigen - Kontonamen nur anzeigen, wenn notwendig + Kontonamen nur bei Bedarf anzeigen Kontonamen nur anzeigen, wenn sie denselben Herausgeber haben. Andere Kontonamen werden ausgeblendet. - Diese Einstellung wird durch die Kachelansicht überschrieben. Kontonamen werden immer unterhalb des Herausgebers angezeigt. + Diese Einstellung wird durch die Kachelansicht überschrieben. Der Kontoname wird unterhalb des Herausgebers angezeigt. Aus Datei importieren Token aus einer Datei importieren Cloud-Sicherungen von Android @@ -58,15 +58,17 @@ Erinnerung zur Sicherung der Datenbank anzeigen, falls die letzten Änderungen nicht gesichert wurden. Erinnerung für Sicherungen deaktivieren Das Deaktivieren dieser Erinnerung bedeutet, dass Aegis nicht mitteilt, ob Änderungen vorgenommen wurden, die noch nicht gesichert sind. Dadurch besteht die Gefahr, dass der Zugriff auf deine Token verloren geht. Möchtest du die Erinnerung wirklich deaktivieren? - Ordner für Sicherungsdateien + Sicherungsverzeichnis Sicherungskopien werden gespeichert in - Sicherungskopie auslösen + Sicherung auslösen Manuell eine Sicherung auslösen Anzahl der zu behaltenden Versionen + \u221E - %1$d Version der Sicherung behalten - %1$d Versionen der Sicherung behalten + %1$d Version der Sicherungsdatei speichern + %1$d Versionen der Sicherungsdatei speichern + Unendlich viele Versionen der Sicherungsdatei speichern Aus App importieren Token aus einer App importieren (benötigt Root-Zugriff) Exportieren @@ -79,13 +81,13 @@ %d inkompatibler Eintrag wurde übersprungen %d inkompatible Einträge wurden übersprungen - Zeigt %s eine Erinnerung zur Eingabe des Passworts an, damit du es nicht vergisst. + Zeigt %s eine Erinnerung zur Eingabe des Passworts an, damit es nicht vergessen wird. Deaktiviert Bildschirmsicherheit Bildschirmfotos und andere Aufnahmeversuche innerhalb der App blockieren Zum Aufdecken antippen - Token werden standardmäßig ausgeblendet. Tippe auf die Token, um den Code anzuzeigen. - Zeitüberschreitung für die Anzeige durch Antippen + Token werden standardmäßig ausgeblendet. Der Code wird durch Antippen des Tokens sichtbar. + Zeitlimit für aufgedeckte Token Automatisches Sperren Wenn %s Deaktiviert @@ -93,15 +95,21 @@ Die Zurück-Taste gedrückt wird Die App minimiert wird Das Gerät gesperrt wird - Sicherung & Exportdatei - Unterschiedliches Passwort für Sicherung & Exportdatei + Sicherung und Exportdatei + Separates Passwort für Sicherung und Exportdatei Wenn diese Option aktiviert ist, kann das Passwort, das zum Entsperren der App verwendet wird, nicht mehr zum Entschlüsseln von Sicherungen und Exportdateien verwendet werden. - Passwort für Sicherung & Exportdatei ändern + Passwort für Sicherung und Exportdatei ändern Gib ein neues Passwort ein, mit dem die Datenbank während der Sicherung und des Exportierens verschlüsselt wird. Verschlüsselung Datenbank verschlüsseln und sie mittels eines Passworts oder biometrischen Daten entsperren Biometrisches Entsperren Biometrische Authentifizierung zum Entsperren der Datenbank erlauben + Durchsuchen: %s + Folgende Felder durchsuchen + Name + Herausgeber + Notiz + Gruppen Passwort ändern Ein neues Passwort zum Entsperren der Datenbank festlegen Keine gemeldeten Ereignisse @@ -121,6 +129,7 @@ Entsperren der Datenbank fehlgeschlagen (Biometrie) Ein Versuch, die Datenbank mittels Biometrie zu entsperren, schlug fehl Unbekanntes Ereignis + (gelöscht) Heute um %1$s %1$s um %2$s Datenbank verschlüsseln @@ -301,6 +310,7 @@ Daher können keine Token importiert werden Entsperren der Datenbank Gruppe umbenennen + Wenn ein Eintrag keiner Gruppe zugewiesen ist, befindet er sich unter »Keine Gruppe«. Gruppe entfernen Möchtest du diese Gruppe wirklich entfernen? Einträge in dieser Gruppe wechseln automatisch zu »Keine Gruppe«. Nicht verwendete Gruppen löschen @@ -328,8 +338,8 @@ Gruppen bearbeiten Verwalten und Löschen von Gruppen Verwendungszähler zurücksetzen - Anzahl der Verwendungen für jeden Eintrag in der Datenbank zurücksetzen - Anzahl der Verwendungen aller Einträge in der Datenbank auf 0 setzen? + Verwendungszähler für jeden Eintrag in der Datenbank zurücksetzen + Den Verwendungszähler aller Einträge in der Datenbank auf 0 setzen? Notiz Löschen Token beim Antippen hervorheben @@ -337,6 +347,7 @@ Beim Kopieren minimieren App nach dem Kopieren eines Tokens minimieren Token in die Zwischenablage kopieren + Suchverhalten Token beim Antippen einfrieren Automatisches Aktualisieren der Token durch Antippen anhalten. Die Token werden nicht aktualisiert, solange sie hervorgehoben sind. Erfordert »Token beim Antippen hervorheben« oder »Zum Aufdecken antippen«. Gib dein Passwort ein, um die PIN-Tastatur zu aktivieren. Beachte, dass dies nur funktioniert, wenn dein Passwort nur aus Zahlen besteht @@ -437,7 +448,7 @@ URI in die Zwischenablage kopiert Eintrag übertragen Scanne diesen QR-Code mit der Authentifizierungs-App, zu der du diesen Eintrag übertragen möchtest - Scanne diese QR-Codes mit Aegis oder Google Authenticator.\n\nAufgrund der Einschränkungen der Google Authenticator-App sind nur TOTP- & HOTP-Token enthalten, die SHA1 verwenden und 6-stellige Codes erzeugen + Scanne diese QR-Codes mit Aegis oder Google Authenticator.\n\nAufgrund der Einschränkungen der Google Authenticator-App sind nur TOTP- und HOTP-Token enthalten, die SHA1 verwenden und 6-stellige Codes erzeugen Sehr schwach Schwach Mittel diff --git a/app/src/main/res/values-el-rGR/strings.xml b/app/src/main/res/values-el-rGR/strings.xml index a488564f..741fde94 100644 --- a/app/src/main/res/values-el-rGR/strings.xml +++ b/app/src/main/res/values-el-rGR/strings.xml @@ -46,7 +46,7 @@ Εμφάνιση του ονόματος λογαριασμού Εμφάνιση ονόματος λογαριασμού μόνο όταν είναι απαραίτητο Εμφάνιση μόνο ονομάτων λογαριασμών κάθε φορά που μοιράζονται τον ίδιο εκδότη. Άλλα ονόματα λογαριασμών θα αποκρύπτονται. - Αυτή η ρύθμιση αντικαθίσταται από τη λειτουργία προβολής πλακιδίων. Το όνομα λογαριασμού θα εμφανίζεται πάντα κάτω από τον εκδότη. + Αυτή η ρύθμιση αντικαθίσταται από τη λειτουργία προβολής πλακιδίων. Το όνομα λογαριασμού θα εμφανίζεται κάτω από τον εκδότη. Εισαγωγή από αρχείο Εισαγωγή αναγνωριστικών από αρχείο Αντίγραφα ασφαλείας cloud Android @@ -63,10 +63,12 @@ \'Εναυσμα αντιγράφου ασφαλείας Χειροκίνητη ενεργοποίηση δημιουργίας αντιγράφου ασφαλείας Αριθμός εκδόσεων που θα κρατηθούν + \u221E Διατηρήστε την %1$d έκδοση του αντιγράφου ασφαλείας Διατηρήστε τις %1$d εκδόσεις του αντιγράφου ασφαλείας + Διατηρήστε έναν άπειρο αριθμό εκδόσεων του αντιγράφου ασφαλείας Εισαγωγή από εφαρμογή Εισαγωγή αναγνωριστικών από εφαρμογή (απαιτείται πρόσβαση root) Εξαγωγή @@ -102,6 +104,12 @@ Κρυπτογράφηση της κρύπτης και ξεκλείδωμα με κωδικό ή βιομετρία Βιομετρικό ξεκλείδωμα Αποδοχή βιομετρικής πιστοποίησης για να ξεκλειδώσετε την κρύπτη + Αναζήτηση μέσω: %s + Αναζήτηση σε οποιοδήποτε από τα ακόλουθα πεδία + Όνομα + Εκδότης + Σημείωση + Ομάδες Αλλαγή κωδικού Ορισμός νέου κωδικού που θα χρειαστεί για να ξεκλειδώσετε την κρύπτης σας Δεν έχουν αναφερθεί συμβάντα @@ -121,6 +129,7 @@ Το ξεκλείδωμα της κρύπτης απέτυχε (βιομετρικά) Αποτυχία προσπάθειας ξεκλειδώματος της κρύπτης με βιομετρικά στοιχεία Άγνωστος τύπος συμβάντος + (διαγράφηκε) Σήμερα στις %1$s %1$s στις %2$s Κρυπτογράφηση κρύπτης @@ -301,6 +310,7 @@ Ως αποτέλεσμα, δεν μπορούν να εισαχθούν αναγνωστικά Ξεκλείδωμα κρύπτης Μετονομασία Ομάδας + Εάν μια καταχώρηση δεν αποτελεί μέρος οποιασδήποτε ομάδας, μπορεί να βρεθεί στο \"Χωρίς ομάδα\". Κατάργηση ομάδας Είστε βέβαιοι ότι θέλετε να καταργήσετε αυτήν την ομάδα; Οι καταχωρίσεις σε αυτήν θα μεταβούν αυτόματα στο \"Χωρίς ομάδα\". Διαγραφή αχρησιμοποίητων ομάδων @@ -337,6 +347,7 @@ Ελαχιστοποίηση κατά την αντιγραφή Ελαχιστοποίηση της εφαρμογής μετά την αντιγραφή ενός αναγνωριστικού Αντιγραφή αναγνωριστικών στο πρόχειρο + Συμπεριφορά αναζήτησης Πάγωμα αναγνωριστικών όταν πατηθούν Παύση της αυτόματης ανανέωσης των αναγνωριστικών πατώντας τα. Τα αναγνωριστικά δεν θα ενημερώνονται όσο είναι συγκεντρωμένα. Απαιτεί \"Επισήμανση αναγνωριστικών όταν πατηθούν\" ή \"Πατήστε για αποκάλυψη\". Εισαγάγετε τον κωδικό πρόσβασής σας για να ενεργοποιήσετε το πληκτρολόγιο PIN. Λάβετε υπόψη ότι αυτό λειτουργεί μόνο εάν ο κωδικός πρόσβασής σας αποτελείται μόνο από αριθμούς diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index f4648457..30641df1 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -46,7 +46,7 @@ Mostrar el nombre de la cuenta Solo mostrar nombres de cuenta necesarios Mostrar nombres de cuenta solo cuando compartan el mismo emisor. Se ocultarán otros nombres de cuenta. - Este ajuste no tiene efecto cuando aparecen en recuadros; el nombre de la cuenta siempre se mostrará debajo del emisor. + Este ajuste no tiene efecto cuando aparecen en recuadros; el nombre de la cuenta se mostrará debajo del emisor. Importar desde un archivo Importa tus claves desde un archivo Copias de seguridad en la nube de Android @@ -63,10 +63,12 @@ Lanzar una copia de seguridad Lanzar una copia de seguridad manualmente Número de versiones a conservar + \u221E Conservar %1$d versión de la copia de seguridad Conservar %1$d versiones de la copia de seguridad + No borrar ninguna copia de seguridad antigua Importar desde una aplicación Importa tus claves desde una aplicación (mediante superusuario o «root») Exportar @@ -102,6 +104,12 @@ Cifra la bóveda y la desbloquea mediante una contraseña o biometría Desbloqueo biométrico Permite la autenticación biométrica para desbloquear la bóveda + Campos a buscar: %s + Incluir los datos de estos campos en tus búsquedas + Nombre + Emisor + Notas + Grupos Cambiar contraseña Crea una nueva contraseña que necesitarás para desbloquear tu bóveda No parece haber ningún cambio @@ -121,6 +129,7 @@ Hubo un fallo al desbloquear la bóveda (biometría) Hubo un intento fallido al utilizar el desbloqueo biométrico Tipo de evento desconocido + (borrado) Hoy a las %1$s %1$s a las %2$s Cifrar la bóveda @@ -301,6 +310,7 @@ Como consecuencia no se pudo importar ninguna de las claves Desbloqueando la bóveda Renombrar grupo + El resto de elementos que no hayas asignado apareceran como «Sin agrupar». Eliminar grupo ¿Seguro que quieres borrar este grupo? Sus elementos se moverán automáticamente a «Sin grupo». Eliminar grupos no utilizados @@ -337,6 +347,7 @@ Minimizar al copiar Minimiza la aplicación tras copiar claves Copiar claves en el portapapeles + Comportamiento de búsqueda Congelar claves al tocarlas Pausa la recarga automática de las claves al tocarlas, por lo que no irán cambiando según expiran. Es necesario que también actives «Resaltar códigos al pulsar» o «Pulsar para mostrar». Escribe tu contraseña para activar el teclado PIN. Ten en cuenta que esto solo funciona si tu contraseña son todo números diff --git a/app/src/main/res/values-eu-rES/strings.xml b/app/src/main/res/values-eu-rES/strings.xml index 62425645..9dd3f454 100644 --- a/app/src/main/res/values-eu-rES/strings.xml +++ b/app/src/main/res/values-eu-rES/strings.xml @@ -28,11 +28,15 @@ Zifratzea, desblokeatzeko elementu biometrikoak erabiltzea, automatikoki blokeatzea eta beste segurtasun ezarpen batzuk kudeatu. Inportatu eta esportatu Aegis edo beste aplikazio batzuen segurtasun-kopiak inportatu. Zure Aegis biltegiaren eskuzko esportazioak sortu. + Erregistroa + Appean gertatutako gertaeren zerrenda agertuko da. Segurtasun-kopiak Konfiguratu segurtasun kopia automatikoak zuk nahi duzun karpetan gorde edo aktibatu Androiden segurtasun kopien sistema. Ikono multzoak Kudeatu eta inportatu ikono multzoak Itxura + Kolore dinamikoak + Zure Androidaren itxuraren araberako koloreak aplikatu Ikuspegia Hizkuntza Erakutsi ikonoak @@ -59,10 +63,12 @@ Segurtasun-kopien abiarazlea Abiarazi segurtasun-kopia eskuz Gorde beharreko bertsio kopurua + \u221E Mantendu segurtasun-kopiaren %1$d bertsio Mantendu segurtasun-kopien %1$d bertsio + Segurtasun kopien infititu bertsio gorde Inportatu aplikaziotik Inportatu tokenak aplikazio batetik (root sarbidea behar du) Esportatu @@ -100,6 +106,26 @@ Baimendu autentifikazio biometrikoa biltegia desblokeatzeko Aldatu pasahitza Ezarri biltegia desblokeatzeko erabiliko duzun pasahitz berria + Ez dago gertaerarik + Ez da garrantzizko gertaerarik gertatu appean + Biltegia desblokeatuta + Biltegia ondo desblokeatu da + Segurtasun kopia sortuta + Biltegiaren segurtasun kopia ondo sortu da + Androidek sortutako segurtasun kopia + Biltegiaren segurtasun kopia Androidek ondo sortu du + Biltegia esportatuta + Biltegiaren kopia bat esportatu da + Sarrera partekatuta + Sarrera bat partekatu da + Biltegia desblokeatzeak huts egin du (pasahitza) + Biltegia pasahitz bat erabiliz desblokeatzeak huts egin du + Biltegia desblokeatzeak huts egin du (biometria) + Biltegia biometria erabilz desblokeatzeak huts egin du + Gertaera ezezaguna + (ezabatuta) + Gaur %1$s + %1$s %2$s Zifratu biltegia Akzio honek zure biltegia Aegisen barne-biltegiratzetik kanpo esportatuko du. Aukeratu zein formatutan esportatu nahi duzun: Zure Aegis biltegiaren zifratu gabeko kopia esportatzera zoaz. Ez dizugu hau egitea gomendatzen. @@ -277,6 +303,8 @@ Esportazioak zerikusirik ez duen sorta baten informazioa du. Saiatu sorta bakoitza bere aldetik inportatzen. Ez izan da tokenik inportatu Biltegia desblokeatzen + Berrizendatu taldea + Sarrera ez bada talde baten parte \"Talde gabekoak\" atalean egongo da. Ezabatu taldea Ziur zaude talde hau ezabatu nahi duzula? Talde honetako sarrerak automatikoki aldatuko dira \'Talderik ez\' aukerara. Ezabatu erabili gabeko taldeak @@ -294,7 +322,10 @@ Kontua (A-tik Z-ra) Kontua (Z-tik A-ra) Erabilera kopurua + Azken erabilera Pertsonalizatua + Azken erabilera + sekula ez Talde berria… Taldea Taldearen izena @@ -413,6 +444,7 @@ Ertaina Ona Sendoa + Pasahitza luzeegia da sendotasuna analisia egiteko Erabili PIN teklatua blokeo pantailan Gaitu hau, blokeatzeko pantailan PIN teklatua gaitu nahi baduzu. Honek zenbaki-pasahitzetarako bakarrik balio du Ezarpenak @@ -423,6 +455,7 @@ Eskaneatu QR kodea Inportatu sarrerak Esleitu ikonoak + Hirugarrenen lizentziak Garbitu sarrerak Zure biltegiak sarrerak ditu dagoeneko. Sarrera horiek ezabatu nahi dituzu fitxategi hau inportatu aurretik?\n\nHori egitean, biltegiko sarreretarako sarbidea galduko da betirako. Garbitu biltegiaren sarrerak @@ -442,6 +475,7 @@ /data/data/com.authy.authy/shared_prefs/com.authy.storage.tokens.authenticator.xml fitxategia aukeratu. andOTPren esportazio/segurtasun-kopia fitxategia aukeratu. Kargatu Bitwardenen esportazio/segurtasun-kopia fitxategi bat. Ezin dituzu zifratutako fitxategiak kargatu. + Battle.net Authenticatoren /data/data/com.blizzard.messenger/shared_prefs/com.blizzard.messenger.authenticator_preferences.xml fitxategia aukeratu. Aukeratu /data/data/com.duosecurity.duomobile/files/duokit/accounts.json fitxategia, DUOren karpeten barruan dagoena. FreeTOPren (1.x bersioa) barne karpetan dagoen /data/data/org.fedorahosted.freeotp/shared_prefs/tokens.xml fitxategia aukeratu. FreeOTP+en esportazio fitxategia aukeratu. diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index 28292499..d6332e0e 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -10,7 +10,7 @@ Palauta oletuskuvake Hylkää Tallenna - Palveluntarjoaja + Myöntäjä PIN (4 - 16 numeroa) PIN (4 numeroa) Ehdotettu @@ -45,8 +45,8 @@ Valitse koodien ryhmittelyyn käytettävien numeroiden määrä Näytä tilin nimi Näytä tilin nimi vain tarvittaessa - Näytä tilien nimet vain silloin, kun niillä on sama palveluntarjoaja. Muiden tilien nimet piilotetaan. - Tämä asetus ohitetaan laatat-näkymätilassa. Tilin nimi näkyy aina palveluntarjoajan alapuolella. + Näytä tilien nimet vain silloin, kun niillä on sama myöntäjä. Muiden tilien nimet piilotetaan. + Tämä asetus ohitetaan laatat-näkymätilassa. Tilin nimi näytetään myöntäjän alapuolella. Tuo tiedostosta Tuo todennuskoodit tiedostosta Androidin pilvivarmuuskopiot @@ -63,10 +63,12 @@ Varmuuskopion käynnistys Käynnistä varmuuskopio manuaalisesti Säilytettävien versioiden määrä + \u221E Säilytä %1$d versio varmuuskopiosta Säilytä %1$d versiota varmuuskopiosta + Säilytä rajaton määrä versioita varmuuskopiosta Tuo sovelluksesta Tuo todennuskoodit sovelluksesta (vaatii root-oikeuden) Vie @@ -121,6 +123,7 @@ Holvin lukituksen avaus epäonnistui (biometria) Holvin lukituksen avaus biometrialla epäonnistui Tuntematon tapahtumatyyppi + (poistettu) Tänään klo %1$s %1$s klo %2$s Salaa holvi @@ -301,6 +304,7 @@ Tämän seurauksena yhtäkään todennuskoodia ei voitu tuoda Holvia avataan Nimeä ryhmä uudelleen + Jos kohde ei kuulu mihinkään ryhmään, se löytyy osion ”Ei ryhmää” alta. Poista ryhmä Poistetaanko tämä ryhmä? Ryhmässä olevat kohteet merkitään automaattisesti ryhmättömiksi. Poista käyttämättömät ryhmät @@ -313,8 +317,8 @@ Nimi Ei ryhmää Järjestä - Palveluntarjoaja (A - Ö) - Palveluntarjoaja (Ö - A) + Myöntäjä (A - Ö) + Myöntäjä (Ö - A) Tilin nimi (A-Ö) Tilin nimi (Ö-A) Käyttömäärä @@ -353,7 +357,7 @@ Tiivis Pieni Laatat - Tuntematon palveluntarjoaja + Tuntematon myöntäjä Tuntematon tilinimi Aegis ei voinut tuoda %d todennuskoodia. Nämä todennuskoodi ohitetaan. Paina \'tiedot\' nähdäksesi lisätietoa virheestä. @@ -500,8 +504,8 @@ Yksi napautus Kaksoisnapautus Piilotettu - Palveluntarjoajan vierellä - Palveluntarjoajan alla + Myöntäjän vierellä + Myöntäjän alla %d sekunti sitten %d sekuntia sitten diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml index 62db5d2b..bf4668b9 100644 --- a/app/src/main/res/values-fr-rFR/strings.xml +++ b/app/src/main/res/values-fr-rFR/strings.xml @@ -46,7 +46,7 @@ Afficher le nom de compte Afficher le nom de compte seulement si nécessaire Afficher les noms de compte seulement lorsqu\'ils partagent le même émetteur. Les autres noms de compte seront masqués. - Ce paramètre est remplacé par le mode d\'affichage des tuiles. Le nom de compte sera toujours affiché sous l\'émetteur. + Ce paramètre est remplacé par le mode d\'affichage par tuiles. Le nom de compte sera affiché sous l\'émetteur. Importer depuis un fichier Importer des jetons depuis un fichier Sauvegardes cloud d\'Android @@ -63,10 +63,12 @@ Déclencher la sauvegarde Déclencher manuellement une sauvegarde Nombre de versions à conserver + \u221E Conserver %1$d version de la sauvegarde Conserver %1$d versions de la sauvegarde + Conserver un nombre infini de versions de la sauvegarde Importer depuis une application Importer des jetons depuis une application (nécessite un accès root) Exporter @@ -102,6 +104,12 @@ Chiffrer le coffre-fort et le déverrouiller avec un mot de passe ou la biométrie Déverrouillage biométrique Autoriser l\'authentification biométrique pour déverrouiller le coffre-fort + Recherchez par : %s + Rechercher dans l\'un des champs suivants + Nom + Émetteur + Note + Groupes Changer le mot de passe Définir un nouveau mot de passe dont vous aurez besoin pour déverrouiller votre coffre-fort Aucun événement signalé @@ -121,6 +129,7 @@ Le déverrouillage du coffre-fort a échoué (données biométriques) Une tentative de déverrouillage du coffre-fort avec des données biométriques a échoué Type d\'événement inconnu + (supprimé) Ajourd\'hui à %1$s %1$s à %2$s Chiffrer le coffre-fort @@ -301,6 +310,7 @@ Aucun jeton ne peut être importé en conséquence Déverrouillage du coffre-fort Renommer le groupe + Si une entrée ne fait partie d\'aucun groupe, elle peut être trouvée sous \"Aucun groupe\". Supprimer groupe Êtes-vous sûr de vouloir supprimer ce groupe ? Les entrées dans ce groupe seront basculées automatiquement dans \"Aucun groupe\". Supprimer les groupes inutilisés @@ -337,6 +347,7 @@ Minimiser lors de la copie Minimiser l\'application après avoir copié un jeton Copier les jetons dans le presse-papier + Comportement de recherche Geler les jetons lorsqu\'ils sont appuyés Mettre en pause l\'actualisation automatique des jetons en appuyant dessus. Les jetons ne seront plus mis à jour tant qu\'ils seront ciblés. Nécessite « Surligner les jetons lorsqu\'ils sont appuyés » ou « Appuyer pour révéler ». Saisissez votre mot de passe pour activer le clavier PIN. Notez que cela ne fonctionne que si votre mot de passe est composé uniquement de chiffres diff --git a/app/src/main/res/values-fy-rNL/strings.xml b/app/src/main/res/values-fy-rNL/strings.xml index 0b2c8648..d6cad92d 100644 --- a/app/src/main/res/values-fy-rNL/strings.xml +++ b/app/src/main/res/values-fy-rNL/strings.xml @@ -46,7 +46,7 @@ Accountnamme toane Accountnamme allinnich wannear nedich toane Accountnammen allinnich toane wannear’t se deselde útjouwer diele. Oare accountnammen wurde ferstoppe. - Dizze ynstelling wurdt oerskreaun troch de tegelwerjeftemodus. Accountnamme wurdt altyd toand ûnder de útjouwer. + Dizze ynstelling wurdt oerskreaun troch de werjeftemodus Tegels. Accountnamme wurdt ûnder de útjouwer toand. Ut bestân ymportearje Tokens fan in bestân út ymportearje Android cloud-reservekopyen @@ -63,10 +63,12 @@ No in reservekopy meitsje Hânmjittich in reservekopy meitsje Oantal ferzjes om te bewarjen + \u221E Bewarje %1$d ferzje fan de reservekopy Bewarje %1$d ferzjes fan de reservekopy + Uneinich oantal ferzjes fan de reservekopy bewarje Fan in app út ymportearje Tokens fan in app út ymportearje (fereasket root-tagong) Eksportearje @@ -121,6 +123,7 @@ Klûs ûntskoatteljen mislearre (biometrysk) In besykjen om de klûs mei in wachtwurd te ûntskoatteljen mei biometryske gegevens is mislearre Unbekend barrenstype + (fuortsmiten) Hjoed om %1$s %1$s om %2$s Fersiferje de klûs @@ -301,6 +304,7 @@ Hjirtroch kinne gjin tokens ymportearre wurde Klûs wurdt ûntskoattele Groep omneame + As in item net yn in groep sit, kin dit fûn wurde ûnder ‘Gjin groep’. Groep fuortsmite Bisto wis datsto dizze groep fuortsmite wolst? Alle items binnen dizze groep wurde automatysk ferpleatst nei ‘Gjin groep’. Net brûkte groepen fuortsmite diff --git a/app/src/main/res/values-gl-rES/strings.xml b/app/src/main/res/values-gl-rES/strings.xml index 0a9901d6..68073fdc 100644 --- a/app/src/main/res/values-gl-rES/strings.xml +++ b/app/src/main/res/values-gl-rES/strings.xml @@ -28,6 +28,8 @@ Configura o cifrado, o desbloqueo por biometría, o bloqueo automático e outros axustes de seguridade. Importar e exportar Importa copias de seguridade de Aegis ou de outras aplicacións de autenticación. Exporta manualmente o teu almacén de Aegis. + Rexistro de auditoría + Atopa unha lista de tódolos eventos importantes que ocorreron na app. Copias de seguridade Configura copias de seguridade automáticas na localización que escollas ou activa a participación no sistema de copias de seguridade na nube de Android. Paquetes de iconas @@ -44,7 +46,6 @@ Mostrar o nome da conta Mostrar o nome da conta só cando sexa necesario Mostrar nomes de conta só cando teñan o mesmo emisor. Os demáis nomes de conta ocultaranse. - Este axuste está anulado polo modo de visualización de mosaico. O nome da conta mostrarase sempre debaixo do emisor. Importar desde un ficheiro Importar tokens desde un ficheiro Copias de seguridade na nube de Android @@ -61,10 +62,12 @@ Executar copia de seguridade Lanza manualmente unha copia de seguridade Número de versións a manter + \u221E Manter %1$d versión da copia de seguridade Manter %1$d versións da copia de seguridade + Manter un número ilimitado de versións da copia de seguridade Importar desde unha aplicación Importar tokens desde unha aplicación (require acceso root) Exportar @@ -102,6 +105,25 @@ Permite a autenticación mediante biometría para desbloquear o almacén Cambiar contrasinal Establece un novo contrasinal co que desbloquear o teu almacén + Non hai ningún evento rexistrado + Non se rexistrou ningún evento importante na app + Almacén desbloqueado + O almacén desbloqueouse correctamente + Copia de seguridade creada + Creouse correctamente unha copia de seguridade do almacén + Creada copia de seguridade de Android + Android creou correctamente unha copia de seguridade do almacén + Almacén exportado + Exportouse unha copia do almacén + Entrada compartida + Compartiuse unha entrada + Fallo de desbloqueo do almacén (contrasinal) + Houbo un intento errado de desbloquear o almacén mediante contrasinal + Fallo de desbloqueo do almacén (biometría) + Houbo un intento errado de desbloquear o almacén mediante datos biométricos + Tipo de evento descoñecido + Hoxe ás %1$s + %1$s ás %2$s Cifrar o almacén Esta acción exportará o almacén fóra do almacenamento interno de Aegis. Escolle o formato no que o queiras exportar: Estás a piques de exportar unha copia non cifrada do teu almacén de Aegis. Isto non está recomendado. @@ -279,6 +301,8 @@ A exportación contén información sobre un lote non relacionado. Intenta importar 1 lote de cada vez. Polo tanto, non se pode importar ningún token Desbloqueando o almacén + Renomear o grupo + Os elementos que non sexan parte de ningún grupo poderanse atopar dentro de \"Sen grupo\". Quitar grupo Tes a certeza de que queres quitar este grupo? As entradas deste grupo pasarán automaticamente a \"Sen grupo\". Borrar grupos sen usar @@ -421,6 +445,7 @@ Aceptable Boa Forte + O contrasinal é demasiado longo para a análise de robustez Usar teclado PIN na pantalla de bloqueo Activa isto se queres habilitar o teclado do PIN na pantalla de bloqueo. Isto só funciona para os contrasinais numéricos Axustes @@ -431,6 +456,7 @@ Escanear un código QR Importar entradas Asignar iconas + Licenzas de terceiros Limpar entradas O teu almacén xa contén entradas. Queres eliminalas antes de importar o ficheiro?\n\nSe o fas, perderás o acceso ás entradas existentes no almacén para sempre. Limpar o contido do almacén @@ -450,6 +476,7 @@ Proporciona unha copia de /data/data/com.authy.authy/shared_prefs/com.authy.storage.tokens.authenticator.xml, localizado no directorio do almacenamento interno de Authy. Proporciona un ficheiro de copia de seguridade ou de exportación de andOTP. Proporciona un ficheiro de copia de seguridade ou de exportación de Bitwarden. Non se admiten os ficheiros cifrados. + Proporciona unha copia de /data/data/com.blizzard.messenger/shared_prefs/com.blizzard.messenger.authenticator_preferences.xml, localizado no directorio do almacenamento interno de Battle.net Authenticator. Proporciona unha copia de /data/data/com.duosecurity.duomobile/files/duokit/accounts.json, localizado no directorio do almacenamento interno de DUO. Proporciona unha copia de /data/data/org.fedorahosted.freeotp/shared_prefs/tokens.xml, localizado no directorio do almacenamento interno de FreeOTP (1.x). Proporciona un ficheiro de exportación de FreeOTP+. diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index b11acae9..f5ca8d8d 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -46,7 +46,7 @@ A fióknév megjelenítése A fióknév megjelenítése csak akkor, ha szükséges A fióknevek megjelenítése csak akkor, ha megegyezik a kibocsátójuk. A többi fióknév rejtve lesz. - Ezt a beállítást felülbírálja a csempenézetes mód. A fióknév mindig látható lesz a kibocsátó alatt. + Ezt a beállítást felülbírálja a csempenézetes mód. A fióknév látható lesz a kibocsátó alatt. Importálás fájlból Tokenek importálása fájlból Android felhős mentések @@ -63,10 +63,12 @@ Biztonsági mentés készítése Biztonsági mentés kézi indítása Megtartandó verziók száma + \u221E %1$d verzió megtartása a mentésből %1$d verzió megtartása a mentésből + Végtelen számú verzió megtartása a biztonsági mentésből Importálás alkalmazásból Tokenek importálása alkalmazásból (root hozzáférés szükséges) Exportálás @@ -121,6 +123,7 @@ A széf feloldása nem sikerült (biometrikus adatok) A széf biometikus adatokkal való feloldása nem sikerült Ismeretlen eseménytípus + (törölve) Ma %1$s-kor %1$s %2$s-kor A széf titkosítása @@ -301,6 +304,7 @@ Ennek eredményeképp egyetlen token sem importálható A széf feloldása Csoport átnevezése + Ha egy bejegyzés egy csoportnak sem tagja, akkor a „Nincs csoport” alatt található. Csoport eltávolítása Biztos, hogy eltávolítja ezt a csoportot? A csoport bejegyzései automatikusan „Csoport nélküli” elemek lesznek. Nem használt csoportok törlése diff --git a/app/src/main/res/values-in-rID/strings.xml b/app/src/main/res/values-in-rID/strings.xml index ecc39ae7..41cbcb4e 100644 --- a/app/src/main/res/values-in-rID/strings.xml +++ b/app/src/main/res/values-in-rID/strings.xml @@ -28,11 +28,15 @@ Menyesuaikan enkripsi, buka kunci dengan biometrik, penguncian otomatis, dan pengaturan keamanan lainnya. Impor & Ekspor Impor cadangan dari Aegis atau aplikasi autentikasi lainnya. Buat ekspor manual dari brankas Aegis. + Log audit + Temukan daftar semua peristiwa penting yang dilaporkan yang terjadi di dalam aplikasi. Cadangan Atur pencadangan otomatis ke lokasi yang Anda pilih atau aktifkan partisipasi di sistem pencadangan awan Android. Paket Ikon Kelola dan impor paket ikon Tema + Warna dinamis + Terapkan lapisan berdasarkan warna tema Android Anda Mode tampilan Bahasa Tampilkan ikon @@ -59,9 +63,11 @@ Perintah pencadangan Perintah pencadangan secara manual Nomor versi untuk disimpan + \u221E Simpan %1$d versi cadangan + Simpan cadangan dalam jumlah tak terbatas Impor dari aplikasi Impor token dari aplikasi (membutuhkan akses root) Ekspor @@ -98,6 +104,26 @@ Izinkan otentikasi biometrik untuk membuka brankas Ganti kata sandi Atur kata sandi baru untuk digunkan membuka brankas Anda + Tidak ada kejadian yang dilaporkan + Tidak ada kejadian penting yang dilaporkan dalam aplikasi ini + Brankas terbuka + Brankas telah berhasil dibuka + Cadangan dibuat + Cadangan brankas telah berhasil dibuat + Cadangan dibuat oleh Android + Cadangan brankas telah berhasil dibuat oleh Android + Brankas diekspor + Salinan brankas telah diekspor + Entri dibagikan + Sebuah entri telah dibagikan + Gagal membuka kunci brankas (kata sandi) + Upaya membuka kunci brankas dengan kata sandi gagal + Gagal membuka kunci brankas (biometrik) + Upaya membuka kunci brankas dengan biometrik gagal + Jenis peristiwa tidak diketahui + (terhapus) + Hari ini pada %1$s + Hari %1$s pada %2$s Enkripsi brankas Tindakan ini akan mengekspor brankas dari penyimpanan internal Aegis. Pilih format yang Anda inginkan untuk ekspor: Anda akan mengekspor salinan tidak terenkripsi dari brankas Aegis Anda. Ini tidak disarankan. @@ -269,6 +295,8 @@ Ekspor berisi informasi untuk batch yang tidak terkait. Coba impor 1 batch dalam satu waktu. Tidak ada token yang dapat diimpor sebagai hasilnya Buka brankas + Ganti Nama Grup + Jika sebuah entri bukan merupakan bagian dari grup mana pun, entri tersebut dapat ditemukan di bawah “Tidak ada grup”. Hapus kelompok Apakah Anda yakin ingin menghapus kelompok ini? Catatan dalam kelompok ini akan secara otomatis beralih ke \'Tidak ada kelompok\'. Menghapus grup yang tidak digunakan @@ -286,7 +314,10 @@ Akun (A ke Z) Akun (Z ke A) Jumlah penggunaan + Terakhir digunakan Kustom + Terakhir digunakan + tidak pernah Kelompok baru… Kelompok Nama kelompok @@ -405,6 +436,7 @@ Baik Baik Kuat + Kata sandi terlalu panjang untuk analisis kekuatan Gunakan keyboard PIN di layar kunci Aktifkan ini jika Anda ingin mengaktifkan keyboard PIN di layar kunci. Ini hanya berfungsi untuk kata sandi numerik Pengaturan @@ -415,6 +447,7 @@ Pindai kode QR Impor entri Tetapkan ikon + Lisensi pihak ketiga Hapus catatan Brankas Anda sudah memiliki catatan. Apakah Anda ingin menghapus catatan ini tanpa mengimpor berkas ini?\n\nJika ini dilakukan, Anda akan kehilangan akses secara permanen ke catatan yang ada di brankas. Hapus konten brankas @@ -434,6 +467,7 @@ /data/data/com.authy.authy/shared_prefs/com.authy.storage.tokens.authenticator.xml, yang terletak di direktori penyimpanan internal Authy. Siapkan berkas ekspor/cadangan andOTP. Masukkan berkas cadangan/ekspor Bitwarden. Berkas terenkripsi tidak didukung. + Sediakan salinan /data/data/com.blizzard.messenger/shared_prefs/com.blizzard.messenger.authenticator_preferences.xml, yang terletak di direktori penyimpanan internal Battle.net Authenticator. Siapkan salinan /data/data/com.duosecurity.duomobile/files/duokit/accounts.json, yang terletak di direktori penyimpanan internal DUO. Berikan salinan dari /data/data/org.fedorahosted.freeotp/shared_prefs/tokens.xml yang terletak di direktori penyimpanan internal FreeOTP (1.x). diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml index 3102923d..5b99cbf9 100644 --- a/app/src/main/res/values-it-rIT/strings.xml +++ b/app/src/main/res/values-it-rIT/strings.xml @@ -44,7 +44,6 @@ Mostra il nome dell\'account Mostra il nome dell\'account solo se necessario Mostra i nomi degli account quando condividono lo stesso servizio. I nomi degli altri account verranno nascosti. - Questa impostazione è sovrascritta dalla visualizzazione a schede. Il nome dell\'account verrà sempre mostrato sotto al servizio. Importa da un file Importa i token da un file Backup cloud di Android diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index 577aac0f..2ea2adac 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -42,7 +42,6 @@ アカウント名を表示 必要に応じてアカウント名のみ表示 同じ発行者を共有するたびにアカウント名のみを表示します。他のアカウント名は非表示になります。 - この設定はタイル表示モードで上書きされています。アカウント名は常に発行者の下に表示されます。 ファイルからインポート ファイルからトークンをインポート Androidクラウドバックアップ diff --git a/app/src/main/res/values-kn-rIN/strings.xml b/app/src/main/res/values-kn-rIN/strings.xml index 88d9a7cc..a38795c7 100644 --- a/app/src/main/res/values-kn-rIN/strings.xml +++ b/app/src/main/res/values-kn-rIN/strings.xml @@ -38,7 +38,6 @@ ಖಾತೆಯ ಹೆಸರನ್ನು ತೋರಿಸಿ ಅಗತ್ಯವಿದ್ದಾಗ ಮಾತ್ರ ಖಾತೆಯ ಹೆಸರನ್ನು ತೋರಿಸಿ ಒಂದೇ ವಿತರಕರನ್ನು ಹಂಚಿಕೊಂಡಾಗ ಮಾತ್ರ ಖಾತೆಯ ಹೆಸರುಗಳನ್ನು ತೋರಿಸಿ. ಇತರ ಖಾತೆಯ ಹೆಸರುಗಳನ್ನು ಮರೆಮಾಡಲಾಗುತ್ತದೆ. - ಈ ಸೆಟ್ಟಿಂಗ್ ಟೈಲ್ಸ್ ವ್ಯೂ ಮೋಡ್‌ನಲ್ಲಿ ಅನ್ವಯಿಸುವುದಿಲ. ಖಾತೆಯ ಹೆಸರನ್ನು ಯಾವಾಗಲೂ ವಿತರಕರ ಕೆಳಗೆ ತೋರಿಸಲಾಗುತ್ತದೆ. ಫೈಲಿಂದ ಆಮದಿಸು ಫೈಲ್‌ನಿಂದ ಟೋಕನ್ಗಳ್ಳನ್ನು ಆಮದು ಮಾಡಿಕೊಳ್ಳಿ ಆಂಡ್ರಾಯ್ಡ್ ಕ್ಲೌಡ್ ಬ್ಯಾಕ್‌ಅಪ್‌ಗಳು diff --git a/app/src/main/res/values-lv-rLV/strings.xml b/app/src/main/res/values-lv-rLV/strings.xml index b625f5ab..b3e56117 100644 --- a/app/src/main/res/values-lv-rLV/strings.xml +++ b/app/src/main/res/values-lv-rLV/strings.xml @@ -46,7 +46,7 @@ Rādīt konta nosaukumu Radīt konta nosaukumu tikai tad, kad nepieciešams Rādīt kontu nosaukumu kad vien tiem ir viens un tas pats izdevējs. Citu kontu nosaukums būs paslēpts. - Šis iestatījums netiek ņemts vērā mozaīkas skatā. Konta nosaukums vienmēr tiks parādīts zem izdevēja. + Šis iestatījums netiek ņemts vērā mozaīkas skatā. Konta nosaukums tiks parādīts zem izdevēja. Ievietot no datnes Ievietot kodus no datnes Android mākoņa rezerves kopijas @@ -63,11 +63,13 @@ Veikt dublēšanu Pašrocīgi veikt dublēšanu Paturamo rezerves kopiju skaits + \u221E Paturēt %1$d rezerves kopijas Paturēt %1$d rezerves kopiju Paturēt %1$d rezerves kopijas + Paturēt neierobežotu skaitu rezerves kopiju Ievietot no lietotnes Ievietot kodus no lietotnes (nepieciešama saknes piekļuve) Izgūt @@ -104,6 +106,12 @@ Šifrēt glabātavu un atslēgt to ar paroli vai biometriju Atslēgšana ar biometriju Ļaut atslēgt glabātavu ar biometriju + Meklē: %s + Meklēt jebkurā no zemāk esošajiem laukiem + Nosaukums + Izsniedzējs + Piezīme + Kopas Mainīt paroli Uzstādīt jaunu paroli, kas būs nepieciešama, lai atslēgtu glabātavu Nav notikumu @@ -123,6 +131,7 @@ Glabātavas atslēgšana neizdevās (biometrija) Mēģinājums atslēgt glabātavu ar biometriju neizdevās Nezināms notikuma veids + (izdzēsts) Šodien %1$s %1$s %2$s Šifrēt glabātavu @@ -309,6 +318,7 @@ Iznākumā nevar ievietot nevienu kodu Atslēgšana ar biometriju Pārdēvēt kopu + Ja ieraksts nav daļa no kādas kopas, to var atrast zem \"Nav kopas\". Noņemt kopu Vai tiešām noņemt šo kopu? Tās ieraksti tiks pārmainīti uz \"Nav kopas\". Izdzēst neizmantotās kopas @@ -345,6 +355,7 @@ Samazināt pēc ievietošanas starpliktuvē Samazināt lietotni pēc koda ievietošanas starpliktuvē Ievietot tekstvienības starpliktuvē + Meklēšanas uzvedība Iesaldēt kodus pēc piesišanas tiem Apturēt kodu atsvaidzināšanu, kad piesit. Kods netiks atjaunots, kamēr vien tas ir izcelts. Ir nepieciešams ieslēgt iestatījumu \"Izcelt kodus, kad piesit\" vai \"Piesist, lai atklātu\". Jāievada parole, lai iespējotu PIN tastatūru. Jāņem vērā, ka tā darbojas tikai tad, ja parole sastāv tikai no cipariem diff --git a/app/src/main/res/values-nl-rNL/strings.xml b/app/src/main/res/values-nl-rNL/strings.xml index 1903ccef..94954ed5 100644 --- a/app/src/main/res/values-nl-rNL/strings.xml +++ b/app/src/main/res/values-nl-rNL/strings.xml @@ -46,7 +46,7 @@ Accountnaam tonen Accountnaam alleen indien nodig tonen Accountnamen alleen tonen wanneer ze dezelfde uitgever hebben. Andere accountnamen worden verborgen. - Deze instelling wordt overschreven door de tegelweergavemodus. Accountnaam wordt altijd getoond onder de uitgever. + Instelling wordt overschreven door de weergavemodus Tegels. Accountnaam wordt getoond onder de uitgever. Importeren vanuit een bestand Importeer tokens vanuit een bestand Android-cloudback-ups @@ -63,10 +63,12 @@ Maak nu een back-up Handmatig een back-up aanzetten Aantal versies om te behouden + \u221E Behoud %1$d versie van de back-up Behoud %1$d versies van de back-up + Oneindig aantal versies van de back-up bewaren Importeren vanuit een app Importeer tokens vanuit een app (vereist root-access) Exporteren @@ -102,6 +104,12 @@ Versleutel de kluis en ontgrendel deze met een wachtwoord of biometrie Ontgrendelen met biometrie Sta biometrische authenticatie toe om de kluis te ontgrendelen + Zoek door: %s + Zoek in een van de volgende velden + Naam + Uitgever + Notitie + Groepen Wachtwoord wijzigen Stel een nieuw wachtwoord in waarmee je de kluis kunt ontgrendelen Geen gerapporteerde gebeurtenissen @@ -121,6 +129,7 @@ Kluis ontgrendelen mislukt (biometrie) Een poging om de kluis te ontgrendelen met biometrie is mislukt Onbekende gebeurtenis + (verwijderd) Vandaag om %1$s %1$s om %2$s Kluis versleutelen @@ -301,6 +310,7 @@ Hierdoor kunnen geen tokens worden geïmporteerd Kluis wordt ontgrendeld Groep hernoemen + Als een item niet in een groep zit, kan dit worden gevonden onder ‘Geen groep’. Groep verwijderen Weet je zeker dat je deze groep wilt verwijderen? Alle items binnen deze groep worden automatisch verplaatst naar ‘Geen groep’. Ongebruikte groepen verwijderen @@ -337,6 +347,7 @@ Na kopiëren minimaliseren Na kopiëren van een code de app minimaliseren Codes naar het klembord kopiëren + Zoekgedrag Codes bevriezen na aantikken Pauzeer automatisch verversen van codes door erop te tikken. Codes zullen niet worden bijgewerkt zolang ze gefocust zijn. Vereist ‘Codes markeren na aantikken’ of ‘Aantikken om te laten zien’. Voer je wachtwoord in om het PIN-toetsenbord in te schakelen. Let op: dit werkt alleen als je wachtwoord uit cijfers bestaat diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml index 5c4ee6ea..bcb93b3e 100644 --- a/app/src/main/res/values-pl-rPL/strings.xml +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -46,7 +46,6 @@ Pokaż nazwę konta Pokaż nazwę konta tylko w razie potrzeby Pokazuj nazwy kont tylko, gdy są z tego samego wydawcy. Inne nazwy kont zostaną ukryte. - To ustawienie jest nadpisane przez tryb wyświetlania pól. Nazwa konta będzie zawsze wyświetlana pod wydawcą. Importuj z pliku Importuj tokeny z aplikacji Kopia zapasowa Android w chmurze @@ -317,6 +316,7 @@ Nie można zaimportować żadnych tokenów Odblokowywanie sejfu Zmień Nazwę Grupy + Jeśli wpis nie jest częścią żadnej grupy, można go znaleźć pod \"Brak grupy\". Usuń grupę Czy na pewno chcesz usunąć tę grupę? Wpisy z tej grupy zostaną automatycznie przeniesione do kategorii \'Brak grupy\'. Usuń nieużywane grupy diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index b414f490..6e0ce020 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -10,7 +10,7 @@ Restaurar ícone padrão Descartar Salvar - Nome do serviço + Emissor PIN (4–16 dígitos) PIN (4 dígitos) Sugerido @@ -46,7 +46,7 @@ Mostrar nome da conta Exibir o nome da conta apenas quando necessário Mostra os nomes de conta apenas quando eles compartilham o mesmo emissor. Outros nomes de conta serão ocultados. - Esta configuração é substituída pelo modo de visualização em grade. O nome da conta será sempre mostrado abaixo do emissor. + Esta configuração é substituída pelo modo de visualização em grade. O nome da conta será mostrado abaixo do emissor. Importar de arquivo Importa tokens de um arquivo Backups na nuvem do Android @@ -63,10 +63,12 @@ Ativar backup Ativa manualmente um backup Número de versões a manter + \u221E Manter %1$d versão do backup Manter %1$d versões do backup + Manter um número infinito de versões do backup Importar de um app Importa tokens de um app (requer acesso root) Exportar @@ -102,6 +104,12 @@ Criptografa o cofre e o desbloqueia com uma senha ou biometria Desbloqueio biométrico Permite autenticação por biometria para desbloquear o cofre + Pesquisar por %s + Pesquisar em qualquer um dos seguintes campos + Nome + Emissor + Nota + Grupos Trocar senha Define uma nova senha que será necessária para desbloquear o cofre Nenhum evento reportado @@ -121,6 +129,7 @@ Falha ao desbloquear o cofre (biometria) Uma tentativa de desbloquear o cofre com a biometria falhou Tipo de evento desconhecido + (excluído) Hoje às %1$s %1$s em %2$s Criptografar o cofre @@ -301,6 +310,7 @@ Como resultado, nenhum token pode ser importado Desbloqueando o cofre Renomear Grupo + Se um item não faz parte de qualquer grupo, ele pode ser encontrada em \"Sem grupo\". Remover grupo Você tem certeza que deseja remover esse grupo? Entradas nesse grupo serão automaticamente para \'Sem grupo\'. Excluir grupos não utilizados @@ -313,10 +323,10 @@ Conta Sem grupo Ordenar - Nome (A to Z) - Nome (Z to A) - Conta (A to Z) - Conta (Z to A) + Emissor (A a Z) + Emissor (Z a A) + Conta (A a Z) + Conta (Z a A) Contagem de uso Último uso Personalizado @@ -337,6 +347,7 @@ Minimizar ao copiar Minimizar o aplicativo após copiar um token Copiar tokens para a área de transferência + Comportamento de pesquisa Congelar tokens quando tocados Pausa a atualização automática dos tokens ao tocá-los. Tokens não serão atualizados desde que o foco esteja neles. Requer \"Destacar tokens quando tocados\" ou \"Tocar para exibir\". Digite sua senha para ativar o teclado PIN. Observe que isso só funciona se a sua senha for constituída apenas por números @@ -353,7 +364,7 @@ Compacto Pequeno Grade - Nome do serviço desconhecido + Emissor desconhecido Nome da conta desconhecido Aegis não pôde importar %d token. Esse token será ignorado. Pressione \'detalhes\' para ver mais informações sobre o erro. diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 34012574..d2344191 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -28,11 +28,15 @@ Configurar criptografia, desbloqueio biométrico, bloqueio automático e outras definições de segurança. Importar e exportar Importar backups Aegis ou de outras aplicações de autenticação. Crie exportações manuais do seu cofre Aegis. + Registo de auditoria + Encontre uma lista de todos os eventos importantes relatados que ocorreram na aplicação. Backups Configure backups automáticos para uma localização à escolha ou ative a possibilidade de backup na nuvem Android. Pacotes de ícones Gerir e importar pacotes de ícones Tema + Cores dinâmicas + Aplicar uma sobreposição baseada nas cores do seu tema Android Modo de exibição Idioma Mostrar ícones @@ -42,7 +46,6 @@ Mostrar nome da conta Exibir o nome da conta apenas quando necessário Mostrar apenas os nomes das contas sempre que estas partilhem o mesmo titular. Os outros nomes de contas serão ocultados. - Esta definição é anulada pelo modo de visualização em mosaico. O nome da conta será sempre apresentado por baixo do emissor. Importar de um ficheiro Importar \'tokens\' de um ficheiro Backups na nuvem Android @@ -100,6 +103,25 @@ Permitir autenticação biométrica para desbloquear o cofre Alterar palavra-passe Defina a palavra-passe que será utilizada para desbloquear o cofre + Sem eventos relatados + Nenhum evento importante foi relatado na aplicação + Cofre desbloqueado + O cofre foi desbloqueado com sucesso + Backup criado + Um backup do cofre foi criado com sucesso + Backup criado pelo Android + Um backup do cofre foi criado com sucesso pelo Android + Cofre exportado + Uma cópia do cofre foi exportada + Entrada partilhada + Uma entrada foi partilhada + O desbloqueio do cofre falhou (palavra-passe) + Falha ao tentar desbloquear o cofre com a palavra-passe + O desbloqueio do cofre falhou (biometria) + Falha ao tentar desbloquear o cofre com biometria + Tipo de evento desconhecido + Hoje às %1$s + %1$s às %2$s Cifrar cofre Esta ação irá exportar o cofre para fora do armazenamento interno do Aegis. Selecione o formato para a exportação: Está prestes a exportar uma cópia não cifrada do seu cofre Aegis. Isto não é recomendado. @@ -111,15 +133,19 @@ Formato de exportação Exportar todos os grupos Selecionar os grupos a exportar + + %d grupo selecionado + %d grupos selecionados + Nenhum grupo selecionado para exportar Exportação do Aegis Authenticator Segurança - Aegis é um aplicativo 2FA focado na segurança. Tokens são armazenados em um cofre, que pode opcionalmente ser criptografado com uma senha de sua escolha. Se um invasor obtiver o seu arquivo criptografado do cofre, eles não serão capazes de acessar o conteúdo sem saber a senha.\n\nNós pré-selecionamos a opção que achamos que seria melhor para o seu dispositivo. + Aegis é uma aplicação 2FA focada em segurança. Tokens são armazenados num cofre, que pode opcionalmente ser criptografado com uma palavra-passe da sua escolha. Se um invasor obtiver o ficheiro criptografado do cofre, ele não conseguirá aceder ao conteúdo sem saber a palavra-passe.\n\nA opção que achamos que seria melhor para o seu dispositivo foi pré-selecionada. Nenhum - Nenhuma senha é necessária para desbloquear o cofre e não será criptografada. Esta opção não é recomendada. + Não será necessária uma palavra-passe para desbloquear o cofre e este não será encriptado. Esta opção não é recomendada. Senha - É necessária uma senha para desbloquear o cofre. - Aviso: Se você esquecer sua senha, você perderá permanentemente o acesso aos seus tokens. Não há como recuperá-los sem a senha. + É necessária uma palavra-passe para desbloquear o cofre. + Aviso: Se se esquecer da sua palavra-passe, perderá permanentemente o acesso aos seus tokens. Não há como recuperá-los sem a mesma. Biometria Além de uma senha, a biometria registrada neste dispositivo, como uma impressão digital ou seu rosto, pode ser usada para desbloquear o cofre. Desbloquear o cofre @@ -140,7 +166,7 @@ Mensal Trimestral Parece que esta cópia de segurança 2FAS está encriptada. Introduza abaixo a palavra-passe. - Parece que seus tokens Authy são criptografados. Por favor, feche o Aegis, abra o Authy e desbloqueie os tokens com sua senha. Em vez disso, Aegis também pode tentar descriptografar seus tokens Authy para você, se você inserir sua senha abaixo. + Parece que os seus tokens do Authy estão encriptados. Por favor, feche o Aegis, abra o Authy e desbloqueie os tokens com a sua palavra-passe. Em vez disso, o Aegis também pode tentar desencriptar os seus tokens do Authy por si, se inserir a sua palavra-passe abaixo. Por favor, introduza a palavra-passe de importação Período (segundos) Função hash @@ -155,9 +181,9 @@ Dígitos Secreto Escanear código QR - Escanear imagem + Digitalizar imagem Inserir manualmente - Configurar desbloqueio biométrico + Configurar o desbloqueio biométrico Copiar Editar Selecionar tudo @@ -165,93 +191,121 @@ Favorito Remover dos favoritos ERRO - Senha + Palavra-passe Confirme a Senha Mostrar senha Nova entrada Adicionar nova entrada - Falha ao desbloquear cofre - Senha incorreta. Certifique-se de que não digitou incorretamente sua senha. - As senhas devem ser idênticas e não vazias + Não foi possível desbloquear o cofre + Palavra-passe incorreta. Certifique-se de que não a digitou incorretamente. + As palavras-passe devem ser idênticas e não vazias Por favor, selecione um método de autenticação - Criptografando o cofre - Exportando o cofre + A encriptar o cofre + A exportar o cofre A ler o ficheiro Pedir acesso root A analisar o código QR A analisar o código QR %d/%d (%s) + + Adicionada %d nova entrada ao cofre + Adicionadas %d novas entradas ao cofre + A importar o pacote de ícones - Excluir entrada + Eliminar entrada Tem a certeza de que quer excluir esta entrada? - Excluir entradas + Esta ação não desativa a 2FA para:\n%s\n\nPara evitar a perda de acesso, certifique-se de que desativou a 2FA ou de que tem uma forma alternativa de gerar códigos para este serviço. + Eliminar entradas Você tem certeza que deseja deletar %d entrada? Você tem certeza que deseja deletar %d entradas? Descartar alterações? - Suas alterações não foram salvas - Erro ao salvar perfil + As suas alterações não foram guardadas + Erro ao guardar o perfil Erro ao atribuir ícones Bem-vindo - Aegis é um aplicativo 2FA gratuito, seguro e opensource + Aegis é uma aplicação 2FA gratuita, segura e open source Configuração concluída Aegis foi configurado e está pronto para uso. - Cofre não encontrado, iniciando configuração… + Cofre não encontrado, a iniciar configuração… Copiado Erros copiados para a área de transferência - Versão copiada para área de transferência + Versão copiada para a área de transferência Ocorreu um erro Ocorreu um erro ao tentar desbloquear o cofre - Ocorreu um erro ao tentar desbloquear o cofre. O seu arquivo de cofre pode estar corrompido. - Ocorreu um erro ao tentar salvar o cofre - Ocorreu um erro ao tentar inicializar o cofre + Ocorreu um erro ao tentar desbloquear o cofre. O ficheiro do cofre pode estar corrompido. + Ocorreu um erro ao tentar guardar o cofre + Ocorreu um erro ao tentar iniciar o cofre Ocorreu um erro ao tentar carregar o cofre do armazenamento - Ocorreu um erro ao tentar descriptografar o cofre com autenticação biométrica. Isso geralmente só acontece se as configurações de segurança do seu dispositivo foram alteradas. Por favor, desbloqueie o cofre com sua senha e reconfigure a autenticação biométrica nas configurações do Aegis. - Ocorreu um erro ao tentar preparar a autenticação biométrica. Isso geralmente só acontece se as configurações de segurança do seu dispositivo foram alteradas. Por favor, desbloqueie o cofre com sua senha e reconfigure a autenticação biométrica nas configurações do Aegis. - Desativar criptografia - Ocorreu um erro ao ativar a criptografia - Ocorreu um erro ao desativar a criptografia - O backup foi agendado com sucesso - Ocorreu um erro ao tentar criar um backup + Ocorreu um erro ao tentar desencriptar o cofre com autenticação biométrica. Isto só acontece normalmente se as definições de segurança do seu dispositivo foram alteradas. Por favor, desbloqueie o cofre com a sua palavra-passe e redefina a autenticação biométrica nas configurações do Aegis. + Ocorreu um erro ao tentar preparar a autenticação biométrica. Isto só acontece normalmente se as definições de segurança do seu dispositivo foram alteradas. Por favor, desbloqueie o cofre com a sua palavra-passe e redefina a autenticação biométrica nas configurações do Aegis. + Desativar encriptação + Tem a certeza de que deseja desativar a encriptação? Isto fará com que o cofre seja armazenado em texto simples. Os backups automáticos também serão desativados. + Ocorreu um erro ao ativar a encriptação + Ocorreu um erro ao desativar a encriptação + O ‘backup’ foi agendado com sucesso + Ocorreu um erro ao tentar criar um ‘backup’ Backup mais recente realizado com sucesso: %s A realização de um backup recente falhou: %s Ainda não houve nenhum backup realizado + Os backups são encriptados utilizando uma palavra-passe separada configurada nas definições de segurança + O módulo DocumentsUI parece estar em falta no seu dispositivo. Trata-se de um componente do sistema necessário para a seleção e criação de documentos. Se utilizou uma ferramenta para "limpar" o seu dispositivo, pode tê-lo eliminado acidentalmente e terá de o reinstalar. Ocorreu um erro durante o processo de importação do pacote de ícones + O pacote de ícones que tenta importar já existe. Pretende substituí-lo? Ocorreu um erro durante o processo de exclusão de um pacote de ícones + + %d ícone + %d ícones + Personalizar Permissão negada Novo formato (v0.6.3 ou mais recente) Formato antigo (v0.6.2 ou antigo) Qual o formato do arquivo de backup andOTP? Este backup TOTP Authenticator é criptografado com uma senha? - Selecione o aplicativo do qual você gostaria de importar + Selecione a aplicação da qual gostaria de importar Selecione o tema + Selecione a posição do nome da conta desejada Selecione o modo de visualização Selecione o estilo de cópia que deseja efetuar - Ocorreu um erro ao tentar analisar o arquivo - Erro: Arquivo não encontrado - Ocorreu um erro ao tentar ler o arquivo - Erro: O aplicativo não está instalado + Ocorreu um erro ao tentar analisar o ficheiro + Erro: Ficheiro não encontrado + Ocorreu um erro ao tentar ler o ficheiro + Erro: A aplicação não está instalada + A versão de %s que está instalada não é suportada. As versões recentes começaram a encriptar alguns dos ficheiros no armazenamento interno, tornando o Aegis incapaz de aceder às informações necessárias para a importação. É provável que a tentativa de importação resulte num erro. Gostaria de continuar na mesma? + Erro: Não é possível obter acesso root %d entrada importada %d entradas importadas + + A mostrar %d entrada + A mostrar %d entradas + + Ocorreu um erro ao importar o cofre Um ou mais erros ocorreram durante a importação Ocorreu um erro ao tentar exportar o cofre O cofre foi exportado - Ocorreu um erro ao tentar definir a senha. - Ocorreu um erro ao tentar ativar o desbloqueio biométrico. Alguns dispositivos têm implementações deficientes da autenticação biométrica e é provável que o seu seja um deles. Considere alternar para uma configuração somente senha. - Nenhuma câmera disponível + Ocorreu um erro ao tentar definir a palavra-passe. + Ocorreu um erro ao tentar ativar o desbloqueio biométrico. Alguns dispositivos têm más implementações da autenticação biométrica e é provável que o seu seja um deles. Considere mudar para uma configuração com apenas palavra-passe. + Nenhuma câmara disponível Ocorreu um erro ao tentar ler o código QR Aegis é incompatível com o algoritmo 2FA das propriedades da Microsoft. Por favor, selecione \"Configurar aplicação sem notificações\" quando configurar 2FA no Office 365. Foi detetada uma exportação incompleta do Google Authenticator - • QR code %d + Faltam alguns códigos QR na sua importação. Os seguintes códigos não foram encontrados:\n\n%s\n\nPode continuar a importar esta exportação parcial, mas recomendamos que tente novamente com todos os códigos QR para não correr o risco de perder o acesso a quaisquer tokens. + • Código QR %d Importar %d tokens mesmo assim - Desbloqueando o cofre + Falha ao importar a exportação do Google Authenticator + A exportação contém informações para um lote não relacionado. Experimente importar um lote de cada vez. + Nenhum token pode ser importado como resultado + A desbloquear o cofre + Mudar o nome do grupo Remover grupo - Tem certeza que deseja remover este grupo? As entradas neste grupo automaticamente alternarão para \'Sem grupo\'. + Tem a certeza de que pretende remover este grupo? As entradas neste grupo mudarão automaticamente para \'Sem grupo\'. Apagar grupos não utilizados + Tem a certeza de que pretende eliminar todos os grupos que não estão atribuídos a uma entrada? Remover pacote de ícones + Tem a certeza de que pretende remover este pacote de ícones? As entradas que utilizam ícones deste pacote não serão afetadas. Detalhes Mostrar detalhes do erro Bloquear @@ -262,19 +316,28 @@ Emissor (Z a A) Conta (A a Z) Conta (Z a A) + Número de utilizações + Última utilização Personalizado + Última utilização + nunca Novo grupo… Grupo Nome do grupo Editar grupos - Gerenciar e excluir seus grupos aqui + Gira e elimine os seus grupos aqui + Repor a contagem de utilização + Repor a contagem de utilização de cada entrada no seu cofre + Tem a certeza de que pretende definir a contagem de utilização de cada entrada no seu cofre como 0? Nota Limpar - Destacar tokens quando tocados + Realçar tokens quando tocados Faça com que os tokens sejam mais fáceis de distinguir um do outro destacando-os temporariamente ao tocá-los Minimizar ao copiar Após copiar um token, minimizar a aplicação Copiar tokens para a área de transferência + Congelar tokens quando tocados + Pausar a atualização automática dos tokens ao tocar neles. Os tokens não serão atualizados desde que estejam em foco. Requer \"Realçar tokens quando tocados\" ou \"Toque para mostrar\". Digite sua senha para ativar o teclado PIN. Observe que isso só funciona se a sua senha for constituída apenas por números Erro ao habilitar o teclado PIN Não é possível configurar o teclado PIN. A sua senha deve ser composta apenas por números. @@ -288,24 +351,33 @@ Normal Compacto Pequena + Blocos Emissor desconhecido Nome de conta desconhecido + + O Aegis não conseguiu importar %d token. Este token será ignorado. Prima \"detalhes\" para obter mais informações sobre o erro. + O Aegis não conseguiu importar %d tokens. Estes tokens serão ignorados. Prima \"detalhes\" para obter mais informações sobre os erros. + + Não é possível processar a ligação profunda + Não foi possível ler e processar o código QR do ficheiro: %s. + Não é possível processar o texto partilhado como OTP + Não é possível ler e processar alguns dos códigos QR. Apenas serão importadas %d/%d entradas. Não foi possível gerar o código QR Selecionar imagem Selecionar ícone Abrir cofre - Abrir scanner + Abrir digitalizador Alternar caixas de seleção Pesquisar - Status de bloqueio - Aegis pode criar uma notificação persistente para notificá-lo quando o cofre estiver bloqueado - O Cofre está desbloqueado. Toque aqui para bloquear. + Estado de bloqueio + O Aegis pode criar uma notificação persistente para informá-lo quando o cofre estiver bloqueado + O cofre está desbloqueado. Toque aqui para bloquear. Versão Registo de alterações O que há de novo Código fonte, problemas e informações Licença - Aegis Authenticator está licenciado sob GPLv3 + O Autenticador Aegis está licenciado sob GPLv3 Licenças de terceiros Licenças das bibliotecas de terceiros utilizadas pelo Aegis Holanda @@ -314,69 +386,109 @@ Suporte Avaliar Apoie-nos deixando uma avaliação na Google Play Store + Este dispositivo não suporta a vista web, necessária para ver o registo de alterações e a licença. Falta-lhe um componente do sistema. Email Sincronização de tempo automática - O Aegis depende da hora do sistema para estar sincronizado para gerar códigos corretos. Um desvio de apenas alguns segundos pode resultar em códigos incorretos. Parece que seu dispositivo não está configurado para sincronizar automaticamente o tempo. Gostaria de fazer isso agora? - Pare de me avisar. Eu sei o que estou fazendo. - Código QR não relacionado. Tente reiniciar o scanner. + O Aegis depende da hora do sistema para estar sincronizado para gerar códigos corretos. Um desvio de apenas alguns segundos pode resultar em códigos incorretos. Parece que o seu dispositivo não está configurado para sincronizar automaticamente o tempo. Gostaria de o fazer agora? + Para de me avisar. Eu sei o que estou a fazer. + Código QR não relacionado. Experimente reiniciar o digitalizador. %d/%d QR code escaneado %d/%d QR codes escaneados #%d códigos QR eram esperados, mas #%d foram escaneados em vez disso - O backup do cofre falhou recentemente + O ‘backup’ do cofre falhou recentemente + Uma tentativa recente de backup do cofre utilizando o %s falhou porque ocorreu um erro. A tentativa de cópia de segurança foi efetuada %s. Verifique as definições de backup para se certificar de que os mesmos podem ser concluídos com êxito. + + Uma tentativa recente de backup do cofre utilizando o %s falhou porque o Aegis não tinha permissão para escrever no destino do backup. A tentativa de backup foi feita %s. Este erro pode ocorrer se tiver movido/renomeado o destino da cópia de segurança ou se tiver restaurado recentemente o Aegis a partir de um backup. Reconfigure o destino do backup. + + backups automáticos do Aegis + sistema de backup na nuvem do Android O último backup está desatualizado (%s) As mudanças não foram gravadas As mudanças não foram gravadas + As alterações recentes ao cofre ainda não foram objeto de backup. É importante efetuar backups regulares para evitar a perda de acesso às suas contas. Considere a possibilidade de configurar backups automáticos nas definições. + Configurar backups + O cofre foi exportado recentemente em texto simples Não mostrar este aviso novamente + Este aviso é mostrado porque exportou recentemente uma cópia não encriptada do cofre. Para manter a segurança dos seus tokens, recomendamos que elimine este ficheiro quando já não for necessário. Trocar câmara Não há códigos a serem mostrados. Comece a adicionar entradas tocando no sinal de mais no canto inferior direito Nenhuma entrada encontrada Não há grupos a serem mostrados. Adicione grupos na tela de edição de uma entrada Nenhum grupo encontrado + Ainda não foram importados quaisquer pacotes de ícones. Toque no sinal de mais para importar um. Dica: experimente aegis-icons. Sem pacotes de ícones Selecionar ícone Sem categoria Concluído + + %d / %d QR code + Códigos QR %d / %d + Próximo Anterior Copiar URI + Não é possível copiar o URI para a área de transferência + URI copiado para a área de transferência Transferir entrada - Escaneie este código QR com o aplicativo de autenticação para o qual você gostaria de transferir esta entrada + Digitalize este código QR com a aplicação de autenticação para a qual gostaria de transferir esta entrada + Digitalize estes códigos QR com o Aegis ou o Google Authenticator.\n\nDevido às limitações do Google Authenticator, apenas estão incluídos os tokens TOTP e HOTP que utilizam SHA1 e produzem códigos de 6 dígitos Muito Fraca Fraca Média Boa Forte - Usar o teclado PIN na tela de bloqueio + Palavra-passe demasiado longa para a análise de resistência + Usar o teclado numérico no ecrã de bloqueio Ative esta opção se quiser habilitar o teclado PIN na tela de bloqueio. Isso só funciona para senhas numéricas Configurações - Gerenciar grupos + Gerir grupos Transferir entradas Sobre Editar entrada Escanear um código QR + Importar entradas Atribuir ícones + Licenças de terceiros Limpar entradas O seu cofre já contém entradas. Você quer remover essas entradas antes de importar este arquivo?\n\nAo fazer isso, você perderá permanentemente o acesso às entradas existentes no cofre. Limpar conteúdo do cofre Aegis recebeu um gatilho de pânico, mas essa configuração está desativada, portanto será ignorado Excluir cofre após gatilho de pânico Excluir cofre quando um gatilho de pânico é recebido do Ripple + Importar cofre do Aegis + Pretende importar de uma aplicação 2FA diferente? Conclua a configuração primeiro e depois vá para as definições. + + Desmarcado %d potencial duplo. Reveja a lista de entradas. + Desmarcados %d potencial duplos. Reveja a lista de entradas. + Fornecer um arquivo de backup de 2FAS Authenticator. Fornecer um arquivo de exportação/backup do Aegis. Fornecer um arquivo de exportação do Autenticador Plus obtido através de Configurações -> Backup & Restaurar -> Exportar como Texto e HTML. + Forneça um ficheiro de exportação do Authenticator Pro obtido através de Settings -> Back up -> Back up to encrypted file (recommended). Fornecer uma cópia de /data/data/com.authy.authy/shared_prefs/com.authy.storage.tokens.authenticator.xml, localizado no diretório de armazenamento interno do Authy. Fornecer um arquivo de exportação/backup do andOTP. + Forneça um ficheiro de exportação/backup Bitwarden. Os ficheiros encriptados não são suportados. + Forneça uma cópia de /data/data/com.blizzard.messenger/shared_prefs/com.blizzard.messenger.authenticator_preferences.xml, localizado no diretório de armazenamento interno do Autenticador Battle.net. + Forneça uma cópia de /data/data/com.duosecurity.duomobile/files/duokit/accounts.json, localizada no diretório de armazenamento interno do DUO. + Forneça uma cópia de /data/data/org.fedorahosted.freeotp/shared_prefs/tokens.xml, localizado no diretório de armazenamento interno do FreeOTP (1.x). Fornecer um arquivo de exportação FreeOTP+. + Apenas são suportados ficheiros de bases de dados do Google Authenticator v5.10 e anteriores.\n\nForneça uma cópia de /data/data/com.google.android.apps.authenticator2/databases/databases, localizada no diretório de armazenamento interno do Google Authenticator. Fornecer uma cópia de /data/data/com.azure.authenticator/databases/PhoneFactor, localizado no diretório de armazenamento interno do Microsoft Authenticator. Fornecer um arquivo de texto simples com um URI do Google Authenticator em cada linha. + Steam v3.0 e versões mais recentes não são suportadas. Forneça uma cópia de /data/data/com.valvesoftware.android.steam.community/files/Steamguard-*.json, localizada no diretório de armazenamento interno do Steam. Fornecer um arquivo de exportação de Autenticador TOTP. Fornecer um arquivo de exportação do WinAuth. Atribuir ícones + Pretende atribuir ícones às entradas importadas? + A entrada encriptada foi ignorada: %s Importar entradas diretamente de %s. Isto requer que a aplicação seja instalada neste dispositivo e que acesso root seja concedido ao Aegis. - grupos + Grupos + Focar pesquisa no início da aplicação + Focar a pesquisa imediatamente após abrir a aplicação. + Metades Sem grupo Grupos de 2 Grupos de 3 @@ -385,4 +497,30 @@ Apenas um toque Duplo toque Ocultar / Ocultos + Ao lado do emissor + Abaixo do emissor + + há %d segundo + há %d segundos + + + há %d minuto + há %d minutos + + + há %d hora + há %d horas + + + há %d dia + há %d dias + + + Há %d ano + Há %d anos + + + %d item selecionado + %d itens selecionados + diff --git a/app/src/main/res/values-ro-rRO/strings.xml b/app/src/main/res/values-ro-rRO/strings.xml index 1a7b9af0..bd486b78 100644 --- a/app/src/main/res/values-ro-rRO/strings.xml +++ b/app/src/main/res/values-ro-rRO/strings.xml @@ -46,7 +46,7 @@ Arată numele contului Arată numele contului doar atunci când este necesar Arată numai numele de cont ce au același emitent. Alte nume de cont vor fi ascunse. - Această setare este suprascrisă de modul vizualizare tiles. Numele contului va fi afișat întotdeauna sub emitent. + Această setare este suprascrisă de modul vizualizare dale. Numele contului va fi afișat mai jos de emitent. Importă din fișier Importă token-uri dintr-un fișier Backup-uri Android în cloud @@ -63,11 +63,13 @@ Declanșare copie de rezervă Declanșează manual o copie de rezervă Numărul de versiuni de păstrat + \u221E Păstraţi %1$d versiune a copiei de rezervă Păstraţi %1$d versiune a copiei de rezervă Păstraţi %1$d de versiuni ale copiei de rezervă + Păstrează un număr infinit de versiuni ale copiei de rezervă Importă din aplicație Importă tokeni dintr-o aplicație (necesită acces root) Exportă @@ -123,6 +125,7 @@ Deblocarea seifului a eșuat (biometrie) Încercarea de a debloca seiful cu datele biometrice a eșuat Tipul evenimentului este necunoscut + (șters) Astăzi, la %1$s %1$s la %2$s Criptează seiful @@ -309,6 +312,7 @@ Nu se pot importa token-uri drept rezultat Deblocarea seifului Redenumește grupul + În cazul în care o intrare nu face parte din niciun grup, aceasta poate fi găsită în categoria „Niciun grup”. Elimină grupul Ești sigur că dorești să ștergi acest grup? Intrările din acest grup vor comuta automat la \'Niciun grup\'. Ștergeți grupurile neutilizate @@ -363,6 +367,11 @@ Tiles Emitent necunoscut Nume de cont necunoscut + + Aegis nu a putut importa tokenul %d. Acest token va fi omis. Apasă pe \"detalii\" pentru a vedea mai multe informații despre erori. + Aegis nu a putut importa tokenurile %d. Aceste tokenuri vor fi omise. Apasă pe \'detalii\' pentru a vedea mai multe informații despre erori. + Aegis nu a putut importa tokenurile %d. Aceste tokenuri vor fi omise. Apasă pe \'detalii\' pentru a vedea mai multe informații despre erori. + Nu se poate procesa link-ul Nu se poate citi și procesa codul QR din fișierul: %s. Imposibil de procesat textul partajat ca un cod OTP @@ -480,6 +489,7 @@ Furnizează o copie a /data/data/com.authy.authy/shared_prefs/com.authy.storage.tokens.authenticator.xml, localizată în directorul de stocare internă al Authy. Furnizați un fişier de export/copie de rezervă andOTP. Furnizează un fișier de backup din aplicația Bitwarden. Fișierele criptate nu sunt suportate. + Furnizează o copie a /data/data/com.blizzard.messenger/shared_prefs/com.blizzard.messenger.authenticator_preferences.xml, localizată în folderul din memoria internă al Battle.net Authenticator. Furnizează o copie a /data/data/com.duosecurity.duomobile/files/duokit/accounts.json, localizată în dosarul din memoria internă al DUO. Furnizează o copie a /data/data/org.fedorahosted.freeotp/shared_prefs/tokens.xml, localizată în dosarul din stocarea internă a FreeOTP (1.x). Furnizează un fișier de export FreeOTP+. diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index 9ac692b1..9e93d512 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -46,7 +46,7 @@ Показывать имя учётной записи Показывать имя учётной записи только при необходимости Показывать названия учётных записей только в случае, если у них один эмитент. Названия других учётных записей не будут отображаться. - Эта настройка переопределяется плиточным режимом просмотра. Название учётной записи всегда будет отображаться под эмитентом. + Эта настройка переопределяется плиточным режимом просмотра. Название учётной записи будет отображаться под эмитентом. Импорт из файла Импорт ключей из файла Облачное резервирование Android @@ -63,12 +63,14 @@ Создать резервную копию Создание резервной копии вручную Количество хранимых версий + \u221E Хранить %1$d версию резервной копии Хранить %1$d версии резервной копии Хранить %1$d версий резервной копии Хранить %1$d версий резервной копии + Не ограничивать количество версий резервных копий Импорт из приложения Импорт ключей из другого приложения (требуются права суперпользователя) Экспорт в файл @@ -106,6 +108,12 @@ Шифровать хранилище и разблокировать его с помощью пароля или биометрии Биометрическая разблокировка Разрешить биометрическую аутентификацию для разблокировки хранилища + Поиск в: %s + Поиск в любом из следующих полей + Имя + Эмитент + Заметка + Группы Изменить пароль Установить новый пароль, который вам понадобится, чтобы разблокировать хранилище Нет записей о событиях @@ -125,6 +133,7 @@ Хранилище не разблокировано (биометрия) Попытка разблокировать хранилище с помощью биометрии завершилась неудачно Неизвестный тип события + (удалено) Сегодня в %1$s %1$s в %2$s Шифровать хранилище @@ -317,6 +326,7 @@ В результате ни один ключ не может быть импортирован Разблокировка хранилища Переименовать группу + Если запись не входит ни в одну группу, её можно найти в разделе «Нет группы». Удалить группу Удалить группу? Записи из этой группы будут автоматически перемещены в «Нет группы». Удалить неиспользуемые группы @@ -353,6 +363,7 @@ Сворачивать при копировании Сворачивать приложение после копирования ключа Копировать ключи в буфер обмена + Поведение поиска Замораживать ключи при нажатии Приостановить автоматическое обновление ключей принажатии на них. Ключи не будут обновляться до тех пор, пока отображаются. Для обновления потребуется «Выделять ключи при нажатии» или «Отображение по нажатию». Введите свой пароль, чтобы включить PIN-клавиатуру. Обратите внимание, что это работает, только если ваш пароль состоит из цифр. diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index 8fa87bf6..e5a1af95 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -40,14 +40,13 @@ Režim zobrazenia Jazyk Zobraziť ikony - Zobrazte ikony vedľa každého záznamu + Zobraziť ikony vedľa každého záznamu Zoskupenie číselných znakov Vyberte číslo po koľkých čísliciach sa majú zoskupovať kódy Zobraziť názov účtu Zobrazovať názov účtu iba pokiaľ to je potrebné Zobraziť názvy účtov len v prípade, že majú rovnakého vydavateľa. Ostatné názvy účtov budú skryté. - Toto nastavenie je prepísané režimom zobrazenia Dlaždice. Názov účtu bude vždy viditeľný pod vydavateľom. - Importovanie zo súboru + Importovať zo súboru Importovať tokeny zo súboru Zálohy na Android cloude Povoliť zálohovaciemu systému Android Cloud zahrnúť Aegis\' trezor v ich zálohách. Táto možnosť je podporovaná iba pre šifrované trezory. @@ -63,13 +62,15 @@ Spustiť zálohu Ručné spustenie zálohy Počet verzií na uchovanie + \u221E Ponechať %1$d verziu zálohy Ponechať %1$d verzie zálohy Ponechať %1$d verzií zálohy Ponechať %1$d verzií zálohy - Importovanie z aplikácie + Ponechať nekonečné množstvo verzií zálohy + Importovať z aplikácie Importovať tokeny z aplikácie (vyžaduje sa prístup root) Exportovať Exportovať trezor @@ -104,7 +105,7 @@ Zadajte nové heslo, ktoré budete potrebovať na odomknutie trezoru Žiadne nahlásené udalosti V aplikácii neboli nahlásené žiadne dôležité udalosti - Trezor je odomknutý + Trezor odomknutý Trezor bol úspešne odomknutý Záloha vytvorená Záloha trezoru bola úspešne vytvorená @@ -123,7 +124,7 @@ %1$s o %2$s Šifrovať trezor Touto akciou sa exportuje trezor z interného úložiska Aegis. Vyberte formát, v ktorom chcete mať export: - Chystáte sa exportovať nezašifrovanú kópiu svojho trezoru Aegis. Toto sa neodporúča . + Chystáte sa exportovať nezašifrovanú kópiu svojho trezoru Aegis. Toto sa neodporúča. Exporty sú šifrované pomocou samostatného hesla nakonfigurovaného v nastaveniach zabezpečenia. Rozumiem rizikám Aegis (.JSON) @@ -181,6 +182,7 @@ Kopírovať Upraviť Vybrať všetko + Priradiť ikonky Obľúbené Odobrať z obľúbených CHYBA @@ -202,6 +204,12 @@ Odstrániť položku Naozaj chcete túto položku odstrániť? Vymazať položky + + Naozaj chcete odstrániť %d položku? + Naozaj chcete odstrániť %d položky? + Naozaj chcete odstrániť %d položiek? + Naozaj chcete odstrániť %d položiek? + Zrušiť zmeny? Vaše zmeny neboli uložené Pri ukladaní profilu sa vyskytla chyba @@ -338,12 +346,20 @@ Zmeny nie sú zálohované Trezor bol nedávno exportovaný ako obyčajný text + Toto upozornenie viac nezobrazovať Prepnúť fotoaparát Neboli nájdené žiadne záznamy Neboli nájdené žiadne skupiny Zatiaľ neboli importované žiadne balíčky ikon. Klepnite na znamienko plus aby ste ho importovali. Tip: vyskúšajte aegis-icons. Žiadne balíčky ikon + Nezaradené Hotovo + + %d / %d QR kódu + %d / %d QR kódov + %d / %d QR kódov + %d / %d QR kódov + Ďalšie Predchádzajúce Skopírovať URI @@ -363,6 +379,9 @@ O programe Upraviť záznam Skenovať QR kód + Priradiť ikonky + Importovať Aegis trezor + Poskytnite súbor exportu/zálohy Aegisu. Nahrajte súbor s Bitwarden exportom/zálohou. Šifrované súbory nie sú podporované. Skupiny Zamerať vyhľadávanie pri spustení aplikácie @@ -376,4 +395,34 @@ Jedno klepnutie Dvojité poklepanie Skryté + + Pred %d sekundou + Pred %d sekundami + Pred %d sekundami + Pred %d sekundami + + + Pred %d minútou + Pred %d minútami + Pred %d minútami + Pred %d minútami + + + Pred %d hodinou + Pred %d hodinami + Pred %d hodinami + Pred %d hodinami + + + Pred %d dňom + Pred %d dňami + Pred %d dňami + Pred %d dňami + + + Pred %d rokom + Pred %d rokmi + Pred %d rokmi + Pred %d rokmi + diff --git a/app/src/main/res/values-sv-rSE/strings.xml b/app/src/main/res/values-sv-rSE/strings.xml index f641259e..a7d8a522 100644 --- a/app/src/main/res/values-sv-rSE/strings.xml +++ b/app/src/main/res/values-sv-rSE/strings.xml @@ -28,6 +28,8 @@ Konfigurera kryptering, biometrisk upplåsning, automatisk låsning och andra säkerhetsinställningar. Import & export Importera säkerhetskopior från Aegis eller andra autentiseringsappar. Skapa manuella exporter av ditt Aegis-valv. + Granskningslogg + Hitta en lista över alla rapporterade viktiga händelser som hände i appen. Säkerhetskopior Ställ in automatiska säkerhetskopior till en plats som du väljer eller aktivera deltagande i Androids molnsäkerhetskopieringssystem. Ikonpaket @@ -44,7 +46,7 @@ Visa kontonamn Visa kontonamn endast vid behov Visa kontonamn endast när de har samma utfärdare. Andra kontonamn kommer att döljas. - Denna inställning åsidosätts av visningsläget paneler. Kontonamn kommer alltid att visas nedanför utfärdaren. + Denna inställning åsidosätts av visningsläget paneler. Kontonamn kommer att visas nedanför utfärdaren. Importera från fil Importera polletter från en fil Android-molnsäkerhetskopior @@ -61,10 +63,12 @@ Skapa säkerhetskopia Skapa en säkerhetskopia manuellt Antal versioner att behålla + \u221E Behåll %1$d version av säkerhetskopian Behåll %1$d versioner av säkerhetskopian + Behåll ett oändligt antal versioner av säkerhetskopian Importera från app Importera polletter från en app (kräver rotåtkomst) Exportera @@ -100,8 +104,30 @@ Kryptera valvet och lås upp det med ett lösenord eller biometri Biometrisk upplåsning Tillåt biometrisk autentisering för att låsa upp valvet + Namn + Grupper Ändra lösenord Ange ett nytt lösenord som kommer att krävas för att låsa upp ditt valv + Inga rapporterade händelser + Inga viktiga händelser har rapporterats i appen + Valv upplåst + Valvet har låsts upp + Säkerhetskopia skapad + En säkerhetskopia av valvet har skapats + Säkerhetskopia skapad av Android + En säkerhetskopia av valvet har skapats av Android + Valv exporterat + En kopia av valvet har exporterats + Post delades + En post delades + Valvupplåsning misslyckades (lösenord) + Ett försök att låsa upp valvet med ett lösenord misslyckades + Valvupplåsning misslyckades (biometri) + Ett försök att låsa upp valvet med biometri misslyckades + Okänd händelsetyp + (raderad) + Idag kl. %1$s + %1$s kl. %2$s Kryptera valvet Denna åtgärd kommer att exportera valvet från Aegis interna lagring. Välj det format som du vill att din export ska vara i: Du håller på att exportera en okrypterad kopia av ditt Aegis-valv. Detta rekommenderas inte. @@ -280,6 +306,7 @@ Inga polletter kan importeras till följd av detta Låser upp valvet Byt namn på grupp + Om en post inte ingår i någon grupp, kan den hittas under \"Grupplös\". Ta bort grupp Är du säker på att du vill ta bort denna grupp? Poster i denna grupp kommer automatiskt att flyttas till \'Grupplös\'. Radera oanvända grupper diff --git a/app/src/main/res/values-tr-rTR/strings.xml b/app/src/main/res/values-tr-rTR/strings.xml index f708bf2a..77c0a127 100644 --- a/app/src/main/res/values-tr-rTR/strings.xml +++ b/app/src/main/res/values-tr-rTR/strings.xml @@ -44,7 +44,6 @@ Hesap adını göster Hesap adını yalnızca gerektiğinde göster Hesap adlarını yalnızca aynı sağlayıcıyı paylaştıklarında göster. Diğer hesap adları gizlenecektir. - Bu ayar, döşeme görüntüleme modu tarafından geçersiz kılınır. Hesap adı her zaman kartı veren kuruluşun altında gösterilecektir. Dosyadan içeriye aktar Veritabanını dosyadan içeriye aktar Android bulut yedekleme diff --git a/app/src/main/res/values-uk-rUA/strings.xml b/app/src/main/res/values-uk-rUA/strings.xml index 9b32babe..5743c812 100644 --- a/app/src/main/res/values-uk-rUA/strings.xml +++ b/app/src/main/res/values-uk-rUA/strings.xml @@ -33,6 +33,7 @@ Пакети піктограм Керування та імпорт пакетами піктограм Тема + Динамічні кольори Режим перегляду Мова Показувати піктограми diff --git a/app/src/main/res/values-vi-rVN/strings.xml b/app/src/main/res/values-vi-rVN/strings.xml index b9effb74..9e1eaab4 100644 --- a/app/src/main/res/values-vi-rVN/strings.xml +++ b/app/src/main/res/values-vi-rVN/strings.xml @@ -46,9 +46,9 @@ Hiện tên tài khoản Hiện tên tài khoản khi cần Chỉ hiện tên tài khoản khi có cùng dịch vụ. Những tên tài khoản khác sẽ bị ẩn. - Cài đặt này bị ghi đè bởi chế độ xem theo ô. Tên tài khoản sẽ luôn được hiển thị bên dưới dịch vụ. - Nhập từ file - Nhập token từ một file + Cài đặt này bị ghi đè bởi chế độ xem theo ô. Tên tài khoản sẽ hiển thị bên dưới dịch vụ. + Nhập từ tập tin + Nhập mã từ tập tin Sao lưu trên mây Android Cho phép hệ thống sao lưu trên mây Android lưu trữ kho Aegis. Chỉ hỗ trợ các kho được mã hoá. Các bản sao lưu thiết bị (D2D) luôn được cho phép, không kể cài đặt trên @@ -63,9 +63,11 @@ Bật sao lưu Bật sao lưu thủ công Số lượng phiên bản tối đa + \u221E Giữ %1$d phiên bản của bản sao lưu + Không giới hạn số bản sao lưu Nhập từ ứng dụng Nhập token từ một ứng dụng (yêu cầu truy cập root) Xuất @@ -81,8 +83,8 @@ Tắt Bảo vệ màn hình Chặn chụp ảnh màn hình trong ứng dụng. - Nhấn để hiện ra - Các token sẽ được ẩn theo mặc định. Nhấn vào các token để hiện ra mã. + Nhấn để hiện + Mã số được ẩn, nhấn vào thì mới hiện. Thời gian chờ nhấn Tự động khóa Khi %s @@ -100,8 +102,14 @@ Khóa kho bằng mật khẩu hoặc sinh trắc học Sinh trắc học Dùng sinh trắc học để mở khóa kho + Tìm trong: %s + Tìm trong các mục + Tên + Dịch vụ + Ghi chú + Nhãn Đổi mật khẩu - Đặt một mật khẩu mở khóa kho mới + Đặt mật khẩu mở khóa kho mới Chưa có Không có sự kiện nào trong ứng dụng Đã mở khóa @@ -119,15 +127,16 @@ Chưa thể mở khóa (sinh trắc học) Mở khóa kho bằng sinh trắc học không thành công Sự kiện chưa rõ + (đã xóa) %1$s hôm nay %2$s lúc %1$s Mã hoá kho Hành động này sẽ xuất kho ra ngoài bộ nhớ trong của Aegis. Hãy chọn định dạng bản xuất: Bạn sắp xuất một bản sao chưa được mã khóa của kho Aegis. Việc này không được khuyến khích. Quá trình xuất được mã hóa bằng mật khẩu riêng được định cấu hình trong cài đặt Bảo mật. - Tôi hiểu rủi ro này + Tôi hiểu rủi ro Aegis (.JSON) - File văn bản (.TXT) + Tập tin văn bản thuần (.TXT) Trang web (.HTML) Định dạng xuất Xuất tất cả nhãn @@ -138,36 +147,37 @@ Chưa chọn nhãn để xuất Xuất Aegis Authenticator Bảo mật - Aegis là một ứng dụng Xác minh 2 bước tập trung vào bảo mật. Các token được lưu trữ trong một kho mã hoá bằng mật khẩu do bạn chọn. Nếu một kẻ tấn công lấy được file kho mã hoá của bạn, họ sẽ không thể truy cập nội dung vì không biết mật khẩu.\n\nChúng tôi đã đề xuất tùy chọn phù hợp nhất với thiết bị của bạn. + Aegis là ứng dụng xác thực hai yếu tố chú trọng vào bảo mật. Mã xác thực được lưu trong kho và kho này có thể được mã hóa bằng mật khẩu do bạn nhập. Trường hợp kẻ tấn công lấy được tập tin chứa kho này, y không thể truy cập nội dung trong kho nếu không biết mật khẩu.\n\nChúng tôi đã đề xuất tùy chọn phù hợp nhất với thiết bị của bạn. Không - Không cần mật khẩu để mở khóa kho và nó sẽ không được mã hóa. Tùy chọn này không được khuyến khích. + Kho không được mã hóa và không cần mật khẩu để mở. +Tùy chọn này không được khuyến khích. Mật khẩu Cần mật khẩu để mở khóa kho. - Cảnh báo: Nếu bạn quên mật khẩu, bạn sẽ vĩnh viễn mất quyền truy cập vào các token. Không có cách nào để khôi phục chúng. + Cảnh báo: Nếu bạn quên mật khẩu, sẽ không có cách để truy cập các mã xác thực. Khôi phục không cần mật khẩu là chuyện trong mơ. Sinh trắc học - Bên cạnh mật khẩu, thì sinh trắc học đã được đăng ký trên thiết bị, như vân tay hoặc khuôn mặt, có thể được sử dụng để mở khóa kho. + Cùng với mật khẩu, sinh trắc học như vân tay hoặc khuôn mặt được đăng ký trên thiết bị có thể được dùng để mở khóa kho. Mở khóa kho Mở khóa\nkho - Hoặc nhấn vào đây để đổi sang sinh trắc học + Nhấn vào đây để đổi sang sinh trắc học Vui lòng nhập mật khẩu Vui lòng nhập tên nhãn Vui lòng nhập số - Vui lòng lặp lại mật khẩu - Mật khẩu không chính xác + Xác nhận lại mật khẩu + Mật khẩu không đúng Đã phát hiện một thay đổi trong cài đặt bảo mật của thiết bị. Vui lòng đi đến \"Aegis > Cài đặt > Bảo mật > Mở khóa sinh trắc học\" để tắt và bật lại mở khóa sinh trắc học. Vui lòng nhập mật khẩu. Chúng tôi thỉnh thoảng hỏi điều này để cho bạn không quên mật khẩu. Mở khóa sinh trắc học theo mặc định - Đôi khi, chúng tôi nhắc bạn nhập mật khẩu để đảm bảo bạn không quên mật khẩu và không bị khóa khỏi kho của mình. Sau khi nhập mật khẩu của bạn một lần, Aegis sẽ mặc định quay lại mở khóa sinh trắc học cho đến khi đến lúc nhắc nhở mật khẩu khác. + Thỉnh thoảng chúng tôi nhắc bạn nhập mật khẩu để đảm bảo bạn không quên mật khẩu và không mất quyền truy cập vào kho của mình. Sau khi nhập mật khẩu của bạn, Aegis sẽ mặc định quay lại mở khóa sinh trắc học cho đến khi đến lần nhắc tiếp theo. Không bao giờ - Hàng tuần + Hằng tuần Nửa tháng Hàng tháng - Hàng quý + Mỗi ba tháng Bản sao lưu 2FAS này được mã hóa. Vui lòng nhập mật khẩu ở dưới. Các token Authy của bạn đã được mã hóa. Vui lòng đóng Aegis, mở Authy và mở khóa các token bằng mật khẩu của bạn. Bên cạnh đó, Aegis cũng có thể thử giải mã các token Authy cho bạn, nếu bạn nhập mật khẩu ở dưới. - Vui lòng nhập mật khẩu nhập + Vui lòng nhập mật khẩu để nhập Thời hạn (s) - Hash + Hàm băm Loại Chia sẻ @@ -182,8 +192,8 @@ Quét ảnh Nhập thủ công Thiết lập mở khóa sinh trắc học - Sao chép - Chỉnh sửa + Chép + Sửa Chọn tất cả Gán biểu tượng Thích @@ -195,12 +205,12 @@ Mục mới Thêm mục mới Không thể mở khóa kho - Mật khẩu không chính xác. Hãy chắc chắn là bạn không nhập nhầm mật khẩu. + Mật khẩu không chính xác. Hãy chắc chắn là bạn không gõ nhầm. Các mật khẩu nên y hệt nhau và không trống Vui lòng chọn một phương pháp xác minh Đang mã hoá kho Đang xuất kho - Đang đọc file + Đang đọc tập tin Yêu cầu truy cập root Đang phân tích mã QR Đang phân tích mã QR %d/%d (%s) @@ -210,7 +220,7 @@ Đang nhập gói biểu tượng Xóa mục Bạn có chắc bạn muốn xóa mục này không? - Việc này không tắt Xác minh 2 bước cho:\n%s\n\nĐể tránh mất quyền truy cập, hãy chắc chắn rằng bạn đã tắt Xác Thực 2 Bước hoặc bạn có một cách khác để tạo mã cho dịch vụ này. + Hành động này không tắt Xác thực 2 yếu tố cho:\n%s\n\nĐể tránh mất quyền truy cập, hãy chắc chắn rằng bạn đã tắt Xác thực 2 yếu tố hoặc bạn có một cách khác để tạo mã cho dịch vụ này. Xóa các mục Bạn có chắc muốn xóa %d mục? @@ -220,7 +230,7 @@ Lỗi khi lưu hồ sơ Lỗi khi gán biểu tượng Chào mừng - Aegis là một ứng dụng Xác minh 2 bước tự do, bảo mật và mã nguồn mở + Aegis là một ứng dụng xác thực 2 yếu tố tự do, bảo mật và nguồn mở Thiết lập hoàn tất Aegis đã được thiết lập và sẵn sàng hoạt động. Không tìm thấy kho, đang bắt đầu thiết lập… @@ -229,14 +239,14 @@ Đã sao chép phiên bản vào bộ nhớ tạm Đã xảy ra lỗi Đã xảy ra lỗi trong khi mở khóa kho - Đã xảy ra lỗi trong khi mở khóa kho. File kho của bạn có thể bị hỏng. + Đã xảy ra lỗi trong khi mở khóa kho. Tập tin kho của bạn có thể bị hỏng. Đã xảy ra lỗi trong khi lưu kho Đã xảy ra lỗi trong khi khởi tạo kho Đã xảy ra lỗi trong khi nạp kho từ bộ nhớ Đã xảy ra lỗi trong khi giải mã kho bằng xác minh sinh trắc học. Điều này thường chỉ xảy ra nếu cài đặt bảo mật của thiết bị đã được thay đổi. Vui lòng mở khóa kho bằng mật khẩu và thiết lập lại xác minh sinh trắc học trong cài đặt của Aegis. Đã xảy ra lỗi trong khi chuẩn bị xác minh sinh trắc học. Điều này thường chỉ xảy ra nếu cài đặt bảo mật của thiết bị đã được thay đổi. Vui lòng mở khóa kho bằng mật khẩu và thiết lập lại xác minh sinh trắc học trong cài đặt của Aegis. Tắt mã hóa - Bạn có chắc muốn tắt mã hóa không? Việc này sẽ khiến kho được lưu trữ dưới dạng văn bản thuần. Các bản sao lưu tự động cũng sẽ bị tắt. + Bạn có chắc muốn tắt mã hóa không? Làm vậy sẽ khiến kho được lưu trữ dưới dạng văn bản thuần. Sao lưu tự động cũng sẽ bị tắt. Đã xảy ra lỗi trong khi bật mã hóa Đã xảy ra lỗi trong khi tắt mã hóa Đã lên lịch sao lưu thành công @@ -254,9 +264,9 @@ Tùy chỉnh Quyền bị từ chối - Định dạng mới (v0.6.3 hoặc mới hơn) - Định dạng cũ (v0.6.2 hoặc cũ hơn) - File sao lưu andOTP có định dạng gì? + Định dạng mới (v0.6.3 trở lên) + Định dạng cũ (v0.6.2 trở xuống) + Tập tin sao lưu andOTP sử dụng định dạng nào? Bản sao lưu TOTP Authenticator này có được mã hóa bằng mật khẩu không? Chọn ứng dụng mà bạn muốn nhập từ đó Chọn chủ đề bạn thích @@ -264,10 +274,10 @@ Chọn chế độ xem bạn thích Chọn thao tác sao chép mà bạn thích Đã xảy ra lỗi trong khi xử lý file - Lỗi: Không tìm thấy file - Đã xảy ra lỗi trong khi đọc file + Lỗi: Không tìm thấy tập tin + Đã xảy ra lỗi trong khi đọc tập tin Lỗi: Ứng dụng không được cài đặt - Phiên bản %s không được hỗ trợ. Các phiên bản gần đây đã bắt đầu mã hóa một số file trong thư mục lưu trữ nội bộ, khiến Aegis không thể truy cập thông tin cần thiết để nhập. Việc cố gắng nhập có thể dẫn đến lỗi. Bạn vẫn muốn tiếp tục? + Phiên bản %s không được hỗ trợ. Các phiên bản gần đây đã bắt đầu mã hóa một số tập tin trong thư mục lưu trữ nội bộ, khiến Aegis không thể truy cập thông tin cần thiết để nhập. Việc cố gắng nhập có thể dẫn đến lỗi. Bạn vẫn muốn tiếp tục? Lỗi: Không thể nhận quyền truy cập root Đã nhập %d mục @@ -293,6 +303,7 @@ Do đó, không thể nhập token nào Đang mở khóa kho Đổi tên nhóm + Nếu một mục không thuộc bất kỳ nhóm nào, nó sẽ ở trong \"Chưa có nhóm\". Xóa nhãn Bạn có chắc muốn xóa nhãn này? Các mục trong nhãn này sẽ tự động chuyển thành \"Không nhãn\". Xóa nhãn không dùng @@ -329,6 +340,7 @@ Thu nhỏ khi sao chép Thu nhỏ ứng dụng sau khi sao chép một token Sao chép token vào bộ nhớ tạm + Hành vi tìm kiếm Đóng băng token khi nhấn vào Tạm dừng làm mới tự động các token bằng cách nhấn vào chúng. Nhập mật khẩu để bật bàn phím mã PIN. Lưu ý rằng việc này chỉ được nếu mật khẩu của bạn chỉ chứa các chữ số @@ -351,7 +363,7 @@ Aegis không thể nhập %d token. Các token đó sẽ bị bỏ qua. Hãy nhấn \'Chi tiết\' để xem thêm thông tin về các lỗi. Không thể xử lý deep link - Không thể đọc và xử lý mã QR từ file: %s. + Không thể đọc và xử lý mã QR từ tập tin: %s. Không thể xử lý văn bản được chia sẻ dưới dạng OTP Không thể đọc và xử lý vài mã QR. Chỉ %d/%d mục sẽ được nhập. Không thể tạo mã QR @@ -405,7 +417,7 @@ Thiết lập sao lưu Kho gần đây đã được xuất ở dạng văn bản thuần Không hiện cảnh báo này nữa - Cảnh báo này xuất hiện vì gần đây bạn đã xuất một bản sao chưa được mã hóa của kho. Để duy trì tính bảo mật cho token, chúng tôi khuyên bạn nên xóa file này khi nó không còn cần thiết nữa. + Cảnh báo này xuất hiện vì gần đây bạn đã xuất một bản sao chưa được mã hóa của kho. Để giữ an toàn mã xác thực của bạn, chúng tôi khuyên bạn nên xóa tập tin này ngay khi bạn không còn cần đến nữa. Đổi camera Chưa có mã nào. Hãy bắt đầu thêm bằng cách nhấn vào ký hiệu dấu cộng ở góc dưới bên phải Chưa có mục nào @@ -445,7 +457,7 @@ Gán biểu tượng Giấy phép bên thứ ba Xóa toàn bộ mục - Kho của bạn đã chứa các mục. Bạn có muốn xóa các mục đó trước khi nhập tệp này không?\n\nNếu làm vậy, bạn sẽ vĩnh viễn mất quyền truy cập vào các mục hiện có trong kho. + Kho của bạn đã chứa các mục. Bạn có muốn xóa các mục đó trước khi nhập từ tập tin này không?\n\nNếu làm vậy, bạn sẽ vĩnh viễn mất quyền truy cập vào các mục hiện có trong kho. Xóa toàn bộ nội dung kho Aegis đã nhận kích hoạt khẩn nhưng cài đặt bị tắt, đang bỏ qua Xóa kho khẩn cấp @@ -455,23 +467,23 @@ Bỏ đánh dấu %d mục khả năng trùng lặp. Vui lòng xem lại danh sách các mục. - Cung cấp một file sao lưu 2FAS Authenticator. + Cung cấp một tập tin sao lưu 2FAS Authenticator. Cung cấp một file xuất/sao lưu Aegis. - Cung cấp một file xuất Authenticator Plus được nhận qua Cài đặt -> Sao lưu & Khôi phục -> Xuất dưới dạng Văn bản và HTML. - Cung cấp file xuất Authenticator Pro có được thông qua Cài đặt -> Sao lưu -> Sao lưu file mã hóa (đề xuất). + Cung cấp một tập tin xuất Authenticator Plus được nhận qua Cài đặt -> Sao lưu & Khôi phục -> Xuất dưới dạng Văn bản và HTML. + Cung cấp tập tin xuất Authenticator Pro có được thông qua Cài đặt -> Sao lưu -> Sao lưu tập tin mã hóa (đề xuất). Cung cấp một bản sao của /data/data/com.authy.authy/shared_prefs/com.authy.storage.tokens.authenticator.xml, nằm trong thư mục bộ nhớ trong của Authy. - Cung cấp một file xuất/sao lưu andOTP. - Hãy chọn file xuất/sao lưu của Bitwarden. Tệp mã hoá không được hỗ trợ. + Cung cấp một tập tin xuất/sao lưu andOTP. + Hãy chọn tập tin xuất/sao lưu của Bitwarden. Tập tin mã hoá không được hỗ trợ. Cung cấp một bản sao của /data/data/com.blizzard.messenger/shared_prefs/com.blizzard.messenger.authenticator_preferences.xml, nằm trong thư mục bộ nhớ trong của Battle.net Authenticator. Cung cấp một bản sao của /data/data/com.duosecurity.duomobile/files/duokit/accounts.json, nằm trong thư mục bộ nhớ trong của DUO. Cung cấp một bản sao của /data/data/org.fedorahosted.freeotp/shared_prefs/tokens.xml, nằm ở thư mục của FreeOTP (1.x) trên bộ nhớ trong. - Cung cấp một file xuất FreeOTP+. - Chỉ có file cơ sở dữ liệu từ Google Authenticator v5.10 và cũ hơn mới được hỗ trợ.\n\nHãy lấy bản sao của /data/data/com.google.android.apps.authenticator2/databases/databases ở trong thư mục bộ nhớ trong của Google Authenticator. + Cung cấp một tập tin xuất FreeOTP+. + Chỉ có tập tin cơ sở dữ liệu từ Google Authenticator v5.10 và cũ hơn mới được hỗ trợ.\n\nHãy lấy bản sao của /data/data/com.google.android.apps.authenticator2/databases/databases ở trong thư mục bộ nhớ trong của Google Authenticator. Cung cấp một bản sao của /data/data/com.azure.authenticator/databases/PhoneFactor, nằm trong thư mục bộ nhớ trong của Microsoft Authenticator. - Cung cấp một file văn bản thuần có một URI Google Authenticator trên mỗi dòng. + Cung cấp một tập tin văn bản thuần có một URI Google Authenticator trên mỗi dòng. Không hỗ trợ Steam v3.0 trở lên. Cung cấp một bản sao /data/data/com.valvesoftware.android.steam.community/files/Steamguard-*.json, nằm trong thư mục lưu trữ nội bộ của Steam. - Cung cấp một file xuất TOTP Authenticator. - Cung cấp một file xuất WinAuth. + Cung cấp một tập tin xuất TOTP Authenticator. + Cung cấp một tập tin xuất WinAuth. Gán biểu tượng Bạn có chắc muốn gán biểu tượng vào những mục đã nhập? Đã bỏ qua mục mã hoá: %s diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index eb5eeb9a..85680133 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -46,7 +46,7 @@ 显示账户名称 仅在必要时显示账户名 仅在多项具有相同颁发者时显示账户名。隐藏其他账户名。 - 此设置被瓷贴视图模式覆盖。账户名将始终显示在发行者下方。 + 此设置被瓷贴视图模式覆盖。账户名将显示在发行者下方。 从文件导入 从文件导入令牌 Android 云备份 @@ -63,9 +63,11 @@ 触发备份 手动触发备份 要保留的版本数 + \u221E 保留 %1$d 个版本备份 + 备份版本无限量保留 从应用导入 从其他应用导入令牌(需要 root 权限) 导出 @@ -100,6 +102,12 @@ 加密数据库,并在解锁时要求密码或生物识别验证。 生物识别解锁 通过生物识别验证来解锁数据库 + 搜索方式:%s + 搜索下列任意字段 + 名称 + 颁发者 + 备注 + 分组 更改密码 设置解锁数据库所需的新密码 没有报告的事件 @@ -119,6 +127,7 @@ 密码库解锁失败 (生物特征) 尝试用生物特征解锁保险库失败 未知事件类型 + (已删除) 今天 %1$s %2$s 的 %1$s 加密数据库 @@ -293,6 +302,7 @@ 没有可导入的令牌 解锁数据库 重命名组 + 不在任何组中的条目会出现在“无分组”中。 删除分组 您确定要删除这个分组吗?此分组内的条目将自动移动到“无分组”。 删除未使用的组 @@ -329,6 +339,7 @@ 复制时最小化 复制令牌后最小化应用 复制令牌到剪贴板 + 搜索行为 轻按冻结令牌 通过轻按令牌来暂停它们的自动刷新。 只要被聚焦,令牌就不会更新。 需要启用“轻按突出显示令牌”或“轻按显示”。 请输入您的密码以启用 PIN 键盘。请注意,只有当您的密码仅由数字构成时才能使用 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 250944b7..bd74363a 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -33,6 +33,7 @@ 圖示合輯 管理與匯入圖示合輯 主題 + 基於您的 Android 主題配色設定程式配色 檢視模式 語言 顯示圖示 @@ -42,7 +43,6 @@ 顯示帳戶名稱 只在必要時顯示帳戶名稱 只顯示擁有共同發行者的帳戶名稱(並隱藏其他帳戶名稱) - 本項設定將被「條列式顯示模式」覆蓋,帳戶名稱將總是在發行者之下顯示。 從檔案匯入 從檔案匯入憑證 Android 雲端備份 @@ -97,6 +97,13 @@ 允許使用生物特徵辨識驗證來解鎖保險箱 變更密碼 為保險箱設定新解鎖密碼 + 保險箱已解鎖 + 保險箱已成功解鎖 + 備份已建立 + 保險箱備份已成功建立 + 備份已由 Android 建立 + 保險箱備份已由 Android 成功建立 + 今天 %1$s 加密保險箱 此動作將保險箱從 Aegis 的內部儲存空間裡匯出,請選擇欲匯出的格式: 即將匯出未加密的 Aegis 保險箱。不建議 @@ -307,6 +314,7 @@ 未知的服務商 未知帳戶 無法從 %s 檔案讀取和處理QR碼 + 無法將共用文本作為 OTP 進行處理 無法產生QR碼 選擇圖片 選擇圖示 @@ -346,6 +354,8 @@ Aegis 內建的自動備份 Android 雲端備份 + 最新的備份已過時 (%s) + 尚未備份最近針對保險箱的操作。週期性的備份是避免遺失登入方法的最佳良方。請考慮在設定選單內啟用自動備份。 設置備份 From 0046e8827ed80b5cfb79afa3f24115e2f972946a Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Sun, 8 Sep 2024 18:41:30 +0200 Subject: [PATCH 029/113] Release v3.2 --- app/build.gradle | 4 ++-- app/src/main/assets/changelog.html | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index deff5c20..1b6ce5d2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -28,8 +28,8 @@ android { applicationId "${packageName}" minSdkVersion 21 targetSdkVersion 34 - versionCode 70 - versionName "3.1.1" + versionCode 71 + versionName "3.2" multiDexEnabled true buildConfigField "String", "GIT_HASH", "\"${getGitHash()}\"" buildConfigField "String", "GIT_BRANCH", "\"${getGitBranch()}\"" diff --git a/app/src/main/assets/changelog.html b/app/src/main/assets/changelog.html index 1f97ffee..cd101724 100644 --- a/app/src/main/assets/changelog.html +++ b/app/src/main/assets/changelog.html @@ -31,6 +31,21 @@

      +

      Version 3.2

      +

      New

      +
        +
      • The ability to add a single entry to multiple groups
      • +
      • Option to keep an infinite number of backups
      • +
      • Option to customize which fields to search for in entries
      • +
      • Allow hiding entry names in the tiled view mode
      • +
      +

      Fixes

      +
        +
      • With "Tap to reveal" enabled, the size of the shown dots would not be consistent with the size of the code digits, on some devices
      • +
      • After importing a backup, the UI would in some cases incorrectly claim that biometric unlock is enabled
      • +
      • The export dialog was not fully visible on some devices
      • +
      • Various other minor UI, stability and performance improvements
      • +

      Version 3.1.1

      Fixes

      From d40e619cab92006c13a256590a1ed5cbf3bd7db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Wed, 11 Sep 2024 12:24:50 +0200 Subject: [PATCH 030/113] Add ability to reorder groups --- .../aegis/ui/GroupManagerActivity.java | 65 ++++++++----------- .../aegis/ui/views/GroupAdapter.java | 20 +++++- .../aegis/vault/VaultRepository.java | 7 +- app/src/main/res/layout/card_group.xml | 1 + 4 files changed, 53 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/GroupManagerActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/GroupManagerActivity.java index b9c09312..b2872e72 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/GroupManagerActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/GroupManagerActivity.java @@ -7,6 +7,7 @@ import android.view.View; import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; +import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -14,13 +15,9 @@ import com.beemdevelopment.aegis.R; import com.beemdevelopment.aegis.ui.dialogs.Dialogs; import com.beemdevelopment.aegis.ui.views.GroupAdapter; import com.beemdevelopment.aegis.util.Cloner; -import com.beemdevelopment.aegis.vault.VaultEntryException; import com.beemdevelopment.aegis.vault.VaultGroup; import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import org.json.JSONException; -import org.json.JSONObject; - import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -30,7 +27,6 @@ import java.util.UUID; public class GroupManagerActivity extends AegisActivity implements GroupAdapter.Listener { private GroupAdapter _adapter; private HashSet _removedGroups; - private HashSet _renamedGroups; private RecyclerView _groupsView; private View _emptyStateView; private BackPressHandler _backPressHandler; @@ -51,32 +47,45 @@ public class GroupManagerActivity extends AegisActivity implements GroupAdapter. getOnBackPressedDispatcher().addCallback(this, _backPressHandler); _removedGroups = new HashSet<>(); - _renamedGroups = new HashSet<>(); if (savedInstanceState != null) { List removedGroups = savedInstanceState.getStringArrayList("removedGroups"); - List renamedGroups = savedInstanceState.getStringArrayList("renamedGroups"); if (removedGroups != null) { for (String uuid : removedGroups) { _removedGroups.add(UUID.fromString(uuid)); } } - if (renamedGroups != null) { - for (String groupObject : renamedGroups) { - try { - _renamedGroups.add(VaultGroup.fromJson(new JSONObject(groupObject))); - } catch (VaultEntryException | JSONException ignored) { - // This is intentionally ignored since the json object is valid - } - } - } } + ItemTouchHelper touchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() { + @Override + public int getMovementFlags( + @NonNull RecyclerView recyclerView, + @NonNull RecyclerView.ViewHolder viewHolder) { + + return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0); + } + + @Override + public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) { + int draggedItemIndex = viewHolder.getBindingAdapterPosition(); + int targetIndex = target.getBindingAdapterPosition(); + + _adapter.onItemMove(draggedItemIndex, targetIndex); + + return true; + } + + @Override + public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { } + }); + _adapter = new GroupAdapter(this); _groupsView = findViewById(R.id.list_groups); LinearLayoutManager layoutManager = new LinearLayoutManager(this); _groupsView.setLayoutManager(layoutManager); _groupsView.setAdapter(_adapter); _groupsView.setNestedScrollingEnabled(false); + touchHelper.attachToRecyclerView(_groupsView); for (VaultGroup group : _vaultManager.getVault().getGroups()) { if (!_removedGroups.contains(group.getUUID())) { @@ -84,11 +93,6 @@ public class GroupManagerActivity extends AegisActivity implements GroupAdapter. } } - for(VaultGroup group: _renamedGroups) { - _adapter.replaceGroup(group.getUUID(), group); - } - - _emptyStateView = findViewById(R.id.vEmptyList); updateEmptyState(); } @@ -100,12 +104,7 @@ public class GroupManagerActivity extends AegisActivity implements GroupAdapter. for (UUID uuid : _removedGroups) { removed.add(uuid.toString()); } - ArrayList renamed = new ArrayList<>(); - for (VaultGroup group : _renamedGroups) { - renamed.add(group.toJson().toString()); - } - outState.putStringArrayList("renamedGroups", renamed); outState.putStringArrayList("removedGroups", removed); } @@ -116,7 +115,6 @@ public class GroupManagerActivity extends AegisActivity implements GroupAdapter. if (!newGroupName.isEmpty()) { VaultGroup newGroup = Cloner.clone(group); newGroup.setName(newGroupName); - _renamedGroups.add(newGroup); _adapter.replaceGroup(group.getUUID(), newGroup); _backPressHandler.setEnabled(true); } @@ -166,23 +164,16 @@ public class GroupManagerActivity extends AegisActivity implements GroupAdapter. for (UUID uuid : _removedGroups) { _vaultManager.getVault().removeGroup(uuid); } - - saveAndBackupVault(); } - if (!_renamedGroups.isEmpty()) { - _renamedGroups.removeIf(group -> _removedGroups.contains(group.getUUID())); - for (VaultGroup renamedGroup : _renamedGroups) { - _vaultManager.getVault().renameGroup(renamedGroup); - } - saveAndBackupVault(); - } + _vaultManager.getVault().replaceGroups(_adapter.getGroups()); + saveAndBackupVault(); finish(); } private void discardAndFinish() { - if (_removedGroups.isEmpty() && _renamedGroups.isEmpty()) { + if (_removedGroups.isEmpty()) { finish(); return; } diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/GroupAdapter.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/GroupAdapter.java index 2dca0cb6..0e3346fc 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/GroupAdapter.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/GroupAdapter.java @@ -7,12 +7,14 @@ import android.view.ViewGroup; import androidx.recyclerview.widget.RecyclerView; import com.beemdevelopment.aegis.R; +import com.beemdevelopment.aegis.helpers.ItemTouchHelperAdapter; +import com.beemdevelopment.aegis.util.CollectionUtils; import com.beemdevelopment.aegis.vault.VaultGroup; import java.util.ArrayList; import java.util.UUID; -public class GroupAdapter extends RecyclerView.Adapter { +public class GroupAdapter extends RecyclerView.Adapter implements ItemTouchHelperAdapter { private GroupAdapter.Listener _listener; private ArrayList _groups; @@ -32,6 +34,10 @@ public class GroupAdapter extends RecyclerView.Adapter { } } + public ArrayList getGroups() { + return _groups; + } + public void replaceGroup(UUID uuid, VaultGroup newGroup) { VaultGroup oldGroup = getGroupByUUID(uuid); int position = _groups.indexOf(oldGroup); @@ -64,6 +70,18 @@ public class GroupAdapter extends RecyclerView.Adapter { }); } + @Override + public void onItemMove(int firstPosition, int secondPosition) { + CollectionUtils.move(_groups, firstPosition, secondPosition); + notifyItemMoved(firstPosition, secondPosition); + } + + @Override + public void onItemDismiss(int position) { } + + @Override + public void onItemDrop(int position) { } + private VaultGroup getGroupByUUID(UUID uuid) { for (VaultGroup group : _groups) { if (group.getUUID().equals(uuid)) { diff --git a/app/src/main/java/com/beemdevelopment/aegis/vault/VaultRepository.java b/app/src/main/java/com/beemdevelopment/aegis/vault/VaultRepository.java index 4044a6fe..b96522f0 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/vault/VaultRepository.java +++ b/app/src/main/java/com/beemdevelopment/aegis/vault/VaultRepository.java @@ -291,8 +291,11 @@ public class VaultRepository { removeGroup(group); } - public void renameGroup(VaultGroup renamedGroup) { - _vault.getGroups().replace(renamedGroup); + public void replaceGroups(Collection groups) { + _vault.getGroups().wipe(); + for (VaultGroup group : groups) { + _vault.getGroups().add(group); + } } public void removeGroup(VaultGroup group) { diff --git a/app/src/main/res/layout/card_group.xml b/app/src/main/res/layout/card_group.xml index 75eec71a..9e867e7e 100644 --- a/app/src/main/res/layout/card_group.xml +++ b/app/src/main/res/layout/card_group.xml @@ -3,6 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" + android:background="?android:attr/colorBackground" android:orientation="horizontal"> Date: Wed, 11 Sep 2024 13:19:19 +0200 Subject: [PATCH 031/113] Make progressbar rounded on the right side --- app/src/main/res/drawable/progress_horizontal.xml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/drawable/progress_horizontal.xml b/app/src/main/res/drawable/progress_horizontal.xml index bb5fdac4..676fb863 100644 --- a/app/src/main/res/drawable/progress_horizontal.xml +++ b/app/src/main/res/drawable/progress_horizontal.xml @@ -1,9 +1,14 @@ - + + - + \ No newline at end of file From 8c1cc9a47559919745f570e74e73ca11dff08ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Wed, 11 Sep 2024 14:03:34 +0200 Subject: [PATCH 032/113] Prevent copying when revealing code --- .../com/beemdevelopment/aegis/ui/views/EntryAdapter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java index 56f521e2..d3c0cbe1 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java @@ -556,11 +556,11 @@ public class EntryAdapter extends RecyclerView.Adapter if (_highlightEntry || _tempHighlightEntry || _tapToReveal) { if (_focusedEntry == entry) { resetFocus(); - - // Prevent copying when singletap is set and focus is reset - handled = _copyBehavior == CopyBehavior.SINGLETAP; } else { focusEntry(entry, _tapToRevealTime); + + // Prevent copying when singletap is set and the entry is being revealed + handled = _copyBehavior == CopyBehavior.SINGLETAP && _tapToReveal; } } From f8603395fa148d6a553717ba672f57856d53525b Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Mon, 16 Sep 2024 22:01:14 +0200 Subject: [PATCH 033/113] Fix a crash that could occur when deleting a broken icon pack import The following crash could occur when trying to import an icon pack for which an empty folder still exists on disk: ``` Exception java.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 1 at jdk.internal.util.Preconditions.outOfBounds (Preconditions.java:64) at jdk.internal.util.Preconditions.outOfBoundsCheckIndex (Preconditions.java:70) at jdk.internal.util.Preconditions.checkIndex (Preconditions.java:266) at java.util.Objects.checkIndex (Objects.java:359) at java.util.ArrayList.remove (ArrayList.java:511) at com.beemdevelopment.aegis.ui.views.IconPackAdapter.removeIconPack (IconPackAdapter.java:38) at com.beemdevelopment.aegis.ui.fragments.preferences.IconPacksManagerFragment.removeIconPack (IconPacksManagerFragment.java:158) at com.beemdevelopment.aegis.ui.fragments.preferences.IconPacksManagerFragment.lambda$importIconPack$3 (IconPacksManagerFragment.java:133) at androidx.appcompat.app.AlertController$ButtonHandler.handleMessage (AlertController.java:167) at android.os.Handler.dispatchMessage (Handler.java:106) at android.os.Looper.loopOnce (Looper.java:226) at android.os.Looper.loop (Looper.java:313) at android.app.ActivityThread.main (ActivityThread.java:8762) at java.lang.reflect.Method.invoke at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:604) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1067) ``` To reproduce on a debug build of Aegis with the latest aegis-icons imported into the app, run the following commands and then try to import the same aegis-icons ZIP again: ``` $ adb shell $ su # rm -r /data/data/com.beemdevelopment.aegis.debug/files/icons/c1018b93-4e8c-490a-b575-30dde62a833e/20230523/* ``` --- .../preferences/IconPacksManagerFragment.java | 10 +--------- .../aegis/ui/views/IconPackAdapter.java | 6 ++++-- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/IconPacksManagerFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/IconPacksManagerFragment.java index 863ddbf0..0b23328e 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/IconPacksManagerFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/IconPacksManagerFragment.java @@ -107,15 +107,7 @@ public class IconPacksManagerFragment extends Fragment implements IconPackAdapte .setMessage(R.string.remove_icon_pack_description) .setIconAttribute(android.R.attr.alertDialogIcon) .setPositiveButton(android.R.string.yes, (dialog, whichButton) -> { - try { - _iconPackManager.removeIconPack(pack); - } catch (IconPackException e) { - e.printStackTrace(); - Dialogs.showErrorDialog(requireContext(), R.string.icon_pack_delete_error, e); - return; - } - _adapter.removeIconPack(pack); - updateEmptyState(); + removeIconPack(pack); }) .setNegativeButton(android.R.string.no, null) .create()); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/IconPackAdapter.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/IconPackAdapter.java index ec232854..3fb64f09 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/IconPackAdapter.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/IconPackAdapter.java @@ -35,8 +35,10 @@ public class IconPackAdapter extends RecyclerView.Adapter { public void removeIconPack(IconPack pack) { int position = _iconPacks.indexOf(pack); - _iconPacks.remove(position); - notifyItemRemoved(position); + if (position >= 0) { + _iconPacks.remove(position); + notifyItemRemoved(position); + } } @NonNull From 9c151d83c1784733e46279186efb1ba1d3c22982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Tue, 27 Aug 2024 22:53:25 +0200 Subject: [PATCH 034/113] Improve group filters --- .../beemdevelopment/aegis/OverallTest.java | 6 +- .../aegis/ui/MainActivity.java | 179 +++++++++++++++++- .../aegis/ui/views/EntryListView.java | 158 +--------------- app/src/main/res/layout/activity_main.xml | 44 +++-- .../main/res/layout/dialog_select_groups.xml | 1 - .../res/layout/fragment_entry_list_view.xml | 15 -- app/src/main/res/values/strings.xml | 1 + 7 files changed, 215 insertions(+), 189 deletions(-) diff --git a/app/src/androidTest/java/com/beemdevelopment/aegis/OverallTest.java b/app/src/androidTest/java/com/beemdevelopment/aegis/OverallTest.java index cc921be7..903efeda 100644 --- a/app/src/androidTest/java/com/beemdevelopment/aegis/OverallTest.java +++ b/app/src/androidTest/java/com/beemdevelopment/aegis/OverallTest.java @@ -177,12 +177,10 @@ public class OverallTest extends AegisTest { } private void changeGroupFilter(String text) { - onView(withId(R.id.chip_group)).perform(click()); if (text == null) { - onView(withId(R.id.btnClear)).perform(click()); + onView(allOf(withText(R.string.all), isDescendantOfA(withId(R.id.groupChipGroup)))).perform(click()); } else { - onView(withText(text)).perform(click()); - onView(isRoot()).perform(pressBack()); + onView(allOf(withText(text), isDescendantOfA(withId(R.id.groupChipGroup)))).perform(click()); } } 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 82680e4f..1418c72e 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -32,6 +32,7 @@ import androidx.activity.OnBackPressedCallback; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.view.ActionMode; import androidx.appcompat.widget.SearchView; @@ -50,21 +51,29 @@ import com.beemdevelopment.aegis.ui.dialogs.Dialogs; import com.beemdevelopment.aegis.ui.fragments.preferences.BackupsPreferencesFragment; import com.beemdevelopment.aegis.ui.fragments.preferences.PreferencesFragment; import com.beemdevelopment.aegis.ui.models.ErrorCardInfo; +import com.beemdevelopment.aegis.ui.models.VaultGroupModel; import com.beemdevelopment.aegis.ui.tasks.QrDecodeTask; import com.beemdevelopment.aegis.ui.views.EntryListView; import com.beemdevelopment.aegis.util.TimeUtils; +import com.beemdevelopment.aegis.util.UUIDMap; import com.beemdevelopment.aegis.vault.VaultEntry; import com.beemdevelopment.aegis.vault.VaultFile; +import com.beemdevelopment.aegis.vault.VaultGroup; import com.beemdevelopment.aegis.vault.VaultRepository; import com.beemdevelopment.aegis.vault.VaultRepositoryException; import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.google.android.material.chip.Chip; +import com.google.android.material.chip.ChipGroup; +import com.google.android.material.color.MaterialColors; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.common.base.Strings; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Date; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -91,6 +100,11 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene private SearchView _searchView; private EntryListView _entryListView; + private Collection _groups; + private ChipGroup _groupChip; + private Set _groupFilter; + private Set _prefGroupFilter; + private FabScrollHelper _fabScrollHelper; private ActionMode _actionMode; @@ -196,7 +210,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene _entryListView.setViewMode(_prefs.getCurrentViewMode()); _entryListView.setCopyBehavior(_prefs.getCopyBehavior()); _entryListView.setSearchBehaviorMask(_prefs.getSearchBehaviorMask()); - _entryListView.setPrefGroupFilter(_prefs.getGroupFilter()); + _prefGroupFilter = _prefs.getGroupFilter(); FloatingActionButton fab = findViewById(R.id.fab); fab.setOnClickListener(v -> { @@ -220,10 +234,150 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene Dialogs.showSecureDialog(dialog); }); + _groupChip = findViewById(R.id.groupChipGroup); _fabScrollHelper = new FabScrollHelper(fab); _selectedEntries = new ArrayList<>(); } + public void setGroups(Collection groups) { + _groups = groups; + _groupChip.setVisibility(_groups.isEmpty() ? View.GONE : View.VISIBLE); + + if (_prefGroupFilter != null) { + Set groupFilter = cleanGroupFilter(_prefGroupFilter); + _prefGroupFilter = null; + if (!groupFilter.isEmpty()) { + _groupFilter = groupFilter; + _entryListView.setGroupFilter(groupFilter, false); + } + } else if (_groupFilter != null) { + Set groupFilter = cleanGroupFilter(_groupFilter); + if (!_groupFilter.equals(groupFilter)) { + _groupFilter = groupFilter; + _entryListView.setGroupFilter(groupFilter, true); + } + } + + _entryListView.setGroups(groups); + initializeGroups(); + } + + private void initializeGroups() { + _groupChip.removeAllViews(); + + addChipTo(_groupChip, new VaultGroupModel(getString(R.string.all))); + + for (VaultGroup group : _groups) { + addChipTo(_groupChip, new VaultGroupModel(group)); + } + + addSaveChip(_groupChip); + } + + private Set cleanGroupFilter(Set groupFilter) { + Set groupUuids = _groups.stream().map(UUIDMap.Value::getUUID).collect(Collectors.toSet()); + + return groupFilter.stream() + .filter(g -> g == null || groupUuids.contains(g)) + .collect(Collectors.toSet()); + } + + private void addChipTo(ChipGroup chipGroup, VaultGroupModel group) { + Chip chip = (Chip) getLayoutInflater().inflate(R.layout.chip_group_filter, null, false); + chip.setText(group.getName()); + chip.setCheckable(true); + chip.setCheckedIconVisible(false); + chip.setChecked(_groupFilter != null && _groupFilter.contains(group.getUUID())); + + if (group.isPlaceholder()) { + chip.setId(0); + chip.setTag(null); + chip.setChecked(_groupFilter == null); + chip.setOnClickListener(v -> { + setSaveChipVisibility(true); + + Chip checkedChip = (Chip) chipGroup.getChildAt(0); + boolean checkedState = checkedChip.isChecked(); + chipGroup.clearCheck(); + + Set groupFilter = getGroupFilter(chipGroup); + if (!checkedState) { + groupFilter = new HashSet<>(); + groupFilter.add(null); + + checkedChip.setChecked(false); + } else { + checkedChip.setChecked(true); + } + + _groupFilter = groupFilter; + _entryListView.setGroupFilter(groupFilter, true); + }); + + chipGroup.addView(chip); + return; + } + + + chip.setOnCheckedChangeListener((group1, checkedId) -> { + setSaveChipVisibility(true); + Set groupFilter = getGroupFilter(chipGroup); + + if (groupFilter.isEmpty()) { + groupFilter.add(null); + } else { + Chip allGroupsChip = (Chip) chipGroup.getChildAt(0); + allGroupsChip.setChecked(false); + } + + _groupFilter = groupFilter; + _entryListView.setGroupFilter(groupFilter, true); + }); + + chip.setTag(group); + chipGroup.addView(chip); + } + + private void addSaveChip(ChipGroup chipGroup) { + Chip chip = (Chip) getLayoutInflater().inflate(R.layout.chip_group_filter, null, false); + + chip.setText(getString(R.string.save)); + chip.setVisibility(View.GONE); + chip.setChipStrokeWidth(0); + chip.setCheckable(false); + chip.setChipBackgroundColorResource(android.R.color.transparent); + chip.setTextColor(MaterialColors.getColor(chip.getRootView(), com.google.android.material.R.attr.colorSecondary)); + chip.setClickable(true); + chip.setCheckedIconVisible(false); + chip.setOnClickListener(v -> { + onSaveGroupFilter(_groupFilter); + setSaveChipVisibility(false); + }); + + chipGroup.addView(chip); + } + + private void setSaveChipVisibility(boolean visible) { + Chip saveChip = (Chip) _groupChip.getChildAt(_groupChip.getChildCount() - 1); + saveChip.setChecked(false); + saveChip.setVisibility(visible ? View.VISIBLE : View.GONE); + } + + private static Set getGroupFilter(ChipGroup chipGroup) { + return chipGroup.getCheckedChipIds().stream() + .map(i -> { + Chip chip = chipGroup.findViewById(i); + if (chip.getTag() != null) { + VaultGroupModel group = (VaultGroupModel) chip.getTag(); + return group.getUUID(); + } + + return null; + }) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + @Override protected void onDestroy() { _entryListView.setListener(null); @@ -252,6 +406,10 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene instance.putString("submittedSearchQuery", _submittedSearchQuery); instance.putBoolean("isDoingIntro", _isDoingIntro); instance.putBoolean("isAuthenticating", _isAuthenticating); + + if (_groupFilter != null) { + instance.putSerializable("prefGroupFilter", new HashSet<>(_groupFilter)); + } } @Override @@ -677,7 +835,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene startAuthActivity(false); } else if (_loaded) { // update the list of groups in the entry list view so that the chip gets updated - _entryListView.setGroups(_vaultManager.getVault().getUsedGroups()); + setGroups(_vaultManager.getVault().getUsedGroups()); // update the usage counts in case they are edited outside of the EntryListView _entryListView.setUsageCounts(_prefs.getUsageCounts()); @@ -717,7 +875,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene updateLockIcon(); if (_loaded) { - _entryListView.setGroups(_vaultManager.getVault().getUsedGroups()); + setGroups(_vaultManager.getVault().getUsedGroups()); updateSortCategoryMenu(); } @@ -836,7 +994,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene private void loadEntries() { if (!_loaded) { - _entryListView.setGroups(_vaultManager.getVault().getUsedGroups()); + setGroups(_vaultManager.getVault().getUsedGroups()); _entryListView.setUsageCounts(_prefs.getUsageCounts()); _entryListView.setLastUsedTimestamps(_prefs.getLastUsedTimestamps()); _entryListView.addEntries(_vaultManager.getVault().getEntries()); @@ -930,6 +1088,19 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene Dialogs.showSecureDialog(dialog); } + @Override + public void onRestoreInstanceState(@Nullable Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + if (savedInstanceState == null) { + return; + } + + HashSet filter = (HashSet) savedInstanceState.getSerializable("prefGroupFilter"); + if (filter != null) { + _prefGroupFilter = filter; + } + } + @Override public void onEntryClick(VaultEntry entry) { if (_actionMode != null) { diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java index 6bd4fb68..b44db60e 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java @@ -13,15 +13,12 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.LayoutAnimationController; -import android.widget.Button; import android.widget.LinearLayout; import androidx.annotation.AttrRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StyleRes; -import androidx.constraintlayout.widget.ConstraintLayout; -import androidx.core.widget.NestedScrollView; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.ItemTouchHelper; @@ -39,10 +36,8 @@ import com.beemdevelopment.aegis.helpers.MetricsHelper; import com.beemdevelopment.aegis.helpers.SimpleItemTouchHelperCallback; import com.beemdevelopment.aegis.helpers.UiRefresher; import com.beemdevelopment.aegis.otp.TotpInfo; -import com.beemdevelopment.aegis.ui.dialogs.Dialogs; import com.beemdevelopment.aegis.ui.glide.GlideHelper; import com.beemdevelopment.aegis.ui.models.ErrorCardInfo; -import com.beemdevelopment.aegis.ui.models.VaultGroupModel; import com.beemdevelopment.aegis.util.UUIDMap; import com.beemdevelopment.aegis.vault.VaultEntry; import com.beemdevelopment.aegis.vault.VaultGroup; @@ -51,11 +46,7 @@ import com.bumptech.glide.ListPreloader; import com.bumptech.glide.RequestBuilder; import com.bumptech.glide.integration.recyclerview.RecyclerViewPreloader; import com.bumptech.glide.util.ViewPreloadSizeProvider; -import com.google.android.material.bottomsheet.BottomSheetBehavior; -import com.google.android.material.bottomsheet.BottomSheetDialog; import com.google.android.material.card.MaterialCardView; -import com.google.android.material.chip.Chip; -import com.google.android.material.chip.ChipGroup; import com.google.android.material.shape.CornerFamily; import com.google.android.material.shape.ShapeAppearanceModel; import com.google.common.base.Strings; @@ -81,11 +72,7 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { private TotpProgressBar _progressBar; private boolean _showProgress; private ViewMode _viewMode; - private Collection _groups; private LinearLayout _emptyStateView; - private Chip _groupChip; - private Set _groupFilter; - private Set _prefGroupFilter; private UiRefresher _refresher; @@ -106,8 +93,6 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_entry_list_view, container, false); _progressBar = view.findViewById(R.id.progressBar); - _groupChip = view.findViewById(R.id.chip_group); - initializeGroupChip(); // set up the recycler view _recyclerView = view.findViewById(R.id.rvKeyProfiles); @@ -173,41 +158,21 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { _preloadSizeProvider.setView(view); } - @Override - public void onViewStateRestored(@Nullable Bundle savedInstanceState) { - super.onViewStateRestored(savedInstanceState); - if (savedInstanceState == null) { - return; - } - - HashSet filter = (HashSet) savedInstanceState.getSerializable("prefGroupFilter"); - if (filter != null) { - _prefGroupFilter = filter; - } - } - - @Override - public void onSaveInstanceState(@NonNull Bundle outState) { - super.onSaveInstanceState(outState); - // user can apply _groupFilter without saving - // restore _groupFilter as _prefGroupFilter in order to reapply correct filter after screen rotate - if (_groupFilter != null) { - outState.putSerializable("prefGroupFilter", new HashSet<>(_groupFilter)); - } - } - @Override public void onDestroyView() { _refresher.destroy(); super.onDestroyView(); } + public void setGroups(Collection groups) { + _adapter.setGroups(groups); + updateDividerDecoration(); + } + public void setGroupFilter(Set groups, boolean animate) { - _groupFilter = groups; _adapter.setGroupFilter(groups); _touchCallback.setIsLongPressDragEnabled(_adapter.isDragAndDropAllowed()); updateEmptyState(); - updateGroupChip(); if (animate) { runEntriesAnimation(); @@ -384,10 +349,6 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { } } - public void setPrefGroupFilter(Set groupFilter) { - _prefGroupFilter = groupFilter; - } - public void setCodeGroupSize(Preferences.CodeGrouping codeGrouping) { _adapter.setCodeGroupSize(codeGrouping); } @@ -519,116 +480,11 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { _recyclerView.scheduleLayoutAnimation(); } - private void addChipTo(ChipGroup chipGroup, VaultGroupModel group) { - Chip chip = (Chip) getLayoutInflater().inflate(R.layout.chip_group_filter, null, false); - chip.setText(group.getName()); - chip.setCheckable(true); - chip.setChecked(_groupFilter != null && _groupFilter.contains(group.getUUID())); - chip.setCheckedIconVisible(true); - chip.setOnCheckedChangeListener((group1, checkedId) -> { - Set groupFilter = getGroupFilter(chipGroup); - setGroupFilter(groupFilter, true); - }); - chip.setTag(group); - chipGroup.addView(chip); - } - - private void initializeGroupChip() { - View view = getLayoutInflater().inflate(R.layout.dialog_select_groups, null); - BottomSheetDialog dialog = new BottomSheetDialog(requireContext()); - NestedScrollView scrollView = view.findViewById(R.id.scrollView); - ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) scrollView.getLayoutParams(); - layoutParams.matchConstraintMaxHeight = getResources().getConfiguration().screenHeightDp; - - dialog.getBehavior().setState(BottomSheetBehavior.STATE_EXPANDED); - dialog.getBehavior().setSkipCollapsed(false); - dialog.setContentView(view); - - ChipGroup chipGroup = view.findViewById(R.id.groupChipGroup); - Button clearButton = view.findViewById(R.id.btnClear); - Button saveButton = view.findViewById(R.id.btnSave); - clearButton.setOnClickListener(v -> { - chipGroup.clearCheck(); - Set groupFilter = Collections.emptySet(); - if (_listener != null) { - _listener.onSaveGroupFilter(groupFilter); - } - setGroupFilter(groupFilter, true); - dialog.dismiss(); - }); - - saveButton.setOnClickListener(v -> { - Set groupFilter = getGroupFilter(chipGroup); - if (_listener != null) { - _listener.onSaveGroupFilter(groupFilter); - } - setGroupFilter(groupFilter, true); - dialog.dismiss(); - }); - - _groupChip.setOnClickListener(v -> { - chipGroup.removeAllViews(); - - for (VaultGroup group : _groups) { - addChipTo(chipGroup, new VaultGroupModel(group)); - } - addChipTo(chipGroup, new VaultGroupModel(getString(R.string.no_group))); - - Dialogs.showSecureDialog(dialog); - }); - } - - private static Set getGroupFilter(ChipGroup chipGroup) { - return chipGroup.getCheckedChipIds().stream() - .map(i -> { - Chip chip = chipGroup.findViewById(i); - VaultGroupModel group = (VaultGroupModel) chip.getTag(); - return group.getUUID(); - }) - .collect(Collectors.toSet()); - } - - private void updateGroupChip() { - if (_groupFilter.isEmpty()) { - _groupChip.setText(R.string.groups); - } else { - _groupChip.setText(String.format("%s (%d)", getString(R.string.groups), _groupFilter.size())); - } - } - private void setShowProgress(boolean showProgress) { _showProgress = showProgress; updateDividerDecoration(); } - public void setGroups(Collection groups) { - _groups = groups; - _adapter.setGroups(groups); - _groupChip.setVisibility(_groups.isEmpty() ? View.GONE : View.VISIBLE); - updateDividerDecoration(); - - if (_prefGroupFilter != null) { - Set groupFilter = cleanGroupFilter(_prefGroupFilter); - _prefGroupFilter = null; - if (!groupFilter.isEmpty()) { - setGroupFilter(groupFilter, false); - } - } else if (_groupFilter != null) { - Set groupFilter = cleanGroupFilter(_groupFilter); - if (!_groupFilter.equals(groupFilter)) { - setGroupFilter(groupFilter, true); - } - } - } - - private Set cleanGroupFilter(Set groupFilter) { - Set groupUuids = _groups.stream().map(UUIDMap.Value::getUUID).collect(Collectors.toSet()); - - return groupFilter.stream() - .filter(g -> g == null || groupUuids.contains(g)) - .collect(Collectors.toSet()); - } - private void updateDividerDecoration() { if (_itemDecoration != null) { _recyclerView.removeItemDecoration(_itemDecoration); @@ -705,8 +561,8 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { } int entryIndex = _adapter.translateEntryPosToIndex(adapterPosition); - // The first entry should have a top margin, but only if the group chip is not shown and the error card is not shown - if (entryIndex == 0 && (_groups == null || _groups.isEmpty()) && !_adapter.isErrorCardShown()) { + // The first entry should have a top margin, but only if the error card is not shown + if (entryIndex == 0 && !_adapter.isErrorCardShown()) { outRect.top = _offset; } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index ccc10366..8462469d 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,6 +1,5 @@ - + + + + + + + + + + - - - - + android:orientation="vertical" + app:layout_behavior="@string/appbar_scrolling_view_behavior"> @@ -48,6 +64,6 @@ android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin" - android:src="@drawable/ic_outline_add_24" /> + android:src="@drawable/ic_outline_add_24" /> diff --git a/app/src/main/res/layout/dialog_select_groups.xml b/app/src/main/res/layout/dialog_select_groups.xml index a8900bc7..5e418a4e 100644 --- a/app/src/main/res/layout/dialog_select_groups.xml +++ b/app/src/main/res/layout/dialog_select_groups.xml @@ -86,7 +86,6 @@ diff --git a/app/src/main/res/layout/fragment_entry_list_view.xml b/app/src/main/res/layout/fragment_entry_list_view.xml index bd452d12..eaacfb4b 100644 --- a/app/src/main/res/layout/fragment_entry_list_view.xml +++ b/app/src/main/res/layout/fragment_entry_list_view.xml @@ -14,21 +14,6 @@ android:visibility="gone" android:max="5000"/> - - Restore default icon Discard Save + All Issuer PIN (4–16 digits) PIN (4 digits) From 91b632b9cfd36f7838f88c96e26fd83dd11a9561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Tue, 17 Sep 2024 20:59:13 +0200 Subject: [PATCH 035/113] Fix batch_index in Google Authenticator export --- app/src/main/proto/google_auth.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/proto/google_auth.proto b/app/src/main/proto/google_auth.proto index e59f2d61..b214f554 100644 --- a/app/src/main/proto/google_auth.proto +++ b/app/src/main/proto/google_auth.proto @@ -37,6 +37,6 @@ message MigrationPayload { repeated OtpParameters otp_parameters = 1; int32 version = 2; int32 batch_size = 3; - int32 batch_index = 4; + optional int32 batch_index = 4; int32 batch_id = 5; } From d81d741feefdca9e6810a4212102cefc6a9c5d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Thu, 19 Sep 2024 00:55:02 +0200 Subject: [PATCH 036/113] Fix capitalization of multiple text fields --- app/src/main/res/layout/activity_edit_entry.xml | 6 +++--- app/src/main/res/layout/dialog_text_input.xml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/layout/activity_edit_entry.xml b/app/src/main/res/layout/activity_edit_entry.xml index 6a63c26b..1ceed3e5 100644 --- a/app/src/main/res/layout/activity_edit_entry.xml +++ b/app/src/main/res/layout/activity_edit_entry.xml @@ -98,7 +98,7 @@ android:id="@+id/text_name" android:layout_width="match_parent" android:layout_height="wrap_content" - android:inputType="text"/> + android:inputType="textCapSentences"/> + android:inputType="textCapSentences"/> @@ -171,7 +171,7 @@ android:id="@+id/text_note" android:layout_width="match_parent" android:layout_height="wrap_content" - android:inputType="text|textMultiLine"/> + android:inputType="text|textMultiLine|textCapSentences"/> + android:inputType="textCapSentences"/> From 58002c31ef9987f4aabf834d419efb41bd29de70 Mon Sep 17 00:00:00 2001 From: Sigmund Xia Date: Thu, 19 Sep 2024 10:26:05 +0800 Subject: [PATCH 037/113] Add support for Ente Auth import --- .../aegis/importers/DatabaseImporter.java | 1 + .../aegis/importers/EnteAuthImporter.java | 32 +++++++++++++++++++ app/src/main/res/values/strings.xml | 1 + .../aegis/importers/DatabaseImporterTest.java | 6 ++++ .../aegis/importers/ente_auth.txt | 7 ++++ 5 files changed, 47 insertions(+) create mode 100644 app/src/main/java/com/beemdevelopment/aegis/importers/EnteAuthImporter.java create mode 100644 app/src/test/resources/com/beemdevelopment/aegis/importers/ente_auth.txt diff --git a/app/src/main/java/com/beemdevelopment/aegis/importers/DatabaseImporter.java b/app/src/main/java/com/beemdevelopment/aegis/importers/DatabaseImporter.java index 62d846fe..e29fd7ee 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/importers/DatabaseImporter.java +++ b/app/src/main/java/com/beemdevelopment/aegis/importers/DatabaseImporter.java @@ -39,6 +39,7 @@ public abstract class DatabaseImporter { _importers.add(new Definition("Battle.net Authenticator", BattleNetImporter.class, R.string.importer_help_battle_net_authenticator, true)); _importers.add(new Definition("Bitwarden", BitwardenImporter.class, R.string.importer_help_bitwarden, false)); _importers.add(new Definition("Duo", DuoImporter.class, R.string.importer_help_duo, true)); + _importers.add(new Definition("Ente Auth", EnteAuthImporter.class, R.string.importer_help_ente_auth, false)); _importers.add(new Definition("FreeOTP (1.x)", FreeOtpImporter.class, R.string.importer_help_freeotp, true)); _importers.add(new Definition("FreeOTP+ (JSON)", FreeOtpPlusImporter.class, R.string.importer_help_freeotp_plus, true)); _importers.add(new Definition("Google Authenticator", GoogleAuthImporter.class, R.string.importer_help_google_authenticator, true)); diff --git a/app/src/main/java/com/beemdevelopment/aegis/importers/EnteAuthImporter.java b/app/src/main/java/com/beemdevelopment/aegis/importers/EnteAuthImporter.java new file mode 100644 index 00000000..e9196b51 --- /dev/null +++ b/app/src/main/java/com/beemdevelopment/aegis/importers/EnteAuthImporter.java @@ -0,0 +1,32 @@ +package com.beemdevelopment.aegis.importers; + +import android.content.Context; + +import com.beemdevelopment.aegis.util.IOUtils; +import com.topjohnwu.superuser.io.SuFile; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class EnteAuthImporter extends DatabaseImporter { + public EnteAuthImporter(Context context) { + super(context); + } + + @Override + protected SuFile getAppPath() { + throw new UnsupportedOperationException(); + } + + @Override + protected State read(InputStream stream, boolean isInternal) throws DatabaseImporterException { + try { + byte[] bytes = IOUtils.readAll(stream); + GoogleAuthUriImporter importer = new GoogleAuthUriImporter(requireContext()); + return importer.read(new ByteArrayInputStream(bytes), isInternal); + } catch (IOException e) { + throw new DatabaseImporterException(e); + } + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index da3ebea7..d0c13fe2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -519,6 +519,7 @@ Supply a Bitwarden export/backup file. Encrypted files are not supported. Supply a copy of /data/data/com.blizzard.messenger/shared_prefs/com.blizzard.messenger.authenticator_preferences.xml, located in the internal storage directory of Battle.net Authenticator. Supply a copy of /data/data/com.duosecurity.duomobile/files/duokit/accounts.json, located in the internal storage directory of DUO. + Supply an Ente Auth export file. Currently only unencrypted files are supported. Supply a copy of /data/data/org.fedorahosted.freeotp/shared_prefs/tokens.xml, located in the internal storage directory of FreeOTP (1.x). Supply a FreeOTP+ export file. Only database files from Google Authenticator v5.10 and prior are supported.\n\nSupply a copy of /data/data/com.google.android.apps.authenticator2/databases/databases, located in the internal storage directory of Google Authenticator. diff --git a/app/src/test/java/com/beemdevelopment/aegis/importers/DatabaseImporterTest.java b/app/src/test/java/com/beemdevelopment/aegis/importers/DatabaseImporterTest.java index d376dfe3..146381a5 100644 --- a/app/src/test/java/com/beemdevelopment/aegis/importers/DatabaseImporterTest.java +++ b/app/src/test/java/com/beemdevelopment/aegis/importers/DatabaseImporterTest.java @@ -84,6 +84,12 @@ public class DatabaseImporterTest { } } + @Test + public void testImportEnteAuth() throws IOException, DatabaseImporterException, OtpInfoException { + List entries = importPlain(EnteAuthImporter.class, "ente_auth.txt"); + checkImportedEntries(entries); + } + @Test public void testImportWinAuth() throws IOException, DatabaseImporterException, OtpInfoException { List entries = importPlain(WinAuthImporter.class, "plain.txt"); diff --git a/app/src/test/resources/com/beemdevelopment/aegis/importers/ente_auth.txt b/app/src/test/resources/com/beemdevelopment/aegis/importers/ente_auth.txt new file mode 100644 index 00000000..8c52e62c --- /dev/null +++ b/app/src/test/resources/com/beemdevelopment/aegis/importers/ente_auth.txt @@ -0,0 +1,7 @@ +otpauth://hotp/Air%20Canada:Benjamin?secret=KUVJJOM753IHTNDSZVCNKL7GII&issuer=Air+Canada&algorithm=SHA256&digits=7&counter=50&codeDisplay=%7B%22pinned%22%3Afalse%2C%22trashed%22%3Afalse%2C%22lastUsedAt%22%3A0%2C%22tapCount%22%3A0%2C%22tags%22%3A%5B%5D%7D +otpauth://totp/Airbnb:Elijah?secret=7ELGJSGXNCCTV3O6LKJWYFV2RA&issuer=Airbnb&algorithm=SHA512&digits=8&period=50&codeDisplay=%7B%22pinned%22%3Afalse%2C%22trashed%22%3Afalse%2C%22lastUsedAt%22%3A0%2C%22tapCount%22%3A0%2C%22tags%22%3A%5B%5D%7D +otpauth://steam/Boeing:Sophia?secret=JRZCL47CMXVOQMNPZR2F7J4RGI&issuer=Boeing&algorithm=SHA1&digits=5&period=30&codeDisplay=%7B%22pinned%22%3Afalse%2C%22trashed%22%3Afalse%2C%22lastUsedAt%22%3A0%2C%22tapCount%22%3A0%2C%22tags%22%3A%5B%5D%7D +otpauth://totp/Deno:Mason?secret=4SJHB4GSD43FZBAI7C2HLRJGPQ&issuer=Deno&algorithm=SHA1&digits=6&period=30&codeDisplay=%7B%22pinned%22%3Afalse%2C%22trashed%22%3Afalse%2C%22lastUsedAt%22%3A0%2C%22tapCount%22%3A0%2C%22tags%22%3A%5B%5D%7D +otpauth://hotp/Issuu:James?secret=YOOMIXWS5GN6RTBPUFFWKTW5M4&issuer=Issuu&algorithm=SHA1&digits=6&counter=1&codeDisplay=%7B%22pinned%22%3Afalse%2C%22trashed%22%3Afalse%2C%22lastUsedAt%22%3A0%2C%22tapCount%22%3A0%2C%22tags%22%3A%5B%5D%7D +otpauth://totp/SPDX:James?secret=5OM4WOOGPLQEF6UGN3CPEOOLWU&issuer=SPDX&algorithm=SHA256&digits=7&period=20&codeDisplay=%7B%22pinned%22%3Afalse%2C%22trashed%22%3Afalse%2C%22lastUsedAt%22%3A0%2C%22tapCount%22%3A0%2C%22tags%22%3A%5B%5D%7D +otpauth://hotp/WWE:Mason?algorithm=sha512&digits=8&issuer=WWE&period=30&secret=5VAML3X35THCEBVRLV24CGBKOY&counter=10300&codeDisplay=%7B%22pinned%22%3Afalse%2C%22trashed%22%3Afalse%2C%22lastUsedAt%22%3A0%2C%22tapCount%22%3A0%2C%22tags%22%3A%5B%5D%7D From bab59e8d0402fa4dd6dace6242914235e173ea38 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Sat, 21 Sep 2024 13:07:34 +0200 Subject: [PATCH 038/113] Update dependencies --- app/build.gradle | 16 ++--- app/src/main/res/raw/aboutlibraries.json | 74 ++++++++++++------------ build.gradle | 4 +- 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 1b6ce5d2..97cbac61 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -144,7 +144,7 @@ aboutLibraries { dependencies { def cameraxVersion = '1.3.4' def glideVersion = '4.16.0' - def guavaVersion = '33.2.1' + def guavaVersion = '33.3.0' def hiltVersion = '2.52' def junitVersion = '4.13.2' def libsuVersion = '6.0.0' @@ -156,7 +156,7 @@ dependencies { annotationProcessor "com.github.bumptech.glide:compiler:${glideVersion}" implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.activity:activity:1.9.1' + implementation 'androidx.activity:activity:1.9.2' implementation 'androidx.appcompat:appcompat:1.7.0' implementation "androidx.biometric:biometric:1.1.0" implementation "androidx.camera:camera-camera2:$cameraxVersion" @@ -165,7 +165,7 @@ dependencies { implementation 'androidx.core:core:1.13.1' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.documentfile:documentfile:1.0.1' - implementation 'androidx.lifecycle:lifecycle-process:2.8.4' + implementation 'androidx.lifecycle:lifecycle-process:2.8.6' implementation "androidx.preference:preference:1.2.1" implementation 'androidx.recyclerview:recyclerview:1.3.2' implementation "androidx.room:room-runtime:$roomVersion" @@ -182,12 +182,12 @@ dependencies { implementation "com.github.topjohnwu.libsu:io:${libsuVersion}" implementation "com.google.guava:guava:${guavaVersion}-android" implementation 'com.google.android.material:material:1.12.0' - implementation 'com.google.protobuf:protobuf-javalite:4.27.3' + implementation 'com.google.protobuf:protobuf-javalite:4.28.2' implementation 'com.google.zxing:core:3.5.3' - implementation('com.mikepenz:aboutlibraries:11.2.2') { + implementation('com.mikepenz:aboutlibraries:11.2.3') { exclude group: 'com.mikepenz', module: 'aboutlibraries-core' } - implementation 'com.mikepenz:aboutlibraries-core-android:11.2.2' + implementation 'com.mikepenz:aboutlibraries-core-android:11.2.3' implementation 'com.nulab-inc:zxcvbn:1.9.0' implementation 'net.lingala.zip4j:zip4j:2.11.5' implementation 'org.bouncycastle:bcprov-jdk18on:1.78.1' @@ -196,7 +196,7 @@ dependencies { androidTestAnnotationProcessor "com.google.dagger:hilt-android-compiler:$hiltVersion" androidTestImplementation "com.google.dagger:hilt-android-testing:$hiltVersion" androidTestImplementation 'androidx.test:core:1.6.1' - androidTestImplementation 'androidx.test:runner:1.6.1' + androidTestImplementation 'androidx.test:runner:1.6.2' androidTestImplementation 'androidx.test:rules:1.6.1' androidTestImplementation 'androidx.test.ext:junit:1.2.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' @@ -211,5 +211,5 @@ dependencies { testImplementation 'org.json:json:20240303' testImplementation 'org.robolectric:robolectric:4.13' - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.2' } diff --git a/app/src/main/res/raw/aboutlibraries.json b/app/src/main/res/raw/aboutlibraries.json index e94d1ad4..609c42e5 100644 --- a/app/src/main/res/raw/aboutlibraries.json +++ b/app/src/main/res/raw/aboutlibraries.json @@ -1,6 +1,6 @@ { "metadata": { - "generated": "2024-08-26T21:01:22.99Z" + "generated": "2024-09-21T10:56:03.535Z" }, "libraries": [ { @@ -13,14 +13,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.9.1", + "artifactVersion": "1.9.2", "description": "Provides the base Activity subclass and the relevant hooks to build a composable structure on top.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Activity", - "website": "https://developer.android.com/jetpack/androidx/releases/activity#1.9.1", + "website": "https://developer.android.com/jetpack/androidx/releases/activity#1.9.2", "licenses": [ "Apache-2.0" ], @@ -38,14 +38,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.9.1", + "artifactVersion": "1.9.2", "description": "Kotlin extensions for 'activity' artifact", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Activity Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/activity#1.9.1", + "website": "https://developer.android.com/jetpack/androidx/releases/activity#1.9.2", "licenses": [ "Apache-2.0" ], @@ -630,7 +630,7 @@ "developers": [ ], - "artifactVersion": "8.5.0", + "artifactVersion": "8.5.2", "description": "", "name": "androidx.databinding:viewbinding", "licenses": [ @@ -867,14 +867,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.6", "description": "Android Lifecycle-Common", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle-Common", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.6", "licenses": [ "Apache-2.0" ], @@ -892,14 +892,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.6", "description": "Android Lifecycle LiveData", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle LiveData", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.6", "licenses": [ "Apache-2.0" ], @@ -917,14 +917,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.6", "description": "Android Lifecycle LiveData Core", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle LiveData Core", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.6", "licenses": [ "Apache-2.0" ], @@ -942,14 +942,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.6", "description": "Kotlin extensions for 'livedata-core' artifact", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "LiveData Core Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.6", "licenses": [ "Apache-2.0" ], @@ -967,14 +967,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.6", "description": "Kotlin extensions for 'livedata' artifact", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "LiveData Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.6", "licenses": [ "Apache-2.0" ], @@ -992,14 +992,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.6", "description": "Android Lifecycle Process", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle Process", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.6", "licenses": [ "Apache-2.0" ], @@ -1017,14 +1017,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.6", "description": "Android Lifecycle Runtime", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle Runtime", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.6", "licenses": [ "Apache-2.0" ], @@ -1042,14 +1042,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.6", "description": "Kotlin extensions for 'lifecycle' artifact", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.6", "licenses": [ "Apache-2.0" ], @@ -1067,14 +1067,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.6", "description": "Android Lifecycle ViewModel", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle ViewModel", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.6", "licenses": [ "Apache-2.0" ], @@ -1092,14 +1092,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.6", "description": "Kotlin extensions for 'viewmodel' artifact", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle ViewModel Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.6", "licenses": [ "Apache-2.0" ], @@ -1117,14 +1117,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.6", "description": "Android Lifecycle ViewModel", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Lifecycle ViewModel with SavedState", - "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.6", "licenses": [ "Apache-2.0" ], @@ -2304,7 +2304,7 @@ "developers": [ ], - "artifactVersion": "2.26.1", + "artifactVersion": "2.28.0", "description": "Error Prone is a static analysis tool for Java that catches common programming mistakes at compile-time.", "scm": { "connection": "scm:git:https://github.com/google/error-prone.git", @@ -2350,7 +2350,7 @@ "developers": [ ], - "artifactVersion": "33.2.1-android", + "artifactVersion": "33.3.0-android", "description": "Guava is a suite of core and expanded libraries that include\n utility classes, Google's collections, I/O classes, and\n much more.", "scm": { "connection": "scm:git:https://github.com/google/guava.git", @@ -2416,7 +2416,7 @@ "developers": [ ], - "artifactVersion": "4.27.3", + "artifactVersion": "4.28.2", "description": "Lite version of Protocol Buffers library. This version is optimized for code size, but does\n not guarantee API/ABI stability.", "scm": { "connection": "scm:git:https://github.com/protocolbuffers/protobuf.git", @@ -2484,7 +2484,7 @@ "name": "Mike Penz" } ], - "artifactVersion": "11.2.2", + "artifactVersion": "11.2.3", "description": "AboutLibraries automatically detects all dependencies of a project and collects their information including the license. Optionally visualising it via the provided ui components.", "scm": { "connection": "scm:git@github.com:mikepenz/AboutLibraries.git", @@ -2714,7 +2714,7 @@ "name": "Suzanne Millstein" } ], - "artifactVersion": "3.42.0", + "artifactVersion": "3.43.0", "description": "checker-qual contains annotations (type qualifiers) that a programmer\nwrites to specify Java code for type-checking by the Checker Framework.", "scm": { "connection": "scm:git:https://github.com/typetools/checker-framework.git", @@ -2870,7 +2870,7 @@ "name": "Kotlin Team" } ], - "artifactVersion": "2.0.0", + "artifactVersion": "2.0.20", "description": "Kotlin Standard Library", "scm": { "connection": "scm:git:https://github.com/JetBrains/kotlin.git", @@ -3030,7 +3030,7 @@ "name": "JetBrains Team" } ], - "artifactVersion": "1.6.3", + "artifactVersion": "1.7.1", "description": "Kotlin multiplatform serialization runtime library", "scm": { "url": "https://github.com/Kotlin/kotlinx.serialization" @@ -3052,7 +3052,7 @@ "name": "JetBrains Team" } ], - "artifactVersion": "1.6.3", + "artifactVersion": "1.7.1", "description": "Kotlin multiplatform serialization runtime library", "scm": { "url": "https://github.com/Kotlin/kotlinx.serialization" @@ -3074,7 +3074,7 @@ "name": "JetBrains Team" } ], - "artifactVersion": "1.6.3", + "artifactVersion": "1.7.1", "description": "Kotlin multiplatform serialization runtime library", "scm": { "url": "https://github.com/Kotlin/kotlinx.serialization" diff --git a/build.gradle b/build.gradle index c703f753..04721bb1 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:8.5.2' + classpath 'com.android.tools.build:gradle:8.6.1' classpath 'com.google.dagger:hilt-android-gradle-plugin:2.52' classpath 'com.google.protobuf:protobuf-gradle-plugin:0.9.4' @@ -16,7 +16,7 @@ buildscript { } plugins { - id 'com.mikepenz.aboutlibraries.plugin' version '11.2.2' + id 'com.mikepenz.aboutlibraries.plugin' version '11.2.3' } allprojects { From 6a5465063507e080de8394f8fc571fce1b018892 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Sat, 21 Sep 2024 14:01:04 +0200 Subject: [PATCH 039/113] Format multiple string substitutions in positional format This resolves the following lint error: "Multiple substitutions specified in non-positional format of string resource" --- app/src/main/res/values-ar-rSA/strings.xml | 14 -------------- app/src/main/res/values-ast-rES/strings.xml | 7 ------- app/src/main/res/values-bg-rBG/strings.xml | 11 ----------- app/src/main/res/values-ca-rES/strings.xml | 11 ----------- app/src/main/res/values-cs-rCZ/strings.xml | 13 ------------- app/src/main/res/values-da-rDK/strings.xml | 11 ----------- app/src/main/res/values-de-rDE/strings.xml | 11 ----------- app/src/main/res/values-el-rGR/strings.xml | 11 ----------- app/src/main/res/values-es-rES/strings.xml | 11 ----------- app/src/main/res/values-eu-rES/strings.xml | 9 --------- app/src/main/res/values-fa-rIR/strings.xml | 5 ----- app/src/main/res/values-fi-rFI/strings.xml | 11 ----------- app/src/main/res/values-fr-rFR/strings.xml | 10 ---------- app/src/main/res/values-fy-rNL/strings.xml | 11 ----------- app/src/main/res/values-gl-rES/strings.xml | 11 ----------- app/src/main/res/values-hi-rIN/strings.xml | 8 -------- app/src/main/res/values-hu-rHU/strings.xml | 11 ----------- app/src/main/res/values-in-rID/strings.xml | 11 ----------- app/src/main/res/values-it-rIT/strings.xml | 11 ----------- app/src/main/res/values-iw-rIL/strings.xml | 5 ----- app/src/main/res/values-ja-rJP/strings.xml | 10 ---------- app/src/main/res/values-lt-rLT/strings.xml | 2 -- app/src/main/res/values-lv-rLV/strings.xml | 12 ------------ app/src/main/res/values-nl-rNL/strings.xml | 11 ----------- app/src/main/res/values-pl-rPL/strings.xml | 12 ------------ app/src/main/res/values-pt-rBR/strings.xml | 10 ---------- app/src/main/res/values-pt-rPT/strings.xml | 11 ----------- app/src/main/res/values-ro-rRO/strings.xml | 11 ----------- app/src/main/res/values-ru-rRU/strings.xml | 13 ------------- app/src/main/res/values-sv-rSE/strings.xml | 11 ----------- app/src/main/res/values-tr-rTR/strings.xml | 11 ----------- app/src/main/res/values-uk-rUA/strings.xml | 11 ----------- app/src/main/res/values-vi-rVN/strings.xml | 10 ---------- app/src/main/res/values-zh-rCN/strings.xml | 9 --------- app/src/main/res/values-zh-rTW/strings.xml | 7 ------- app/src/main/res/values/strings.xml | 14 +++++++------- 36 files changed, 7 insertions(+), 361 deletions(-) diff --git a/app/src/main/res/values-ar-rSA/strings.xml b/app/src/main/res/values-ar-rSA/strings.xml index cdaaeff2..3c5379c7 100644 --- a/app/src/main/res/values-ar-rSA/strings.xml +++ b/app/src/main/res/values-ar-rSA/strings.xml @@ -219,7 +219,6 @@ قراءة الملف طلب صلاحية الجذر تحليل رمز QR - تحليل رمز QR %d/%d (%s) تم إضافة %d مدخل جديد إلى المخزن تم إضافة %d مدخل جديد إلى المخزن @@ -400,7 +399,6 @@ تعذرت معالجة الارتباط العميق غير قادر على قراءة ومعالجة رمز QR من الملف: %s. غير قادر على معالجة النص المُشارك ك OTP - غير قادر على قراءة ومعالجة بعض رموز QR. سيتم استيراد %d/%d فقط من المدخلات. تعذّر توليد كود QR اختر صورة اختر أيقونة @@ -431,19 +429,7 @@ يعتمد Aegis على وقت النظام لتوليد الأكواد الصحيحة. انحراف بمقادر بضعة ثواني يمكن أن يؤدي إلى أكواد خاطئة. يبدوا أن جهازك غير معيّن إلى مزامنة الوقت تلقائيًا. هل ترغب بفعل ذلك الآن؟ إيقاف تحذيري. أنا أعرف ما أفعله. تم العثور على كود QR لا علاقة له. حاول إعادة تشغيل الماسح. - - تم مسح %d/%d رمز QR - تم مسح %d/%d رمز QR - تم مسح %d/%d رموز QR - تم مسح %d/%d رموز QR - تم مسح %d/%d رمز QR - تم مسح %d/%d رمز QR - - انتظرت كود QR #%d، ولكن مسحت #%d بدلًا منه النسخ الاحتياطي للمخزن فشل مؤخرًا - فشلت محاولة النسخ الاحتياطي للمخزون باستخدام %s بسبب حدوث خطأ. تمت محاولة النسخ الاحتياطي %s. الرجاء التحقق من إعدادات النسخ الاحتياطي للتأكد من أن النسخ الاحتياطي يمكن أن يكتمل بنجاح. - - فشلت محاولة النسخ الاحتياطي الأخيرة للمحفظة باستخدام %s لأن Aegis لم يكن لديه الإذن قراءة وجهة النسخ الاحتياطي. تمت محاولة النسخ الاحتياطي %s. يمكن أن يحدث هذا الخطأ إذا قمت بنقل/إعادة تسمية وجهة النسخ الاحتياطي أو إذا قمت للتو باستعادة Aegis من نسخة احتياطية. الرجاء إعادة إعداد وجهة النسخ الإحتياطي. النسخ الاحتياطية التلقائية المضنة في Aegis نظام النسخ الاحتياطي السحابي للأندرويد أحدث نسخة احتياطية قديمة (%s) diff --git a/app/src/main/res/values-ast-rES/strings.xml b/app/src/main/res/values-ast-rES/strings.xml index 7df617e3..ba354d71 100644 --- a/app/src/main/res/values-ast-rES/strings.xml +++ b/app/src/main/res/values-ast-rES/strings.xml @@ -165,7 +165,6 @@ Esportando l\'arca Lleendo\'l ficheru Analizándo\'l códigu QR - Analizando\'l códigu QR %d/%d (%s) Amestóse %d entrada nueva a l\'arca Amestáronse %d entraes nueves a l\'arca @@ -305,7 +304,6 @@ Nun ye posible procesar l\'enllaz fondu Nun se posible lleer ya procesar el códigu QR del ficheru: %s. Nun ye posible procesar el testu compartíu como cadena d\'OTP - Nun ye posible lleer ya procesar dalgunos códigos QR. Namás van esportase %d/%d entraes. Nun ye posible xenerar el códigu QR Seleición d\'una semeya Seleición d\'un iconu @@ -336,11 +334,6 @@ Aegis encóntase na hora del sistema pa xenerar códigos correutos ya la esviación d\'unos segundos na hora podría facer que se xeneren códigos incorreutos. Paez que\'l preséu nun ta configuráu pa sincronizar automáticamente la hora. ¿Quies facelo agora? Dexar d\'alvertime, sé lo que faigo. Atopóse un códigu QR que nun tien rellación. Prueba a reaniciar l\'escaniador. - - Escanióse %d/%d códigos QR - Escaniáronse %d/%d códigos QR - - Esperábase\'l códigu QR #%d, mas escanióse\'l #%d La copia de seguranza de l\'arca falló apocayá Copies de seguranza automátiques d\'Aegis Sistema de copies de segurazan na ñube d\'Android diff --git a/app/src/main/res/values-bg-rBG/strings.xml b/app/src/main/res/values-bg-rBG/strings.xml index 7689c3f8..61688e79 100644 --- a/app/src/main/res/values-bg-rBG/strings.xml +++ b/app/src/main/res/values-bg-rBG/strings.xml @@ -215,7 +215,6 @@ Прочитане на файла Достъп до правата на суперпотребителя Анализиране на QR кода - Анализиране на QR код %d/%d (%s) Към хранилището е добавен %d запис Към хранилището са добавени %d записа @@ -373,7 +372,6 @@ Грешка при обработка на препратка към секция в приложението Грешка при прочитане и обработка на QR кода от файла: %s. Грешка при обработка на споделения текст като еднократна парола - Грешка при прочитане и обработка на някои от QR кодовете. %d от общо %d записа са внесени. Грешка при създаване на QR код Изберете картина Изберете икона @@ -404,16 +402,7 @@ Aegis разчита системният часовник да бъде верен, за да може да изчислява правилните кодове. Отклонение от само няколко секунди може да доведе до грешни изчисления. Изглежда устройството не е настроено да се сверява. Искате ли да го настроите сега? Без предупреждения. Аз зная какво правя. Намерен е несвързан QR код. Рестартирате скенера. - - Сканирани %d/%d QR кодове - Сканирани %d/%d QR кодове - - Очакван е QR код №%d, но е сканиран №%d Резервно копие на хранилището е било неуспешно - Един от последните опити за резервно копие на хранилището чрез %s е неуспешен поради грешка. Това се е случило %s. Проверете настройките и се уверете, че резервни копия могат да бъдат създавани с тези настройки. - - Скорошен опит за резервно копие на хранилището с използване на %s е неуспешен, защото Aegis няма разрешение да записва в местоназначението. Опитът е направен %s. Такава грешка може да възникне, ако сте преместили или преименували местоназначението или ако наскоро сте възстановили Aegis от резервно копие. Настройте местоназначението за резервно копие. - Вградените резервни копия на Aegis Облачните резервни копия на Андроид Последното резервно копие е остаряло (%s) diff --git a/app/src/main/res/values-ca-rES/strings.xml b/app/src/main/res/values-ca-rES/strings.xml index 7c6ce971..f8de17b6 100644 --- a/app/src/main/res/values-ca-rES/strings.xml +++ b/app/src/main/res/values-ca-rES/strings.xml @@ -215,7 +215,6 @@ S\'està llegint el fitxer Demanant accés root Anàlisi del codi QR - Anàlisi del codi QR %d/%d (%s) S\'ha afegit %d entrada nova a la caixa forta S\'han afegit %d entrades noves a la caixa forta @@ -373,7 +372,6 @@ No es pot processar l\'enllaç profund No es pot llegir i processar el codi QR del fitxer: %s. No es pot processar el text compartit com a OTP - No es poden llegir i processar alguns dels codis QR. Només s\'importaran %d/%d entrades. La generació del codi QR ha fallat Tria imatge Tria icona @@ -404,16 +402,7 @@ Cal que l\'hora del sistema sigui correcta per tal de generar codis correctes. Una desviació d\'uns quants segons pot causar codis no vàlids. Sembla que el teu dispositiu no està configurat per a sincronitzar la hora automàticament. Vols activar-ho ara? No cal que m\'avisis més. Sé el que estic fent. Codi QR no vàlid. Prova-ho un altre cop. - - S\'ha escanejat %d/%d codi QR - S\'han escanejat %d/%d codis QR - - S\'esperava codi QR #%d, però s\'ha trobat #%d en el seu lloc Ha fallat la còpia de seguretat recentment - Una còpia de seguretat de la caixa forta utilitzant %s ha fallat. La còpia s\'ha intentat %s. Si us plau, comprova la configuració de la còpia per a assegurar-te de que les còpies es poden fer correctament. - - Un intent recent de còpia de seguretat de la caixa forta utilitzant %s ha fallat perquè l\'Aegis no té permís d\'escriptura en el destí de la còpia de seguretat. La còpia s\'ha intentat %s. Aquest error pot aparèixer si has mogut/reanomenat el destí de la còpia de seguretat o si has restaurat l\'Aegis recentment des d\'una còpia de seguretat. Si us plau torna a configurar el destí de la còpia de seguretat. - Còpies de seguretat integrades a Aegis Còpia al núvol d\'Android L\'última còpia de seguretat és molt antiga (%s) diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 486feae3..7dd3ccf6 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -221,7 +221,6 @@ Čtení souboru Žádání o přístup root Analyzování QR kódu - Analyzuji QR kód %d/%d (%s) Do trezoru byl přidán %d nový záznam Do trezoru byly přidány %d nové záznamy @@ -391,7 +390,6 @@ Nepodařilo se zpracovat odkaz Nepodařilo se přečíst a zpracovat QR kód ze souboru: %s. Nepodařilo se zpracovat sdílený text jako OTP - Nepodařilo se přečíst a zpracovat některé QR kódy. Bude importováno pouze %d/%d položek. QR kód nelze vygenerovat Vyberte obrázek Vybrat ikonu @@ -422,18 +420,7 @@ Aegis při generování správných kódů spoléhá na synchronizaci systémového času. Odchylka pouze několika sekund může mít za následek nesprávné kódy. Zdá se, že vaše zařízení není nakonfigurováno pro automatickou synchronizaci času. Chcete nastavit automatickou synchronizaci času? Už mě neupozorňujte. Vím, co dělám. Nalezen nesouvisející QR kód. Zkuste skener restartovat. - - Naskenován %d/%d QR kódu - Naskenováno %d/%d QR kódů - Naskenováno %d/%d QR kódů - Naskenováno %d/%d QR kódů - - Očekáván QR kód #%d, avšak naskenován byl #%d Vytvoření zálohy trezoru se nedávno nezdařilo - Pokus o nedávnou zálohu trezoru pomocí %s selhal, protože došlo k chybě. Pokus o zálohu byl uskutečněn %s. Zkontrolujte prosím svá nastavení pro ujištění se, že zálohy mohou být úspěšně dokončeny. - - Nedávný pokus o zálohu trezoru pomocí %s selhal, protože Aegis neměl oprávnění k zápisu do cílového adresáře. Pokus o zálohu byl proveden %s. Tato chyba může nastat, když přesunete/přejmenujete cíl zálohy nebo pokud jste nedávno obnovili Aegis ze zálohy. Nastavte prosím znovu cíl pro zálohu. - Zabudované zálohy aplikace Aegis Cloudový zálohovací systém systému Android Poslední záloha je zastaralá (%s) diff --git a/app/src/main/res/values-da-rDK/strings.xml b/app/src/main/res/values-da-rDK/strings.xml index c5d3479f..e8d2c04b 100644 --- a/app/src/main/res/values-da-rDK/strings.xml +++ b/app/src/main/res/values-da-rDK/strings.xml @@ -215,7 +215,6 @@ Læser fil Anmoder om root-adgang Analyserer QR-kode - Analyserer QR-kode %d/%d (%s) Tilføjede %d ny post til boksen Tilføjede %d nye poster til boksen @@ -373,7 +372,6 @@ Dybt link kan ikke behandles Kan ikke læse og behandle QR-koden fra filen: %s. Kan ikke behandle delt tekst som OTP - Kan ikke læse og behandle nogle af QR-koderne. Kun %d/%d poster importeres. Kan ikke generere QR-kode Vælg billede Vælg ikon @@ -404,16 +402,7 @@ Aegis er afhængig af systemtiden for at være i synk til generering af korrekte koder. En afvigelse på kun et par sekunder kan resultere i forkerte koder. Det ser ud til, at enheden ikke er opsat til auto-synk af tid. Opsæt dette nu? Ophør med at advare mig. Jeg ved, hvad jeg gør. Ikke-relateret QR-kode fundet. Prøv at genstarte skanneren. - - Skannede %d/%d QR-koder - Skannede %d/%d QR-koder - - Forventede QR kode #%d, men skannede #%d i stedet Bokssikkerhedskopiering mislykkedes for nylig - Et nyligt Bokssikkerhedskopieringsforsøg vha. %s mislykkedes, da en fejl opstod. Sikkerhedskopieringen blev forsøgt: %s. Tjek sikkerhedskopieringsindstillingerne for at sikre, at sikkerhedskopieringer kan fuldføres. - - Et nyligt Bokssikkerhedskopieringsforsøg vha. %s fejlede grundet Aegis\' manglende skriverettighed på sikkerhedskopidestinationen. Sikkerhedskopieringen forsøgt %s. Fejlen kan opstå, hvis sikkerhedskopidestinationen er blevet flyttet/omdøbt, eller Aegis for nylig er gendannet fra en sikkerhedskopi. Genopsæt sikkerhedskopidestination. - Aegis\' indbyggede automatiske sikkerhedskopieringer Android cloud-sikkerhedskopieringssystem Seneste sikkerhedskopi er forældet (%s) diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index 21c7d655..6b874286 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -215,7 +215,6 @@ Datei wird gelesen Root-Zugriff wird angefordert QR-Code wird analysiert - QR-Code %d/%d (%s) wird analysiert %d neuer Eintrag zur Datenbank hinzugefügt %d neue Einträge zur Datenbank hinzugefügt @@ -373,7 +372,6 @@ Deep-Link konnte nicht verarbeitet werden QR-Code konnte nicht aus der Datei gelesen und verarbeitet werden: %s. Gemeinsamer Text kann nicht als OTP verarbeitet werden - Einige der QR-Codes konnten nicht gelesen und verarbeitet werden. Nur %d/%d Einträge werden importiert. QR-Code konnte nicht generiert werden Bild auswählen Symbol auswählen @@ -404,16 +402,7 @@ Aegis ist auf die Synchronisierung der Systemzeit angewiesen, um korrekte Codes zu generieren. Eine Abweichung von nur wenigen Sekunden kann zu falschen Codes führen. Es sieht so aus, als ob dein Gerät nicht so konfiguriert ist, dass es die Zeit automatisch synchronisiert. Möchtest du das jetzt tun? Höre auf, mich zu warnen. Ich weiß, was ich tue. Nicht zugehöriger QR-Code gefunden. Versuche, den Scanner neu zu starten. - - 1 QR-Code gescannt - %d/%d QR-Codes gescannt - - QR-Code #%d erwartet, stattdessen wurde #%d gescannt Sicherungskopie ist kürzlich fehlgeschlagen - Ein kürzlicher Sicherungsversuch der Datenbank mit %s ist fehlgeschlagen, da ein Fehler aufgetreten ist. Die Sicherung wurde am %s versucht. Bitte überprüfe deine Sicherungseinstellungen, um sicherzustellen, dass Sicherungen erfolgreich abgeschlossen werden können. - - Ein kürzlich durchgeführter Sicherungsversuch auf %s schlug fehl, da Aegis keine Berechtigung zum Schreiben auf das Sicherungsziel hatte. Die Sicherung wurde %s versucht. Dieser Fehler kann auftreten, wenn das Sicherungsziel verschoben/umbenannt wurde oder wenn Aegis kürzlich aus einer Sicherung wiederhergestellt wurde. Bitte konfiguriere das Sicherungsziel neu. - Automatisierte Sicherungen von Aegis Cloud-Sicherungssystem von Android Die letzte Sicherung ist veraltet (%s) diff --git a/app/src/main/res/values-el-rGR/strings.xml b/app/src/main/res/values-el-rGR/strings.xml index 741fde94..259ee620 100644 --- a/app/src/main/res/values-el-rGR/strings.xml +++ b/app/src/main/res/values-el-rGR/strings.xml @@ -215,7 +215,6 @@ Ανάγνωση αρχείου Αίτηση πρόσβασης root Ανάλυση κωδικού QR - Ανάλυση κωδικού QR %d/%d (%s) Προστέθηκε %d νέα καταχώρηση στην κρύπτη Προστέθηκαν %d νέες καταχωρήσεις στην κρύπτη @@ -373,7 +372,6 @@ Δεν είναι δυνατή η επεξεργασία βαθιάς σύνδεσης Αδυναμία ανάγνωσης και επεξεργασίας QR κωδικού από αρχείο: %s. Δεν είναι δυνατή η επεξεργασία κοινόχρηστου κειμένου ως OTP - Δεν είναι δυνατή η ανάγνωση και επεξεργασία μερικών QR κωδικών. Θα εισαχθούν μόνο %d/%d καταχωρήσεις. Δεν είναι δυνατή η δημιουργία κωδικού QR Επιλέξτε εικόνα Επιλέξτε εικονίδιο @@ -404,16 +402,7 @@ Το Aegis βασίζεται στον χρόνο του συστήματος για να είναι συγχρονισμένο για τη δημιουργία σωστών κωδικών. Μια απόκλιση λίγων δευτερολέπτων θα μπορούσε να οδηγήσει σε εσφαλμένους κωδικούς. Φαίνεται ότι η συσκευή σας δεν έχει ρυθμιστεί ώστε να συγχρονίζει αυτόματα την ώρα. Θα θέλατε να το κάνετε τώρα; Σταμάτα να με προειδοποιείς. Ξέρω τι κάνω. Βρέθηκε μη σχετικός κωδικός QR. Δοκιμάστε να κάνετε επανεκκίνηση του σαρωτή. - - Σαρωμένος %d/%d κωδικός QR - Σαρωμένοι %d/%d κωδικοί QR - - Αναμενόταν κωδικός QR #%d, αλλά σαρώθηκε #%d αντί αυτού Η δημιουργία αντιγράφων ασφαλείας κρύπτης απέτυχε πρόσφατα - Μια πρόσφατη προσπάθεια δημιουργίας αντιγράφων ασφαλείας κρύπτης με χρήση %s απέτυχε επειδή παρουσιάστηκε σφάλμα. Έγινε προσπάθεια δημιουργίας αντιγράφων ασφαλείας %s. Παρακαλώ ελέγξτε τις ρυθμίσεις δημιουργίας αντιγράφων ασφαλείας για να βεβαιωθείτε ότι τα αντίγραφα ασφαλείας μπορούν να ολοκληρωθούν με επιτυχία. - - Μια πρόσφατη προσπάθεια δημιουργίας αντιγράφων ασφαλείας κρύπτης με χρήση %s απέτυχε επειδή το Aegis δεν είχε άδεια να εγγράψει στον προορισμό αντιγράφου ασφαλείας. Το αντίγραφο ασφαλείας επιχειρήθηκε %s. Αυτό το σφάλμα μπορεί να συμβεί αν μετακινήσατε / μετονομάσατε τον προορισμό αντιγράφου ασφαλείας ή αν αποκαταστήσατε πρόσφατα το Aegis από ένα αντίγραφο ασφαλείας. Παρακαλώ ρυθμίστε ξανά τον προορισμό του αντιγράφου ασφαλείας. - Ενσωματωμένα αυτόματα αντίγραφα ασφαλείας του Aegis Σύστημα αντιγράφων ασφαλείας στο cloud του Android Το τελευταίο αντίγραφο ασφαλείας είναι παρωχημένο (%s) diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index 30641df1..bcb503b4 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -215,7 +215,6 @@ Leyendo archivo Solicitando acceso a la raíz Analizando código QR - Analizando código QR %d/%d (%s) Añadida %d nueva entrada a la bóveda Añadidas %d nuevas claves a la bóveda @@ -373,7 +372,6 @@ No se puede procesar el enlace profundo No se puede leer y procesar el código QR del archivo: %s. No se puede procesar el texto compartido como OTP - No se pueden leer y procesar algunos de los códigos QR. Solo se importarán %d/%d entradas. No se puede generar el código QR Seleccionar imagen Seleccionar icono @@ -404,16 +402,7 @@ Aegis depende que la hora de tu dispositivo esté bien para generar códigos válidos en cada momento. Una pequeña diferencia de unos segundos podría hacer que los códigos no se acepten. Parece que tu dispositivo no está configurado para sincronizar automáticamente la hora. ¿Quieres hacerlo ahora? No molestar, sé muy bien lo que hago. Encontrado código QR no relacionado. Intente reiniciar el escáner. - - Escaneado %d/%d código QR - Escaneados %d/%d códigos QR - - Se esperaba el código QR número %d, pero parece que has escaneado el número %d La copia de seguridad de la bóveda ha fallado recientemente - Ha fallado una copia de la bóveda mediante %s realizada %s. Asegúrate de que la configuración esté bien para evitar problemas. - - Ha fallado una copia de la bóveda mediante %s realizada %s porque Aegis no tenía permiso para escribir la carpeta elegida. Este error puede producirse si se ha movido o renombrado la carpeta o si has importado los ajustes de Aegis desde otro dispositivo. Vuelve a configurar la carpeta destino. - Copias de seguridad automáticas de Aegis Sistema de copias de seguridad en la nube de Android La última copia de seguridad está desactualizada (%s) diff --git a/app/src/main/res/values-eu-rES/strings.xml b/app/src/main/res/values-eu-rES/strings.xml index 9dd3f454..1fd1b1bc 100644 --- a/app/src/main/res/values-eu-rES/strings.xml +++ b/app/src/main/res/values-eu-rES/strings.xml @@ -209,7 +209,6 @@ Fitxategia irakurtzen Root sarbidea eskatzen QR kodea aztertzen - QR kodea aztertzen %d/%d (%s) Sarrera berri %d gehitu da %d sarrera berri gehitu dira @@ -366,7 +365,6 @@ Ezin izan da esteka sakona prozesatu Ezin izan da fitxategian oinarritutako QR kodea prozesatu: %s. Ezin izan da partekatutako testua OTP bezala prozesatu - Ezin izan dira QR kode batzuk irakurri eta prozesatu. %d/%d sarrera inportatuko dira bakarrik. Ezin da QR kodea sortu Aukeratu irudia Aukeratu ikonoa @@ -397,14 +395,7 @@ Aegis-ek konfiantza du sistemaren denboran, kode zuzenak sortzeko sinkronizatuta egoteko. Segundo batzuetako desbideratzea kode okerrak eragin ditzake. Badirudi zure gailua ez dagoela denbora automatikoki sinkronizatzeko konfiguratuta. Orain egitea gustatuko litzaizuke? Utzi aholkuak emateari. Badakit zer egiten ari naizen. Erlazionatu gabeko QR kodea aurkitu da. Saiatu eskanerra berrabiarazten. - - %d/%d eskaneatutako QR kodeak - %d/%d eskaneatutako QR kodeak - - Itxarondako QR kodea #%d, baina haren ordez #%d eskaneatuta Biltegiaren segurtasun-kopiak akatsa eman du berriki - %s erabiliz egindako biltegiaren segurtasun kopiak huts egin du. Saiakera noiz egin den: %s. Ziurtatu segurtasun kopien ezarpenak ondo daudela hauek ondo egin daitezen. - %s erabiliz egin den segurtasun-kopia baten saiakerak huts egin du Aegisek ez baitu baimenik helburuan ezer idazteko. Segurtasun kopiaren saiakera %s izan da. Errore hau kopia mugitu/berrizendatu egin duzulako izan daiteke edo Aegis segurtasun-kopia batetik berrezarri duzulako. Konfiguratu berriz zure kopien helburu karpeta. Aegisek egindako segurtasun kopia automatikoak Androidek lainoan egidako segurtasun kopiak Azken segurtasun kopia zaharregia da (%s) diff --git a/app/src/main/res/values-fa-rIR/strings.xml b/app/src/main/res/values-fa-rIR/strings.xml index bcc82db5..554e0ce6 100644 --- a/app/src/main/res/values-fa-rIR/strings.xml +++ b/app/src/main/res/values-fa-rIR/strings.xml @@ -250,11 +250,6 @@ این برنامه نیاز به زمان دقیق برای ساختن کد جدید دارد. تفاوت چند ثانیه‌ای ممکن است باعث ایجاد کد اشتباه شود. به نظر می‌رسد ساعت دستگاه شما به صورت خودکار تنظیم نشده است. آیا میخواهید این کار را انجام دهید؟ دیگر به من هشدار نده. می‌دانم دارم چکار می‌کنم. یک بارکد دوبعدی نا مربوط دریافت شد. لطفا اسکنر خود را ریستارت کنید. - - %d/%d بارکد دوبعدیs اسکن شد - %d/%d بارکد دوبعدیs اسکن شد - - بجای اینکه بارکد دوبعدی %d اسکن شود، بارکد دوبعدی %d اسکن شد. خطا پشتیبان گیری از مخزن تغییر دوربین کدی برای نمایش موجود ندارد. لطفا برای اضافه کردن از دکمه به علاوه در پایین صفحه استفاده کنید. diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index d6332e0e..f913e65a 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -209,7 +209,6 @@ Luetaan tiedostoa Pyydetään root-oikeuksia Analysoidaan QR-koodia - Luetaan QR-koodia %d/%d (%s) %d uusi kohde lisätty holviin %d uutta kohdetta lisätty holviin @@ -366,7 +365,6 @@ Syvää linkkiä ei voitu käsitellä Tiedoston %s QR-koodia ei voitu lukea ja käsitellä. Jaettua tekstiä ei voitu käsitellä OTP:nä - Joitakin QR-koodeja ei voitu lukea ja käsitellä. Vain %d/%d kohdetta tuodaan. QR-koodia ei voitu luoda Valitse kuva Valitse kuvake @@ -397,16 +395,7 @@ Aegis vaatii, että järjestelmän aika on synkronoitu oikeiden koodien luomiseksi. Vain muutaman sekunnin poikkeama voi johtaa virheellisiin koodeihin. Näyttää siltä, että laitettasi ei ole määritetty synkronoimaan aika automaattisesti. Haluatko tehdä niin nyt? Lopeta varoitus. Tiedän mitä teen. Asiaankuulumaton QR-koodi löytyi. Yritä käynnistää skanneri uudelleen. - - %d/%d QR-koodia skannattu - %d/%d QR-koodia skannattu - - Odotettiin QR-koodia #%d, mutta skannattu #%d sen sijaan Holvin varmuuskopiointi epäonnistui äskettäin - Äskettäinen holvin varmuuskopiointiyritys %s käyttämällä epäonnistui, koska tapahtui virhe. Varmuuskopiointia yritettiin %s. Tarkista varmuuskopiointiasetukset varmistaaksesi, että varmuuskopiointi onnistuu. - - Äskettäinen holvin varmuuskopiointiyritys %s käyttäen epäonnistui, koska Aegisilla ei ollut kirjoitusoikeutta varmuuskopiointikohteeseen. Varmuuskopiointia yritettiin %s. Tämä virhe voi ilmetä, jos olet siirtänyt tai nimennyt varmuuskopiointikohteen uudelleen tai jos olet hiljattain palauttanut Aegiksen varmuuskopiosta. Määritä varmuuskopiointikohde uudelleen. - Aegisin sisäänrakennetut automaattiset varmuuskopiot Androidin pilvivarmuuskopiointijärjestelmä Viimeisin varmuuskopiointi on vanhentunut (%s) diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml index bf4668b9..7ee1693a 100644 --- a/app/src/main/res/values-fr-rFR/strings.xml +++ b/app/src/main/res/values-fr-rFR/strings.xml @@ -215,7 +215,6 @@ Lecture du fichier Demande d\'accès root Analyse du code QR - Analyse du code QR %d/%d (%s) Ajout de %d nouvelle entrée dans le coffre-fort Ajout de %d nouvelles entrées dans le coffre-fort @@ -373,7 +372,6 @@ Impossible de traiter le lien profond Impossible de lire et de traiter le code QR depuis le fichier : %s. Impossible de traiter le texte partagé comme OTP - Impossible de lire et de traiter certains codes QR. Seules %d/%d entrées seront importées. Impossible de générer le code QR Sélectionner image Sélectionner une icône @@ -404,15 +402,7 @@ Aegis s\'appuie sur l\'heure du système pour être synchronisé afin de générer des codes corrects. Un écart de quelques secondes seulement pourrait aboutir à des codes incorrects. Il semble que votre appareil n\'est pas configuré pour synchroniser le temps automatiquement. Souhaitez-vous le faire maintenant ? Arrêter de m\'avertir. Je sais ce que je fais. Code QR non lié trouvé. Essayez de redémarrer le scanner. - - %d/%d code QR scanné - %d/%d codes QR scannés - - Code QR n°%d attendu, mais n°%d scanné à la place La sauvegarde du coffre-fort a échoué récemment - Une tentative récente de sauvegarde du coffre-fort en utilisant %s a échoué car une erreur est survenue. La sauvegarde a été tentée %s. Veuillez vérifier vos paramètres de sauvegarde pour vous assurer que les sauvegardes peuvent être terminées avec succès. - Une récente tentative de sauvegarde du coffre-fort en utilisant %s a échoué car Aegis n\'avait pas la permission d\'écrire dans la destination de la sauvegarde. La sauvegarde a été tentée %s. Cette erreur peut se produire si vous avez déplacé/renommé la destination de la sauvegarde ou si vous avez récemment restauré Aegis depuis une sauvegarde. Veuillez reconfigurer la destination de la sauvegarde. - Sauvegardes automatiques intégrées dans Aegis Système de sauvegarde cloud d\'Android La dernière sauvegarde est obsolète (%s) diff --git a/app/src/main/res/values-fy-rNL/strings.xml b/app/src/main/res/values-fy-rNL/strings.xml index d6cad92d..ce0ca113 100644 --- a/app/src/main/res/values-fy-rNL/strings.xml +++ b/app/src/main/res/values-fy-rNL/strings.xml @@ -209,7 +209,6 @@ Bestân lêze Root-tagong wurdt oanfrege QR-koade analysearje - QR-koade analysearje %d/%d (%s) %d nij item tafoege oan de klûs %d nije items tafoege oan de klûs @@ -366,7 +365,6 @@ Deeplink kin net ferwurke wurde QR-koade koe net út bestân lêzen en ferwurke wurde: %s. Dielde tekst kin net as OTP ferwurke wurde - Guon QR-koaden kinne net lêzen en ferwurke wurde. Allinnich%d/%d items wurde ymportearre. QR-koade koe net generearre wurde Ofbylding selektearje Piktogram selektearje @@ -397,16 +395,7 @@ Aegis is ôfhinklik fan syngronisearre systeemtiid om krekte koaden te generearjen. In ôfwiking fan op syn minst inkelde sekonden kin liede ta net krekte koaden. It liket derop dat dyn apparaat net ynsteld is om de tiid automatysk te syngronisearjen. Wolsto dit no dwaan? Stop mei my te warskôgjen. Ik wit wat ik doch. Net relatearre QR-koade fûn. Probearje de scanner opnij te starten. - - %d/%d QR-koade scand - %d/%d QR-koaden scand - - QR-koade #%d waard ferwachte, mar yn stee dêrfan #%d scand Klûsreservekopy koartlyn mislearre - In resinte reservekopy fan de klûs mei %s mislearre, omdat der wat misgien is. De reservekopybesykjen wie op %s. Kontrolearje de resevekopy-ynstellingen om wis te wêzen dat reservekopyen mei sukses foltôge wurde kinne. - - In resint besykjen in reservekopy fan de klûs te meitsjen mei %s is mislearre. Aegis hat gjin tastimming om te skriuwen nei de reservekopylokaasje. De reservekopy is %s probearre. Dizze flater kin barre as jo de reservekopylokaasje ferpleatst/omneamd hawwe of as jo koartlyn in Aegis-reservekopy wersteld hawwe. Konfigurearje de reservekopylokaasje opnij. - it ynboude automatyske reservekopyen fan Aegis it cloudreservekopysysteem fan Android De meast resinte reservekopy is ferâldere (%s) diff --git a/app/src/main/res/values-gl-rES/strings.xml b/app/src/main/res/values-gl-rES/strings.xml index 68073fdc..473087e5 100644 --- a/app/src/main/res/values-gl-rES/strings.xml +++ b/app/src/main/res/values-gl-rES/strings.xml @@ -207,7 +207,6 @@ Lendo ficheiro Pedindo acceso root Analizando código QR - Analizando código QR %d/%d (%s) Engadida %d nova entrada ao almacén Engadidas %d novas entradas ao almacén @@ -364,7 +363,6 @@ Non se puido procesar o enlace profundo Non se puido ler e procesar o código QR do ficheiro: %s. Non se puido procesar o texto compartido como OTP - Non se puideron ler e procesar algúns dos códigos QR. Só se importarán %d/%d entradas. Non se puido xerar o código QR Seleccionar imaxe Seleccionar icona @@ -395,16 +393,7 @@ Aegis depende de que a hora do sistema estea sincronizada para poder xerar códigos correctos. Unha desviación de tan só uns poucos segundos pode resultar en que os códigos sexan incorrectos. Semella que o teu dispositivo non está configurado para sincronizar automaticamente a hora. Queres configuralo agora? Non me avises máis. Sei o que fago. Atopouse un código QR non relacionado. Proba a reiniciar o escáner. - - %d/%d código QR escaneado - %d/%d códigos QR escaneados - - Esperábase o código QR nº %d, pero escaneouse o nº %d A copia de seguridade do almacén fallou recentemente - Un intento de facer unha copia de seguridade do almacén usando %s fallou debido a algún erro. A copia de seguridade intentouse %s. Comproba os axustes da copia de seguridade para asegurarte de que poidan completar correctamente. - - Un recente intento de copia de seguridade utilizando %s fallou porque Aegis non tiña permiso de escritura no destino da copia de seguridade. A copia de seguridade intentouse %s. Este erro pode ocorrer se moveches ou renomeaches o destino ou se fai pouco que recuperaches Aegis desde unha copia de seguridade. Volve a configurar o destino da copia de seguridade. - Copias de seguridade automáticas de Aegis Copias de seguridade na nube de Android A última copia de seguridade está desactualizada (%s) diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/app/src/main/res/values-hi-rIN/strings.xml index 2c23894f..5dec1e32 100644 --- a/app/src/main/res/values-hi-rIN/strings.xml +++ b/app/src/main/res/values-hi-rIN/strings.xml @@ -173,7 +173,6 @@ फ़ाइल डेटा पढ़ना रूट एक्सेस रिक्वेस्ट कर रहा क्यूआर कोड एनालाइज कर रहा है - एनालाइजिंग क्यूआर कोड %d/%d (%s) वॉल्ट में %d नयी एंट्री जोड़ी गई वॉल्ट में %d नयी एंट्रीज जोड़ी गईं @@ -314,7 +313,6 @@ डीप लिंक प्रक्रिया करने में असमर्थ क्यूआर कोड को फाइल:%s से पढ़ने और प्रोसेस करने में असमर्थ. शेयर्ड टेक्स्ट को ओटीपी के रूप में प्रोसेस करने में असफल - कुछ क्यूआर कोड को पढ़ने और प्रोसेस करने में असमर्थ। केवल %d/%d प्रविष्टियाँ इंपोर्ट की जाएंगी। क्यूआर कोड उत्पन्न करने में असमर्थ छवि चयन करें आइकन चयन करें @@ -345,13 +343,7 @@ Aegis सही कोड उत्पन्न करने के लिए सिस्टम समय पर निर्भर करता है। केवल कुछ सेकंड के विचलन से गलत कोड हो सकते हैं। ऐसा लगता है कि आपका डिवाइस समय को स्वचालित रूप से सिंक्रनाइज़ करने के लिए कॉन्फ़िगर नहीं किया गया है। क्या आप अब ऐसा करना चाहेंगे? मुझे चेतावनी देना बंद करें। मैं जानता हूँ मैं क्या कर रहा हूँ असंबंधित क्यूआर कोड मिला। स्कैनर को पुनरारंभ करने का प्रयास करें। - - %d/%d क्यूआर कोड स्कैन किए गए - %d/%d क्यूआर कोड स्कैन किए गए - - अपेक्षित क्यूआर कोड #%d, लेकिन इसके बजाय #%d को स्कैन किया गया हाल ही में वॉल्ट बैकअप विफल रहा - %s का उपयोग करके हाल ही में वॉल्ट बैकअप का प्रयास विफल हो गया क्योंकि कोई त्रुटि उत्पन्न हुई। बैकअप का प्रयास %s किया गया था. यह सुनिश्चित करने के लिए कि बैकअप सफलतापूर्वक पूरा हो सकता है, कृपया अपनी बैकअप सेटिंग्स जांचें। एजिस के बिल्ट-इन स्वचालित बैकअप्स एंड्रॉयड क्लाउड बैकअप सिस्टम लेटेस्ट बैकअप आउटडेटेड है (%s) diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index f5ca8d8d..7d64e71f 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -209,7 +209,6 @@ Fájl olvasása Root hozzáférés igénylése QR-kód elemzése - QR-kód elemzése %d./%d (%s) %d új bejegyzés hozzáadva a széfhez %d új bejegyzés hozzáadva a széfhez @@ -366,7 +365,6 @@ Az alkalmazáshivatkozás nem dolgozható fel A QR-kód nem olvasható le és dolgozható fel a fájlból: %s. A megosztott szöveg nem dolgozható fel OTP-ként - Egyes QR-kódok nem olvashatók le és dolgozhatók fel. Csak %d/%d bejegyzés lesz importálva. A QR-kód nem állítható elő Kép kiválasztása Ikon kiválasztása @@ -397,16 +395,7 @@ Az Aegis a rendszeridőre támaszkodik a helyes kódok előállításánál. Néhány másodperces eltérés is hibás kódok előállítását eredményezheti. Úgy tűnik az eszközön nincs bekapcsolva az automatikus időszinkronizálás. Be akarja most ezt kapcsolni? Ne figyelmeztessen. Tudom mit csinálok. Nem kapcsolódó QR-kód található. Próbálja meg újraindítani a leolvasót. - - %d/%d QR-kód leolvasva - %d/%d QR-kód leolvasva - - A várt #%d QR-kód helyett ez került leolvasásra: #%d Egy széf mentése nemrég sikertelen volt - Egy közelmúltbeli, az %s használó széfmentés sikertelen volt, mert hiba történt. A biztonsági mentés ekkor volt megpróbálva: %s. Ellenőrizze a biztonsági mentési beállításokat, hogy biztosítsa a mentések sikeres végrehajtását. - - A közelmúltban egy széf „%s” típusú biztonsági mentése nem sikerült, mert az Aegisnek nem volt engedélyeze a cél helyére írni. A biztonsági mentés kísérlete %s volt. Ez a hiba akkor történhet, ha áthelyezte/átnevezte a biztonsági mnentés célját, vagy ha nemrég állította vissza mentésből az Aegist. Állítsa be újra a biztonsági mentés helyét. - Aegis beépített biztonsági mentését Android felhős mentési rendszerét A legfrissebb biztonsági mentés elavult (%s) diff --git a/app/src/main/res/values-in-rID/strings.xml b/app/src/main/res/values-in-rID/strings.xml index 41cbcb4e..e43f7dee 100644 --- a/app/src/main/res/values-in-rID/strings.xml +++ b/app/src/main/res/values-in-rID/strings.xml @@ -206,7 +206,6 @@ Baca berkas Meminta akses root Menganalisis kode QR - Menganalisis kode QR %d/%d (%s) Menambahkan %d entri baru ke brankas @@ -357,7 +356,6 @@ Tidak dapat memproses tautan dalam Tidak dapat membaca dan memproses kode QR dari berkas: %s. Tidak dapat memproses teks bersama sebagai OTP - Tidak dapat membaca dan memproses beberapa dari kode QR. Hanya %d/%d entri yang akan diimpor. Tidak dapat membuat kode QR Pilih gambar Pilih ikon @@ -388,15 +386,6 @@ Aegis mengandalkan waktu sistem untuk disinkronkan menjadi kode yang benar. Selisih hanya beberapa detik dapat menyebabkan kode salah. Sepertinya perangkat Anda tidak dikonfigurasi untuk menyinkronkan waktu secara otomatis. Apakah Anda ingin melakukannya sekarang? Berhenti memperingatkan saya. Saya tahu apa yang saya lakukan. Ditemukan kode QR yang tidak terkait. Coba mulai ulang pemindai. - - Pindai %d/%d code QR - - Kode QR yang ditemukan #%d, namun hanya #%d yang dipindai - Pencadangan Brankas baru-baru ini gagal - Upaya pencadangan vault baru-baru ini menggunakan %s gagal karena terjadi kesalahan. Pencadangan dilakukan dengan menggunakan %s. Periksa pengaturan pencadangan Anda untuk memastikan pencadangan berhasil diselesaikan. - - Upaya pencadangan vault baru-baru ini menggunakan %s gagal karena Aegis tidak memiliki izin untuk menulis ke tujuan pencadangan. Pencadangan telah dicoba %s. Kesalahan ini dapat terjadi jika Anda memindahkan/mengganti nama tujuan pencadangan atau jika Anda baru saja memulihkan Aegis dari pencadangan. Harap konfigurasikan ulang tujuan pencadangan. - Pencadangan otomatis bawaan Aegis Sistem pencadangan awan Android Backup terakhir sudah kedaluwarsa (%s) diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml index 5b99cbf9..8fd4406f 100644 --- a/app/src/main/res/values-it-rIT/strings.xml +++ b/app/src/main/res/values-it-rIT/strings.xml @@ -184,7 +184,6 @@ Lettura del file in corso Richiesta accesso root Analisi del codice QR - Analisi del codice QR %d/%d (%s) Aggiunta %d nuova voce alla cassaforte Aggiunte %d nuove voci alla cassaforte @@ -340,7 +339,6 @@ Impossibile elaborare il collegamento Impossibile leggere ed elaborare il codice QR dal file: %s. Impossibile elaborare il testo condiviso come OTP - Impossibile leggere ed elaborare alcuni dei codici QR. Ne verranno importati solo %d/%d. Impossibile generare il codice QR Seleziona immagine Seleziona icona @@ -371,16 +369,7 @@ Aegis si basa sull\'esatta sincronizzazione dell\'orario di sistema per generare codici corretti. Una deviazione di pochi secondi potrebbe portare a codici errati. Sembra che il tuo dispositivo non sia configurato per sincronizzare automaticamente l\'ora. Vuoi farlo adesso? Smettetela di avvertirmi. So cosa sto facendo. Trovato codice QR non correlato. Prova a riavviare lo scanner. - - Scansionato %d/%d codici QR - Scansionati %d/%d codici QR - - Previsto codice QR #%d, ma scansionato #%d invece Backup della cassaforte fallito recentemente - Un recente tentativo di backup della cassaforte utilizzando %s non è riuscito perché si è verificato un errore. Il backup è stato tentato %s. Controlla le impostazioni di backup per assicurarti che i backup possano essere completati correttamente. - - Un recente tentativo di backup della cassaforte con %s non è riuscito perché Aegis non aveva l\'autorizzazione di scrittura nella destinazione del backup. Il backup è stato tentato %s. Questo errore può verificarsi se hai spostato o rinominato la destinazione del backup o se hai recentemente ripristinato Aegis da un backup. Configura nuovamente la destinazione del backup. - i backup automatici integrati di Aegis il sistema di backup su cloud di Android L\'ultimo backup è vecchio (%s) diff --git a/app/src/main/res/values-iw-rIL/strings.xml b/app/src/main/res/values-iw-rIL/strings.xml index 29044781..7f4d21bd 100644 --- a/app/src/main/res/values-iw-rIL/strings.xml +++ b/app/src/main/res/values-iw-rIL/strings.xml @@ -180,7 +180,6 @@ קריאת קובץ בקשת גישה לשורש ניתוח קוד QR - מנתח קוד QR %d/%d (%s) הוספה %d כניסה חדשה לכספת נוספו %d ערכים חדשים לכספת @@ -307,7 +306,6 @@ לא ניתן לעבד קישור עמוק לא ניתן לקרוא ולעבד קוד QR מהקובץ: %s. לא ניתן לעבד טקסט משותף כ-OTP - לא ניתן לקרוא ולעבד חלק מקודי ה-QR. רק %d/%d ערכים ייובאו. לא ניתן ליצור קוד QR בחר תמונה בחר סמל @@ -338,10 +336,7 @@ Aegis מסתמכת על זמן המערכת להיות מסונכרן כדי ליצור קודים נכונים. סטייה של מספר שניות בלבד עלולה לגרום לקודים שגויים. נראה שהמכשיר שלך לא מוגדר לסנכרון אוטומטי של השעה. האם תרצה לעשות זאת כעת? תפסיק להזהיר אותי. אני יודע מה אני עושה. נמצא קוד QR לא קשור. נסה להפעיל מחדש את הסורק. - צפי לקוד QR #%d, אך במקום זאת נסרק #%d גיבוי הכספת נכשל לאחרונה - ניסיון גיבוי של כספת לאחרונה באמצעות %s נכשל מכיוון שאירעה שגיאה. בוצע ניסיון הגיבוי %s. אנא בדוק את הגדרות הגיבוי שלך כדי לוודא שהגיבויים יכולים להסתיים בהצלחה. - גיבויים אוטומטיים מובנים של Aegis מערכת גיבוי בענן של אנדרואיד הגיבוי האחרון מיושן (%s) diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index 2ea2adac..c5c9cf6a 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -179,7 +179,6 @@ ファイルを読み込み中 root権限を要求中 QRコードを解析中 - QRコードを解析中 %d/%d (%s) %d 個の新しいエントリーを保管庫に追加しました @@ -325,7 +324,6 @@ ディープリンクを処理できません ファイル %s からQRコードを読み取り処理できません。 OTPとして共有テキストを処理できません - QRコードの一部を読み取り処理できません。 %d/%d 個のエントリーのみインポートされます。 QRコードを生成できません 画像を選択 アイコンを選択 @@ -357,15 +355,7 @@ Aegisが正しいコードを生成するためには、システム時刻が正しく同期されている必要があります。 わずか数秒のずれでも誤ったコードを生成する可能性があります。このデバイスは時刻を自動的に同期するように設定されていないようです。今すぐ同期しますか? 警告は不要です。 関連のないQRコードが見つかりました。スキャナーを再起動してみてください。 - - %d/%d QRコードをスキャン - - QRコード#%dを期待していましたが、代わりに#%dをスキャンしました 保管庫のバックアップが失敗しました - %s を使用した保管庫のバックアップはエラーのため失敗しました。処理が正常終了するよう、バックアップ設定を確認してください。 - - Aegis にはバックアップ先に書き込む権限がないため、%s を使用した保管庫のバックアップに失敗しました。バックアップの失敗は %sです。このエラーは、バックアップ先の移動/名前を変更した場合や、最近 Aegis をバックアップから復元した場合に発生することがあります。バックアップ先を再設定してみてください。 - Aegisの内蔵自動バックアップ Androidのクラウドバックアップシステム 最新のバックアップが古くなっています (%s) diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt-rLT/strings.xml index 0072ef76..d13d8019 100644 --- a/app/src/main/res/values-lt-rLT/strings.xml +++ b/app/src/main/res/values-lt-rLT/strings.xml @@ -117,7 +117,6 @@ Pasirinkite tapatybės nustatymo metodą Šifruojama slėptuvė Analizuojamas QR kodas - Analizuojamas QR kodas %d/%d (%s) Importuojamas piktogramų paketas Ištrinti įrašą Ar tikrai norite ištrinti šį įrašą? @@ -245,7 +244,6 @@ Automatinis laiko sinchronizavimas Daugiau manęs nebeįspėkite. Aš žinau, ką darau. Rastas nesusijęs QR kodas. Pabandykite paleisti skenerį iš naujo. - Tikėtasi #%d QR kodo, bet vietoj to, nuskenuotas #%d Pakeitimų atsarginė kopija nėra daroma Daugiau neberodyti šio įspėjimo diff --git a/app/src/main/res/values-lv-rLV/strings.xml b/app/src/main/res/values-lv-rLV/strings.xml index b3e56117..ce58e9df 100644 --- a/app/src/main/res/values-lv-rLV/strings.xml +++ b/app/src/main/res/values-lv-rLV/strings.xml @@ -218,7 +218,6 @@ Nolasa datni Pieprasa neierobežotu piekļuvi Notiek kvadrātkoda nolasīšana - Apstrādā kvadrātkodu %d/%d (%s) Glabātavai pievienoti %d jaunu ierakstu Glabātavai pievienots %d jauns ieraksts @@ -382,7 +381,6 @@ Nevar apstrādāt dziļo saiti Nav iespējams nolasīt un apstrādāt kvadrātkodu no datnes: %s. Nav iespējams apstrādāt kopīgoto tekstu kā OTP - Nav iespējams nolasīt un apstrādāt dažus no kvadrātkodiem. Tikai %d/%d ieraksti tiks ievietoti. Nav iespējams izveidot kvadrātkodu Atlasīt attēlu Atlasīt ikonu @@ -413,17 +411,7 @@ Aegis paļaujas, ka sistēmas laiks sakrīt, lai izveidotu pareizus kodus. Dažu sekunžu nobīde var izraisīt nepareizus kodus. Izskatās, ka šī ierīce nav uzstādīta, lai automātiski sinhronizētu laiku. Vai izdarīt to tagad? Nebrīdināt mani. Es zinu, ko es daru. Atrasts nesaistīts kvadrātkods. Jāmēģina pārsāknēt nolasītāju. - - Nolasīti %d/%d kvadrātkodi - Nolasīts %d/%d kvadrātkods - Nolasīti %d/%d kvadrātkodi - - Sagaidāms kvadrātkods #%d, bet tā vietā nolasīts #%d Glabātavas dublēšana nesen neizdevās - Nesens rezerves kopijas veidošanas mēģinājums, izmantojot %s, neizdevās, jo atgadījās kļūda. Rezerves kopiju tika mēģināts izveidot %s. Lūgums pārskatīt rezerves kopēšanas iestatījumus, lai pārliecinātos, ka var veiksmīgi veikt rezerves kopiju izveidošanu. - - Nesens glabātavas dublēšanas mēģinājums izmantojot %s neizdevās, jo Aegis nebija atļaujas rakstīt rezerves kopijas paredzētajā vietā. Dublēšana tika mēģināta %s. Šī kļūda var atgadīties, ja tika pārvietota vai pāsaukta rezerves kopiju atrašanās vieta vai ja nesen Aegis tika atjaunots no rezerves kopijas. Lūgums atkārtoti iestatī rezerves kopiju atrašanās vietu. - Aegis iebūvētā automātisko rezerves kopiju veidošana Android mākoņa rezerves kopiju sistēma Jaunākā rezerves kopija ir novecojusi (%s) diff --git a/app/src/main/res/values-nl-rNL/strings.xml b/app/src/main/res/values-nl-rNL/strings.xml index 94954ed5..c5488d83 100644 --- a/app/src/main/res/values-nl-rNL/strings.xml +++ b/app/src/main/res/values-nl-rNL/strings.xml @@ -215,7 +215,6 @@ Bestand lezen Root-toegang wordt aangevraagd QR-code analyseren - QR-code analyseren %d/%d (%s) %d nieuwe items aan de kluis toegevoegd %d nieuwe items aan de kluis toegevoegd @@ -373,7 +372,6 @@ Kan de deeplink niet verwerken Kan de QR-code van bestand niet lezen en verwerken: %s. Kan gedeelde tekst niet verwerken als OTP - Kan sommige QR-codes niet lezen en verwerken. Alleen %d/%d items worden geïmporteerd. Kan de QR-code niet genereren Foto selecteren Icoon selecteren @@ -404,16 +402,7 @@ Aegis is afhankelijk van gesynchroniseerde systeemtijd om juiste codes te genereren. Een afwijking van slechts enkele seconden kan leiden tot onjuiste codes. Het lijkt erop dat je apparaat niet is ingesteld om de tijd automatisch te synchroniseren. Wil je dit nu doen? Stop met me te waarschuwen. Ik weet wat ik doe. Ongerelateerde QR-code gevonden. Probeer de scanner opnieuw te starten. - - %d/%d QR-code gescand - %d/%d QR-codes gescand - - QR-code #%d werd verwacht, maar in plaats daarvan #%d gescand Kluis back-up onlangs mislukt - Een recente back-up van de kluis met %s mislukte omdat er iets misging. De back-uppoging was op %s. Controleer de back-upinstellingen om zeker te zijn dat back-ups met succes kunnen worden voltooid. - - Een recente poging een reservekopie van de kluis te maken met %s is mislukt. Aegis heeft geen toestemming om te schrijven naar de back-uplocatie. De back-up is %s geprobeerd. Deze fout kan optreden als je de back-uplocatie hebt verplaatst/hernoemd of als je onlangs een Aegis-back-up hebt hersteld. Configureer de back-uplocatie opnieuw. - het ingebouwde automatische back-ups van Aegis het cloud back-upsysteem van Android De meest recente back-up is verouderd (%s) diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml index bcb93b3e..4d403339 100644 --- a/app/src/main/res/values-pl-rPL/strings.xml +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -211,7 +211,6 @@ Odczytywanie pliku Żądanie dostępu do roota Analizowanie kodu QR - Analizowanie kodu QR %d/%d (%s) Dodano %d nowy wpis do sejfu Dodano %d nowe wpisy do sejfu @@ -380,7 +379,6 @@ Nie można przetworzyć głębokiego linku Nie można odczytać i przetworzyć kodu QR z pliku: %s. Nie można przetworzyć udostępnionego tekstu jako OTP - Nie można odczytać i przetworzyć niektórych kodów QR. Zaimportowano tylko %d/%d wpisów. Nie udało się wygenerować kodu QR Wybierz obraz Wybierz ikonę @@ -411,17 +409,7 @@ Aby wygenerować poprawne kody, aplikacja Aegis korzysta z synchronizacji czasu systemowego. Różnica czasu zaledwie kilku sekund może spowodować nieprawidłowe kody. Wygląda na to, że Twoje urządzenie nie jest skonfigurowane do automatycznej synchronizacji czasu. Czy chcesz skorzystać z tej funkcji? Nie ostrzegaj mnie. Wiem co robię. Znaleziono niepowiązany kod QR. Spróbuj ponownie uruchomić skaner. - - Zeskanowano %d/%d kodów QR - Zeskanowano %d/%d kodów QR - Zeskanowano %d/%d kodów QR - Zeskanowano %d/%d kodów QR - - Aplikacja oczekiwała kodu QR nr %d, lecz zeskanowano kod nr %d Ostatnia kopia zapasowa sejfu nie powiodła się - Ostatnia próba wykonania kopii zapasowej sejfu z użyciem %s nie powiodła się, ponieważ wystąpił błąd. Kopia zapasowa została wykonana w: %s. Sprawdź ustawienia kopii zapasowej, aby upewnić się, że wykonywanie kopii zapasowych może się pomyślnie zakończyć. - Niedawna próba wykonania kopii zapasowej używając %s nie powiodła się, ponieważ Aegis nie miał uprawnienia do zapisu w wybranym folderze. Próba zapisu była wykonana %s. Teb błąd może wystąpić po przeniesieniu/zmianie nazwy wybranego folderu lub po niedawnym przywróceniu Aegis z kopii zapasowej. Proszę wybrać poprawny folder. - Wbudowane automatyczne kopie zapasowe Aegis System kopii zapasowej w chmurze Android Najnowsza kopia zapasowa jest nieaktualna (%s) diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 6e0ce020..66155c54 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -215,7 +215,6 @@ Lendo arquivo Solicitando acesso root Analisando QR code - Analisando o QR code %d/%d (%s) Adicionada %d nova entrada ao cofre Adicionadas %d novas entradas ao cofre @@ -373,7 +372,6 @@ Incapaz de processar a ligação profunda Incapaz de ler e processar o QR code do arquivo: %s. Incapaz de processar texto compartilhado como OTP - Não foi possível ler e processar alguns dos QR codes. Apenas %d/%d serão importadas. Não foi possível gerar o QR code Selecionar imagem Selecionar ícone @@ -404,15 +402,7 @@ Aegis depende da hora do sistema para ficar em sincronia para gerar os códigos corretos. Uma diferença de apenas alguns segundos poderia resultar em códigos incorretos. Parece que seu dispositivo não está configurado para sincronizar automaticamente a hora. Gostaria de ativar essa opção agora? Pare de me avisar. Eu sei o que estou fazendo. QR code não relacionado encontrado. Tente reiniciar o scanner. - - %d/%d QR code escaneado - %d/%d QR codes escaneados - - Esperados #%d QR code, mas escaneados #%d ao invés Backup do cofre falhou recentemente - Uma tentativa recente de backup do cofre utilizando o %s falhou, pois ocorreu um erro. O backup foi tentado %s. Por favor, verifique as configurações de backup para garantir que ele possa ser concluído com sucesso. - Uma recente tentativa de backup de segurança do cofre usando %s falhou porque o Aegis não tem permissão para escrever no destino da cópia de segurança. O backup foi tentado %s. Este erro pode ocorrer se você mover/renomeou o destino do backup ou se você restaurou recentemente Aegis de um backup. Por favor, reconfigure o destino do backup. - Backups automáticos do Aegis Sistema de backup em nuvem do Android O backup mais recente está desatualizado (%s) diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index d2344191..821a5bee 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -205,7 +205,6 @@ A ler o ficheiro Pedir acesso root A analisar o código QR - A analisar o código QR %d/%d (%s) Adicionada %d nova entrada ao cofre Adicionadas %d novas entradas ao cofre @@ -361,7 +360,6 @@ Não é possível processar a ligação profunda Não foi possível ler e processar o código QR do ficheiro: %s. Não é possível processar o texto partilhado como OTP - Não é possível ler e processar alguns dos códigos QR. Apenas serão importadas %d/%d entradas. Não foi possível gerar o código QR Selecionar imagem Selecionar ícone @@ -392,16 +390,7 @@ O Aegis depende da hora do sistema para estar sincronizado para gerar códigos corretos. Um desvio de apenas alguns segundos pode resultar em códigos incorretos. Parece que o seu dispositivo não está configurado para sincronizar automaticamente o tempo. Gostaria de o fazer agora? Para de me avisar. Eu sei o que estou a fazer. Código QR não relacionado. Experimente reiniciar o digitalizador. - - %d/%d QR code escaneado - %d/%d QR codes escaneados - - #%d códigos QR eram esperados, mas #%d foram escaneados em vez disso O ‘backup’ do cofre falhou recentemente - Uma tentativa recente de backup do cofre utilizando o %s falhou porque ocorreu um erro. A tentativa de cópia de segurança foi efetuada %s. Verifique as definições de backup para se certificar de que os mesmos podem ser concluídos com êxito. - - Uma tentativa recente de backup do cofre utilizando o %s falhou porque o Aegis não tinha permissão para escrever no destino do backup. A tentativa de backup foi feita %s. Este erro pode ocorrer se tiver movido/renomeado o destino da cópia de segurança ou se tiver restaurado recentemente o Aegis a partir de um backup. Reconfigure o destino do backup. - backups automáticos do Aegis sistema de backup na nuvem do Android O último backup está desatualizado (%s) diff --git a/app/src/main/res/values-ro-rRO/strings.xml b/app/src/main/res/values-ro-rRO/strings.xml index bd486b78..07b1e693 100644 --- a/app/src/main/res/values-ro-rRO/strings.xml +++ b/app/src/main/res/values-ro-rRO/strings.xml @@ -212,7 +212,6 @@ Citire fişier Solicită acces root Se analizează codul QR - Se analizează codul QR %d%d (%s) Au fost adăugate %d de noi intrări în seif Au fost adăugate %d noi intrări în seif @@ -375,7 +374,6 @@ Nu se poate procesa link-ul Nu se poate citi și procesa codul QR din fișierul: %s. Imposibil de procesat textul partajat ca un cod OTP - Nu se pot citi şi procesa unele dintre codurile QR. Doar %d/%d intrări vor fi importate. Nu se poate genera codul QR Selectare imagine Selectare pictogramă @@ -406,16 +404,7 @@ Aegis-ul se bazează pe un sistem de timp pentru a fi sincronizat pentru a genera codurile corecte. O abatere de doar câteva secunde ar putea duce la coduri incorecte. Se pare că dispozitivul tău nu este configurat pentru a sincroniza automat timpul. Dorești să faci acest lucru acum? Nu mă mai avertiza. Ştiu ce fac. Cod QR negăsit găsit. Încearcă să repornești scanerul. - - Cod %d/%d QR scanat - Coduri %d/%d QR scanate - Coduri %d/%d QR scanate - - Se aștepta codul QR #%d, dar scanat #%d în schimb Copia de rezervă a seifului a eșuat recent - O încercare recentă de backup a seifului folosind %s a eșuat deoarece a apărut o eroare. S-a încercat crearea unei copii de siguranță la: %s. Vă rugăm să verificați setările copiilor de rezervă pentru a vă asigura că acestea pot fii create cu succes. - O încercare recentă de backup a seifului folosind %s a eșuat deoarece Aegis nu a avut permisiunea de a scrie în dosarul destinație. Sa încercat creearea unui backup la %s. Această eroare poate apărea dacă ați mutat/redenumit destinația copiei de rezervă sau dacă ați restaurat recent Aegis dintr-o copie de rezervă. Vă rugăm să reconfiguraţi destinaţia copiei de rezervă. - Copiile de siguranță încorporate în aplicație Sistemul de backup în cloud Android Ultima copie de rezervă este învechită (%s) diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index 9e93d512..c22aa28d 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -221,7 +221,6 @@ Чтение файла Запрос root-доступа Анализ QR-кода - Анализ QR-кода %d/%d (%s) Добавлена %d новая запись в хранилище Добавлены %d новые записи в хранилище @@ -391,7 +390,6 @@ Невозможно обработать глубокую ссылку Невозможно считать и обработать QR-код из файла: %s. Невозможно обработать текст как OTP - Невозможно считать и обработать некоторые QR-коды. Импортируется только %d/%d. Невозможно сгенерировать QR-код Выберите изображение Выберите значок @@ -422,18 +420,7 @@ Aegis полагается на системное время для генерации правильных кодов. Отклонение всего в несколько секунд может привести к неверным кодам. Кажется, ваше устройство не настроено для автоматической синхронизации времени. Хотите сделать это сейчас? Прекратите меня предупреждать, я знаю, что делаю. Найден несвязанный QR-код. Попробуйте перезапустить сканер. - - Отсканировано QR-кодов %d/%d - Отсканировано QR-кодов %d/%d - Отсканировано QR-кодов %d/%d - Отсканировано QR-кодов %d/%d - - Ожидался QR-код #%d, но вместо этого отсканирован #%d Недавно произошла ошибка резервного копирования хранилища - Последнее резервное копирование хранилища с использованием %s не выполнено из-за ошибки. Попытка производилась %s. Убедитесь, что настройки резервного копирования правильные. - - Недавняя попытка резервного копирования хранилища с использованием %s не выполнена, поскольку у Aegis нет разрешения на запись в место назначения резервной копии. Попытка создания резервной копии была %s. Эта ошибка может возникать, если вы переместили/переименовали место назначения резервной копии или если недавно восстановили параметры Aegis из резервной копии. Пожалуйста, перенастройте место назначения резервной копии. - Встроенное автоматическое резервирование Aegis Системное облачное резервирование Android Резервная копия устарела (%s) diff --git a/app/src/main/res/values-sv-rSE/strings.xml b/app/src/main/res/values-sv-rSE/strings.xml index a7d8a522..272e87e8 100644 --- a/app/src/main/res/values-sv-rSE/strings.xml +++ b/app/src/main/res/values-sv-rSE/strings.xml @@ -211,7 +211,6 @@ Läser fil Begär rotåtkomst Analyserar rutkod - Analyserar rutkod %d/%d (%s) Lade till %d ny post i valvet Lade till %d nya poster i valvet @@ -368,7 +367,6 @@ Kunde inte bearbeta djuplänk Kunde inte läsa och bearbeta rutkod från fil: %s. Kunde inte bearbeta delad text som OTP - Kunde inte läsa och bearbeta några av rutkoderna. Endast %d/%d poster kommer att importeras. Kunde inte generera rutkod Välj bild Välj ikon @@ -399,16 +397,7 @@ Aegis förlitar sig på att systemtiden är i synk för att kunna generera korrekta koder. En avvikelse på bara några sekunder kan resultera i felaktiga koder. Det verkar som om din enhet inte är konfigurerad för att synkronisera tiden automatiskt. Vill du göra det nu? Sluta varna mig. Jag vet vad jag gör. Orelaterad rutkod hittades. Pröva att starta om skannern. - - Skannade %d/%d rutkoder - Skannade %d/%d rutkoder - - Förutsatte rutkod #%d men skannade #%d i stället Säkerhetskopiering av valvet misslyckades nyligen - Ett nyligt försök att säkerhetskopiera valvet via %s misslyckades eftersom ett fel uppstod. Försöket gjordes för %s. Vänligen kontrollera dina säkerhetskopieringsinställningar för att se till att säkerhetskopior kan skapas framgångsrikt. - - Ett nyligt försök att säkerhetskopiera valvet via %s misslyckades eftersom Aegis inte hade behörighet att skriva till lagringsplatsen för säkerhetskopior. Försöket gjordes för %s. Detta fel kan uppstå om du har flyttat/bytt namn på lagringsplatsen för säkerhetskopior eller om du nyligen har återställt Aegis från en säkerhetskopia. Vänligen konfigurera om lagringsplatsen för säkerhetskopior. - Aegis inbyggda automatiska säkerhetskopior Androids molnsäkerhetskopieringssystem Senaste säkerhetskopian är föråldrad (%s) diff --git a/app/src/main/res/values-tr-rTR/strings.xml b/app/src/main/res/values-tr-rTR/strings.xml index 77c0a127..7703d4b0 100644 --- a/app/src/main/res/values-tr-rTR/strings.xml +++ b/app/src/main/res/values-tr-rTR/strings.xml @@ -184,7 +184,6 @@ Dosya okunuyor Root erişimi denetleniyor QR kodunu analiz ediliyor - QR kodu %d/%d (%s) analiz ediliyor Kasaya %d yeni giriş eklendi Kasaya %d yeni giriş eklendi @@ -339,7 +338,6 @@ Derin bağlantı işlenemiyor Dosyadan QR kodu okunamıyor ve işlenemiyor: %s. OTP olarak paylaşılan metin işlenemiyor - Bazı QR kodlar okunamıyor ve işlenemiyor. Yalnızca %d/%d girişleri içe aktarılacak. QR Kodu oluşturulamadı Resim seç Simge seç @@ -370,16 +368,7 @@ Aegis doğru kodları oluşturmak üzere sistem zamanın senkron olmasına ihtiyaç duyar. Birkaç saniyelik sapma hatalı kod oluşumuna neden olabilir. Görünüşe göre cihazınız zamanı otomatik senkronize etmeye ayarlanmamış. Şimdi ayarlamak ister misiniz? Beni uyarmayı bırak. Ne yaptığımı biliyorum. Alakasız QR kod bulundu. Tarayıcıyı yeniden başlatmayı deneyin. - - %d/%d QR kodları tarandı - %d/%d QR kodları tarandı - - Beklenen QR kodu #%d idi, ancak bunun yerine #%d tarandı Kasa yedeklenmesi başarısız oldu - Bir hata nedeniyle %s ile son kasa yedeği alınamadı. Yedekleme denemesi %s. Yedeklemenin başarılı olması için lütfen yedekleme ayarlarınızı kontrol edin. - - Aegis\'in yedekleme konumuna yazma izni olmadığı için %s kullanılarak yapılan yeni bir kasa yedekleme denemesi başarısız oldu. Yedekleme %s olarak denendi. Bu hata, yedekleme konumunu taşıdıysanız/yeniden adlandırdıysanız veya yakın zamanda Aegis\'i bir yedekten geri yüklediyseniz oluşabilir. Lütfen yedekleme konumunu yeniden yapılandırın. - Aegis dahili otomatik yedekleri Android\'in bulut yedekleme sistemi Son yedek güncel değil (%s) diff --git a/app/src/main/res/values-uk-rUA/strings.xml b/app/src/main/res/values-uk-rUA/strings.xml index 5743c812..952eeb81 100644 --- a/app/src/main/res/values-uk-rUA/strings.xml +++ b/app/src/main/res/values-uk-rUA/strings.xml @@ -173,7 +173,6 @@ Читання файлу Запит на root-доступ Аналіз QR-коду - Аналіз QR-коду %d/%d (%s) Додано %d новий запис у сховище Додано %d нові записи у сховище @@ -325,7 +324,6 @@ Не вдалося обробити глибоке посилання Не вдається прочитати і обробити QR-код із файлу: %s. Неможливо обробити вхідний текст як OTP - Не вдалося прочитати та обробити деякі з QR-кодів. Буде імпортовано лише %d/%d запис/и/ів. Не вдається згенерувати QR-код Виберіть зображення Виберіть іконку @@ -356,16 +354,7 @@ Aegis залежить від системного часу для генерації правильних кодів. Відхилення всього на кілька секунд може призвести до неправильних кодів. Схоже, ваш пристрій не налаштовано на автоматичну синхронізацію часу. Бажаєте зробити це зараз? Припиніть мене попереджати. Я знаю, що роблю. Знайдено непов\'язаний QR-код. Спробуйте перезапустити сканер. - - Відскановано %d/%d QR-кодів - Відскановано %d/%d QR-кодів - Відскановано %d/%d QR-кодів - Відскановано %d/%d QR-кодів - - Очікувався QR-код #%d, але замість цього відскановано #%d Нещодавно не вдалося створити резервну копію сховища - Недавня спроба резервного копіювання сховища з використанням %s зазнала невдачі. Спроба створити резервну копію була здійснена о %s. Будь ласка, перевірте налаштування резервного копіювання, щоб переконатися, що резервні копії будуть успішно виконані. - Вбудоване автоматичне резервне копіювання Aegis Система хмарного резервного копіювання Android Остання резервна копія застаріла (%s) diff --git a/app/src/main/res/values-vi-rVN/strings.xml b/app/src/main/res/values-vi-rVN/strings.xml index 9e1eaab4..b387f243 100644 --- a/app/src/main/res/values-vi-rVN/strings.xml +++ b/app/src/main/res/values-vi-rVN/strings.xml @@ -213,7 +213,6 @@ Đang đọc tập tin Yêu cầu truy cập root Đang phân tích mã QR - Đang phân tích mã QR %d/%d (%s) Đã thêm %d mục mới vào kho @@ -365,7 +364,6 @@ Không thể xử lý deep link Không thể đọc và xử lý mã QR từ tập tin: %s. Không thể xử lý văn bản được chia sẻ dưới dạng OTP - Không thể đọc và xử lý vài mã QR. Chỉ %d/%d mục sẽ được nhập. Không thể tạo mã QR Chọn ảnh Chọn biểu tượng @@ -396,15 +394,7 @@ Aegis dựa vào việc thời gian hệ thống được đồng bộ để tạo các mã chính xác. Một sự sai lệch chỉ vài giây cũng có thể dẫn đến các mã không chính xác. Có vẻ như thiết bị của bạn không được thiết lập tự đồng bộ thời gian. Bạn có muốn bật tính năng này? Đừng cảnh báo tôi nữa. Tôi biết tôi đang làm gì. Đã tìm thấy mã QR không liên quan. Hãy thử khởi động lại trình quét. - - Đã quét %d/%d mã QR - - Dự định quét mã QR #%d, nhưng thay vào đó đã quét #%d Sao lưu kho thất bại - Một bản sao lưu kho gần đây bằng cách sử dụng %s đã thất bại. Bản sao lưu đã thử %s. Vui lòng kiểm tra cài đặt sao lưu của bạn để đảm bảo quá trình sao lưu có thể hoàn tất. - - Lần sao lưu kho gần đây bằng %s không thành công vì Aegis không có quyền ghi vào thư mục. Đã thử sao lưu %s. Lỗi này có thể xảy ra nếu bạn di chuyển/đổi tên thư mục sao lưu hoặc nếu gần đây bạn đã khôi phục Aegis từ bản sao lưu. Vui lòng chọn lại thư mục sao lưu. - Sao lưu tự động tích hợp của Aegis Sao lưu đám mây của Android Bản sao lưu cuối cùng đã cũ (%s) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 85680133..62e6b4da 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -212,7 +212,6 @@ 正在读取文件 正在请求 root 权限 正在分析二维码 - 正在分析二维码 %d/%d (%s) 添加了 %d 个新条目到保险库 @@ -364,7 +363,6 @@ 无法处理深层链接 无法从文件读取和处理二维码: %s。 无法将共享文本作为 OTP 进行处理 - 无法读取和处理一些二维码。仅导入 %d/%d 条目。 无法生成二维码 选择图片 选择图标 @@ -395,14 +393,7 @@ Aegis 依靠系统时间来同步生成正确的验证码。仅几秒钟的偏差可能会导致验证码错误。您的设备似乎未配置为自动同步时间。您现在要设置自动同步时间吗? 不要再次提醒。我知道我在做什么。 找到不相关的二维码。请尝试重新扫描。 - - 已扫描 %d/%d 二维码 - - 预期二维码 #%d,已扫描 #%d 数据库最近备份失败 - 因发生错误,上次使用 %s 备份密码库的尝试失败。尝试于 %s。请检查您的备份设置以确保备份成功完成。 - 上次使用 %s 备份密码库失败,Aegis 缺少写入备份目标的权限。尝试于 %s。错误可能因为您最近移动或重命名了备份目标,或者您最近从一个备份中还原了 Aegis ,请重新配置备份目标。 - Aegis 内置的自动备份 Android 的云备份系统 最新备份已过时 (%s) diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index bd74363a..03ee7ee9 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -185,7 +185,6 @@ 讀取檔案中 需要使用 root 分析 QR code 中 - 正在分析 QR 圖碼 %d/%d (%s) 增加 %d 個條目進保險箱 @@ -345,13 +344,7 @@ 僅幾秒鐘的偏差可能會導致驗證碼錯誤。您的裝置似乎未設定為自動同步時間。您現在要設定自動同步時間嗎? 不要再次提醒。我知道我在做什麼。 找到不相關的QR碼。請嘗試重新掃描。 - - 已掃描 %d/%d - - 預期QR碼 %d,已掃描 %d 近期的保險箱備份失敗 - 因為錯誤發生,最近一次嘗試使用 %s 的備份行為失敗。本次備份使用 %s。請檢查您的備份設定以確保備份能順利完成。 - Aegis 內建的自動備份 Android 雲端備份 最新的備份已過時 (%s) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d0c13fe2..40152096 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -225,7 +225,7 @@ Reading file Requesting root access Analyzing QR code - Analyzing QR code %d/%d (%s) + Analyzing QR code %1$d/%2$d (%3$s) Added %d new entry to the vault Added %d new entries to the vault @@ -385,7 +385,7 @@ Unable to process deep link Unable to read and process QR code from file: %s. Unable to process shared text as OTP - Unable to read and process some of the QR codes. Only %d/%d entries will be imported. + Unable to read and process some of the QR codes. Only %1$d/%2$d entries will be imported. Unable to generate QR code Select picture Select icon @@ -421,20 +421,20 @@ Stop warning me. I know what I\'m doing. Unrelated QR code found. Try restarting the scanner. - Scanned %d/%d QR codes - Scanned %d/%d QR codes + Scanned %1$d/%2$d QR codes + Scanned %1$d/%2$d QR codes - Expected QR code #%d, but scanned #%d instead + Expected QR code #%1$d, but scanned #%2$d instead Vault backup failed recently - A recent vault backup attempt using %s failed because an error occurred. The backup was attempted %s. Please check your backup settings to make sure backups can complete successfully. + A recent vault backup attempt using %1$s failed because an error occurred. The backup was attempted %2$s. Please check your backup settings to make sure backups can complete successfully. - A recent vault backup attempt using %s failed because Aegis did not have permission to write to the backup destination. The backup was attempted %s. This error can occur if you moved/renamed the backup destination or if you recently restored Aegis from a backup. Please reconfigure the backup destination. + A recent vault backup attempt using %1$s failed because Aegis did not have permission to write to the backup destination. The backup was attempted %2$s. This error can occur if you moved/renamed the backup destination or if you recently restored Aegis from a backup. Please reconfigure the backup destination. Aegis\' built-in automatic backups Android\'s cloud backup system From d433957c2f7fb59f3632f4078f72f3a8ec02ea14 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Sat, 21 Sep 2024 14:12:06 +0200 Subject: [PATCH 040/113] Remove usage of deprecated PreferenceManager --- .../java/com/beemdevelopment/aegis/AegisTestRunner.java | 2 +- app/src/main/java/com/beemdevelopment/aegis/Preferences.java | 2 +- .../test/java/com/beemdevelopment/aegis/PreferencesTest.java | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/src/androidTest/java/com/beemdevelopment/aegis/AegisTestRunner.java b/app/src/androidTest/java/com/beemdevelopment/aegis/AegisTestRunner.java index 44c06845..970f9ff0 100644 --- a/app/src/androidTest/java/com/beemdevelopment/aegis/AegisTestRunner.java +++ b/app/src/androidTest/java/com/beemdevelopment/aegis/AegisTestRunner.java @@ -3,8 +3,8 @@ package com.beemdevelopment.aegis; import android.app.Application; import android.app.Instrumentation; import android.content.Context; -import android.preference.PreferenceManager; +import androidx.preference.PreferenceManager; import androidx.test.core.app.ApplicationProvider; import androidx.test.runner.AndroidJUnitRunner; diff --git a/app/src/main/java/com/beemdevelopment/aegis/Preferences.java b/app/src/main/java/com/beemdevelopment/aegis/Preferences.java index c3077639..913b6f03 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/Preferences.java +++ b/app/src/main/java/com/beemdevelopment/aegis/Preferences.java @@ -5,9 +5,9 @@ import android.content.SharedPreferences; import android.content.res.Resources; import android.net.Uri; import android.os.Build; -import android.preference.PreferenceManager; import androidx.annotation.Nullable; +import androidx.preference.PreferenceManager; import com.beemdevelopment.aegis.util.JsonUtils; import com.beemdevelopment.aegis.util.TimeUtils; diff --git a/app/src/test/java/com/beemdevelopment/aegis/PreferencesTest.java b/app/src/test/java/com/beemdevelopment/aegis/PreferencesTest.java index 166d6a47..5a487aea 100644 --- a/app/src/test/java/com/beemdevelopment/aegis/PreferencesTest.java +++ b/app/src/test/java/com/beemdevelopment/aegis/PreferencesTest.java @@ -7,15 +7,13 @@ import static org.junit.Assert.assertTrue; import android.content.Context; import android.content.SharedPreferences; -import android.os.Build; -import android.preference.PreferenceManager; +import androidx.preference.PreferenceManager; import androidx.test.core.app.ApplicationProvider; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import java.util.Date; From baa8068d51a799340656316f90f27e49b118695b Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Sat, 21 Sep 2024 14:17:29 +0200 Subject: [PATCH 041/113] Redefine "import_partial_export_anyway" as a quantity string --- .../java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java | 2 +- app/src/main/res/values-ar-rSA/strings.xml | 1 - app/src/main/res/values-ast-rES/strings.xml | 1 - app/src/main/res/values-bg-rBG/strings.xml | 1 - app/src/main/res/values-ca-rES/strings.xml | 1 - app/src/main/res/values-cs-rCZ/strings.xml | 1 - app/src/main/res/values-da-rDK/strings.xml | 1 - app/src/main/res/values-de-rDE/strings.xml | 1 - app/src/main/res/values-el-rGR/strings.xml | 1 - app/src/main/res/values-es-rES/strings.xml | 1 - app/src/main/res/values-eu-rES/strings.xml | 1 - app/src/main/res/values-fi-rFI/strings.xml | 1 - app/src/main/res/values-fr-rFR/strings.xml | 1 - app/src/main/res/values-fy-rNL/strings.xml | 1 - app/src/main/res/values-gl-rES/strings.xml | 1 - app/src/main/res/values-hi-rIN/strings.xml | 1 - app/src/main/res/values-hu-rHU/strings.xml | 1 - app/src/main/res/values-in-rID/strings.xml | 1 - app/src/main/res/values-it-rIT/strings.xml | 1 - app/src/main/res/values-iw-rIL/strings.xml | 1 - app/src/main/res/values-ja-rJP/strings.xml | 1 - app/src/main/res/values-lv-rLV/strings.xml | 1 - app/src/main/res/values-nl-rNL/strings.xml | 1 - app/src/main/res/values-pl-rPL/strings.xml | 1 - app/src/main/res/values-pt-rBR/strings.xml | 1 - app/src/main/res/values-pt-rPT/strings.xml | 1 - app/src/main/res/values-ro-rRO/strings.xml | 1 - app/src/main/res/values-ru-rRU/strings.xml | 1 - app/src/main/res/values-sv-rSE/strings.xml | 1 - app/src/main/res/values-tr-rTR/strings.xml | 1 - app/src/main/res/values-uk-rUA/strings.xml | 1 - app/src/main/res/values-vi-rVN/strings.xml | 1 - app/src/main/res/values-zh-rCN/strings.xml | 1 - app/src/main/res/values-zh-rTW/strings.xml | 1 - app/src/main/res/values/strings.xml | 5 ++++- 35 files changed, 5 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java b/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java index f814369f..50ddc131 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java @@ -554,7 +554,7 @@ public class Dialogs { .setView(view) .setCancelable(false) .setIconAttribute(android.R.attr.alertDialogIcon) - .setPositiveButton(context.getString(R.string.import_partial_export_anyway, entries), (dialog, which) -> { + .setPositiveButton(context.getResources().getQuantityText(R.plurals.import_partial_export_anyway, entries), (dialog, which) -> { dismissHandler.onClick(dialog, which); }) .setNegativeButton(android.R.string.cancel, null); diff --git a/app/src/main/res/values-ar-rSA/strings.xml b/app/src/main/res/values-ar-rSA/strings.xml index 3c5379c7..e1dd69ee 100644 --- a/app/src/main/res/values-ar-rSA/strings.xml +++ b/app/src/main/res/values-ar-rSA/strings.xml @@ -327,7 +327,6 @@ اكتُشف تصدير Google Authenticator غير مكتمل بعض رموز QR مفقودة من الاستيراد. لم يتم العثور على الرموز التالية:\n\n%s\n\nيمكنك الاستمرار في استيراد هذا التصدير الجزئي ولكننا نوصي بإعادة المحاولة باستخدام جميع رموز QR حتى لا تخاطر بفقدان الوصول إلى أي رموز. • رمز QR %d - استيراد %d رموز على أي حال فشل استيراد تصدير Google Authenticator يحتوي التصدير على معلومات عن دُفعة غير ذات صلة. حاول استيراد دفعة واحدة في كل مرة. نتيجة لذلك، لا يمكن استيراد أي رموز diff --git a/app/src/main/res/values-ast-rES/strings.xml b/app/src/main/res/values-ast-rES/strings.xml index ba354d71..e9f58cab 100644 --- a/app/src/main/res/values-ast-rES/strings.xml +++ b/app/src/main/res/values-ast-rES/strings.xml @@ -249,7 +249,6 @@ Detectóse una esportación incompleta de Google Authenticator Falten dalgunos códigos QR na importación. Nun s\'atoparon los códigos siguientes:\n\n%s\n\nPues siguir cola importación d\'esta esportación parcial mas aconseyamos volver tentalo con tolos códigos QR pa que nun t\'arriesgues a perder l\'accesu a nengún pase. • Códigu QR %d - Importar %d pases de toes toes La importación de la esportación de Google Authenticator falló La esportación contién información d\'un llote que nun tien rellación. Prueba a importar llotes d\'unu nunu. Como resultáu, nun se pue importar nengún pase diff --git a/app/src/main/res/values-bg-rBG/strings.xml b/app/src/main/res/values-bg-rBG/strings.xml index 61688e79..e9c2d16c 100644 --- a/app/src/main/res/values-bg-rBG/strings.xml +++ b/app/src/main/res/values-bg-rBG/strings.xml @@ -303,7 +303,6 @@ Установени са частично изнасени данни за Google Authenticator Няколко QR кода не са внесени. Следните кодове липсват:\n\n%s\n\nМожете да продължите с частично внесените данни, но е препоръчително да направите нов опит с всички QR кодове без да рискувате загуба на кодове за защите. • QR код %d - Внасяне на %d кода за достъп въпреки това Грешка при внасяне към Google Authenticator Изнесеното съдържа части от несвързана порция кодове. Внасяйте всяка порция поотделно. Като резултат не са внесени кодове за защита diff --git a/app/src/main/res/values-ca-rES/strings.xml b/app/src/main/res/values-ca-rES/strings.xml index f8de17b6..7795242c 100644 --- a/app/src/main/res/values-ca-rES/strings.xml +++ b/app/src/main/res/values-ca-rES/strings.xml @@ -303,7 +303,6 @@ S\'ha detectat una exportació incompleta de Google Authenticator Falten alguns codis QR a la importació. No s\'han trobat els codis següents:\n\n%s\n\nPodeu continuar important aquesta exportació parcial, però us recomanem que torneu a provar amb tots els codis QR perquè no us arriscareu a perdre l\'accés a cap token. • codi QR %d - Importeu %d tokens de totes maneres No s\'ha pogut importar l\'exportació de Google Authenticator L\'exportació conté informació d\'un lot no relacionat. Proveu d\'importar 1 lot alhora. Com a resultat, no es poden importar tokens diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 7dd3ccf6..392403b5 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -319,7 +319,6 @@ Zjištěn neúplný export z Google Authenticator Ve vašem importu chybí některé QR kódy. Nebyly nalezeny následující kódy:\n\n%s\n\nMůžete pokračovat s importováním tohoto částečného exportu, ale doporučujeme to zkusit znovu se všemi QR kódy, abyste neriskovali ztrátu přístupu k některým tokenům. • QR kód %d - Přesto importovat %d tokenů Importování exportu z Google Authenticator selhalo Export obsahuje informace o nesouvisejícím balíku. Zkuste importovat 1 balík najednou. Nebyly importovány žádné tokeny diff --git a/app/src/main/res/values-da-rDK/strings.xml b/app/src/main/res/values-da-rDK/strings.xml index e8d2c04b..c98cab94 100644 --- a/app/src/main/res/values-da-rDK/strings.xml +++ b/app/src/main/res/values-da-rDK/strings.xml @@ -303,7 +303,6 @@ Ufuldstændig Google Authenticator-eksport detekteret Nogle QR-koder mangler i importen. Flg. koder er ikke fundet:\n\n%s\n\nMan kan fortsætte med import af denne delvise eksport, dog anbefales det at prøve igen med alle QR-koderne, så man ikke risikerer at miste adgang til nogle tokens. • QR-kode %d - Importér %d tokens alligevel Import af Google Authenticator-eksport mislykkedes Eksporten indeholder information om et urelateret sæt. Prøv at importere 1 sæt ad gangen. Som konsekvens, kan ingen tokener importeres diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index 6b874286..c42cdb6a 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -303,7 +303,6 @@ Unvollständiger Google Authenticator-Export erkannt Einige QR-Codes fehlen in deinem Importversuch. Die folgenden Codes wurden nicht gefunden:\n\n%s\n\nDu kannst mit dem Importieren dieses Teilexports fortfahren, aber wir empfehlen es mit allen QR-Codes erneut zu versuchen, damit du nicht riskierst, den Zugriff auf Token zu verlieren. • QR-Code %d - %d Token trotzdem importieren Importieren von Google Authenticator-Export fehlgeschlagen Die Exportdatei enthält Informationen über ein nicht zugehöriges Set. Versuche, jeweils 1 Set zu importieren. Daher können keine Token importiert werden diff --git a/app/src/main/res/values-el-rGR/strings.xml b/app/src/main/res/values-el-rGR/strings.xml index 259ee620..49c3aad8 100644 --- a/app/src/main/res/values-el-rGR/strings.xml +++ b/app/src/main/res/values-el-rGR/strings.xml @@ -303,7 +303,6 @@ Εντοπίστηκε ημιτελής εξαγωγή του Επαληθευτή Google Ορισμένοι κωδικοί QR λείπουν από την εισαγωγή σας. Οι ακόλουθοι κωδικοί δεν βρέθηκαν:\n\n%s\n\nΜπορείτε να συνεχίσετε την εισαγωγή αυτής της μερικής εξαγωγής, αλλά σας συνιστούμε να ξαναδοκιμάσετε με όλους τους κωδικούς QR ώστε να μην κινδυνεύετε να χάσετε πρόσβαση σε οποιαδήποτε αναγνωστικά. • Κωδικός QR %d - Εισαγωγή %d αναγνωριστικών ούτως ή άλλως Η εισαγωγή της εξαγωγής του Επαληθευτή Google απέτυχε Η εξαγωγή περιέχει πληροφορίες για μια άσχετη παρτίδα. Δοκιμάστε να εισαγάγετε 1 παρτίδα τη φορά. Ως αποτέλεσμα, δεν μπορούν να εισαχθούν αναγνωστικά diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index bcb503b4..0453721a 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -303,7 +303,6 @@ Se ha detectado una exportación incompleta de Google Authenticator Algunos código QR de importación no están. Faltan los siguientes códigos:\n\n%s\n\nPuedes seguir adelante con esta importación parcial, pero te recomendamos volver a probar otra vez a escanear todos los códigos QR para evitar que pierdas el acceso a alguno de ellos. • código QR %d - Aún así quieres seguir con la importación de estos %d códigos Ha fallado la importación de lo exportado de Google Authenticator La exportación contiene información para un lote no relacionado. Intente importar 1 lote a la vez. Como consecuencia no se pudo importar ninguna de las claves diff --git a/app/src/main/res/values-eu-rES/strings.xml b/app/src/main/res/values-eu-rES/strings.xml index 1fd1b1bc..00e2ef69 100644 --- a/app/src/main/res/values-eu-rES/strings.xml +++ b/app/src/main/res/values-eu-rES/strings.xml @@ -297,7 +297,6 @@ Google Authenticatorren esportazioa ez da osoa QR kode batzuk falta dira zure inportazioan. Kode hauek ez dira aurktu: \n\n%s\n\nZatikako inportazio honekin jarrai dezakezu baina berriz ere QR kode guztiekin saiatzea gomendatzen dizugu tokenetarako sarrera gal ez dezazun. • QR kodea %d - Inportatu %d token edonola ere Google Authenticatorren esportazioa inportatzeak huts egin du Esportazioak zerikusirik ez duen sorta baten informazioa du. Saiatu sorta bakoitza bere aldetik inportatzen. Ez izan da tokenik inportatu diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index f913e65a..c4e97e70 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -297,7 +297,6 @@ Puutteellinen Google Authenticatorin varmuuskopio havaittu Jotkin QR-koodit puuttuvat tuonnistasi. Seuraavia koodeja ei löytynyt:\n\n%s\n\nVoit jatkaa tämän osittaisen viennin tuontia, mutta suosittelemme kokeilemaan uudelleen kaikilla QR-koodeilla, jotta et menetä pääsyä todennuskoodeihin. • QR-koodi %d - Tuo %d todennuskoodia silti Google Authenticatorin varmuuskopion tuonti epäonnistui Vienti sisältää tietoa liittymättömästä erästä. Yritä tuoda 1 erä kerrallaan. Tämän seurauksena yhtäkään todennuskoodia ei voitu tuoda diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml index 7ee1693a..70fc6df1 100644 --- a/app/src/main/res/values-fr-rFR/strings.xml +++ b/app/src/main/res/values-fr-rFR/strings.xml @@ -303,7 +303,6 @@ Export Google Authenticator incomplet détecté Certains codes QR sont manquants dans votre export. Les codes suivants n\'ont pas été trouvés :\n\n%s\n\nVous pouvez continuer à importer cet export partiel, mais nous vous recommandons de réessayer avec tous les codes QR afin de ne risquer de perdre l\'accès à aucun jeton. • code QR %d - Importer %d jetons quand même L\'import de l\'export Google Authenticator a échoué L\'export contient des informations pour un lot non lié. Essayez d\'importer 1 lot à la fois. Aucun jeton ne peut être importé en conséquence diff --git a/app/src/main/res/values-fy-rNL/strings.xml b/app/src/main/res/values-fy-rNL/strings.xml index ce0ca113..4401343a 100644 --- a/app/src/main/res/values-fy-rNL/strings.xml +++ b/app/src/main/res/values-fy-rNL/strings.xml @@ -297,7 +297,6 @@ Net folsleine Google Authenticator-eksport detektearre Inkelde QR-koaden ûntbrekke yn de ymport. De folgjende koaden binne net fûn:\n\n%s\n\nDo kinst trochgean mei it ymportearjen fan dizze ûnfolsleine eksport, mar wy rekommandearje oan it opnij te probearjen mei alle QR-koaden, sadatsto net it risiko rinst de tagong ta tokens te ferliezen. • QR-koade %d - %d tokens dochs ymportearje Ymportearjen fan Google Authenticator-eksport mislearre Eksport befettet ynformaasje foar in net relatearre batch. Probearje 1 batch tagelyk te ymportearjen. Hjirtroch kinne gjin tokens ymportearre wurde diff --git a/app/src/main/res/values-gl-rES/strings.xml b/app/src/main/res/values-gl-rES/strings.xml index 473087e5..9b71cf41 100644 --- a/app/src/main/res/values-gl-rES/strings.xml +++ b/app/src/main/res/values-gl-rES/strings.xml @@ -295,7 +295,6 @@ Detectouse una exportación de Google Authenticator incompleta Faltan algúns códigos QR na importación. Os seguintes códigos non se atoparon:\n\n%s\n\nPodes continuar importando esta exportación parcial, pero o recomendable é volvelo a intentar con tódolos códigos QR para que non te arrisques a perder o acceso a ningún token. • código QR %d - Importar %d tokens de todas formas Fallou a importación do exportado con Google Authenticator A exportación contén información sobre un lote non relacionado. Intenta importar 1 lote de cada vez. Polo tanto, non se pode importar ningún token diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/app/src/main/res/values-hi-rIN/strings.xml index 5dec1e32..a63878a8 100644 --- a/app/src/main/res/values-hi-rIN/strings.xml +++ b/app/src/main/res/values-hi-rIN/strings.xml @@ -258,7 +258,6 @@ अपूर्ण गूगल ऑथेंटिकेटर एक्सपोर्ट का पता चला आपके इंपोर्ट से कुछ क्यूआर कोड गायब हैं। निम्नलिखित कोड नहीं मिले:\n\n%s\n\nआप इस आंशिक एक्सपोर्ट को इंपोर्ट करना जारी रख सकते हैं लेकिन हम सभी क्यूआर कोड के साथ पुनः प्रयास करने की सलाह देते हैं ताकि आप किसी भी टोकन तक पहुंच खोने का जोखिम न उठाएं| • क्यूआर कोड %d - फिर भी %d टोकंस इंपोर्ट करें गूगल ऑथेंटिकेटर एक्सपोर्ट को इंपोर्ट करना असफल हुआ एक्सपोर्ट में किसी असंबंधित बैच की जानकारी शामिल है. एक समय में 1 बैच इंपोर्ट करने का प्रयास करें। परिणामस्वरूप कोई टोकन आयात नहीं किया जा सकता diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index 7d64e71f..62073ddf 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -297,7 +297,6 @@ Hiányos Google Authenticator export észlelve Néhány QR-kód hiányzik az importból. Ezek a kódok nem találhatók:\n\n%s\n\nFolytathatja a részleges export importálását, de javasoljuk, hogy próbálja újra az összes QR-kóddal, hogy ne kockáztassa a hozzáférése elvesztését egyetlen tokennél sem. • %d. QR-kód - %d token importálása mindenképp A Google Authenticator export importálása sikertelen Az export nem kapcsolódó köteg információit tartalmazza. Egyszerre csak 1 köteget próbáljon meg importálni. Ennek eredményeképp egyetlen token sem importálható diff --git a/app/src/main/res/values-in-rID/strings.xml b/app/src/main/res/values-in-rID/strings.xml index e43f7dee..ef0c6bb4 100644 --- a/app/src/main/res/values-in-rID/strings.xml +++ b/app/src/main/res/values-in-rID/strings.xml @@ -289,7 +289,6 @@ Ekspor Google Authenticator tidak lengkap terdeteksi Beberapa kode QR tidak ditemukan dalam impor Anda. Kode berikut ini tidak ditemukan:\n\n%s\n\nAnda dapat melanjutkan mengimpor ekspor parsial ini, tetapi kami sarankan untuk mencoba kembali dengan semua kode QR agar Anda tidak mengambil risiko kehilangan akses ke token apa pun. • - Kode QR %d - Tetap mengimpor %d token Mengimpor ekspor Google Authenticator gagal Ekspor berisi informasi untuk batch yang tidak terkait. Coba impor 1 batch dalam satu waktu. Tidak ada token yang dapat diimpor sebagai hasilnya diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml index 8fd4406f..560357fe 100644 --- a/app/src/main/res/values-it-rIT/strings.xml +++ b/app/src/main/res/values-it-rIT/strings.xml @@ -272,7 +272,6 @@ Rilevata esportazione di Google Authenticator incompleta Alcuni codici QR non sono presenti nell\'importazione. Non sono stati trovati i seguenti codici:\n\n%s\n\nPuoi continuare a importare questa esportazione parziale, ma ti consigliamo di riprovare con tutti i codici QR in modo da non perdere l\'accesso ai token. • QR code %d - Importa comunque %d token Importazione dell\'esportazione di Google Authenticator non riuscita L\'esportazione contiene informazioni per un lotto non correlato. Provare a importare un lotto alla volta. Di conseguenza non è possibile importare token diff --git a/app/src/main/res/values-iw-rIL/strings.xml b/app/src/main/res/values-iw-rIL/strings.xml index 7f4d21bd..1e2ab5f4 100644 --- a/app/src/main/res/values-iw-rIL/strings.xml +++ b/app/src/main/res/values-iw-rIL/strings.xml @@ -251,7 +251,6 @@ זוהה ייצוא לא שלם של Google Authenticator כמה קודי QR חסרים בייבוא שלך. הקודים הבאים לא נמצאו:\n\n%s\n\nתוכל להמשיך לייבא את הייצוא החלקי הזה, אך אנו ממליצים לנסות שוב עם כל קודי ה-QR כדי לא להסתכן באובדן גישה לכל קודי אסימונים. • קוד QR %d - ייבוא אסימוני %d בכל מקרה ייבוא ייצוא מאמת Google נכשל ייצוא מכיל מידע עבור אצווה לא קשורה. נסה לייבא אצווה אחת בכל פעם. לא ניתן לייבא אסימונים כתוצאה מכך diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index c5c9cf6a..4fbd3294 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -262,7 +262,6 @@ 不完全な Google Authenticator のエクスポートが検出されました インポート内の一部のQRコードが見つかりません。以下のコードが見つかりませんでした:\n\n%s\n\n正常な部分のみでインポートを継続することはできますが、トークンへのアクセス方法を失う危険性があるため、すべてのQRコードを再試行することをお勧めします。 • QRコード %d - とにかく %d 個のトークンをインポートする Google Authenticator エクスポートのインポートに失敗しました エクスポートには関連のないバッチの情報が含まれています。一度にひとつのバッチをインポートしてください。 インポートできるトークンはありません diff --git a/app/src/main/res/values-lv-rLV/strings.xml b/app/src/main/res/values-lv-rLV/strings.xml index ce58e9df..be0edb3f 100644 --- a/app/src/main/res/values-lv-rLV/strings.xml +++ b/app/src/main/res/values-lv-rLV/strings.xml @@ -311,7 +311,6 @@ Noteikta nepilnīga Google Authenticator izgūšanas datne Trūkst dažu kvadrātkodu no ievietošanas. Šie kodi netika atrasti:\n\n%s\n\nVar turpināt ievietošanu no šīs nepilnīgās izgūšanas datnes, bet mēs iesakām mēģināt atkārtoti ar visiem kvadrātkodiem, lai nebūtu jāzaudē piekļuve kodiem. • kvadrātkods %d - Vienalga ievietot %d kodus Neizdevās ievietošana no Google Authenticator izgūšanas datnes Izgūšanas datne satur informāciju par nesaistītu kopumu. Var mēģināt ievietot atsevišķi pa vienam kopumam. Iznākumā nevar ievietot nevienu kodu diff --git a/app/src/main/res/values-nl-rNL/strings.xml b/app/src/main/res/values-nl-rNL/strings.xml index c5488d83..ada1992b 100644 --- a/app/src/main/res/values-nl-rNL/strings.xml +++ b/app/src/main/res/values-nl-rNL/strings.xml @@ -303,7 +303,6 @@ Onvolledige Google Authenticator-export gedetecteerd Enkele QR-codes ontbreken in de import. De volgende codes zijn niet gevonden:\n\n%s\n\nJe kan doorgaan met het importeren van deze gedeeltelijke export, maar we raden aan het opnieuw te proberen met alle QR-codes, zodat je niet het risico loopt de toegang tot tokens te verliezen. • QR-code %d - %d tokens toch importeren Importeren van Google Authenticator-export mislukt Export bevat informatie voor een niet gerelateerde batch. Probeer 1 batch tegelijk te importeren. Hierdoor kunnen geen tokens worden geïmporteerd diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml index 4d403339..db9893e9 100644 --- a/app/src/main/res/values-pl-rPL/strings.xml +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -309,7 +309,6 @@ Wykryto niekompletny eksport z Google Authenticator W imporcie brakuje niektórych kodów QR. Następujące kody nie zostały znalezione:\n\n%s\n\nMożesz kontynuować importowanie tego częściowego eksportu, ale zalecamy ponowną próbę z wszystkimi kodami QR, aby nie ryzykować utraty dostępu do tokenów. • Kod QR %d - Zaimportuj tokeny %d mimo to Importowanie danych z Google Authenticator nie powiodło się Eksport zawiera informacje dla niepowiązanej partii. Spróbuj importować 1 partię jednocześnie. Nie można zaimportować żadnych tokenów diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 66155c54..2240e6b1 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -303,7 +303,6 @@ Exportação incompleta do Google Authenticator detectada Alguns QR codes estão faltando em sua importação. Os seguintes códigos não foram encontrados:\n\n%s\n\nVocê pode continuar importando esta exportação parcial, mas recomendamos tentar novamente com todos os códigos QR para que não corra o risco de perder o acesso a quaisquer tokens. • QR code %d - Importar %d tokens mesmo assim Falha ao importar exportação do Google Authenticator A exportação contém informações para um lote não relacionado. Tente importar 1 lote de cada vez. Como resultado, nenhum token pode ser importado diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 821a5bee..0770e45b 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -293,7 +293,6 @@ Foi detetada uma exportação incompleta do Google Authenticator Faltam alguns códigos QR na sua importação. Os seguintes códigos não foram encontrados:\n\n%s\n\nPode continuar a importar esta exportação parcial, mas recomendamos que tente novamente com todos os códigos QR para não correr o risco de perder o acesso a quaisquer tokens. • Código QR %d - Importar %d tokens mesmo assim Falha ao importar a exportação do Google Authenticator A exportação contém informações para um lote não relacionado. Experimente importar um lote de cada vez. Nenhum token pode ser importado como resultado diff --git a/app/src/main/res/values-ro-rRO/strings.xml b/app/src/main/res/values-ro-rRO/strings.xml index 07b1e693..2f926a21 100644 --- a/app/src/main/res/values-ro-rRO/strings.xml +++ b/app/src/main/res/values-ro-rRO/strings.xml @@ -305,7 +305,6 @@ S-a detectat exportul incomplet a datelor din autentificatorul Google Unele coduri QR lipsesc din fișerul importat. Următoarele coduri nu au fost găsite:\n\n%s\n\nPuteţi continua importul acestui fișier parţial, dar vă recomandăm să încercaţi din nou cu toate codurile QR pentru a nu risca pierderea niciunui token. • codul QR %d - Importă jetoanele %d oricum Importarea din Google Authenticator a eșuat Exportul conține informații pentru un calup neasociat. Încercați să importați câte un calup pe rând. Nu se pot importa token-uri drept rezultat diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index c22aa28d..bae5799c 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -319,7 +319,6 @@ Обнаружен неполный экспорт Google Authenticator Некоторые QR-коды отсутствуют в импорте. Следующие коды не найдены:\n\n%s\n\nВы можете продолжить импорт этого неполного экспорта, но лучше сделать повторный экспорт со всеми QR-кодами, чтобы избежать риска потери доступа к ключам. • QR-код %d - Принудительно импортировать %d ключей Невожможно импортировать экспорт из Google Authenticator Экспорт содержит информацию для несвязанного пакета. Попробуйте импортировать по 1 пакету за раз. В результате ни один ключ не может быть импортирован diff --git a/app/src/main/res/values-sv-rSE/strings.xml b/app/src/main/res/values-sv-rSE/strings.xml index 272e87e8..5a78a421 100644 --- a/app/src/main/res/values-sv-rSE/strings.xml +++ b/app/src/main/res/values-sv-rSE/strings.xml @@ -299,7 +299,6 @@ Ofullständig Google Authenticator-export upptäckt Vissa rutkoder saknas från din import. Följande koder hittades inte:\n\n%s\n\nDu kan fortsätta att importera denna partiella export, men vi rekommenderar att du försöker igen med alla rutkoder, så att du inte riskerar att förlora åtkomst till några polletter. • rutkod %d - Importera %d polletter ändå Import av Google Authenticator-export misslyckades Exporten innehåller information gällande en orelaterad omgång. Försök att importera 1 omgång i taget. Inga polletter kan importeras till följd av detta diff --git a/app/src/main/res/values-tr-rTR/strings.xml b/app/src/main/res/values-tr-rTR/strings.xml index 7703d4b0..4e0b6d44 100644 --- a/app/src/main/res/values-tr-rTR/strings.xml +++ b/app/src/main/res/values-tr-rTR/strings.xml @@ -272,7 +272,6 @@ Eksik Google Authenticator dışa aktarımı algılandı İçe aktarma işleminizde bazı QR kodları eksik. aşağıdaki kodlar bulunamadı:\n\n%s\n\nBu kısmi dışa aktarmayı içe aktarmaya devam edebilirsiniz, ancak herhangi bir tokena erişimi kaybetme riskine girmemek için tüm QR kodlarıyla yeniden denemenizi öneririz. • QR kodu %d - Yine de %d tokenı içe aktar Dışa aktarılmış Google Authenticator dosyasını içe aktarma işlemi başarısız oldu Dışa aktarma, ilgisiz bir toplu iş için bilgi içerir. Bir seferde 1 partiyi içe aktarmayı deneyin. Sonuç olarak hiçbir token içe aktarılamaz diff --git a/app/src/main/res/values-uk-rUA/strings.xml b/app/src/main/res/values-uk-rUA/strings.xml index 952eeb81..60068ad2 100644 --- a/app/src/main/res/values-uk-rUA/strings.xml +++ b/app/src/main/res/values-uk-rUA/strings.xml @@ -268,7 +268,6 @@ Виявлено неповний експорт з Google Authenticator Деякі QR-коди відсутні у вашому імпорті. Наступні коди не були знайдені:\n\n%s\n\nВи можете продовжити імпорт цього часткового файлу експорту, але ми рекомендуємо спробувати ще раз з усіма QR-кодами, щоб уникнути ризику втрати доступу до токенів. • QR-код %d - Однаково імпортувати %d токен/и/ів Не вдалося імпортувати дані з Google Authenticator Експорт містить інформацію про непов\'язаний пакет. Спробуйте імпортувати пакети по одному. В результаті жоден токен не може бути імпортований diff --git a/app/src/main/res/values-vi-rVN/strings.xml b/app/src/main/res/values-vi-rVN/strings.xml index b387f243..939f013e 100644 --- a/app/src/main/res/values-vi-rVN/strings.xml +++ b/app/src/main/res/values-vi-rVN/strings.xml @@ -296,7 +296,6 @@ Đã phát hiện quá trình xuất Google Authenticator chưa hoàn tất Một số mã QR bị thiếu trong quá trình nhập. Không tìm thấy các mã sau:\n\n%s\n\nBạn có thể tiếp tục nhập bản xuất này nhưng chúng tôi khuyên bạn nên thử lại với tất cả các mã QR để không có nguy cơ mất quyền truy cập vào bất kỳ token nào. • Mã QR %d - Vẫn cứ nhập %d token Quá trình xuất Google Authenticator thất bại Bản xuất chứa thông tin về một batch không liên quan. Hãy thử nhập 1 batch mỗi lần. Do đó, không thể nhập token nào diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 62e6b4da..6c58020b 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -295,7 +295,6 @@ 检测到不完整的 Google 身份验证器导出 您的导入缺少一些 QR 码。 找不到下列代码:\n\n%s\n\n您仍可以继续导入已有部分,但建议您重试所有 QR 码,以避免出现丢失令牌的风险。 • QR 码 %d - 继续导入 %d 个令牌 导入 Google 身份验证器的导出文件失败 导出文件包含多个批次的内容。请一次只导入一个批次。 没有可导入的令牌 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 03ee7ee9..e456002f 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -258,7 +258,6 @@ Aegis 不相容於微軟私有的雙因素驗證演算法。請確保在 Microsoft 365 設定雙因素驗證時選擇「設定無通知的應用程式」。 偵測到不完整的 Google Authenticator 匯出 • QR 圖碼 %d - 仍要匯入 %d 個令牌 匯入 Google Authenticator 失敗 解鎖保險箱 重新命名群組 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 40152096..fd6cb2fd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -314,7 +314,10 @@ Incomplete Google Authenticator export detected Some QR codes are missing from your import. The following codes were not found:\n\n%s\n\nYou may continue importing this partial export but we recommend retrying with all of the QR codes so you don\'t risk losing access to any tokens. • QR code %d - Import %d tokens anyway + + Import %d token anyway + Import %d tokens anyway + Importing Google Authenticator export failed Export contains information for an unrelated batch. Try importing 1 batch at a time. No tokens can be imported as a result From 257a40eefa31aa6018f88782477219ebccb797c0 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Sat, 21 Sep 2024 14:42:37 +0200 Subject: [PATCH 042/113] Remove some unused resources (and increase severity of check) --- app/build.gradle | 1 - app/lint.xml | 7 +++++- .../main/res/color/dialog_button_color.xml | 5 ---- .../res/color/dialog_button_ripple_color.xml | 23 ------------------- .../drawable/ic_outline_filter_list_24.xml | 10 -------- .../main/res/drawable/rounded_background.xml | 6 ----- app/src/main/res/values-w600dp/dimens.xml | 3 --- app/src/main/res/values-w60dp/dimens.xml | 3 --- app/src/main/res/values/colors.xml | 2 +- app/src/main/res/values/dimens.xml | 4 ---- app/src/main/res/values/strings.xml | 12 +++++----- app/src/main/res/values/themes.xml | 2 +- 12 files changed, 14 insertions(+), 64 deletions(-) delete mode 100644 app/src/main/res/color/dialog_button_color.xml delete mode 100644 app/src/main/res/color/dialog_button_ripple_color.xml delete mode 100644 app/src/main/res/drawable/ic_outline_filter_list_24.xml delete mode 100644 app/src/main/res/drawable/rounded_background.xml delete mode 100644 app/src/main/res/values-w600dp/dimens.xml delete mode 100644 app/src/main/res/values-w60dp/dimens.xml diff --git a/app/build.gradle b/app/build.gradle index 97cbac61..4fc2bbab 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -108,7 +108,6 @@ android { lint { abortOnError true checkDependencies true - disable 'MissingQuantity', 'MissingTranslation' } buildFeatures { buildConfig true diff --git a/app/lint.xml b/app/lint.xml index 4cdb0450..f9f30d6e 100644 --- a/app/lint.xml +++ b/app/lint.xml @@ -1,10 +1,15 @@ + + - + + + + diff --git a/app/src/main/res/color/dialog_button_color.xml b/app/src/main/res/color/dialog_button_color.xml deleted file mode 100644 index 6abb6590..00000000 --- a/app/src/main/res/color/dialog_button_color.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/app/src/main/res/color/dialog_button_ripple_color.xml b/app/src/main/res/color/dialog_button_ripple_color.xml deleted file mode 100644 index d5a3e9d9..00000000 --- a/app/src/main/res/color/dialog_button_ripple_color.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_outline_filter_list_24.xml b/app/src/main/res/drawable/ic_outline_filter_list_24.xml deleted file mode 100644 index ac6b9761..00000000 --- a/app/src/main/res/drawable/ic_outline_filter_list_24.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/rounded_background.xml b/app/src/main/res/drawable/rounded_background.xml deleted file mode 100644 index 682c748a..00000000 --- a/app/src/main/res/drawable/rounded_background.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/src/main/res/values-w600dp/dimens.xml b/app/src/main/res/values-w600dp/dimens.xml deleted file mode 100644 index 311a717f..00000000 --- a/app/src/main/res/values-w600dp/dimens.xml +++ /dev/null @@ -1,3 +0,0 @@ - - 36sp - diff --git a/app/src/main/res/values-w60dp/dimens.xml b/app/src/main/res/values-w60dp/dimens.xml deleted file mode 100644 index f93bfa8c..00000000 --- a/app/src/main/res/values-w60dp/dimens.xml +++ /dev/null @@ -1,3 +0,0 @@ - - 32sp - diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 08860e02..38d45937 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,4 +1,4 @@ - + #2b5bb5 #ffffff #d9e2ff diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 48b396f6..104bdeb9 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -1,8 +1,4 @@ - - 16dp - 16dp 16dp 48dp - 46sp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fd6cb2fd..79d77d9f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,4 +1,4 @@ - + Aegis Aegis Authenticator Beem Development @@ -555,23 +555,23 @@ Next to the issuer Below the issuer - + %d second ago %d seconds ago - + %d minute ago %d minutes ago - + %d hour ago %d hours ago - + %d day ago %d days ago - + %d year ago %d years ago diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index f6529d4c..8f84698c 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -248,7 +248,7 @@ - - - + + @@ -179,6 +182,7 @@ #000000 #000000 @android:color/white + #2F2F2F @android:color/white From e8d712ec7189282dbd5aaeaacf0b506ef1cd9636 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Fri, 24 Jan 2025 14:34:41 +0100 Subject: [PATCH 093/113] Flush temporary export file before starting ExportTask The previous logic was not an issue because FileOutputStream is unbuffered, but still, this is more correct. --- .../preferences/ImportExportPreferencesFragment.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/ImportExportPreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/ImportExportPreferencesFragment.java index f544bf6f..b995b235 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/ImportExportPreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/ImportExportPreferencesFragment.java @@ -518,11 +518,10 @@ public class ImportExportPreferencesFragment extends PreferencesFragment { file = File.createTempFile(VaultRepository.FILENAME_PREFIX_EXPORT + "-", ".json", getExportCacheDir()); outStream = new FileOutputStream(file); cb.exportVault(outStream); - - new ExportTask(requireContext(), new ExportResultListener()).execute(getLifecycle(), new ExportTask.Params(file, uri)); } catch (VaultRepositoryException | IOException e) { e.printStackTrace(); Dialogs.showErrorDialog(requireContext(), R.string.exporting_vault_error, e); + return; } finally { try { if (outStream != null) { @@ -532,6 +531,8 @@ public class ImportExportPreferencesFragment extends PreferencesFragment { e.printStackTrace(); } } + + new ExportTask(requireContext(), new ExportResultListener()).execute(getLifecycle(), new ExportTask.Params(file, uri)); }, _exportFilter); _exportFilter = null; } From 78ee38ba7d60794944f7ee463c468e22dbbd7fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Sun, 1 Dec 2024 23:08:05 +0100 Subject: [PATCH 094/113] Add ability to multiselect groups --- .../beemdevelopment/aegis/Preferences.java | 4 ++++ .../aegis/ui/MainActivity.java | 23 ++++++++----------- app/src/main/res/layout/activity_main.xml | 3 +-- app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/preferences_behavior.xml | 7 ++++++ 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/Preferences.java b/app/src/main/java/com/beemdevelopment/aegis/Preferences.java index 95f3ed4c..6e86f4f7 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/Preferences.java +++ b/app/src/main/java/com/beemdevelopment/aegis/Preferences.java @@ -86,6 +86,10 @@ public class Preferences { return _prefs.getBoolean("pref_tap_to_reveal", false); } + public boolean isGroupMultiselectEnabled() { + return _prefs.getBoolean("pref_groups_multiselect", false); + } + public boolean isEntryHighlightEnabled() { return _prefs.getBoolean("pref_highlight_entry", false); } 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 1dc5cbd5..29ac2c69 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -274,6 +274,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene private void initializeGroups() { _groupChip.removeAllViews(); + _groupChip.setSingleSelection(!_prefs.isGroupMultiselectEnabled()); for (VaultGroup group : _groups) { addChipTo(_groupChip, new VaultGroupModel(group)); @@ -313,29 +314,24 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene } chip.setOnCheckedChangeListener((group1, isChecked) -> { - Set groupFilter = new HashSet<>(); if (_actionMode != null) { _actionMode.finish(); } setSaveChipVisibility(true); - if (!isChecked) { - group1.setChecked(false); + // Reset group filter if last checked group gets unchecked + if (!isChecked && _groupFilter.size() == 1) { + Set groupFilter = new HashSet<>(); + + chipGroup.clearCheck(); _groupFilter = groupFilter; _entryListView.setGroupFilter(groupFilter); return; } - Object chipTag = group1.getTag(); - if (chipTag == GroupPlaceholderType.NO_GROUP) { - groupFilter.add(null); - } else { - groupFilter = getGroupFilter(chipGroup); - } - - _groupFilter = groupFilter; - _entryListView.setGroupFilter(groupFilter); + _groupFilter = getGroupFilter(chipGroup); + _entryListView.setGroupFilter(_groupFilter); }); chipGroup.addView(chip); @@ -368,8 +364,10 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene private static Set getGroupFilter(ChipGroup chipGroup) { return chipGroup.getCheckedChipIds().stream() + .filter(Objects::nonNull) .map(i -> { Chip chip = chipGroup.findViewById(i); + if (chip.getTag() instanceof VaultGroupModel) { VaultGroupModel group = (VaultGroupModel) chip.getTag(); return group.getUUID(); @@ -377,7 +375,6 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene return null; }) - .filter(Objects::nonNull) .collect(Collectors.toSet()); } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 7a288e1e..b2ca2d00 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -39,8 +39,7 @@ android:id="@+id/groupChipGroup" android:layout_width="match_parent" android:layout_height="wrap_content" - app:selectionRequired="true" - app:singleSelection="true"/> + app:selectionRequired="true"/> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2725c77f..b2ec52ff 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -373,6 +373,8 @@ Highlight tokens when tapped Make tokens easier to distinguish from each other by temporarily highlighting them when tapped + Multiselect groups + Allow the selection of multiple groups at the same time Minimize on copy Minimize the app after copying a token Copy tokens to the clipboard diff --git a/app/src/main/res/xml/preferences_behavior.xml b/app/src/main/res/xml/preferences_behavior.xml index ac2fa0d2..46f636f4 100644 --- a/app/src/main/res/xml/preferences_behavior.xml +++ b/app/src/main/res/xml/preferences_behavior.xml @@ -26,6 +26,13 @@ android:title="@string/pref_copy_behavior_title" app:iconSpaceReserved="false"/> + + Date: Mon, 24 Feb 2025 13:41:42 +0100 Subject: [PATCH 095/113] Update divider decoration when filter/sort changes This fixes an issue where the item decoration may be wrong in some cases. For example, adding a new entry to the bottom of the list may not update the decoration of the item that was previously the last one in the list. To reproduce, use this vault: https://alexbakker.me/u/mov4455gp5.json. Start without a group filter, apply sorting based on Issuer (A to Z) and enable group multiselect. Then: - Tap the "Test" chip - Tap the "Test2" chip - Tap the "No group" chip - Notice that the offset between the last 2 entries looks wrong: https://alexbakker.me/u/nedcyiro2q.png Probably introduced in 9131cae944f354c95873aa1c257e87b0c9b1f210. --- .../main/java/com/beemdevelopment/aegis/ui/MainActivity.java | 2 +- .../com/beemdevelopment/aegis/ui/views/EntryListView.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) 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 0a06c0e8..f1b27f21 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -220,8 +220,8 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene _entryListView.setPauseFocused(_prefs.isPauseFocusedEnabled()); _entryListView.setTapToReveal(_prefs.isTapToRevealEnabled()); _entryListView.setTapToRevealTime(_prefs.getTapToRevealTime()); - _entryListView.setSortCategory(_prefs.getCurrentSortCategory(), false); _entryListView.setViewMode(_prefs.getCurrentViewMode()); + _entryListView.setSortCategory(_prefs.getCurrentSortCategory(), false); _entryListView.setCopyBehavior(_prefs.getCopyBehavior()); _entryListView.setSearchBehaviorMask(_prefs.getSearchBehaviorMask()); _prefGroupFilter = _prefs.getGroupFilter(); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java index 3d359290..ff6ff97a 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java @@ -200,6 +200,7 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { _adapter.setGroupFilter(groups); _touchCallback.setIsLongPressDragEnabled(_adapter.isDragAndDropAllowed()); updateEmptyState(); + updateDividerDecoration(); } public void setIsLongPressDragEnabled(boolean enabled) { @@ -232,6 +233,7 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { public void setSortCategory(SortCategory sortCategory, boolean apply) { _adapter.setSortCategory(sortCategory, apply); _touchCallback.setIsLongPressDragEnabled(_adapter.isDragAndDropAllowed()); + updateDividerDecoration(); } public void setUsageCounts(Map usageCounts) { @@ -253,8 +255,8 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { public void setSearchFilter(String search) { _adapter.setSearchFilter(search); _touchCallback.setIsLongPressDragEnabled(_adapter.isDragAndDropAllowed()); - updateEmptyState(); + updateDividerDecoration(); } public void setSelectedEntry(VaultEntry entry) { From fbfdd50069db6ec720b3a3d20bb1eced9dd3b6dd Mon Sep 17 00:00:00 2001 From: jahway603 Date: Tue, 15 Apr 2025 18:54:46 -0400 Subject: [PATCH 096/113] [FAQ] clarified about which password to use when importing your vault to resolve Issue #1636 --- FAQ.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/FAQ.md b/FAQ.md index 815490aa..6d514574 100644 --- a/FAQ.md +++ b/FAQ.md @@ -86,6 +86,14 @@ Another common setup is to configure Aegis to back up to a folder on local storage of your device and then have a separate app (like [Syncthing](https://syncthing.net/)) sync that folder anywhere you want. +## Encrypted Backups + +### Why do I not get prompted to enter an encryption password when exporting? + +Aegis uses the same password you have configured to encrypt your vault as the +password which is used when exporting and importing your vault; so when prompted, +you will enter that when importing your vault. + ## Importing ### When importing from Authenticator Plus, an error is shown claiming that Accounts.txt is missing From c81e08bf1feb72e48f105abdca56c9f24ae5caa4 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Wed, 23 Apr 2025 15:51:49 +0200 Subject: [PATCH 097/113] Fall back to default values in the FreeOTP importer --- .../aegis/importers/FreeOtpImporter.java | 6 +++--- .../aegis/importers/DatabaseImporterTest.java | 9 +++++++++ .../aegis/importers/freeotp_v2_null_algo.xml | Bin 0 -> 1066 bytes 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 app/src/test/resources/com/beemdevelopment/aegis/importers/freeotp_v2_null_algo.xml diff --git a/app/src/main/java/com/beemdevelopment/aegis/importers/FreeOtpImporter.java b/app/src/main/java/com/beemdevelopment/aegis/importers/FreeOtpImporter.java index 8b96299b..0266ca95 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/importers/FreeOtpImporter.java +++ b/app/src/main/java/com/beemdevelopment/aegis/importers/FreeOtpImporter.java @@ -298,8 +298,8 @@ public class FreeOtpImporter extends DatabaseImporter { private static VaultEntry convertEntry(JSONObject obj) throws DatabaseImporterEntryException { try { String type = obj.getString("type").toLowerCase(Locale.ROOT); - String algo = obj.getString("algo"); - int digits = obj.getInt("digits"); + String algo = obj.optString("algo", OtpInfo.DEFAULT_ALGORITHM); + int digits = obj.optInt("digits", OtpInfo.DEFAULT_DIGITS); byte[] secret = toBytes(obj.getJSONArray("secret")); String issuer = obj.getString("issuerExt"); @@ -308,7 +308,7 @@ public class FreeOtpImporter extends DatabaseImporter { OtpInfo info; switch (type) { case "totp": - int period = obj.getInt("period"); + int period = obj.optInt("period", TotpInfo.DEFAULT_PERIOD); if (issuer.equals("Steam")) { info = new SteamInfo(secret, algo, digits, period); } else { diff --git a/app/src/test/java/com/beemdevelopment/aegis/importers/DatabaseImporterTest.java b/app/src/test/java/com/beemdevelopment/aegis/importers/DatabaseImporterTest.java index 4742eabd..1457d118 100644 --- a/app/src/test/java/com/beemdevelopment/aegis/importers/DatabaseImporterTest.java +++ b/app/src/test/java/com/beemdevelopment/aegis/importers/DatabaseImporterTest.java @@ -257,6 +257,15 @@ public class DatabaseImporterTest { checkImportedEntries(entries); } + @Test + public void testImportFreeOtpV2NullAlgo() throws IOException, DatabaseImporterException, OtpInfoException { + List entries = importEncrypted(FreeOtpImporter.class, "freeotp_v2_null_algo.xml", encryptedState -> { + final char[] password = "test".toCharArray(); + return ((FreeOtpImporter.EncryptedState) encryptedState).decrypt(password); + }); + checkImportedEntries(entries); + } + @Test public void testImportFreeOtpPlus() throws IOException, DatabaseImporterException, OtpInfoException { List entries = importPlain(FreeOtpPlusImporter.class, "freeotp_plus.json"); diff --git a/app/src/test/resources/com/beemdevelopment/aegis/importers/freeotp_v2_null_algo.xml b/app/src/test/resources/com/beemdevelopment/aegis/importers/freeotp_v2_null_algo.xml new file mode 100644 index 0000000000000000000000000000000000000000..dc890c5c66d0c0ba93b80a9e815c512863d94c7c GIT binary patch literal 1066 zcma)*O>Wab7=}%&Qp%1E2N+nPnbu>EJ$5#wv?;BsLZoJgD=~?kCe%NXJ*A1F+=xpc zPQaEsa0lMc4ivE>QsVLVKi~7_%TH&gshww^%xANIXJ`5TnQ5k%X1=rglAJzo&j^%W=ad>gFG7OLg@+`H zi}Ca$O7eLKdyF83cVF|6`|dRjGBC9%GMm*64FWGJQCYM_M(88DZ5wi>VQ$YH<4Wmr z^yn;}&tc&*Y)cNS+pKJ_e^!|B)!C6u*qW`a^Xh+=DJ-R1r@vyern$@N{=#ChCs|oB zzA>Gbf0=SK%5p?pnx-ldVwdv_ufzAl0X5w#OoQuPWJ|lXyJE#repA&mJ1r11cyn=b z>fPgQGie|_R4Dr8xL(d}mLiMwkklbX27nUJ2b>h%c?l-51R9Mc2O*CL8nM8tuzH}< zn_c>_Mnnsg@QlbzXNA23eS4Ok=A;Qi4`LFE09X(K%E;q@E3x;OvIsu12s7vb1$+90ZI iq*GjpMuIj28V}b~vfG>+bM3Y?utYe(L`Z$TUi<>?SPG*6 literal 0 HcmV?d00001 From afa1fbd3ae8ef36b266a4032be1c75abac0ffcb8 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Wed, 23 Apr 2025 16:20:34 +0200 Subject: [PATCH 098/113] Specify country code for the Portuguese translation --- app/src/main/res/values/arrays.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 17ac962e..bf4c1c64 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -100,7 +100,7 @@ lt fa pl - pt + pt_PT pt_BR ro ru From 03c00d51ba1f7f4dbea151bda33c96253489ccfd Mon Sep 17 00:00:00 2001 From: mimi89999 Date: Wed, 19 Mar 2025 09:43:56 +0100 Subject: [PATCH 099/113] Add Crowdin config file and update crowdin-cli Co-authored-by: Alexander Bakker --- .crowdin/config.example.yml | 10 ---------- .github/workflows/crowdin.yml | 14 ++++---------- crowdin.yml | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 20 deletions(-) delete mode 100644 .crowdin/config.example.yml create mode 100644 crowdin.yml diff --git a/.crowdin/config.example.yml b/.crowdin/config.example.yml deleted file mode 100644 index 4ef788a3..00000000 --- a/.crowdin/config.example.yml +++ /dev/null @@ -1,10 +0,0 @@ -project_id: "372633" -api_token: "" -base_path: "../app/src/main" -base_url: "https://api.crowdin.com" -preserve_hierarchy: true - -files: -- source: "res/values/strings.xml" - dest: "strings.xml" - translation: "res/values-%android_code%/%original_file_name%" diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml index e0fd559c..e7898362 100644 --- a/.github/workflows/crowdin.yml +++ b/.github/workflows/crowdin.yml @@ -13,19 +13,13 @@ jobs: - uses: actions/checkout@v4 - name: Install crowdin-cli run: | - wget https://github.com/crowdin/crowdin-cli/releases/download/3.7.2/crowdin-cli.zip - echo "ee9f838b819ccedc33c9b2537055e5ba7d7934561b24df1e1a6274cbd6e27f2d crowdin-cli.zip" | sha256sum -c + wget https://github.com/crowdin/crowdin-cli/releases/download/4.6.1/crowdin-cli.zip + echo "7afd70de3a747ac631a5bad7866008163ae1d50c4606b5773f0b90a5481ffde2 crowdin-cli.zip" | sha256sum -c unzip crowdin-cli.zip -d crowdin-cli - name: Upload to Crowdin env: - CROWDIN_TOKEN: "${{ secrets.CROWDIN_TOKEN }}" + CROWDIN_PERSONAL_TOKEN: "${{ secrets.CROWDIN_TOKEN }}" run: | - java -jar ./crowdin-cli/3.7.2/crowdin-cli.jar upload sources \ + java -jar ./crowdin-cli/4.6.1/crowdin-cli.jar upload sources \ --no-progress \ - --token "$CROWDIN_TOKEN" \ - --project-id 372633 \ - --base-path app/src/main \ - --source res/values/strings.xml \ - --translation "res/values-%android_code%/%original_file_name%" \ - --dest strings.xml \ --branch master diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 00000000..59912b50 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,14 @@ +project_id: "372633" +preserve_hierarchy: true +base_path: "app/src/main" +base_url: "https://api.crowdin.com" +api_token_env: "CROWDIN_PERSONAL_TOKEN" +files: + - type: "android" + source: "res/values/strings.xml" + dest: "strings.xml" + translation: "res/values-%android_code%/%original_file_name%" + - type: "android" + source: "res/values-v29/strings.xml" + dest: "strings-v29.xml" + translation: "res/values-%android_code%-v29/%original_file_name%" From 3818f9408d8ae1831cfee1a8bdd53c1572f1321a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Mon, 24 Feb 2025 19:39:41 +0100 Subject: [PATCH 100/113] Add brightness slider for transfer activity --- .../aegis/ui/TransferEntriesActivity.java | 31 ++++++++++++-- .../main/res/layout/activity_share_entry.xml | 42 ++++++++++++------- app/src/main/res/values/strings.xml | 1 + 3 files changed, 55 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/TransferEntriesActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/TransferEntriesActivity.java index a4deae57..a0559d7a 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/TransferEntriesActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/TransferEntriesActivity.java @@ -10,6 +10,7 @@ import android.graphics.Color; import android.os.Build; import android.os.Bundle; import android.os.PersistableBundle; +import android.provider.Settings; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; @@ -47,6 +48,8 @@ public class TransferEntriesActivity extends AegisActivity { private Button _previousButton; private Button _copyButton; private int _currentEntryCount = 1; + private float _deviceBrightness; + private boolean _isMaxBrightnessSet = false; @Override protected void onCreate(Bundle savedInstanceState) { @@ -146,13 +149,33 @@ public class TransferEntriesActivity extends AegisActivity { _qrImage.getViewTreeObserver().removeOnGlobalLayoutListener(this); } }); + + _deviceBrightness = getSystemBrightness(); + _qrImage.setOnClickListener(v -> { + if (!_isMaxBrightnessSet) { + setBrightness(1f); + _isMaxBrightnessSet = true; + } else { + setBrightness(_deviceBrightness); + _isMaxBrightnessSet = false; + } + }); } - @Override - public void onAttachedToWindow() { - // Max brightness to make the QR codes easier to scan + private float getSystemBrightness() { + int brightness = 0; + try { + brightness = Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS); + } catch (Settings.SettingNotFoundException e) { + e.printStackTrace(); + } + + return brightness / 255f; + } + + private void setBrightness(float brightnessAmount) { WindowManager.LayoutParams attrs = getWindow().getAttributes(); - attrs.screenBrightness = 1.0f; + attrs.screenBrightness = brightnessAmount; getWindow().setAttributes(attrs); } diff --git a/app/src/main/res/layout/activity_share_entry.xml b/app/src/main/res/layout/activity_share_entry.xml index 3050c056..455f3356 100644 --- a/app/src/main/res/layout/activity_share_entry.xml +++ b/app/src/main/res/layout/activity_share_entry.xml @@ -25,8 +25,8 @@ android:id="@+id/layoutShareEntry" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingHorizontal="30dp" - android:layout_marginTop="?attr/actionBarSize"> + android:layout_marginTop="?attr/actionBarSize" + android:paddingHorizontal="30dp"> + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.3" + app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Aegis.ImageView.Rounded" /> + app:layout_constraintTop_toBottomOf="@+id/ivQrCode" + tools:text="Issuer" /> + app:layout_constraintTop_toBottomOf="@+id/tvIssuer" + tools:text="Accountname" />