Compare commits
84 Commits
374-improv
...
v1.12-r9-b
Author | SHA1 | Date | |
---|---|---|---|
![]() |
da0513c768 | ||
![]() |
37f520cdbe | ||
![]() |
c98572bee0 | ||
![]() |
b1774ffc4b | ||
![]() |
57aaa0c4cd | ||
![]() |
b961ae1b33 | ||
![]() |
5e418e2b1b | ||
![]() |
6d22a213f3 | ||
![]() |
a76addc43f | ||
![]() |
1d96217713 | ||
![]() |
d2b8fdcfff | ||
![]() |
507b671448 | ||
![]() |
3118ffaeb5 | ||
![]() |
0abe29bd77 | ||
![]() |
f3a7831390 | ||
![]() |
37cd58f7ba | ||
![]() |
7dd80a8ef7 | ||
![]() |
c78636264b | ||
![]() |
035506a5a3 | ||
![]() |
4cf46ef062 | ||
![]() |
c7b8063171 | ||
![]() |
0a8b149c9a | ||
![]() |
9240a27791 | ||
![]() |
e90d5b903c | ||
![]() |
50b4a9f1b9 | ||
![]() |
9783c3b5fe | ||
![]() |
7a837e3237 | ||
![]() |
c8f6714373 | ||
![]() |
bc0313aa6a | ||
![]() |
0f98668bcd | ||
![]() |
8d1195ac96 | ||
![]() |
df731ac1b3 | ||
![]() |
bd784fa13d | ||
![]() |
a6bc5e657c | ||
![]() |
56c4cdb321 | ||
![]() |
42a4a83c7d | ||
![]() |
fe3933e154 | ||
![]() |
3efe130ee8 | ||
![]() |
5808857749 | ||
![]() |
a7397c3316 | ||
![]() |
d12f936898 | ||
![]() |
67f7d74bb9 | ||
![]() |
b0d0f06073 | ||
![]() |
67ee571c27 | ||
![]() |
a360695271 | ||
![]() |
149857a516 | ||
![]() |
fb8ffb802f | ||
![]() |
e957073457 | ||
![]() |
da86b0f50b | ||
![]() |
0aa78ffd66 | ||
![]() |
ce0087af99 | ||
![]() |
576bfeecfe | ||
![]() |
c0e2f34b79 | ||
![]() |
84d0c32610 | ||
![]() |
40184dbd55 | ||
![]() |
2d17bdde19 | ||
![]() |
e2babde1fa | ||
![]() |
e1f26fb045 | ||
![]() |
adbbfa0ac1 | ||
![]() |
37a013135e | ||
![]() |
acc6ea7f85 | ||
![]() |
62f012713a | ||
![]() |
0d726c1789 | ||
![]() |
f162e868b9 | ||
![]() |
0a1f95653f | ||
![]() |
27451825c6 | ||
![]() |
bdd6f1033e | ||
![]() |
c0413f9b74 | ||
![]() |
59d6fc8fdb | ||
![]() |
c500245647 | ||
![]() |
026a263f10 | ||
![]() |
839e6d3cb4 | ||
![]() |
735f4caf89 | ||
![]() |
11af71ef82 | ||
![]() |
e09577d17f | ||
![]() |
c1dbf171f5 | ||
![]() |
4ca4ec10be | ||
![]() |
77fded4964 | ||
![]() |
578491b1c7 | ||
![]() |
eee3ffd861 | ||
![]() |
89696d7f0d | ||
![]() |
a202c76bf0 | ||
![]() |
c9936ab76b | ||
![]() |
7ac6f7ed51 |
13
.github/workflows/build.yml
vendored
13
.github/workflows/build.yml
vendored
@@ -309,6 +309,14 @@ jobs:
|
||||
run: |
|
||||
make java
|
||||
|
||||
- name: Update dotnet workloads
|
||||
run: |
|
||||
dotnet workload update
|
||||
|
||||
- name: Select the manifest
|
||||
run: |
|
||||
make manifestlink Flavor=Net
|
||||
|
||||
- name: Install NuGet dependencies (net)
|
||||
run: make nuget Flavor=Net
|
||||
|
||||
@@ -327,12 +335,17 @@ jobs:
|
||||
path: |
|
||||
src/keepass2android/bin/*/*-Signed.apk
|
||||
|
||||
- name: Select the manifest
|
||||
run: |
|
||||
make manifestlink Flavor=NoNet
|
||||
|
||||
- name: Install NuGet dependencies (nonet)
|
||||
run: make nuget Flavor=NoNet
|
||||
|
||||
- name: Build keepass2android (nonet)
|
||||
run: |
|
||||
make msbuild Flavor=NoNet
|
||||
|
||||
- name: Test Autofill
|
||||
working-directory: ./src/Kp2aAutofillParser.Tests
|
||||
run: dotnet test
|
||||
|
122
.github/workflows/release.yml
vendored
Normal file
122
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
name: Create keepass2android release
|
||||
env:
|
||||
NAME: 'Release'
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v1.*"
|
||||
jobs:
|
||||
|
||||
build-release:
|
||||
|
||||
runs-on: windows-2022
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
flavor: [Net, NoNet]
|
||||
target: [apk, apk_split]
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Extract key store
|
||||
env:
|
||||
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
|
||||
KeyStore: "${{ github.workspace }}/kp2a.keystore"
|
||||
|
||||
shell: bash
|
||||
run: |
|
||||
echo $KeyStore
|
||||
echo $KEYSTORE_BASE64 | base64 --decode > $KeyStore
|
||||
|
||||
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
|
||||
- name: Cache NuGet packages
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.nuget/packages
|
||||
key: ${{ runner.os }}-nuget-${{ hashFiles('src/**/*.csproj', 'src/**/packages.config') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-nuget-
|
||||
|
||||
# Workaround an issue when building on windows-2022. Error was
|
||||
# D8 : OpenJDK 64-Bit Server VM warning : INFO: os::commit_memory(0x00000000ae400000, 330301440, 0) failed; error='The paging file is too small for this operation to complete' (DOS error/errno=1455) [D:\a\keepass2android\keepass2android\src\keepass2android\keepass2android-app.csproj]
|
||||
# C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Xamarin\Android\Xamarin.Android.D8.targets(81,5): error MSB6006: "java.exe" exited with code 1. [D:\a\keepass2android\keepass2android\src\keepass2android\keepass2android-app.csproj]
|
||||
- name: Configure Pagefile
|
||||
uses: al-cheb/configure-pagefile-action@a3b6ebd6b634da88790d9c58d4b37a7f4a7b8708 # v1.4
|
||||
with:
|
||||
minimum-size: 8GB
|
||||
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
# If we want to also have nmake, use this instead
|
||||
#uses: ilammy/msvc-dev-cmd@v1
|
||||
|
||||
- name: Switch to JDK-17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Display java version
|
||||
run: java -version
|
||||
|
||||
- name: Build native dependencies
|
||||
shell: cmd
|
||||
run: |
|
||||
make native
|
||||
|
||||
- name: Build java dependencies
|
||||
shell: cmd
|
||||
run: |
|
||||
make java
|
||||
|
||||
- name: Update dotnet workloads
|
||||
run: |
|
||||
dotnet workload update
|
||||
|
||||
- name: Select the manifest
|
||||
run: |
|
||||
make manifestlink Flavor=${{ matrix.flavor }}
|
||||
|
||||
- name: Install NuGet dependencies
|
||||
run: make nuget Flavor=${{ matrix.flavor }}
|
||||
|
||||
- name: Build APK (net)
|
||||
env:
|
||||
KeyStore: "${{ github.workspace }}/kp2a.keystore"
|
||||
MyAndroidSigningStorePass: ${{ secrets.KEY_STORE_PASSWORD }}
|
||||
MyAndroidSigningKeyPass: ${{ secrets.KEY_PASSWORD }}
|
||||
DropboxAppKey: ${{ secrets.DROPBOX_APP_KEY }}
|
||||
DropboxAppSecret: ${{ secrets.DROPBOX_APP_SECRET }}
|
||||
DropboxAppFolderAppKey: ${{ secrets.DROPBOX_APP_FOLDER_APP_KEY }}
|
||||
DropboxAppFolderAppSecret: ${{ secrets.DROPBOX_APP_FOLDER_APP_SECRET }}
|
||||
|
||||
run: |
|
||||
make ${{ matrix.target }} Configuration=Release Flavor=${{ matrix.flavor }}
|
||||
|
||||
- name: List files
|
||||
shell: bash
|
||||
run: |
|
||||
ls src/keepass2android-app/bin/**/*.*
|
||||
|
||||
- name: Archive production artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: signed APK (built on ${{ github.job }})
|
||||
path: |
|
||||
src/keepass2android-app/bin/Release/**/*.apk
|
||||
|
||||
#- name: Upload APK to GitHub Release
|
||||
# uses: softprops/action-gh-release@v2
|
||||
# if: github.ref_type == 'tag'
|
||||
# with:
|
||||
# files: |
|
||||
# src/keepass2android-app/bin/Release/net8.0-android/*/publish/*.apk src/keepass2android-app/bin/Release/net8.0-android/publish/*.apk
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -64,7 +64,7 @@ Thumbs.db
|
||||
/src/java/android-filechooser/code/projectzip/project.zip
|
||||
/src/java/android-filechooser/code/unused.txt
|
||||
|
||||
/src/Kp2aBusinessLogic/Io/DropboxFileStorageKeys.cs
|
||||
/src/Kp2aBusinessLogic/Io/DropboxFileStorage.g.cs
|
||||
|
||||
/src/java/workspace/DriveTest
|
||||
|
||||
|
23
Makefile
23
Makefile
@@ -62,11 +62,11 @@ $(info )
|
||||
|
||||
# On linux use xabuild, on Windows use MSBuild.exe, otherwise (macos?) use msbuild.
|
||||
ifeq ($(detected_OS),Linux)
|
||||
MSBUILD_binary := xabuild
|
||||
MSBUILD := $(shell $(WHICH) $(MSBUILD_binary))
|
||||
MSBUILD_binary := dotnet
|
||||
MSBUILD := $(shell $(WHICH) $(MSBUILD_binary)) publish
|
||||
else ifeq ($(detected_OS),Windows)
|
||||
MSBUILD_binary := MSBuild.exe
|
||||
MSBUILD := $(shell $(WHICH) $(MSBUILD_binary) 2> nul)
|
||||
MSBUILD_binary := dotnet
|
||||
MSBUILD := $(shell $(WHICH) $(MSBUILD_binary) 2> nul) publish
|
||||
ifeq ($(MSBUILD),)
|
||||
# Additional heuristic to find MSBUILD_BINARY on Windows
|
||||
VSWHERE := "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
|
||||
@@ -312,19 +312,20 @@ manifestlink:
|
||||
$(CREATE_MANIFEST_LINK)
|
||||
|
||||
#####
|
||||
src/Kp2aBusinessLogic/Io/DropboxFileStorageKeys.cs:
|
||||
ifeq ($(detected_OS),Windows)
|
||||
$(CP) src\Kp2aBusinessLogic\Io\DropboxFileStorageKeysDummy.cs src\Kp2aBusinessLogic\Io\DropboxFileStorageKeys.cs
|
||||
else
|
||||
$(CP) src/Kp2aBusinessLogic/Io/DropboxFileStorageKeysDummy.cs $@
|
||||
endif
|
||||
|
||||
msbuild: manifestlink native java nuget src/Kp2aBusinessLogic/Io/DropboxFileStorageKeys.cs
|
||||
msbuild: manifestlink native java nuget
|
||||
$(MSBUILD) src/KeePass.sln -target:keepass2android-app -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -p:BuildProjectReferences=true $(MSBUILD_PARAM) -p:Platform="Any CPU" -m
|
||||
|
||||
apk: msbuild
|
||||
$(MSBUILD) src/keepass2android-app/keepass2android-app.csproj -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -t:SignAndroidPackage $(MSBUILD_PARAM) -p:Platform=AnyCPU -m
|
||||
|
||||
apk_split: msbuild
|
||||
$(MSBUILD) src/keepass2android-app/keepass2android-app.csproj -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -t:SignAndroidPackage $(MSBUILD_PARAM) -p:Platform=AnyCPU -m -p:RuntimeIdentifier=android-arm
|
||||
$(MSBUILD) src/keepass2android-app/keepass2android-app.csproj -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -t:SignAndroidPackage $(MSBUILD_PARAM) -p:Platform=AnyCPU -m -p:RuntimeIdentifier=android-arm64
|
||||
$(MSBUILD) src/keepass2android-app/keepass2android-app.csproj -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -t:SignAndroidPackage $(MSBUILD_PARAM) -p:Platform=AnyCPU -m -p:RuntimeIdentifier=android-x86
|
||||
$(MSBUILD) src/keepass2android-app/keepass2android-app.csproj -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -t:SignAndroidPackage $(MSBUILD_PARAM) -p:Platform=AnyCPU -m -p:RuntimeIdentifier=android-x64
|
||||
src/build-scripts/rename-output-apks.sh src/keepass2android-app/bin/Release/net8.0-android/
|
||||
|
||||
build_all: msbuild
|
||||
|
||||
##### Cleanup targets
|
||||
|
@@ -86,17 +86,12 @@ namespace KeePassLib.Interfaces
|
||||
/// the current work.</returns>
|
||||
bool SetText(string strNewText, LogStatusType lsType);
|
||||
|
||||
void UpdateMessage(String message);
|
||||
|
||||
|
||||
void UpdateSubMessage(String submessage);
|
||||
|
||||
/// <summary>
|
||||
/// Check if the user cancelled the current work.
|
||||
/// </summary>
|
||||
/// <returns>Returns <c>true</c> if the caller should continue
|
||||
/// the current work.</returns>
|
||||
bool ContinueWork();
|
||||
/// <summary>
|
||||
/// Check if the user cancelled the current work.
|
||||
/// </summary>
|
||||
/// <returns>Returns <c>true</c> if the caller should continue
|
||||
/// the current work.</returns>
|
||||
bool ContinueWork();
|
||||
}
|
||||
|
||||
public sealed class NullStatusLogger : IStatusLogger
|
||||
@@ -105,12 +100,6 @@ namespace KeePassLib.Interfaces
|
||||
public void EndLogging() { }
|
||||
public bool SetProgress(uint uPercent) { return true; }
|
||||
public bool SetText(string strNewText, LogStatusType lsType) { return true; }
|
||||
public void UpdateMessage(string message){
|
||||
}
|
||||
|
||||
public void UpdateSubMessage(string submessage){
|
||||
}
|
||||
|
||||
public bool ContinueWork() { return true; }
|
||||
public bool ContinueWork() { return true; }
|
||||
}
|
||||
}
|
||||
|
@@ -21,7 +21,6 @@ using System.IO;
|
||||
using Android;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Preferences;
|
||||
using KeePassLib.Serialization;
|
||||
|
||||
@@ -35,17 +34,9 @@ namespace keepass2android
|
||||
|
||||
public static void Log(string message)
|
||||
{
|
||||
if (message != null)
|
||||
{
|
||||
message += Thread.CurrentThread.ManagedThreadId != 0
|
||||
? " (Thread ID: " + Thread.CurrentThread.ManagedThreadId + ")"
|
||||
: "";
|
||||
if (Looper.MainLooper == Looper.MyLooper())
|
||||
message += " (Main Looper)";
|
||||
Android.Util.Log.Debug("KP2A", message);
|
||||
}
|
||||
|
||||
if (LogToFile)
|
||||
if (message != null)
|
||||
Android.Util.Log.Debug("KP2A", message);
|
||||
if (LogToFile)
|
||||
{
|
||||
lock (_fileLocker)
|
||||
{
|
||||
@@ -125,12 +116,23 @@ namespace keepass2android
|
||||
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.SetAction(Intent.ActionSend);
|
||||
sendIntent.PutExtra(Intent.ExtraText, File.ReadAllText(LogFilename));
|
||||
string logText = File.ReadAllText(LogFilename);
|
||||
|
||||
sendIntent.PutExtra(Intent.ExtraText, logText);
|
||||
sendIntent.PutExtra(Intent.ExtraEmail, "crocoapps@gmail.com");
|
||||
sendIntent.PutExtra(Intent.ExtraSubject, "Keepass2Android log");
|
||||
sendIntent.SetType("text/plain");
|
||||
ctx.StartActivity(Intent.CreateChooser(sendIntent, "Send log to..."));
|
||||
}
|
||||
try
|
||||
{
|
||||
ctx.StartActivity(Intent.CreateChooser(sendIntent, "Send log to..."));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Toast.MakeText(ctx, $"Error sending log of length {logText.Length} bytes: " + e.Message, ToastLength.Long)?.Show();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void LogTask(object task, string activityName)
|
||||
{
|
||||
|
@@ -208,7 +208,7 @@ namespace KeePassLib.Serialization
|
||||
if (!string.IsNullOrEmpty(strHash) && (m_pbHashOfHeader != null) &&
|
||||
!m_bRepairMode)
|
||||
{
|
||||
// Debug.Assert(m_uFileVersion < FileVersion32_4);
|
||||
Debug.Assert(m_uFileVersion < FileVersion32_4);
|
||||
|
||||
byte[] pbHash = Convert.FromBase64String(strHash);
|
||||
if (!MemUtil.ArraysEqual(pbHash, m_pbHashOfHeader))
|
||||
|
@@ -83,6 +83,7 @@ namespace KeePassLib.Serialization
|
||||
if (m_bUsedOnce)
|
||||
throw new InvalidOperationException("Do not reuse KdbxFile objects!");
|
||||
m_bUsedOnce = true;
|
||||
Kp2aLog.Log("Starting to load KDBX file...");
|
||||
|
||||
#if KDBX_BENCHMARK
|
||||
Stopwatch swTime = Stopwatch.StartNew();
|
||||
@@ -257,7 +258,8 @@ namespace KeePassLib.Serialization
|
||||
MessageService.ShowInfo("Loading KDBX took " +
|
||||
swTime.ElapsedMilliseconds.ToString() + " ms.");
|
||||
#endif
|
||||
}
|
||||
Kp2aLog.Log("Finished loading KDBX file.");
|
||||
}
|
||||
|
||||
private void CommonCleanUpRead(List<Stream> lStreams, HashingStreamEx sHashing)
|
||||
{
|
||||
@@ -488,7 +490,7 @@ namespace KeePassLib.Serialization
|
||||
|
||||
ProtectedBinary pb = new ProtectedBinary(bProt, pbData,
|
||||
1, pbData.Length - 1);
|
||||
//Debug.Assert(m_pbsBinaries.Find(pb) < 0); // No deduplication?
|
||||
Debug.Assert(m_pbsBinaries.Find(pb) < 0); // No deduplication?
|
||||
m_pbsBinaries.Add(pb);
|
||||
|
||||
if (bProt) MemUtil.ZeroByteArray(pbData);
|
||||
|
@@ -95,7 +95,7 @@ namespace Kp2aAutofillParserTest
|
||||
StructureParserBase<TestInputField> parser =
|
||||
new StructureParserBase<TestInputField>(new TestLogger(), new TestDalSourceTrustAll());
|
||||
|
||||
var result = parser.ParseForFill(false, autofillView);
|
||||
var result = parser.ParseForFill(autofillView);
|
||||
if (expectedPackageName != null)
|
||||
Assert.Equal(expectedPackageName, result.PackageName);
|
||||
if (expectedWebDomain != null)
|
||||
|
@@ -58,7 +58,8 @@
|
||||
"IsFocused": false,
|
||||
"InputType": 97,
|
||||
"HtmlInfoTag": null,
|
||||
"HtmlInfoTypeAttribute": null
|
||||
"HtmlInfoTypeAttribute": null,
|
||||
"ExpectedAssignedHints": [ "username" ]
|
||||
},
|
||||
{
|
||||
"IdEntry": "password_text_input_layout",
|
||||
@@ -81,6 +82,7 @@
|
||||
"InputType": 129,
|
||||
"HtmlInfoTag": null,
|
||||
"HtmlInfoTypeAttribute": null,
|
||||
"ExpectedAssignedHints": [ "password" ]
|
||||
|
||||
},
|
||||
{
|
||||
|
@@ -476,8 +476,16 @@ namespace Kp2aAutofillParser
|
||||
|
||||
foreach (var field in autofillFields.HintMap.Values.Distinct())
|
||||
{
|
||||
if (field == null || field.AutofillHints == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach (var hint in field.AutofillHints)
|
||||
{
|
||||
if (hint == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (GetPartitionIndex(hint) == partitionIndex)
|
||||
{
|
||||
filteredCollection.Add(field);
|
||||
@@ -793,14 +801,14 @@ namespace Kp2aAutofillParser
|
||||
}
|
||||
}
|
||||
|
||||
public AutofillTargetId ParseForFill(bool isManual, AutofillView<FieldT> autofillView)
|
||||
public AutofillTargetId ParseForFill(AutofillView<FieldT> autofillView)
|
||||
{
|
||||
return Parse(true, isManual, autofillView);
|
||||
return Parse(true, autofillView);
|
||||
}
|
||||
|
||||
public AutofillTargetId ParseForSave(AutofillView<FieldT> autofillView)
|
||||
{
|
||||
return Parse(false, true, autofillView);
|
||||
return Parse(false, autofillView);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -808,8 +816,7 @@ namespace Kp2aAutofillParser
|
||||
/// </summary>
|
||||
/// <returns>The parse.</returns>
|
||||
/// <param name="forFill">If set to <c>true</c> for fill.</param>
|
||||
/// <param name="isManualRequest"></param>
|
||||
protected virtual AutofillTargetId Parse(bool forFill, bool isManualRequest, AutofillView<FieldT> autofillView)
|
||||
protected virtual AutofillTargetId Parse(bool forFill, AutofillView<FieldT> autofillView)
|
||||
{
|
||||
AutofillTargetId result = new AutofillTargetId()
|
||||
{
|
||||
@@ -876,8 +883,9 @@ namespace Kp2aAutofillParser
|
||||
|
||||
}
|
||||
|
||||
//for "heuristic determination" we demand that one of the filled fields is focused:
|
||||
if (passwordFields.Concat(usernameFields).Any(f => f.IsFocused))
|
||||
//for "heuristic determination" we demand that there is a password field or one of the username fields is focused:
|
||||
//Note that "IsFocused" might be false even when tapping the field. It might require long-press to autofill.
|
||||
if (passwordFields.Any() || usernameFields.Any(f => f.IsFocused))
|
||||
{
|
||||
foreach (var uf in usernameFields)
|
||||
AddFieldToHintMap(uf, new string[] { AutofillHintsHelper.AutofillHintUsername });
|
||||
|
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
|
||||
|
||||
Keepass2Android is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Keepass2Android 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Java.Lang;
|
||||
using Java.Security;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to run a task while a progress dialog is shown
|
||||
/// </summary>
|
||||
public class BlockingOperationStarter
|
||||
{
|
||||
|
||||
private readonly OperationWithFinishHandler _task;
|
||||
private readonly IKp2aApp _app;
|
||||
|
||||
public BlockingOperationStarter(IKp2aApp app, OperationWithFinishHandler task)
|
||||
{
|
||||
_task = task;
|
||||
_app = app;
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
_app.CancelBackgroundOperations();
|
||||
OperationRunner.Instance.Run(_app, _task, true);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -41,7 +41,7 @@ namespace keepass2android
|
||||
/// Interface through which Activities and the logic layer can access some app specific functionalities and Application static data
|
||||
/// </summary>
|
||||
/// This also contains methods which are UI specific and should be replacable for testing.
|
||||
public interface IKp2aApp : ICertificateValidationHandler, IActiveContextProvider
|
||||
public interface IKp2aApp : ICertificateValidationHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Locks all currently open databases, quicklocking if available (unless false is passed for allowQuickUnlock)
|
||||
@@ -52,9 +52,7 @@ namespace keepass2android
|
||||
/// <summary>
|
||||
/// Loads the specified data as the currently open database, as unlocked.
|
||||
/// </summary>
|
||||
Database LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compKey,
|
||||
IKp2aStatusLogger statusLogger, IDatabaseFormat databaseFormat, bool makeCurrent,
|
||||
IDatabaseModificationWatcher modificationWatcher);
|
||||
Database LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compKey, ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat, bool makeCurrent);
|
||||
|
||||
|
||||
HashSet<PwGroup> DirtyGroups { get; }
|
||||
@@ -98,6 +96,7 @@ namespace keepass2android
|
||||
EventHandler<DialogClickEventArgs> yesHandler,
|
||||
EventHandler<DialogClickEventArgs> noHandler,
|
||||
EventHandler<DialogClickEventArgs> cancelHandler,
|
||||
Context ctx,
|
||||
string messageSuffix = "");
|
||||
|
||||
/// <summary>
|
||||
@@ -108,6 +107,7 @@ namespace keepass2android
|
||||
EventHandler<DialogClickEventArgs> yesHandler,
|
||||
EventHandler<DialogClickEventArgs> noHandler,
|
||||
EventHandler<DialogClickEventArgs> cancelHandler,
|
||||
Context ctx,
|
||||
string messageSuffix = "");
|
||||
|
||||
void ShowMessage(Context ctx, int resourceId, MessageSeverity severity);
|
||||
@@ -136,17 +136,10 @@ namespace keepass2android
|
||||
bool CheckForDuplicateUuids { get; }
|
||||
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE
|
||||
ICertificateErrorHandler CertificateErrorHandler { get; }
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
bool SyncInBackgroundPreference { get; set; }
|
||||
void StartBackgroundSyncService();
|
||||
|
||||
ReaderWriterLockSlim DatabasesBackgroundModificationLock { get; }
|
||||
bool CancelBackgroundOperations();
|
||||
|
||||
/// <summary>
|
||||
/// Registers an action that should be executed when the context instance with the given id has been resumed.
|
||||
/// </summary>
|
||||
void RegisterPendingActionForContextInstance(int contextInstanceId, ActionOnOperationFinished actionToPerformWhenContextIsResumed);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -186,11 +186,8 @@ namespace keepass2android.Io
|
||||
Kp2aLog.Log("couldn't open from remote " + ioc.Path);
|
||||
#endif
|
||||
Kp2aLog.Log(ex.ToString());
|
||||
if (TriggerWarningWhenFallingBackToCache)
|
||||
{
|
||||
_cacheSupervisor.CouldntOpenFromRemote(ioc, ex);
|
||||
}
|
||||
|
||||
|
||||
_cacheSupervisor.CouldntOpenFromRemote(ioc, ex);
|
||||
return File.OpenRead(cachedFilePath);
|
||||
}
|
||||
}
|
||||
@@ -330,10 +327,7 @@ namespace keepass2android.Io
|
||||
Kp2aLog.Log("couldn't save to remote " + ioc.Path);
|
||||
Kp2aLog.Log(e.ToString());
|
||||
//notify the supervisor so it might display a warning or schedule a retry
|
||||
if (TriggerWarningWhenFallingBackToCache)
|
||||
{
|
||||
_cacheSupervisor.CouldntSaveToRemote(ioc, e); }
|
||||
|
||||
_cacheSupervisor.CouldntSaveToRemote(ioc, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -638,9 +632,7 @@ namespace keepass2android.Io
|
||||
set { _cachedStorage.IsOffline = value; }
|
||||
}
|
||||
|
||||
public bool TriggerWarningWhenFallingBackToCache { get; set; }
|
||||
|
||||
public void OnRequestPermissionsResult(IFileStorageSetupActivity fileStorageSetupActivity, int requestCode,
|
||||
public void OnRequestPermissionsResult(IFileStorageSetupActivity fileStorageSetupActivity, int requestCode,
|
||||
string[] permissions, Permission[] grantResults)
|
||||
{
|
||||
_cachedStorage.OnRequestPermissionsResult(fileStorageSetupActivity, requestCode, permissions, grantResults);
|
||||
|
@@ -1,13 +0,0 @@
|
||||
namespace keepass2android.Io
|
||||
{
|
||||
public partial class DropboxFileStorage
|
||||
{
|
||||
private const string AppKey = "dummy";
|
||||
private const string AppSecret = "dummy";
|
||||
}
|
||||
public partial class DropboxAppFolderFileStorage
|
||||
{
|
||||
private const string AppKey = "dummy";
|
||||
private const string AppSecret = "dummy";
|
||||
}
|
||||
}
|
27
src/Kp2aBusinessLogic/Io/GenerateSecrets.targets
Normal file
27
src/Kp2aBusinessLogic/Io/GenerateSecrets.targets
Normal file
@@ -0,0 +1,27 @@
|
||||
<Project>
|
||||
<Target Name="GenerateDropboxSecrets" BeforeTargets="BeforeCompile"
|
||||
Inputs="@(DropboxSecretLines)"
|
||||
Outputs="DropboxFileStorage.g.cs">
|
||||
|
||||
<WriteLinesToFile
|
||||
File="Io/DropboxFileStorage.g.cs"
|
||||
Lines="@(DropboxSecretLines->'%(Text)')"
|
||||
Overwrite="true"
|
||||
/>
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<DropboxSecretLines Include="GeneratedDropboxSecrets">
|
||||
<Text>namespace keepass2android.Io {
|
||||
public partial class DropboxFileStorage {
|
||||
private const string AppKey = "$(DropboxAppKey)";
|
||||
private const string AppSecret = "$(DropboxAppSecret)";
|
||||
}
|
||||
public partial class DropboxAppFolderFileStorage {
|
||||
private const string AppKey = "$(DropboxAppFolderAppKey)";
|
||||
private const string AppSecret = "$(DropboxAppFolderAppSecret)";
|
||||
}
|
||||
}</Text>
|
||||
</DropboxSecretLines>
|
||||
</ItemGroup>
|
||||
</Project>
|
@@ -111,11 +111,6 @@ namespace keepass2android.Io
|
||||
}
|
||||
|
||||
Java.Lang.Exception exception = e as Java.Lang.Exception;
|
||||
|
||||
if ((exception is Java.Lang.InterruptedException) || (exception is Java.IO.InterruptedIOException))
|
||||
{
|
||||
throw new Java.Lang.InterruptedException(exception.Message);
|
||||
}
|
||||
if (exception != null)
|
||||
{
|
||||
var ex = new Exception(exception.LocalizedMessage ??
|
||||
|
@@ -11,8 +11,7 @@ namespace keepass2android.Io
|
||||
public interface IOfflineSwitchable
|
||||
{
|
||||
bool IsOffline { get; set; }
|
||||
bool TriggerWarningWhenFallingBackToCache { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encapsulates another IFileStorage. Allows to switch to offline mode by throwing
|
||||
@@ -22,9 +21,8 @@ namespace keepass2android.Io
|
||||
{
|
||||
private readonly IFileStorage _baseStorage;
|
||||
public bool IsOffline { get; set; }
|
||||
public bool TriggerWarningWhenFallingBackToCache { get; set; }
|
||||
|
||||
public OfflineSwitchableFileStorage(IFileStorage baseStorage)
|
||||
public OfflineSwitchableFileStorage(IFileStorage baseStorage)
|
||||
{
|
||||
_baseStorage = baseStorage;
|
||||
}
|
||||
|
@@ -4,30 +4,43 @@
|
||||
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<DefineConstants Condition="'$(Flavor)'=='NoNet'">NO_QR_SCANNER;EXCLUDE_JAVAFILESTORAGE;NoNet</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentFTP" Version="51.1.0" />
|
||||
<PackageReference Include="MegaApiClient" Version="1.10.4" />
|
||||
<PackageReference Include="Microsoft.Graph" Version="5.68.0" />
|
||||
<PackageReference Include="Microsoft.Identity.Client" Version="4.67.1" />
|
||||
<PackageReference Include="FluentFTP" Version="51.1.0" Condition="'$(Flavor)'!='NoNet'"/>
|
||||
<PackageReference Include="MegaApiClient" Version="1.10.4" Condition="'$(Flavor)'!='NoNet'"/>
|
||||
<PackageReference Include="Microsoft.Graph" Version="5.68.0" Condition="'$(Flavor)'!='NoNet'"/>
|
||||
<PackageReference Include="Microsoft.Identity.Client" Version="4.67.1" Condition="'$(Flavor)'!='NoNet'"/>
|
||||
<PackageReference Include="Xamarin.AndroidX.Browser" Version="1.8.0" />
|
||||
<PackageReference Include="Xamarin.AndroidX.Core" Version="1.13.1.5" />
|
||||
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.11.0.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AndroidFileChooserBinding\AndroidFileChooserBinding.csproj" />
|
||||
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj" />
|
||||
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj" Condition="'$(Flavor)'!='NoNet'" />
|
||||
<ProjectReference Include="..\KeePassLib2Android\KeePassLib2Android.csproj" />
|
||||
<ProjectReference Include="..\KP2AKdbLibraryBinding\KP2AKdbLibraryBinding.csproj" />
|
||||
<ProjectReference Include="..\TwofishCipher\TwofishCipher.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Io/DropboxFileStorageKeysDummy.cs" />
|
||||
<Compile Remove="Io/DropboxFileStorageKeysDummy.cs" />
|
||||
<Content Remove="Io/DropboxFileStorageKeysDummy.cs" />
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(Flavor)'=='NoNet'">
|
||||
<None Remove="Io/OneDrive2FileStorage.cs" />
|
||||
<Compile Remove="Io/OneDrive2FileStorage.cs" />
|
||||
<Content Remove="Io/OneDrive2FileStorage.cs" />
|
||||
<None Remove="Io/MegaFileStorage.cs" />
|
||||
<Compile Remove="Io/MegaFileStorage.cs" />
|
||||
<Content Remove="Io/MegaFileStorage.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="Io/GenerateSecrets.targets" />
|
||||
<ItemGroup>
|
||||
<Compile Include="Io/DropboxFileStorage.g.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
@@ -1,239 +0,0 @@
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using System.Threading.Tasks;
|
||||
using Thread = Java.Lang.Thread;
|
||||
|
||||
namespace keepass2android;
|
||||
|
||||
/// <summary>
|
||||
/// Allows to run tasks in the background. The UI is not blocked by the task. Tasks continue to run in the BackgroundSyncService if the app goes to background while tasks are active.
|
||||
/// </summary>
|
||||
public class OperationRunner
|
||||
{
|
||||
//singleton instance
|
||||
private static OperationRunner _instance = null;
|
||||
|
||||
public static OperationRunner Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new OperationRunner();
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
void Initialize(IKp2aApp app)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public struct OperationWithMetadata
|
||||
{
|
||||
public OperationWithMetadata()
|
||||
{
|
||||
Operation = null;
|
||||
}
|
||||
|
||||
public OperationWithFinishHandler Operation { get; set; }
|
||||
public bool RunBlocking { get; set; } = false;
|
||||
}
|
||||
|
||||
public ProgressUiAsStatusLoggerAdapter StatusLogger => _statusLogger;
|
||||
|
||||
private OperationRunner()
|
||||
{
|
||||
//private constructor
|
||||
}
|
||||
|
||||
private readonly Queue<OperationWithMetadata> _taskQueue = new Queue<OperationWithMetadata>();
|
||||
private readonly object _taskQueueLock = new object();
|
||||
private Java.Lang.Thread? _thread = null;
|
||||
private OperationWithMetadata? _currentlyRunningTask = null;
|
||||
private ProgressUiAsStatusLoggerAdapter _statusLogger = null;
|
||||
private IProgressDialog _progressDialog;
|
||||
private IKp2aApp _app;
|
||||
|
||||
public void Run(IKp2aApp app, OperationWithFinishHandler operation, bool runBlocking = false)
|
||||
{
|
||||
lock (Instance._taskQueueLock)
|
||||
{
|
||||
_taskQueue.Enqueue(new OperationWithMetadata(){ Operation = operation, RunBlocking = runBlocking});
|
||||
operation.SetStatusLogger(_statusLogger);
|
||||
|
||||
// Start thread to run the task (unless it's already running)
|
||||
if (_thread == null)
|
||||
{
|
||||
_statusLogger.StartLogging("", false);
|
||||
_thread = new Java.Lang.Thread(() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
|
||||
lock (_taskQueueLock)
|
||||
{
|
||||
if (!_taskQueue.Any())
|
||||
{
|
||||
_thread = null;
|
||||
_statusLogger.EndLogging();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentlyRunningTask = _taskQueue.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
if (_currentlyRunningTask.Value.RunBlocking)
|
||||
{
|
||||
app.UiThreadHandler.Post(
|
||||
() =>
|
||||
{
|
||||
TrySetupProgressDialog();
|
||||
});
|
||||
}
|
||||
|
||||
var originalFinishedHandler = _currentlyRunningTask.Value.Operation.operationFinishedHandler;
|
||||
_currentlyRunningTask.Value.Operation.operationFinishedHandler = new ActionOnOperationFinished(app, (
|
||||
(success, message, context) =>
|
||||
{
|
||||
if (_currentlyRunningTask?.RunBlocking == true)
|
||||
{
|
||||
_app.UiThreadHandler.Post(() =>
|
||||
{
|
||||
_progressDialog?.Dismiss();
|
||||
}
|
||||
);
|
||||
}
|
||||
_currentlyRunningTask = null;
|
||||
|
||||
}), originalFinishedHandler);
|
||||
_currentlyRunningTask.Value.Operation.Run();
|
||||
|
||||
while (_currentlyRunningTask != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Kp2aLog.Log("Thread interrupted.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
_thread.Start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private bool TrySetupProgressDialog()
|
||||
{
|
||||
string currentMessage = "Initializing...";
|
||||
string currentSubmessage = "";
|
||||
|
||||
if (_statusLogger != null)
|
||||
{
|
||||
currentMessage = _statusLogger.LastMessage;
|
||||
currentSubmessage = _statusLogger.LastSubMessage;
|
||||
}
|
||||
|
||||
if (_progressDialog != null)
|
||||
{
|
||||
var pd = _progressDialog;
|
||||
_app.UiThreadHandler.Post(() =>
|
||||
{
|
||||
pd.Dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
// Show process dialog
|
||||
_progressDialog = _app.CreateProgressDialog(_app.ActiveContext);
|
||||
if (_progressDialog == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var progressUi = new ProgressDialogUi(_app, _app.UiThreadHandler, _progressDialog);
|
||||
_statusLogger.SetNewProgressUi(progressUi);
|
||||
|
||||
_statusLogger.StartLogging("", false);
|
||||
_statusLogger.UpdateMessage(currentMessage);
|
||||
_statusLogger.UpdateSubMessage(currentSubmessage);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetNewActiveContext(IKp2aApp app)
|
||||
{
|
||||
_app = app;
|
||||
Context? context = app.ActiveContext;
|
||||
bool isAppContext = context == null || (context.ApplicationContext == context);
|
||||
lock (_taskQueueLock)
|
||||
{
|
||||
if (isAppContext && _thread != null)
|
||||
{
|
||||
//this will register the service as new active context (see BackgroundSyncService.OnStartCommand())
|
||||
app.StartBackgroundSyncService();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_currentlyRunningTask?.RunBlocking == true && (context is Activity { IsFinishing: false, IsDestroyed:false}))
|
||||
{
|
||||
app.UiThreadHandler.Post(() =>
|
||||
{
|
||||
TrySetupProgressDialog();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var progressUi = (context as IProgressUiProvider)?.ProgressUi;
|
||||
if (_statusLogger == null)
|
||||
{
|
||||
_statusLogger = new ProgressUiAsStatusLoggerAdapter(progressUi, app);
|
||||
}
|
||||
else
|
||||
{
|
||||
_statusLogger.SetNewProgressUi(progressUi);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var task in _taskQueue.Concat(_currentlyRunningTask == null ?
|
||||
new List<OperationWithMetadata>() : [_currentlyRunningTask.Value])
|
||||
)
|
||||
{
|
||||
task.Operation.SetStatusLogger(_statusLogger);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void CancelAll()
|
||||
{
|
||||
lock (_taskQueueLock)
|
||||
{
|
||||
if (_thread != null)
|
||||
{
|
||||
_thread.Interrupt();
|
||||
_thread = null;
|
||||
_statusLogger?.EndLogging();
|
||||
}
|
||||
|
||||
_taskQueue.Clear();
|
||||
_currentlyRunningTask = null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -22,152 +22,116 @@ using KeePassLib.Interfaces;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public interface IKp2aStatusLogger : IStatusLogger
|
||||
{
|
||||
void UpdateMessage(UiStringKey stringKey);
|
||||
string LastMessage { get; }
|
||||
string LastSubMessage { get; }
|
||||
}
|
||||
|
||||
public interface IProgressUi
|
||||
{
|
||||
void Show();
|
||||
void Hide();
|
||||
void UpdateMessage(String message);
|
||||
void UpdateSubMessage(String submessage);
|
||||
}
|
||||
|
||||
public interface IProgressUiProvider
|
||||
{
|
||||
IProgressUi? ProgressUi { get; }
|
||||
}
|
||||
|
||||
|
||||
public class Kp2aNullStatusLogger : IKp2aStatusLogger
|
||||
{
|
||||
public void StartLogging(string strOperation, bool bWriteOperationToLog)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void EndLogging()
|
||||
{
|
||||
}
|
||||
|
||||
public bool SetProgress(uint uPercent)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetText(string strNewText, LogStatusType lsType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private string _lastMessage;
|
||||
private string _lastSubMessage;
|
||||
public void UpdateMessage(string message)
|
||||
{
|
||||
_lastMessage = message;
|
||||
}
|
||||
|
||||
public void UpdateSubMessage(string submessage)
|
||||
{
|
||||
_lastSubMessage = submessage;
|
||||
}
|
||||
|
||||
public bool ContinueWork()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void UpdateMessage(UiStringKey stringKey)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string LastMessage { get { return _lastMessage; } }
|
||||
public string LastSubMessage { get { return _lastSubMessage; } }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// StatusLogger implementation which shows the progress in a progress dialog
|
||||
/// </summary>
|
||||
public class ProgressDialogUi: IProgressUi
|
||||
{
|
||||
/// <summary>
|
||||
/// StatusLogger implementation which shows the progress in a progress dialog
|
||||
/// </summary>
|
||||
public class ProgressDialogStatusLogger: IStatusLogger {
|
||||
private readonly IProgressDialog _progressDialog;
|
||||
|
||||
readonly IKp2aApp _app;
|
||||
private readonly Handler _handler;
|
||||
private string _message = "";
|
||||
private string _submessage;
|
||||
private readonly IKp2aApp _app;
|
||||
|
||||
public String LastSubMessage => _submessage;
|
||||
public String LastMessage => _message;
|
||||
public String SubMessage => _submessage;
|
||||
public String Message => _message;
|
||||
|
||||
public ProgressDialogStatusLogger() {
|
||||
|
||||
}
|
||||
|
||||
public ProgressDialogUi(IKp2aApp app, Handler handler, IProgressDialog pd)
|
||||
{
|
||||
_app = app;
|
||||
public ProgressDialogStatusLogger(IKp2aApp app, Handler handler, IProgressDialog pd) {
|
||||
_app = app;
|
||||
_progressDialog = pd;
|
||||
_handler = handler;
|
||||
}
|
||||
|
||||
public void UpdateMessage(UiStringKey stringKey) {
|
||||
if (_app != null)
|
||||
UpdateMessage(_app.GetResourceString(stringKey));
|
||||
}
|
||||
|
||||
public void UpdateSubMessage(String submessage)
|
||||
{
|
||||
Kp2aLog.Log("status submessage: " + submessage);
|
||||
_submessage = submessage;
|
||||
if (_app != null && _progressDialog != null && _handler != null)
|
||||
{
|
||||
_handler.Post(() =>
|
||||
{
|
||||
if (!String.IsNullOrEmpty(submessage))
|
||||
{
|
||||
_progressDialog.SetMessage(_message + " (" + submessage + ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
_progressDialog.SetMessage(_message);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
_handler.Post(() =>
|
||||
{
|
||||
_progressDialog?.Show();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
_handler.Post(() =>
|
||||
{
|
||||
_progressDialog?.Dismiss();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public void UpdateMessage(string message)
|
||||
{
|
||||
Kp2aLog.Log("status message: " + message);
|
||||
public void UpdateMessage (String message)
|
||||
{
|
||||
Kp2aLog.Log("status message: " + message);
|
||||
_message = message;
|
||||
if (_app != null && _progressDialog != null && _handler != null)
|
||||
{
|
||||
_handler.Post(() =>
|
||||
{
|
||||
_progressDialog.SetMessage(message);
|
||||
});
|
||||
}
|
||||
}
|
||||
if ( _app!= null && _progressDialog != null && _handler != null ) {
|
||||
_handler.Post(() => {_progressDialog.SetMessage(message); } );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public void UpdateSubMessage(String submessage)
|
||||
{
|
||||
Kp2aLog.Log("status submessage: " + submessage);
|
||||
_submessage = submessage;
|
||||
if (_app != null && _progressDialog != null && _handler != null)
|
||||
{
|
||||
_handler.Post(() =>
|
||||
{
|
||||
if (!String.IsNullOrEmpty(submessage))
|
||||
{
|
||||
_progressDialog.SetMessage(_message + " (" + submessage + ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
_progressDialog.SetMessage(_message);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#region IStatusLogger implementation
|
||||
|
||||
|
||||
public void StartLogging (string strOperation, bool bWriteOperationToLog)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void EndLogging ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public bool SetProgress (uint uPercent)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetText (string strNewText, LogStatusType lsType)
|
||||
{
|
||||
if (strNewText.StartsWith("KP2AKEY_"))
|
||||
{
|
||||
UiStringKey key;
|
||||
if (Enum.TryParse(strNewText.Substring("KP2AKEY_".Length), true, out key))
|
||||
{
|
||||
UpdateMessage(_app.GetResourceString(key), lsType);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
UpdateMessage(strNewText, lsType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void UpdateMessage(string message, LogStatusType lsType)
|
||||
{
|
||||
if (lsType == LogStatusType.AdditionalInfo)
|
||||
{
|
||||
UpdateSubMessage(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
public bool ContinueWork ()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
179
src/Kp2aBusinessLogic/ProgressTask.cs
Normal file
179
src/Kp2aBusinessLogic/ProgressTask.cs
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
|
||||
|
||||
Keepass2Android is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Keepass2Android 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Java.Lang;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to run a task while a progress dialog is shown
|
||||
/// </summary>
|
||||
public class ProgressTask
|
||||
{
|
||||
//for handling Activity recreation situations, we need access to the currently active task. It must hold that there is no more than one active task.
|
||||
private static ProgressTask _currentTask = null;
|
||||
|
||||
public static void SetNewActiveActivity(Activity activeActivity)
|
||||
{
|
||||
if (_currentTask != null)
|
||||
{
|
||||
_currentTask.ActiveActivity = activeActivity;
|
||||
}
|
||||
}
|
||||
public static void RemoveActiveActivity(Activity activity)
|
||||
{
|
||||
if ((_currentTask != null) && (_currentTask._activeActivity == activity))
|
||||
_currentTask.ActiveActivity = null;
|
||||
|
||||
}
|
||||
|
||||
public Activity ActiveActivity
|
||||
{
|
||||
get { return _activeActivity; }
|
||||
private set
|
||||
{
|
||||
if (_activeActivity != null && _activeActivity != _previouslyActiveActivity)
|
||||
{
|
||||
_previouslyActiveActivity = _activeActivity;
|
||||
|
||||
}
|
||||
_activeActivity = value;
|
||||
if (_task != null)
|
||||
_task.ActiveActivity = _activeActivity;
|
||||
if (_activeActivity != null)
|
||||
{
|
||||
SetupProgressDialog(_app);
|
||||
_progressDialog.Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Activity PreviouslyActiveActivity
|
||||
{
|
||||
get { return _previouslyActiveActivity; }
|
||||
|
||||
}
|
||||
|
||||
private readonly Handler _handler;
|
||||
private readonly RunnableOnFinish _task;
|
||||
private IProgressDialog _progressDialog;
|
||||
private readonly IKp2aApp _app;
|
||||
private Java.Lang.Thread _thread;
|
||||
private Activity _activeActivity, _previouslyActiveActivity;
|
||||
private ProgressDialogStatusLogger _progressDialogStatusLogger;
|
||||
|
||||
public ProgressTask(IKp2aApp app, Activity activity, RunnableOnFinish task)
|
||||
{
|
||||
_activeActivity = activity;
|
||||
_task = task;
|
||||
_handler = app.UiThreadHandler;
|
||||
_app = app;
|
||||
|
||||
SetupProgressDialog(app);
|
||||
|
||||
// Set code to run when this is finished
|
||||
_task.OnFinishToRun = new AfterTask(activity, task.OnFinishToRun, _handler, this);
|
||||
|
||||
_task.SetStatusLogger(_progressDialogStatusLogger);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void SetupProgressDialog(IKp2aApp app)
|
||||
{
|
||||
string currentMessage = "Initializing...";
|
||||
string currentSubmessage = "";
|
||||
|
||||
if (_progressDialogStatusLogger != null)
|
||||
{
|
||||
currentMessage = _progressDialogStatusLogger.Message;
|
||||
currentSubmessage = _progressDialogStatusLogger.SubMessage;
|
||||
}
|
||||
|
||||
if (_progressDialog != null)
|
||||
{
|
||||
var pd = _progressDialog;
|
||||
app.UiThreadHandler.Post(() =>
|
||||
{
|
||||
pd.Dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
// Show process dialog
|
||||
_progressDialog = app.CreateProgressDialog(_activeActivity);
|
||||
_progressDialog.SetTitle(_app.GetResourceString(UiStringKey.progress_title));
|
||||
_progressDialogStatusLogger = new ProgressDialogStatusLogger(_app, _handler, _progressDialog);
|
||||
_progressDialogStatusLogger.UpdateMessage(currentMessage);
|
||||
_progressDialogStatusLogger.UpdateSubMessage(currentSubmessage);
|
||||
}
|
||||
|
||||
public void Run(bool allowOverwriteCurrentTask = false)
|
||||
{
|
||||
if ((!allowOverwriteCurrentTask) && (_currentTask != null))
|
||||
throw new System.Exception("Cannot start another ProgressTask while ProgressTask is already running! " + _task.GetType().Name + "/" + _currentTask._task.GetType().Name);
|
||||
_currentTask = this;
|
||||
|
||||
// Show process dialog
|
||||
_progressDialog.Show();
|
||||
|
||||
|
||||
// Start Thread to Run task
|
||||
_thread = new Java.Lang.Thread(_task.Run);
|
||||
_thread.Start();
|
||||
}
|
||||
|
||||
public void JoinWorkerThread()
|
||||
{
|
||||
_thread.Join();
|
||||
}
|
||||
|
||||
private class AfterTask : OnFinish {
|
||||
readonly ProgressTask _progressTask;
|
||||
|
||||
public AfterTask (Activity activity, OnFinish finish, Handler handler, ProgressTask pt): base(activity, finish, handler)
|
||||
{
|
||||
_progressTask = pt;
|
||||
}
|
||||
|
||||
public override void Run() {
|
||||
base.Run();
|
||||
|
||||
if (Handler != null) //can be null in tests
|
||||
{
|
||||
// Remove the progress dialog
|
||||
Handler.Post(delegate
|
||||
{
|
||||
_progressTask._progressDialog.Dismiss();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
_progressTask._progressDialog.Dismiss();
|
||||
}
|
||||
_currentTask = null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -1,94 +0,0 @@
|
||||
using KeePassLib.Interfaces;
|
||||
|
||||
namespace keepass2android;
|
||||
|
||||
public class ProgressUiAsStatusLoggerAdapter : IKp2aStatusLogger
|
||||
{
|
||||
private IProgressUi? _progressUi;
|
||||
private readonly IKp2aApp _app;
|
||||
|
||||
private string _lastMessage = "";
|
||||
private string _lastSubMessage = "";
|
||||
private bool _isVisible = false;
|
||||
|
||||
public ProgressUiAsStatusLoggerAdapter(IProgressUi progressUi, IKp2aApp app)
|
||||
{
|
||||
_progressUi = progressUi;
|
||||
_app = app;
|
||||
}
|
||||
|
||||
public void SetNewProgressUi(IProgressUi progressUi)
|
||||
{
|
||||
_progressUi?.Hide();
|
||||
_progressUi = progressUi;
|
||||
if (_isVisible)
|
||||
{
|
||||
progressUi?.Show();
|
||||
progressUi?.UpdateMessage(_lastMessage);
|
||||
progressUi?.UpdateSubMessage(_lastSubMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
progressUi?.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
public void StartLogging(string strOperation, bool bWriteOperationToLog)
|
||||
{
|
||||
_progressUi?.Show();
|
||||
_isVisible = true;
|
||||
}
|
||||
|
||||
public void EndLogging()
|
||||
{
|
||||
_progressUi?.Hide();
|
||||
_isVisible = false;
|
||||
}
|
||||
|
||||
public bool SetProgress(uint uPercent)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetText(string strNewText, LogStatusType lsType)
|
||||
{
|
||||
if (strNewText.StartsWith("KP2AKEY_"))
|
||||
{
|
||||
UiStringKey key;
|
||||
if (Enum.TryParse(strNewText.Substring("KP2AKEY_".Length), true, out key))
|
||||
{
|
||||
UpdateMessage(_app.GetResourceString(key));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
UpdateMessage(strNewText);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void UpdateMessage(string message)
|
||||
{
|
||||
_progressUi?.UpdateMessage(message);
|
||||
_lastMessage = message;
|
||||
}
|
||||
|
||||
public void UpdateSubMessage(string submessage)
|
||||
{
|
||||
_progressUi?.UpdateSubMessage(submessage);
|
||||
_lastSubMessage = submessage;
|
||||
}
|
||||
|
||||
public bool ContinueWork()
|
||||
{
|
||||
return !Java.Lang.Thread.Interrupted();
|
||||
}
|
||||
|
||||
public void UpdateMessage(UiStringKey stringKey)
|
||||
{
|
||||
if (_app != null)
|
||||
UpdateMessage(_app.GetResourceString(stringKey));
|
||||
}
|
||||
|
||||
public string LastMessage { get { return _lastMessage; } }
|
||||
public string LastSubMessage { get { return _lastSubMessage; } }
|
||||
}
|
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -16,7 +15,14 @@ namespace KeePass.Util
|
||||
string errorMessage = e.Message;
|
||||
if (e is Java.Lang.Exception javaException)
|
||||
{
|
||||
errorMessage = javaException.Message ?? errorMessage;
|
||||
try
|
||||
{
|
||||
errorMessage = javaException.LocalizedMessage ?? javaException.Message ?? errorMessage;
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return errorMessage;
|
||||
|
@@ -13,15 +13,16 @@ using keepass2android.Io;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public class CheckDatabaseForChanges: OperationWithFinishHandler
|
||||
public class CheckDatabaseForChanges: RunnableOnFinish
|
||||
{
|
||||
private readonly Context _context;
|
||||
private readonly IKp2aApp _app;
|
||||
|
||||
|
||||
public CheckDatabaseForChanges(IKp2aApp app, OnOperationFinishedHandler operationFinishedHandler)
|
||||
: base(app, operationFinishedHandler)
|
||||
public CheckDatabaseForChanges(Activity context, IKp2aApp app, OnFinish finish)
|
||||
: base(context, finish)
|
||||
{
|
||||
_context = context;
|
||||
_app = app;
|
||||
}
|
||||
|
||||
|
@@ -85,14 +85,17 @@ namespace keepass2android
|
||||
/// <summary>
|
||||
/// Do not call this method directly. Call App.Kp2a.LoadDatabase instead.
|
||||
/// </summary>
|
||||
public void LoadData(IKp2aApp app, IOConnectionInfo iocInfo, MemoryStream databaseData, CompositeKey compositeKey, IKp2aStatusLogger status, IDatabaseFormat databaseFormat)
|
||||
public void LoadData(IKp2aApp app, IOConnectionInfo iocInfo, MemoryStream databaseData, CompositeKey compositeKey, ProgressDialogStatusLogger status, IDatabaseFormat databaseFormat)
|
||||
{
|
||||
PwDatabase pwDatabase = new PwDatabase();
|
||||
|
||||
IFileStorage fileStorage = _app.GetFileStorage(iocInfo);
|
||||
Stream s = databaseData ?? fileStorage.OpenFileForRead(iocInfo);
|
||||
var fileVersion = _app.GetFileStorage(iocInfo).GetCurrentFileVersionFast(iocInfo);
|
||||
PopulateDatabaseFromStream(pwDatabase, s, iocInfo, compositeKey, status, databaseFormat);
|
||||
Kp2aLog.Log("LoadData: Retrieving stream");
|
||||
Stream s = databaseData ?? fileStorage.OpenFileForRead(iocInfo);
|
||||
Kp2aLog.Log("LoadData: GetCurrentFileVersion");
|
||||
var fileVersion = _app.GetFileStorage(iocInfo).GetCurrentFileVersionFast(iocInfo);
|
||||
Kp2aLog.Log("LoadData: PopulateDatabaseFromStream");
|
||||
PopulateDatabaseFromStream(pwDatabase, s, iocInfo, compositeKey, status, databaseFormat);
|
||||
LastFileVersion = fileVersion;
|
||||
|
||||
status.UpdateSubMessage("");
|
||||
@@ -149,7 +152,7 @@ namespace keepass2android
|
||||
get { return GetFingerprintModePrefKey(Ioc); }
|
||||
}
|
||||
|
||||
protected virtual void PopulateDatabaseFromStream(PwDatabase pwDatabase, Stream s, IOConnectionInfo iocInfo, CompositeKey compositeKey, IKp2aStatusLogger status, IDatabaseFormat databaseFormat)
|
||||
protected virtual void PopulateDatabaseFromStream(PwDatabase pwDatabase, Stream s, IOConnectionInfo iocInfo, CompositeKey compositeKey, ProgressDialogStatusLogger status, IDatabaseFormat databaseFormat)
|
||||
{
|
||||
IFileStorage fileStorage = _app.GetFileStorage(iocInfo);
|
||||
var filename = fileStorage.GetFilenameWithoutPathAndExt(iocInfo);
|
||||
@@ -194,9 +197,9 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
|
||||
public void SaveData(IFileStorage fileStorage) {
|
||||
public void SaveData() {
|
||||
|
||||
using (IWriteTransaction trans = fileStorage.OpenWriteTransaction(Ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions)))
|
||||
using (IWriteTransaction trans = _app.GetFileStorage(Ioc).OpenWriteTransaction(Ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions)))
|
||||
{
|
||||
DatabaseFormat.Save(KpDatabase, trans.OpenFile());
|
||||
|
||||
|
@@ -396,6 +396,8 @@ namespace keepass2android
|
||||
{
|
||||
PwGroupV3 toGroup = new PwGroupV3();
|
||||
toGroup.Name = fromGroup.Name;
|
||||
//todo remove
|
||||
Android.Util.Log.Debug("KP2A", "save kdb: group " + fromGroup.Name);
|
||||
|
||||
toGroup.TCreation = new PwDate(ConvertTime(fromGroup.CreationTime));
|
||||
toGroup.TLastAccess= new PwDate(ConvertTime(fromGroup.LastAccessTime));
|
||||
|
@@ -4,152 +4,109 @@ using System.IO;
|
||||
using System.Text;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using KeePassLib.Serialization;
|
||||
using keepass2android.Io;
|
||||
using KeePass.Util;
|
||||
using Group.Pals.Android.Lib.UI.Filechooser.Utils;
|
||||
using KeePassLib;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public class SynchronizeCachedDatabase: OperationWithFinishHandler
|
||||
public class SynchronizeCachedDatabase: RunnableOnFinish
|
||||
{
|
||||
private readonly Activity _context;
|
||||
private readonly IKp2aApp _app;
|
||||
private IDatabaseModificationWatcher _modificationWatcher;
|
||||
private readonly Database _database;
|
||||
private SaveDb _saveDb;
|
||||
|
||||
|
||||
public SynchronizeCachedDatabase(IKp2aApp app, Database database, OnOperationFinishedHandler operationFinishedHandler, IDatabaseModificationWatcher modificationWatcher)
|
||||
: base(app, operationFinishedHandler)
|
||||
{
|
||||
_app = app;
|
||||
_database = database;
|
||||
_modificationWatcher = modificationWatcher;
|
||||
}
|
||||
public SynchronizeCachedDatabase(Activity context, IKp2aApp app, OnFinish finish)
|
||||
: base(context, finish)
|
||||
{
|
||||
_context = context;
|
||||
_app = app;
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
IOConnectionInfo ioc = _database.Ioc;
|
||||
IFileStorage fileStorage = _app.GetFileStorage(ioc);
|
||||
if (!(fileStorage is CachingFileStorage))
|
||||
{
|
||||
throw new Exception("Cannot sync a non-cached database!");
|
||||
}
|
||||
try
|
||||
{
|
||||
IOConnectionInfo ioc = _app.CurrentDb.Ioc;
|
||||
IFileStorage fileStorage = _app.GetFileStorage(ioc);
|
||||
if (!(fileStorage is CachingFileStorage))
|
||||
{
|
||||
throw new Exception("Cannot sync a non-cached database!");
|
||||
}
|
||||
StatusLogger.UpdateMessage(UiStringKey.SynchronizingCachedDatabase);
|
||||
CachingFileStorage cachingFileStorage = (CachingFileStorage) fileStorage;
|
||||
|
||||
StatusLogger.UpdateMessage(UiStringKey.SynchronizingCachedDatabase);
|
||||
CachingFileStorage cachingFileStorage = (CachingFileStorage)fileStorage;
|
||||
|
||||
//download file from remote location and calculate hash:
|
||||
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.DownloadingRemoteFile));
|
||||
string hash;
|
||||
|
||||
MemoryStream remoteData;
|
||||
try
|
||||
{
|
||||
remoteData = cachingFileStorage.GetRemoteDataAndHash(ioc, out hash);
|
||||
Kp2aLog.Log("Checking for file change. Current hash = " + hash);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.RestoringRemoteFile));
|
||||
cachingFileStorage.UpdateRemoteFile(ioc,
|
||||
_app.GetBooleanPreference(PreferenceKey.UseFileTransactions));
|
||||
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
|
||||
//download file from remote location and calculate hash:
|
||||
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.DownloadingRemoteFile));
|
||||
string hash;
|
||||
|
||||
MemoryStream remoteData;
|
||||
try
|
||||
{
|
||||
remoteData = cachingFileStorage.GetRemoteDataAndHash(ioc, out hash);
|
||||
Kp2aLog.Log("Checking for file change. Current hash = " + hash);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.RestoringRemoteFile));
|
||||
cachingFileStorage.UpdateRemoteFile(ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions));
|
||||
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
|
||||
Kp2aLog.Log("Checking for file change: file not found");
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//check if remote file was modified:
|
||||
//check if remote file was modified:
|
||||
var baseVersionHash = cachingFileStorage.GetBaseVersionHash(ioc);
|
||||
Kp2aLog.Log("Checking for file change. baseVersionHash = " + baseVersionHash);
|
||||
if (baseVersionHash != hash)
|
||||
{
|
||||
//remote file is modified
|
||||
if (cachingFileStorage.HasLocalChanges(ioc))
|
||||
{
|
||||
//conflict! need to merge
|
||||
var _saveDb = new SaveDb(_app, new ActionOnOperationFinished(_app,
|
||||
(success, result, activity) =>
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
Finish(false, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
|
||||
}
|
||||
}), _database, false, remoteData, _modificationWatcher);
|
||||
_saveDb.SetStatusLogger(StatusLogger);
|
||||
_saveDb.DoNotSetStatusLoggerMessage = true; //Keep "sync db" as main message
|
||||
_saveDb.SyncInBackground = false;
|
||||
_saveDb.Run();
|
||||
if (baseVersionHash != hash)
|
||||
{
|
||||
//remote file is modified
|
||||
if (cachingFileStorage.HasLocalChanges(ioc))
|
||||
{
|
||||
//conflict! need to merge
|
||||
_saveDb = new SaveDb(_context, _app, new ActionOnFinish(ActiveActivity, (success, result, activity) =>
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
Finish(false, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
|
||||
}
|
||||
_saveDb = null;
|
||||
}), _app.CurrentDb, false, remoteData);
|
||||
_saveDb.Run();
|
||||
|
||||
_database.UpdateGlobals();
|
||||
_app.CurrentDb.UpdateGlobals();
|
||||
|
||||
_app.MarkAllGroupsAsDirty();
|
||||
}
|
||||
else
|
||||
{
|
||||
//only the remote file was modified -> reload database.
|
||||
var onFinished = new ActionOnOperationFinished(_app, (success, result, activity) =>
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
Finish(false, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
new Handler(Looper.MainLooper).Post(() =>
|
||||
{
|
||||
_database.UpdateGlobals();
|
||||
|
||||
_app.MarkAllGroupsAsDirty();
|
||||
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
var _loadDb = new LoadDb(_app, ioc, Task.FromResult(remoteData),
|
||||
_database.KpDatabase.MasterKey, null, onFinished, true, false, _modificationWatcher);
|
||||
_loadDb.SetStatusLogger(StatusLogger);
|
||||
_loadDb.DoNotSetStatusLoggerMessage = true; //Keep "sync db" as main message
|
||||
_loadDb.Run();
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//remote file is unmodified
|
||||
if (cachingFileStorage.HasLocalChanges(ioc))
|
||||
{
|
||||
//but we have local changes -> upload:
|
||||
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.UploadingFile));
|
||||
cachingFileStorage.UpdateRemoteFile(ioc,
|
||||
_app.GetBooleanPreference(PreferenceKey.UseFileTransactions));
|
||||
StatusLogger.UpdateSubMessage("");
|
||||
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
|
||||
}
|
||||
else
|
||||
{
|
||||
//files are in sync: just set the result
|
||||
Finish(true, _app.GetResourceString(UiStringKey.FilesInSync));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Java.Lang.InterruptedException e)
|
||||
{
|
||||
Kp2aLog.LogUnexpectedError(e);
|
||||
//no Finish()
|
||||
}
|
||||
catch (Java.IO.InterruptedIOException e)
|
||||
{
|
||||
Kp2aLog.LogUnexpectedError(e);
|
||||
//no Finish()
|
||||
}
|
||||
_app.MarkAllGroupsAsDirty();
|
||||
}
|
||||
else
|
||||
{
|
||||
//only the remote file was modified -> reload database.
|
||||
//note: it's best to lock the database and do a complete reload here (also better for UI consistency in case something goes wrong etc.)
|
||||
_app.TriggerReload(_context, (bool result) => Finish(result));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//remote file is unmodified
|
||||
if (cachingFileStorage.HasLocalChanges(ioc))
|
||||
{
|
||||
//but we have local changes -> upload:
|
||||
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.UploadingFile));
|
||||
cachingFileStorage.UpdateRemoteFile(ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions));
|
||||
StatusLogger.UpdateSubMessage("");
|
||||
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
|
||||
}
|
||||
else
|
||||
{
|
||||
//files are in sync: just set the result
|
||||
Finish(true, _app.GetResourceString(UiStringKey.FilesInSync));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Kp2aLog.LogUnexpectedError(e);
|
||||
@@ -158,5 +115,10 @@ namespace keepass2android
|
||||
|
||||
}
|
||||
|
||||
public void JoinWorkerThread()
|
||||
{
|
||||
if (_saveDb != null)
|
||||
_saveDb.JoinWorkerThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
57
src/Kp2aBusinessLogic/database/edit/ActionOnFinish.cs
Normal file
57
src/Kp2aBusinessLogic/database/edit/ActionOnFinish.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll.
|
||||
|
||||
Keepass2Android is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Keepass2Android 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Android.App;
|
||||
using Android.OS;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public class ActionOnFinish: OnFinish
|
||||
{
|
||||
public delegate void ActionToPerformOnFinsh(bool success, String message, Activity activeActivity);
|
||||
|
||||
readonly ActionToPerformOnFinsh _actionToPerform;
|
||||
|
||||
public ActionOnFinish(Activity activity, ActionToPerformOnFinsh actionToPerform) : base(activity, null, null)
|
||||
{
|
||||
_actionToPerform = actionToPerform;
|
||||
}
|
||||
|
||||
public ActionOnFinish(Activity activity, ActionToPerformOnFinsh actionToPerform, OnFinish finish) : base(activity, finish)
|
||||
{
|
||||
_actionToPerform = actionToPerform;
|
||||
}
|
||||
|
||||
//if set to true, the previously active active will be passed to ActionToPerformOnFinish instead null if no activity is on foreground
|
||||
public bool AllowInactiveActivity { get; set; }
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
if (Message == null)
|
||||
Message = "";
|
||||
if (Handler != null)
|
||||
{
|
||||
Handler.Post(() => {_actionToPerform(Success, Message, ActiveActivity);});
|
||||
}
|
||||
else
|
||||
_actionToPerform(Success, Message, AllowInactiveActivity ? (ActiveActivity ?? PreviouslyActiveActivity) : ActiveActivity);
|
||||
base.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll.
|
||||
|
||||
Keepass2Android is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Keepass2Android 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using keepass2android;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public class ActionOnOperationFinished: OnOperationFinishedHandler
|
||||
{
|
||||
public delegate void ActionToPerformOnFinsh(bool success, String message, Context activeContext);
|
||||
|
||||
readonly ActionToPerformOnFinsh _actionToPerform;
|
||||
|
||||
public ActionOnOperationFinished(IKp2aApp app, ActionToPerformOnFinsh actionToPerform) : base(app, null, null)
|
||||
{
|
||||
_actionToPerform = actionToPerform;
|
||||
}
|
||||
|
||||
public ActionOnOperationFinished(IKp2aApp app, ActionToPerformOnFinsh actionToPerform, OnOperationFinishedHandler operationFinishedHandler) : base(app, operationFinishedHandler)
|
||||
{
|
||||
_actionToPerform = actionToPerform;
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
if (Message == null)
|
||||
Message = "";
|
||||
if (Handler != null)
|
||||
{
|
||||
Handler.Post(() =>
|
||||
{
|
||||
_actionToPerform(Success, Message, ActiveContext);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
_actionToPerform(Success, Message, ActiveContext);
|
||||
}
|
||||
base.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Action which runs when the contextInstanceId is the active context
|
||||
// otherwise it is registered as pending action for the context instance.
|
||||
public class ActionInContextInstanceOnOperationFinished : ActionOnOperationFinished
|
||||
{
|
||||
private readonly int _contextInstanceId;
|
||||
private IKp2aApp _app;
|
||||
|
||||
public ActionInContextInstanceOnOperationFinished(int contextInstanceId, IKp2aApp app, ActionToPerformOnFinsh actionToPerform) : base(app, actionToPerform)
|
||||
{
|
||||
_contextInstanceId = contextInstanceId;
|
||||
_app = app;
|
||||
}
|
||||
public ActionInContextInstanceOnOperationFinished(int contextInstanceId, IKp2aApp app, ActionToPerformOnFinsh actionToPerform, OnOperationFinishedHandler operationFinishedHandler) : base(app, actionToPerform, operationFinishedHandler)
|
||||
{
|
||||
_contextInstanceId = contextInstanceId;
|
||||
_app = app;
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
if ((ActiveContext as IContextInstanceIdProvider)?.ContextInstanceId != _contextInstanceId)
|
||||
{
|
||||
_app.RegisterPendingActionForContextInstance(_contextInstanceId, this);
|
||||
}
|
||||
else _app.UiThreadHandler.Post(() => base.Run());
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ using KeePassLib;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public class AddEntry : OperationWithFinishHandler {
|
||||
public class AddEntry : RunnableOnFinish {
|
||||
protected Database Db
|
||||
{
|
||||
get { return _app.CurrentDb; }
|
||||
@@ -30,20 +30,22 @@ namespace keepass2android
|
||||
private readonly IKp2aApp _app;
|
||||
private readonly PwEntry _entry;
|
||||
private readonly PwGroup _parentGroup;
|
||||
private readonly Activity _ctx;
|
||||
private readonly Database _db;
|
||||
|
||||
public static AddEntry GetInstance(IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnOperationFinishedHandler operationFinishedHandler, Database db) {
|
||||
public static AddEntry GetInstance(Activity ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish, Database db) {
|
||||
|
||||
return new AddEntry(db, app, entry, parentGroup, operationFinishedHandler);
|
||||
return new AddEntry(ctx, db, app, entry, parentGroup, finish);
|
||||
}
|
||||
|
||||
public AddEntry(Database db, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnOperationFinishedHandler operationFinishedHandler):base(app, operationFinishedHandler) {
|
||||
public AddEntry(Activity ctx, Database db, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish):base(ctx, finish) {
|
||||
_ctx = ctx;
|
||||
_db = db;
|
||||
_parentGroup = parentGroup;
|
||||
_app = app;
|
||||
_entry = entry;
|
||||
|
||||
_operationFinishedHandler = new AfterAdd(app.CurrentDb, entry, app,operationFinishedHandler);
|
||||
_onFinishToRun = new AfterAdd(ctx, app.CurrentDb, entry, app,OnFinishToRun);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,17 +65,17 @@ namespace keepass2android
|
||||
_db.Elements.Add(_entry);
|
||||
|
||||
// Commit to disk
|
||||
SaveDb save = new SaveDb(_app, _app.CurrentDb, operationFinishedHandler);
|
||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.Run();
|
||||
}
|
||||
|
||||
private class AfterAdd : OnOperationFinishedHandler {
|
||||
private class AfterAdd : OnFinish {
|
||||
private readonly Database _db;
|
||||
private readonly PwEntry _entry;
|
||||
private readonly IKp2aApp _app;
|
||||
|
||||
public AfterAdd( Database db, PwEntry entry, IKp2aApp app, OnOperationFinishedHandler operationFinishedHandler):base(app, operationFinishedHandler) {
|
||||
public AfterAdd(Activity activity, Database db, PwEntry entry, IKp2aApp app, OnFinish finish):base(activity, finish) {
|
||||
_db = db;
|
||||
_entry = entry;
|
||||
_app = app;
|
||||
|
@@ -23,7 +23,7 @@ using KeePassLib;
|
||||
namespace keepass2android
|
||||
{
|
||||
|
||||
public class AddGroup : OperationWithFinishHandler {
|
||||
public class AddGroup : RunnableOnFinish {
|
||||
internal Database Db
|
||||
{
|
||||
get { return _app.CurrentDb; }
|
||||
@@ -38,16 +38,18 @@ namespace keepass2android
|
||||
public PwGroup Group;
|
||||
internal PwGroup Parent;
|
||||
protected bool DontSave;
|
||||
|
||||
|
||||
public static AddGroup GetInstance(IKp2aApp app, string name, int iconid, PwUuid groupCustomIconId, PwGroup parent, OnOperationFinishedHandler operationFinishedHandler, bool dontSave) {
|
||||
return new AddGroup(app, name, iconid, groupCustomIconId, parent, operationFinishedHandler, dontSave);
|
||||
readonly Activity _ctx;
|
||||
|
||||
|
||||
public static AddGroup GetInstance(Activity ctx, IKp2aApp app, string name, int iconid, PwUuid groupCustomIconId, PwGroup parent, OnFinish finish, bool dontSave) {
|
||||
return new AddGroup(ctx, app, name, iconid, groupCustomIconId, parent, finish, dontSave);
|
||||
}
|
||||
|
||||
|
||||
private AddGroup(IKp2aApp app, String name, int iconid, PwUuid groupCustomIconId, PwGroup parent, OnOperationFinishedHandler operationFinishedHandler, bool dontSave)
|
||||
: base(app, operationFinishedHandler)
|
||||
private AddGroup(Activity ctx, IKp2aApp app, String name, int iconid, PwUuid groupCustomIconId, PwGroup parent, OnFinish finish, bool dontSave)
|
||||
: base(ctx, finish)
|
||||
{
|
||||
_ctx = ctx;
|
||||
_name = name;
|
||||
_iconId = iconid;
|
||||
_groupCustomIconId = groupCustomIconId;
|
||||
@@ -55,7 +57,7 @@ namespace keepass2android
|
||||
DontSave = dontSave;
|
||||
_app = app;
|
||||
|
||||
_operationFinishedHandler = new AfterAdd(_app, this, operationFinishedHandler);
|
||||
_onFinishToRun = new AfterAdd(ctx, this, OnFinishToRun);
|
||||
}
|
||||
|
||||
|
||||
@@ -72,15 +74,15 @@ namespace keepass2android
|
||||
_app.CurrentDb.Elements.Add(Group);
|
||||
|
||||
// Commit to disk
|
||||
SaveDb save = new SaveDb(_app, _app.CurrentDb, operationFinishedHandler, DontSave, null);
|
||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun, DontSave);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.Run();
|
||||
}
|
||||
|
||||
private class AfterAdd : OnOperationFinishedHandler {
|
||||
private class AfterAdd : OnFinish {
|
||||
readonly AddGroup _addGroup;
|
||||
|
||||
public AfterAdd(IKp2aApp app, AddGroup addGroup,OnOperationFinishedHandler operationFinishedHandler): base(app, operationFinishedHandler) {
|
||||
public AfterAdd(Activity activity, AddGroup addGroup,OnFinish finish): base(activity, finish) {
|
||||
_addGroup = addGroup;
|
||||
}
|
||||
|
||||
|
@@ -26,7 +26,7 @@ using KeePassLib.Utility;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public class AddTemplateEntries : OperationWithFinishHandler {
|
||||
public class AddTemplateEntries : RunnableOnFinish {
|
||||
|
||||
public class TemplateEntry
|
||||
{
|
||||
@@ -130,13 +130,15 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
private readonly IKp2aApp _app;
|
||||
|
||||
public AddTemplateEntries(IKp2aApp app, OnOperationFinishedHandler operationFinishedHandler)
|
||||
: base(app, operationFinishedHandler)
|
||||
private readonly Activity _ctx;
|
||||
|
||||
public AddTemplateEntries(Activity ctx, IKp2aApp app, OnFinish finish)
|
||||
: base(ctx, finish)
|
||||
{
|
||||
_app = app;
|
||||
_ctx = ctx;
|
||||
_app = app;
|
||||
|
||||
//_operationFinishedHandler = new AfterAdd(this, operationFinishedHandler);
|
||||
//_onFinishToRun = new AfterAdd(this, OnFinishToRun);
|
||||
}
|
||||
|
||||
public static readonly List<TemplateEntry> TemplateEntries = new List<TemplateEntry>()
|
||||
@@ -311,7 +313,7 @@ namespace keepass2android
|
||||
_app.DirtyGroups.Add(templateGroup);
|
||||
|
||||
// Commit to disk
|
||||
SaveDb save = new SaveDb(_app, _app.CurrentDb, operationFinishedHandler);
|
||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.Run();
|
||||
}
|
||||
@@ -335,6 +337,7 @@ namespace keepass2android
|
||||
_app.DirtyGroups.Add(_app.CurrentDb.KpDatabase.RootGroup);
|
||||
_app.CurrentDb.GroupsById[templateGroup.Uuid] = templateGroup;
|
||||
_app.CurrentDb.Elements.Add(templateGroup);
|
||||
|
||||
}
|
||||
addedEntries = new List<PwEntry>();
|
||||
|
||||
@@ -366,11 +369,11 @@ namespace keepass2android
|
||||
return entry;
|
||||
}
|
||||
|
||||
private class AfterAdd : OnOperationFinishedHandler {
|
||||
private class AfterAdd : OnFinish {
|
||||
private readonly Database _db;
|
||||
private readonly List<PwEntry> _entries;
|
||||
|
||||
public AfterAdd(IKp2aApp app, Database db, List<PwEntry> entries, OnOperationFinishedHandler operationFinishedHandler):base(app, operationFinishedHandler) {
|
||||
public AfterAdd(Activity activity, Database db, List<PwEntry> entries, OnFinish finish):base(activity, finish) {
|
||||
_db = db;
|
||||
_entries = entries;
|
||||
|
||||
|
@@ -16,8 +16,8 @@ namespace keepass2android.database.edit
|
||||
{
|
||||
public class CopyEntry: AddEntry
|
||||
{
|
||||
public CopyEntry(IKp2aApp app, PwEntry entry, OnOperationFinishedHandler operationFinishedHandler, Database db)
|
||||
: base(db, app, CreateCopy(entry, app), entry.ParentGroup, operationFinishedHandler)
|
||||
public CopyEntry(Activity ctx, IKp2aApp app, PwEntry entry, OnFinish finish, Database db)
|
||||
: base(ctx, db, app, CreateCopy(entry, app), entry.ParentGroup, finish)
|
||||
{
|
||||
}
|
||||
|
||||
|
@@ -26,24 +26,27 @@ using KeePassLib.Keys;
|
||||
namespace keepass2android
|
||||
{
|
||||
|
||||
public class CreateDb : OperationWithFinishHandler {
|
||||
public class CreateDb : RunnableOnFinish {
|
||||
private readonly IOConnectionInfo _ioc;
|
||||
private readonly bool _dontSave;
|
||||
private readonly Activity _ctx;
|
||||
private readonly IKp2aApp _app;
|
||||
private CompositeKey _key;
|
||||
private readonly bool _makeCurrent;
|
||||
|
||||
public CreateDb(IKp2aApp app, Activity ctx, IOConnectionInfo ioc, OnOperationFinishedHandler operationFinishedHandler, bool dontSave, bool makeCurrent): base(app, operationFinishedHandler) {
|
||||
_ioc = ioc;
|
||||
public CreateDb(IKp2aApp app, Activity ctx, IOConnectionInfo ioc, OnFinish finish, bool dontSave, bool makeCurrent): base(ctx, finish) {
|
||||
_ctx = ctx;
|
||||
_ioc = ioc;
|
||||
_dontSave = dontSave;
|
||||
_makeCurrent = makeCurrent;
|
||||
_app = app;
|
||||
}
|
||||
|
||||
public CreateDb(IKp2aApp app, Activity ctx, IOConnectionInfo ioc, OnOperationFinishedHandler operationFinishedHandler, bool dontSave, CompositeKey key, bool makeCurrent)
|
||||
: base(app, operationFinishedHandler)
|
||||
public CreateDb(IKp2aApp app, Activity ctx, IOConnectionInfo ioc, OnFinish finish, bool dontSave, CompositeKey key, bool makeCurrent)
|
||||
: base(ctx, finish)
|
||||
{
|
||||
_ioc = ioc;
|
||||
_ctx = ctx;
|
||||
_ioc = ioc;
|
||||
_dontSave = dontSave;
|
||||
_app = app;
|
||||
_key = key;
|
||||
@@ -74,19 +77,19 @@ namespace keepass2android
|
||||
db.SearchHelper = new SearchDbHelper(_app);
|
||||
|
||||
// Add a couple default groups
|
||||
AddGroup internet = AddGroup.GetInstance(_app, "Internet", 1, null, db.KpDatabase.RootGroup, null, true);
|
||||
AddGroup internet = AddGroup.GetInstance(_ctx, _app, "Internet", 1, null, db.KpDatabase.RootGroup, null, true);
|
||||
internet.Run();
|
||||
AddGroup email = AddGroup.GetInstance(_app, "eMail", 19, null, db.KpDatabase.RootGroup, null, true);
|
||||
AddGroup email = AddGroup.GetInstance(_ctx, _app, "eMail", 19, null, db.KpDatabase.RootGroup, null, true);
|
||||
email.Run();
|
||||
|
||||
List<PwEntry> addedEntries;
|
||||
AddTemplateEntries addTemplates = new AddTemplateEntries(_app, null);
|
||||
AddTemplateEntries addTemplates = new AddTemplateEntries(_ctx, _app, null);
|
||||
addTemplates.AddTemplates(out addedEntries);
|
||||
|
||||
// Commit changes
|
||||
SaveDb save = new SaveDb(_app, db, operationFinishedHandler, _dontSave, null);
|
||||
SaveDb save = new SaveDb(_ctx, _app, db, OnFinishToRun, _dontSave);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
_operationFinishedHandler = null;
|
||||
_onFinishToRun = null;
|
||||
save.Run();
|
||||
|
||||
db.UpdateGlobals();
|
||||
|
@@ -1,39 +0,0 @@
|
||||
using Java.Lang;
|
||||
|
||||
namespace keepass2android;
|
||||
|
||||
public interface IDatabaseModificationWatcher
|
||||
{
|
||||
void BeforeModifyDatabases();
|
||||
void AfterModifyDatabases();
|
||||
}
|
||||
|
||||
public class NullDatabaseModificationWatcher : IDatabaseModificationWatcher
|
||||
{
|
||||
public void BeforeModifyDatabases() { }
|
||||
public void AfterModifyDatabases() { }
|
||||
}
|
||||
|
||||
public class BackgroundDatabaseModificationLocker(IKp2aApp app) : IDatabaseModificationWatcher
|
||||
{
|
||||
public void BeforeModifyDatabases()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (app.DatabasesBackgroundModificationLock.TryEnterWriteLock(TimeSpan.FromSeconds(0.1)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (Java.Lang.Thread.Interrupted())
|
||||
{
|
||||
throw new InterruptedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AfterModifyDatabases()
|
||||
{
|
||||
app.DatabasesBackgroundModificationLock.ExitWriteLock();
|
||||
}
|
||||
}
|
@@ -29,8 +29,8 @@ namespace keepass2android
|
||||
private readonly PwEntry _entry;
|
||||
private UiStringKey _statusMessage;
|
||||
|
||||
public DeleteEntry(IKp2aApp app, PwEntry entry, OnOperationFinishedHandler operationFinishedHandler):base(operationFinishedHandler, app) {
|
||||
|
||||
public DeleteEntry(Activity activiy, IKp2aApp app, PwEntry entry, OnFinish finish):base(activiy, finish, app) {
|
||||
Ctx = activiy;
|
||||
Db = app.FindDatabaseForElement(entry);
|
||||
_entry = entry;
|
||||
|
||||
|
@@ -29,25 +29,25 @@ namespace keepass2android
|
||||
private PwGroup _group;
|
||||
protected bool DontSave;
|
||||
|
||||
public DeleteGroup(Activity activity, IKp2aApp app, PwGroup group, OnOperationFinishedHandler operationFinishedHandler)
|
||||
: base(operationFinishedHandler, app)
|
||||
public DeleteGroup(Activity activity, IKp2aApp app, PwGroup group, OnFinish finish)
|
||||
: base(activity, finish, app)
|
||||
{
|
||||
SetMembers(app, group, false);
|
||||
SetMembers(activity, app, group, false);
|
||||
}
|
||||
/*
|
||||
public DeleteGroup(Context ctx, Database db, PwGroup group, Activity act, OnOperationFinishedHandler operationFinishedHandler, bool dontSave)
|
||||
: base(operationFinishedHandler)
|
||||
public DeleteGroup(Context ctx, Database db, PwGroup group, Activity act, OnFinish finish, bool dontSave)
|
||||
: base(finish)
|
||||
{
|
||||
SetMembers(ctx, db, group, act, dontSave);
|
||||
}
|
||||
|
||||
public DeleteGroup(Context ctx, Database db, PwGroup group, OnOperationFinishedHandler operationFinishedHandler, bool dontSave):base(operationFinishedHandler) {
|
||||
public DeleteGroup(Context ctx, Database db, PwGroup group, OnFinish finish, bool dontSave):base(finish) {
|
||||
SetMembers(ctx, db, group, null, dontSave);
|
||||
}
|
||||
*/
|
||||
private void SetMembers(IKp2aApp app, PwGroup group, bool dontSave)
|
||||
private void SetMembers(Activity activity, IKp2aApp app, PwGroup group, bool dontSave)
|
||||
{
|
||||
base.SetMembers(app.FindDatabaseForElement(group));
|
||||
base.SetMembers(activity, app.FindDatabaseForElement(group));
|
||||
|
||||
_group = group;
|
||||
DontSave = dontSave;
|
||||
|
@@ -12,11 +12,11 @@ namespace keepass2android
|
||||
private readonly List<IStructureItem> _elementsToDelete;
|
||||
private readonly bool _canRecycle;
|
||||
|
||||
public DeleteMultipleItemsFromOneDatabase(Activity activity, Database db, List<IStructureItem> elementsToDelete, OnOperationFinishedHandler operationFinishedHandler, IKp2aApp app)
|
||||
: base(operationFinishedHandler, app)
|
||||
public DeleteMultipleItemsFromOneDatabase(Activity activity, Database db, List<IStructureItem> elementsToDelete, OnFinish finish, IKp2aApp app)
|
||||
: base(activity, finish, app)
|
||||
{
|
||||
_elementsToDelete = elementsToDelete;
|
||||
SetMembers(db);
|
||||
SetMembers(activity, db);
|
||||
|
||||
//determine once. The property is queried for each delete operation, but might return false
|
||||
//after one entry/group is deleted (and thus in recycle bin and thus can't be recycled anymore)
|
||||
|
@@ -6,10 +6,10 @@ using KeePassLib;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public abstract class DeleteRunnable : OperationWithFinishHandler
|
||||
public abstract class DeleteRunnable : RunnableOnFinish
|
||||
{
|
||||
protected DeleteRunnable(OnOperationFinishedHandler operationFinishedHandler, IKp2aApp app)
|
||||
: base(app, operationFinishedHandler)
|
||||
protected DeleteRunnable(Activity activity, OnFinish finish, IKp2aApp app)
|
||||
: base(activity, finish)
|
||||
{
|
||||
App = app;
|
||||
}
|
||||
@@ -18,10 +18,11 @@ namespace keepass2android
|
||||
|
||||
protected Database Db;
|
||||
|
||||
|
||||
protected Activity Ctx;
|
||||
|
||||
protected void SetMembers( Database db)
|
||||
protected void SetMembers(Activity activity, Database db)
|
||||
{
|
||||
Ctx = activity;
|
||||
Db = db;
|
||||
}
|
||||
|
||||
@@ -130,18 +131,18 @@ namespace keepass2android
|
||||
(dlgSender, dlgEvt) =>
|
||||
{
|
||||
DeletePermanently = true;
|
||||
BlockingOperationStarter pt = new BlockingOperationStarter(App, this);
|
||||
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
||||
pt.Run();
|
||||
|
||||
},
|
||||
(dlgSender, dlgEvt) =>
|
||||
{
|
||||
DeletePermanently = false;
|
||||
BlockingOperationStarter pt = new BlockingOperationStarter(App, this);
|
||||
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
||||
pt.Run();
|
||||
},
|
||||
(dlgSender, dlgEvt) => { },
|
||||
messageSuffix);
|
||||
Ctx, messageSuffix);
|
||||
|
||||
|
||||
|
||||
@@ -152,12 +153,12 @@ namespace keepass2android
|
||||
QuestionNoRecycleResourceId,
|
||||
(dlgSender, dlgEvt) =>
|
||||
{
|
||||
BlockingOperationStarter pt = new BlockingOperationStarter(App, this);
|
||||
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
||||
pt.Run();
|
||||
},
|
||||
null,
|
||||
(dlgSender, dlgEvt) => { },
|
||||
messageSuffix);
|
||||
Ctx, messageSuffix);
|
||||
|
||||
|
||||
}
|
||||
@@ -214,7 +215,7 @@ namespace keepass2android
|
||||
Android.Util.Log.Debug("KP2A", "Calling PerformDelete..");
|
||||
PerformDelete(touchedGroups, permanentlyDeletedGroups);
|
||||
|
||||
_operationFinishedHandler = new ActionOnOperationFinished(App,(success, message, context) =>
|
||||
_onFinishToRun = new ActionOnFinish(ActiveActivity,(success, message, activity) =>
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
@@ -235,10 +236,10 @@ namespace keepass2android
|
||||
// Let's not bother recovering from a failure to save. It is too much work.
|
||||
App.Lock(false, false);
|
||||
}
|
||||
}, operationFinishedHandler);
|
||||
}, OnFinishToRun);
|
||||
|
||||
// Commit database
|
||||
SaveDb save = new SaveDb( App, Db, operationFinishedHandler, false, null);
|
||||
SaveDb save = new SaveDb(Ctx, App, Db, OnFinishToRun, false);
|
||||
save.ShowDatabaseIocInStatus = ShowDatabaseIocInStatus;
|
||||
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
|
@@ -23,7 +23,7 @@ using KeePassLib;
|
||||
namespace keepass2android
|
||||
{
|
||||
|
||||
public class EditGroup : OperationWithFinishHandler {
|
||||
public class EditGroup : RunnableOnFinish {
|
||||
internal Database Db
|
||||
{
|
||||
get { return _app.FindDatabaseForElement(Group); }
|
||||
@@ -36,17 +36,19 @@ namespace keepass2android
|
||||
private readonly PwIcon _iconId;
|
||||
private readonly PwUuid _customIconId;
|
||||
internal PwGroup Group;
|
||||
readonly Activity _ctx;
|
||||
|
||||
public EditGroup(IKp2aApp app, String name, PwIcon iconid, PwUuid customIconId, PwGroup group, OnOperationFinishedHandler operationFinishedHandler)
|
||||
: base(app, operationFinishedHandler)
|
||||
public EditGroup(Activity ctx, IKp2aApp app, String name, PwIcon iconid, PwUuid customIconId, PwGroup group, OnFinish finish)
|
||||
: base(ctx, finish)
|
||||
{
|
||||
_ctx = ctx;
|
||||
_name = name;
|
||||
_iconId = iconid;
|
||||
Group = group;
|
||||
_customIconId = customIconId;
|
||||
_app = app;
|
||||
|
||||
_operationFinishedHandler = new AfterEdit(app, this, operationFinishedHandler);
|
||||
_onFinishToRun = new AfterEdit(ctx, this, OnFinishToRun);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,16 +60,16 @@ namespace keepass2android
|
||||
Group.Touch(true);
|
||||
|
||||
// Commit to disk
|
||||
SaveDb save = new SaveDb(_app, Db, operationFinishedHandler);
|
||||
SaveDb save = new SaveDb(_ctx, _app, Db, OnFinishToRun);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.Run();
|
||||
}
|
||||
|
||||
private class AfterEdit : OnOperationFinishedHandler {
|
||||
private class AfterEdit : OnFinish {
|
||||
readonly EditGroup _editGroup;
|
||||
|
||||
public AfterEdit(IKp2aApp app, EditGroup editGroup, OnOperationFinishedHandler operationFinishedHandler)
|
||||
: base(app, operationFinishedHandler)
|
||||
public AfterEdit(Activity ctx, EditGroup editGroup, OnFinish finish)
|
||||
: base(ctx, finish)
|
||||
{
|
||||
_editGroup = editGroup;
|
||||
}
|
||||
|
@@ -21,10 +21,10 @@ using Android.App;
|
||||
namespace keepass2android
|
||||
{
|
||||
|
||||
public abstract class FileOnFinish : OnOperationFinishedHandler {
|
||||
public abstract class FileOnFinish : OnFinish {
|
||||
private String _filename = "";
|
||||
|
||||
protected FileOnFinish(IKp2aApp app, FileOnFinish operationFinishedHandler):base(app, operationFinishedHandler) {
|
||||
protected FileOnFinish(Activity activity, FileOnFinish finish):base(activity, finish) {
|
||||
}
|
||||
|
||||
public string Filename
|
||||
|
@@ -1,13 +0,0 @@
|
||||
namespace keepass2android;
|
||||
|
||||
// A context instance can be the instance of an Activity. Even if the activity is recreated (due to a configuration change, for example), the instance id must remain the same
|
||||
// but it must be different for other activities/services or if the activity is finished and then starts again.
|
||||
// We want to be able to perform actions on a context instance, even though that instance might not live at the time when we want to perform the action.
|
||||
// In that case, we want to be able to register the action such that it is performed when the activity is recreated.
|
||||
public interface IContextInstanceIdProvider
|
||||
{
|
||||
|
||||
int ContextInstanceId { get; }
|
||||
|
||||
|
||||
}
|
@@ -21,88 +21,60 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Android.App;
|
||||
using Android.OS;
|
||||
using KeePass.Util;
|
||||
using keepass2android.database.edit;
|
||||
using keepass2android.Io;
|
||||
using KeePassLib;
|
||||
using KeePassLib.Keys;
|
||||
using KeePassLib.Serialization;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public class LoadDb : OperationWithFinishHandler {
|
||||
public class LoadDb : RunnableOnFinish {
|
||||
private readonly IOConnectionInfo _ioc;
|
||||
private readonly Task<MemoryStream> _databaseData;
|
||||
private readonly CompositeKey _compositeKey;
|
||||
private readonly string? _keyfileOrProvider;
|
||||
private readonly string _keyfileOrProvider;
|
||||
private readonly IKp2aApp _app;
|
||||
private readonly bool _rememberKeyfile;
|
||||
IDatabaseFormat _format;
|
||||
|
||||
public bool DoNotSetStatusLoggerMessage = false;
|
||||
|
||||
|
||||
public LoadDb(IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, CompositeKey compositeKey,
|
||||
string keyfileOrProvider, OnOperationFinishedHandler operationFinishedHandler,
|
||||
bool updateLastUsageTimestamp, bool makeCurrent, IDatabaseModificationWatcher modificationWatcher = null): base(app, operationFinishedHandler)
|
||||
|
||||
public LoadDb(Activity activity, IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, CompositeKey compositeKey, String keyfileOrProvider, OnFinish finish, bool updateLastUsageTimestamp, bool makeCurrent): base(activity, finish)
|
||||
{
|
||||
_modificationWatcher = modificationWatcher ?? new NullDatabaseModificationWatcher();
|
||||
_app = app;
|
||||
_app = app;
|
||||
_ioc = ioc;
|
||||
_databaseData = databaseData;
|
||||
_compositeKey = compositeKey;
|
||||
_keyfileOrProvider = keyfileOrProvider;
|
||||
_updateLastUsageTimestamp = updateLastUsageTimestamp;
|
||||
_makeCurrent = makeCurrent;
|
||||
_rememberKeyfile = app.GetBooleanPreference(PreferenceKey.remember_keyfile);
|
||||
}
|
||||
|
||||
|
||||
_rememberKeyfile = app.GetBooleanPreference(PreferenceKey.remember_keyfile);
|
||||
}
|
||||
|
||||
protected bool success = false;
|
||||
private bool _updateLastUsageTimestamp;
|
||||
private readonly bool _makeCurrent;
|
||||
private readonly IDatabaseModificationWatcher _modificationWatcher;
|
||||
|
||||
public override void Run()
|
||||
public override void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
//make sure the file data is stored in the recent files list even if loading fails
|
||||
SaveFileData(_ioc, _keyfileOrProvider);
|
||||
|
||||
|
||||
var fileStorage = _app.GetFileStorage(_ioc);
|
||||
|
||||
RequiresSubsequentSync = false;
|
||||
SaveFileData(_ioc, _keyfileOrProvider);
|
||||
|
||||
|
||||
if (!DoNotSetStatusLoggerMessage)
|
||||
{
|
||||
StatusLogger.UpdateMessage(UiStringKey.loading_database);
|
||||
}
|
||||
|
||||
StatusLogger.UpdateMessage(UiStringKey.loading_database);
|
||||
//get the stream data into a single stream variable (databaseStream) regardless whether its preloaded or not:
|
||||
MemoryStream preloadedMemoryStream = _databaseData == null ? null : _databaseData.Result;
|
||||
MemoryStream databaseStream;
|
||||
if (preloadedMemoryStream != null)
|
||||
{
|
||||
//note: if the stream has been loaded already, we don't need to trigger another sync later on
|
||||
databaseStream = preloadedMemoryStream;
|
||||
}
|
||||
else
|
||||
if (preloadedMemoryStream != null)
|
||||
databaseStream = preloadedMemoryStream;
|
||||
else
|
||||
{
|
||||
if (_app.SyncInBackgroundPreference && fileStorage is CachingFileStorage cachingFileStorage &&
|
||||
cachingFileStorage.IsCached(_ioc))
|
||||
{
|
||||
cachingFileStorage.IsOffline = true;
|
||||
//no warning. We'll trigger a sync later.
|
||||
cachingFileStorage.TriggerWarningWhenFallingBackToCache = false;
|
||||
RequiresSubsequentSync = true;
|
||||
|
||||
}
|
||||
using (Stream s = fileStorage.OpenFileForRead(_ioc))
|
||||
using (Stream s = _app.GetFileStorage(_ioc).OpenFileForRead(_ioc))
|
||||
{
|
||||
databaseStream = new MemoryStream();
|
||||
s.CopyTo(databaseStream);
|
||||
@@ -110,13 +82,8 @@ namespace keepass2android
|
||||
}
|
||||
}
|
||||
|
||||
if (!StatusLogger.ContinueWork())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//ok, try to load the database. Let's start with Kdbx format and retry later if that is the wrong guess:
|
||||
_format = new KdbxDatabaseFormat(KdbxDatabaseFormat.GetFormatToUse(fileStorage.GetFileExtension(_ioc)));
|
||||
_format = new KdbxDatabaseFormat(KdbxDatabaseFormat.GetFormatToUse(_app.GetFileStorage(_ioc).GetFileExtension(_ioc)));
|
||||
TryLoad(databaseStream);
|
||||
|
||||
|
||||
@@ -153,13 +120,7 @@ namespace keepass2android
|
||||
Finish(false, _app.GetResourceString(UiStringKey.DuplicateUuidsError) + " " + ExceptionUtil.GetErrorMessage(e) + _app.GetResourceString(UiStringKey.DuplicateUuidsErrorAdditional), false, Exception);
|
||||
return;
|
||||
}
|
||||
catch (Java.Lang.InterruptedException)
|
||||
{
|
||||
Kp2aLog.Log("Load interrupted");
|
||||
//close without Finish()
|
||||
return;
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (Exception e)
|
||||
{
|
||||
if (!(e is InvalidCompositeKeyException))
|
||||
Kp2aLog.LogUnexpectedError(e);
|
||||
@@ -170,15 +131,14 @@ namespace keepass2android
|
||||
|
||||
}
|
||||
|
||||
public bool RequiresSubsequentSync { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Holds the exception which was thrown during execution (if any)
|
||||
/// </summary>
|
||||
public Exception Exception { get; set; }
|
||||
|
||||
Database TryLoad(MemoryStream databaseStream)
|
||||
{
|
||||
Kp2aLog.Log("LoadDb: Copying database in memory");
|
||||
//create a copy of the stream so we can try again if we get an exception which indicates we should change parameters
|
||||
//This is not optimal in terms of (short-time) memory usage but is hard to avoid because the Keepass library closes streams also in case of errors.
|
||||
//Alternatives would involve increased traffic (if file is on remote) and slower loading times, so this seems to be the best choice.
|
||||
@@ -187,21 +147,16 @@ namespace keepass2android
|
||||
workingCopy.Seek(0, SeekOrigin.Begin);
|
||||
//reset stream if we need to reuse it later:
|
||||
databaseStream.Seek(0, SeekOrigin.Begin);
|
||||
if (!StatusLogger.ContinueWork())
|
||||
{
|
||||
throw new Java.Lang.InterruptedException();
|
||||
}
|
||||
|
||||
//now let's go:
|
||||
Kp2aLog.Log("LoadDb: Ready to start loading");
|
||||
//now let's go:
|
||||
try
|
||||
{
|
||||
Database newDb =
|
||||
_app.LoadDatabase(_ioc, workingCopy, _compositeKey, StatusLogger, _format, _makeCurrent, _modificationWatcher);
|
||||
Kp2aLog.Log("LoadDB OK");
|
||||
|
||||
{
|
||||
Database newDb = _app.LoadDatabase(_ioc, workingCopy, _compositeKey, StatusLogger, _format, _makeCurrent);
|
||||
Kp2aLog.Log("LoadDB OK");
|
||||
|
||||
Finish(true, _format.SuccessMessage);
|
||||
return newDb;
|
||||
}
|
||||
return newDb;
|
||||
}
|
||||
catch (OldFormatException)
|
||||
{
|
||||
_format = new KdbDatabaseFormat(_app);
|
||||
|
@@ -10,16 +10,18 @@ using KeePassLib.Interfaces;
|
||||
|
||||
namespace keepass2android.database.edit
|
||||
{
|
||||
public class MoveElements: OperationWithFinishHandler
|
||||
public class MoveElements: RunnableOnFinish
|
||||
{
|
||||
private readonly List<IStructureItem> _elementsToMove;
|
||||
private readonly PwGroup _targetGroup;
|
||||
private readonly IKp2aApp _app;
|
||||
private readonly Activity _ctx;
|
||||
private readonly IKp2aApp _app;
|
||||
|
||||
public MoveElements(List<IStructureItem> elementsToMove, PwGroup targetGroup,IKp2aApp app, OnOperationFinishedHandler operationFinishedHandler) : base(app, operationFinishedHandler)
|
||||
public MoveElements(List<IStructureItem> elementsToMove, PwGroup targetGroup, Activity ctx, IKp2aApp app, OnFinish finish) : base(ctx, finish)
|
||||
{
|
||||
_elementsToMove = elementsToMove;
|
||||
_targetGroup = targetGroup;
|
||||
_ctx = ctx;
|
||||
_app = app;
|
||||
}
|
||||
|
||||
@@ -121,24 +123,24 @@ namespace keepass2android.database.edit
|
||||
|
||||
int indexToSave = 0;
|
||||
bool allSavesSuccess = true;
|
||||
void ContinueSave(bool success, string message, Context activeActivity)
|
||||
void ContinueSave(bool success, string message, Activity activeActivity)
|
||||
{
|
||||
allSavesSuccess &= success;
|
||||
indexToSave++;
|
||||
if (indexToSave == allDatabasesToSave.Count)
|
||||
{
|
||||
operationFinishedHandler.SetResult(allSavesSuccess);
|
||||
operationFinishedHandler.Run();
|
||||
OnFinishToRun.SetResult(allSavesSuccess);
|
||||
OnFinishToRun.Run();
|
||||
return;
|
||||
}
|
||||
SaveDb saveDb = new SaveDb( _app, allDatabasesToSave[indexToSave], new ActionOnOperationFinished(_app, ContinueSave), false, null);
|
||||
SaveDb saveDb = new SaveDb(_ctx, _app, allDatabasesToSave[indexToSave], new ActionOnFinish(activeActivity, ContinueSave), false);
|
||||
saveDb.SetStatusLogger(StatusLogger);
|
||||
saveDb.ShowDatabaseIocInStatus = allDatabasesToSave.Count > 1;
|
||||
saveDb.Run();
|
||||
}
|
||||
|
||||
|
||||
SaveDb save = new SaveDb(_app, allDatabasesToSave[0], new ActionOnOperationFinished(_app, ContinueSave), false, null);
|
||||
SaveDb save = new SaveDb(_ctx, _app, allDatabasesToSave[0], new ActionOnFinish(ActiveActivity, ContinueSave), false);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.ShowDatabaseIocInStatus = allDatabasesToSave.Count > 1;
|
||||
save.Run();
|
||||
|
@@ -22,16 +22,10 @@ using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Widget;
|
||||
using Google.Android.Material.Dialog;
|
||||
using KeePassLib.Interfaces;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public interface IActiveContextProvider
|
||||
{
|
||||
Context ActiveContext { get; }
|
||||
}
|
||||
|
||||
public abstract class OnOperationFinishedHandler
|
||||
public abstract class OnFinish
|
||||
{
|
||||
protected bool Success;
|
||||
protected String Message;
|
||||
@@ -43,41 +37,63 @@ namespace keepass2android
|
||||
set;
|
||||
}
|
||||
|
||||
protected Context ActiveContext
|
||||
{
|
||||
get
|
||||
{
|
||||
return _activeContextProvider?.ActiveContext;
|
||||
}
|
||||
}
|
||||
|
||||
protected OnOperationFinishedHandler NextOnOperationFinishedHandler;
|
||||
protected OnFinish BaseOnFinish;
|
||||
protected Handler Handler;
|
||||
private IKp2aStatusLogger _statusLogger = new Kp2aNullStatusLogger(); //default: no logging but not null -> can be used whenever desired
|
||||
private readonly IActiveContextProvider _activeContextProvider;
|
||||
private ProgressDialogStatusLogger _statusLogger = new ProgressDialogStatusLogger(); //default: no logging but not null -> can be used whenever desired
|
||||
private Activity _activeActivity, _previouslyActiveActivity;
|
||||
|
||||
public IKp2aStatusLogger StatusLogger
|
||||
|
||||
public ProgressDialogStatusLogger StatusLogger
|
||||
{
|
||||
get { return _statusLogger; }
|
||||
set { _statusLogger = value; }
|
||||
} protected OnOperationFinishedHandler(IActiveContextProvider activeContextProvider, Handler handler)
|
||||
{
|
||||
_activeContextProvider = activeContextProvider;
|
||||
NextOnOperationFinishedHandler = null;
|
||||
Handler = handler;
|
||||
}
|
||||
|
||||
protected OnOperationFinishedHandler(IActiveContextProvider activeContextProvider, OnOperationFinishedHandler operationFinishedHandler, Handler handler)
|
||||
public Activity ActiveActivity
|
||||
{
|
||||
get { return _activeActivity; }
|
||||
set
|
||||
{
|
||||
if (_activeActivity != null && _activeActivity != _previouslyActiveActivity)
|
||||
{
|
||||
_previouslyActiveActivity = _activeActivity;
|
||||
|
||||
}
|
||||
_activeActivity = value;
|
||||
if (BaseOnFinish != null)
|
||||
{
|
||||
BaseOnFinish.ActiveActivity = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Activity PreviouslyActiveActivity
|
||||
{
|
||||
get { return _previouslyActiveActivity; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected OnFinish(Activity activeActivity, Handler handler)
|
||||
{
|
||||
ActiveActivity = activeActivity;
|
||||
BaseOnFinish = null;
|
||||
Handler = handler;
|
||||
|
||||
}
|
||||
|
||||
protected OnFinish(Activity activeActivity, OnFinish finish, Handler handler)
|
||||
{
|
||||
_activeContextProvider = activeContextProvider;
|
||||
NextOnOperationFinishedHandler = operationFinishedHandler;
|
||||
ActiveActivity = activeActivity;
|
||||
BaseOnFinish = finish;
|
||||
Handler = handler;
|
||||
}
|
||||
|
||||
protected OnOperationFinishedHandler(IActiveContextProvider activeContextProvider, OnOperationFinishedHandler operationFinishedHandler)
|
||||
{
|
||||
_activeContextProvider = activeContextProvider;
|
||||
NextOnOperationFinishedHandler = operationFinishedHandler;
|
||||
protected OnFinish(Activity activeActivity, OnFinish finish)
|
||||
{
|
||||
ActiveActivity = activeActivity;
|
||||
BaseOnFinish = finish;
|
||||
Handler = null;
|
||||
}
|
||||
|
||||
@@ -94,19 +110,14 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
public virtual void Run() {
|
||||
if (NextOnOperationFinishedHandler == null) return;
|
||||
if (BaseOnFinish == null) return;
|
||||
// Pass on result on call finish
|
||||
NextOnOperationFinishedHandler.SetResult(Success, Message, ImportantMessage, Exception);
|
||||
|
||||
var handler = Handler ?? NextOnOperationFinishedHandler.Handler ?? null;
|
||||
|
||||
if (handler != null ) {
|
||||
handler.Post(() =>
|
||||
{
|
||||
NextOnOperationFinishedHandler.Run();
|
||||
});
|
||||
BaseOnFinish.SetResult(Success, Message, ImportantMessage, Exception);
|
||||
|
||||
if ( Handler != null ) {
|
||||
Handler.Post(BaseOnFinish.Run);
|
||||
} else {
|
||||
NextOnOperationFinishedHandler.Run();
|
||||
BaseOnFinish.Run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +128,7 @@ namespace keepass2android
|
||||
public static void DisplayMessage(Context ctx, string message, bool makeDialog)
|
||||
{
|
||||
if ( !String.IsNullOrEmpty(message) ) {
|
||||
Kp2aLog.Log("OnOperationFinishedHandler message: " + message);
|
||||
Kp2aLog.Log("OnFinish message: " + message);
|
||||
if (makeDialog && ctx != null)
|
||||
{
|
||||
try
|
||||
@@ -141,4 +152,3 @@ namespace keepass2android
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
|
||||
|
||||
Keepass2Android is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Keepass2Android 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using KeePassLib.Interfaces;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
|
||||
public abstract class OperationWithFinishHandler {
|
||||
|
||||
protected OnOperationFinishedHandler _operationFinishedHandler;
|
||||
public IKp2aStatusLogger StatusLogger = new Kp2aNullStatusLogger(); //default: empty but not null
|
||||
private IActiveContextProvider _activeContextProvider;
|
||||
|
||||
protected OperationWithFinishHandler(IActiveContextProvider activeContextProvider, OnOperationFinishedHandler operationFinishedHandler)
|
||||
{
|
||||
_activeContextProvider = activeContextProvider;
|
||||
_operationFinishedHandler = operationFinishedHandler;
|
||||
}
|
||||
|
||||
public OnOperationFinishedHandler operationFinishedHandler
|
||||
{
|
||||
get { return _operationFinishedHandler; }
|
||||
set { _operationFinishedHandler = value; }
|
||||
}
|
||||
|
||||
|
||||
protected void Finish(bool result, String message, bool importantMessage = false, Exception exception = null) {
|
||||
if ( operationFinishedHandler != null ) {
|
||||
operationFinishedHandler.SetResult(result, message, importantMessage, exception);
|
||||
operationFinishedHandler.Run();
|
||||
}
|
||||
}
|
||||
|
||||
protected void Finish(bool result) {
|
||||
if ( operationFinishedHandler != null ) {
|
||||
operationFinishedHandler.SetResult(result);
|
||||
operationFinishedHandler.Run();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetStatusLogger(IKp2aStatusLogger statusLogger) {
|
||||
if (operationFinishedHandler != null)
|
||||
{
|
||||
operationFinishedHandler.StatusLogger = statusLogger;
|
||||
}
|
||||
StatusLogger = statusLogger;
|
||||
}
|
||||
|
||||
public abstract void Run();
|
||||
}
|
||||
}
|
||||
|
78
src/Kp2aBusinessLogic/database/edit/RunnableOnFinish.cs
Normal file
78
src/Kp2aBusinessLogic/database/edit/RunnableOnFinish.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
|
||||
|
||||
Keepass2Android is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Keepass2Android 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
|
||||
public abstract class RunnableOnFinish {
|
||||
|
||||
protected OnFinish _onFinishToRun;
|
||||
public ProgressDialogStatusLogger StatusLogger = new ProgressDialogStatusLogger(); //default: empty but not null
|
||||
private Activity _activeActivity;
|
||||
|
||||
protected RunnableOnFinish(Activity activeActivity, OnFinish finish)
|
||||
{
|
||||
_activeActivity = activeActivity;
|
||||
_onFinishToRun = finish;
|
||||
}
|
||||
|
||||
public OnFinish OnFinishToRun
|
||||
{
|
||||
get { return _onFinishToRun; }
|
||||
set { _onFinishToRun = value; }
|
||||
}
|
||||
|
||||
public Activity ActiveActivity
|
||||
{
|
||||
get { return _activeActivity; }
|
||||
set
|
||||
{
|
||||
_activeActivity = value;
|
||||
if (_onFinishToRun != null)
|
||||
_onFinishToRun.ActiveActivity = _activeActivity;
|
||||
}
|
||||
}
|
||||
|
||||
protected void Finish(bool result, String message, bool importantMessage = false, Exception exception = null) {
|
||||
if ( OnFinishToRun != null ) {
|
||||
OnFinishToRun.SetResult(result, message, importantMessage, exception);
|
||||
OnFinishToRun.Run();
|
||||
}
|
||||
}
|
||||
|
||||
protected void Finish(bool result) {
|
||||
if ( OnFinishToRun != null ) {
|
||||
OnFinishToRun.SetResult(result);
|
||||
OnFinishToRun.Run();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetStatusLogger(ProgressDialogStatusLogger status) {
|
||||
if (OnFinishToRun != null)
|
||||
{
|
||||
OnFinishToRun.StatusLogger = status;
|
||||
}
|
||||
StatusLogger = status;
|
||||
}
|
||||
|
||||
public abstract void Run();
|
||||
}
|
||||
}
|
||||
|
@@ -30,69 +30,57 @@ using keepass2android.Io;
|
||||
using Debug = System.Diagnostics.Debug;
|
||||
using Exception = System.Exception;
|
||||
using KeePass.Util;
|
||||
using Thread = System.Threading.Thread;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Save the database. If the file has changed, ask the user if he wants to overwrite or sync.
|
||||
/// </summary>
|
||||
|
||||
public class SaveDb : OperationWithFinishHandler {
|
||||
public class SaveDb : RunnableOnFinish {
|
||||
private readonly IKp2aApp _app;
|
||||
private readonly Database _db;
|
||||
private readonly bool _dontSave;
|
||||
private readonly IDatabaseModificationWatcher _modificationWatcher;
|
||||
private bool requiresSubsequentSync = false; //if true, we need to sync the file after saving.
|
||||
|
||||
public bool DoNotSetStatusLoggerMessage = false;
|
||||
|
||||
/// <summary>
|
||||
/// stream for reading the data from the original file. If this is set to a non-null value, we know we need to sync
|
||||
/// </summary>
|
||||
private readonly Stream _streamForOrigFile;
|
||||
|
||||
private readonly Context _ctx;
|
||||
private Java.Lang.Thread _workerThread;
|
||||
|
||||
public SaveDb(IKp2aApp app, Database db, OnOperationFinishedHandler operationFinishedHandler, bool dontSave, IDatabaseModificationWatcher modificationWatcher)
|
||||
: base(app, operationFinishedHandler)
|
||||
public SaveDb(Activity ctx, IKp2aApp app, Database db, OnFinish finish, bool dontSave)
|
||||
: base(ctx, finish)
|
||||
{
|
||||
_db = db;
|
||||
_ctx = ctx;
|
||||
_app = app;
|
||||
_dontSave = dontSave;
|
||||
_modificationWatcher = modificationWatcher ?? new NullDatabaseModificationWatcher();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for sync
|
||||
/// </summary>
|
||||
/// <param name="ctx"></param>
|
||||
/// <param name="app"></param>
|
||||
/// <param name="operationFinishedHandler"></param>
|
||||
/// <param name="finish"></param>
|
||||
/// <param name="dontSave"></param>
|
||||
/// <param name="streamForOrigFile">Stream for reading the data from the (changed) original location</param>
|
||||
public SaveDb(IKp2aApp app, OnOperationFinishedHandler operationFinishedHandler, Database db, bool dontSave, Stream streamForOrigFile, IDatabaseModificationWatcher modificationWatcher = null)
|
||||
: base(app, operationFinishedHandler)
|
||||
public SaveDb(Activity ctx, IKp2aApp app, OnFinish finish, Database db, bool dontSave, Stream streamForOrigFile)
|
||||
: base(ctx, finish)
|
||||
{
|
||||
_modificationWatcher = modificationWatcher ?? new NullDatabaseModificationWatcher();
|
||||
_db = db;
|
||||
_db = db;
|
||||
_ctx = ctx;
|
||||
_app = app;
|
||||
_dontSave = dontSave;
|
||||
_streamForOrigFile = streamForOrigFile;
|
||||
SyncInBackground = _app.SyncInBackgroundPreference;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public SaveDb(IKp2aApp app, Database db, OnOperationFinishedHandler operationFinishedHandler, IDatabaseModificationWatcher modificationWatcher = null)
|
||||
: base(app, operationFinishedHandler)
|
||||
public SaveDb(Activity ctx, IKp2aApp app, Database db, OnFinish finish)
|
||||
: base(ctx, finish)
|
||||
{
|
||||
|
||||
_modificationWatcher = modificationWatcher ?? new NullDatabaseModificationWatcher();
|
||||
_app = app;
|
||||
_ctx = ctx;
|
||||
_app = app;
|
||||
_db = db;
|
||||
_dontSave = false;
|
||||
SyncInBackground = _app.SyncInBackgroundPreference;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowDatabaseIocInStatus { get; set; }
|
||||
|
||||
@@ -115,42 +103,29 @@ namespace keepass2android
|
||||
if (ShowDatabaseIocInStatus)
|
||||
message += " (" + _app.GetFileStorage(_db.Ioc).GetDisplayName(_db.Ioc) + ")";
|
||||
|
||||
if (!DoNotSetStatusLoggerMessage)
|
||||
{
|
||||
StatusLogger.UpdateMessage(message);
|
||||
}
|
||||
|
||||
IOConnectionInfo ioc = _db.Ioc;
|
||||
StatusLogger.UpdateMessage(message);
|
||||
|
||||
IOConnectionInfo ioc = _db.Ioc;
|
||||
IFileStorage fileStorage = _app.GetFileStorage(ioc);
|
||||
|
||||
if (SyncInBackground && fileStorage is IOfflineSwitchable offlineSwitchable)
|
||||
{
|
||||
offlineSwitchable.IsOffline = true;
|
||||
//no warning. We'll trigger a sync later.
|
||||
offlineSwitchable.TriggerWarningWhenFallingBackToCache = false;
|
||||
requiresSubsequentSync = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (_streamForOrigFile == null)
|
||||
if (_streamForOrigFile == null)
|
||||
{
|
||||
if ((!_app.GetBooleanPreference(PreferenceKey.CheckForFileChangesOnSave))
|
||||
|| (_db.KpDatabase.HashOfFileOnDisk == null)) //first time saving
|
||||
{
|
||||
PerformSaveWithoutCheck(fileStorage, ioc);
|
||||
FinishWithSuccess();
|
||||
Finish(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool hasStreamForOrigFile = (_streamForOrigFile != null);
|
||||
bool hasChangeFast = hasStreamForOrigFile ||
|
||||
fileStorage.CheckForFileChangeFast(ioc, _db.LastFileVersion); //first try to use the fast change detection;
|
||||
bool hasHashChanged = !requiresSubsequentSync && (
|
||||
hasChangeFast ||
|
||||
bool hasHashChanged = hasChangeFast ||
|
||||
(FileHashChanged(ioc, _db.KpDatabase.HashOfFileOnDisk) ==
|
||||
FileHashChange.Changed)); //if that fails, hash the file and compare:
|
||||
FileHashChange.Changed); //if that fails, hash the file and compare:
|
||||
|
||||
if (hasHashChanged)
|
||||
{
|
||||
@@ -183,14 +158,15 @@ namespace keepass2android
|
||||
RunInWorkerThread(() =>
|
||||
{
|
||||
PerformSaveWithoutCheck(fileStorage, ioc);
|
||||
FinishWithSuccess();
|
||||
Finish(true);
|
||||
});
|
||||
},
|
||||
//cancel
|
||||
(sender, args) =>
|
||||
{
|
||||
RunInWorkerThread(() => Finish(false));
|
||||
}
|
||||
},
|
||||
_ctx
|
||||
);
|
||||
}
|
||||
|
||||
@@ -198,7 +174,7 @@ namespace keepass2android
|
||||
else
|
||||
{
|
||||
PerformSaveWithoutCheck(fileStorage, ioc);
|
||||
FinishWithSuccess();
|
||||
Finish(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -218,67 +194,22 @@ namespace keepass2android
|
||||
}
|
||||
else
|
||||
{
|
||||
FinishWithSuccess();
|
||||
Finish(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public bool SyncInBackground { get; set; }
|
||||
|
||||
private void FinishWithSuccess()
|
||||
{
|
||||
if (requiresSubsequentSync)
|
||||
{
|
||||
var syncTask = new SynchronizeCachedDatabase(_app, _db, new ActionOnOperationFinished(_app,
|
||||
(success, message, context) =>
|
||||
{
|
||||
if (!System.String.IsNullOrEmpty(message))
|
||||
_app.ShowMessage(context, message, success ? MessageSeverity.Info : MessageSeverity.Error);
|
||||
|
||||
}), new BackgroundDatabaseModificationLocker(_app)
|
||||
);
|
||||
OperationRunner.Instance.Run(_app, syncTask);
|
||||
}
|
||||
Finish(true);
|
||||
}
|
||||
|
||||
private void MergeAndFinish(IFileStorage fileStorage, IOConnectionInfo ioc)
|
||||
{
|
||||
//note: when synced, the file might be downloaded once again from the server. Caching the data
|
||||
//in the hashing function would solve this but increases complexity. I currently assume the files are
|
||||
//small.
|
||||
|
||||
try
|
||||
{
|
||||
_modificationWatcher.BeforeModifyDatabases();
|
||||
}
|
||||
catch (Java.Lang.InterruptedException)
|
||||
{
|
||||
// leave without Finish()
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
MergeIn(fileStorage, ioc);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_modificationWatcher.AfterModifyDatabases();
|
||||
|
||||
}
|
||||
|
||||
MergeIn(fileStorage, ioc);
|
||||
PerformSaveWithoutCheck(fileStorage, ioc);
|
||||
new Handler(Looper.MainLooper).Post(() =>
|
||||
{
|
||||
_db.UpdateGlobals();
|
||||
});
|
||||
|
||||
FinishWithSuccess();
|
||||
_db.UpdateGlobals();
|
||||
Finish(true);
|
||||
}
|
||||
|
||||
|
||||
private void RunInWorkerThread(Action runHandler)
|
||||
{
|
||||
try
|
||||
@@ -351,7 +282,7 @@ namespace keepass2android
|
||||
private void PerformSaveWithoutCheck(IFileStorage fileStorage, IOConnectionInfo ioc)
|
||||
{
|
||||
StatusLogger.UpdateSubMessage("");
|
||||
_db.SaveData(fileStorage);
|
||||
_db.SaveData();
|
||||
_db.LastFileVersion = fileStorage.GetCurrentFileVersionFast(ioc);
|
||||
}
|
||||
|
||||
|
@@ -22,24 +22,26 @@ using KeePassLib.Keys;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public class SetPassword : OperationWithFinishHandler {
|
||||
public class SetPassword : RunnableOnFinish {
|
||||
|
||||
private readonly String _password;
|
||||
private readonly String _keyfile;
|
||||
private readonly IKp2aApp _app;
|
||||
private readonly bool _dontSave;
|
||||
private readonly Activity _ctx;
|
||||
|
||||
public SetPassword(IKp2aApp app, String password, String keyfile, OnOperationFinishedHandler operationFinishedHandler): base(app, operationFinishedHandler) {
|
||||
|
||||
public SetPassword(Activity ctx, IKp2aApp app, String password, String keyfile, OnFinish finish): base(ctx, finish) {
|
||||
_ctx = ctx;
|
||||
_app = app;
|
||||
_password = password;
|
||||
_keyfile = keyfile;
|
||||
_dontSave = false;
|
||||
}
|
||||
|
||||
public SetPassword(IKp2aApp app, String password, String keyfile, OnOperationFinishedHandler operationFinishedHandler, bool dontSave)
|
||||
: base(app, operationFinishedHandler)
|
||||
public SetPassword(Activity ctx, IKp2aApp app, String password, String keyfile, OnFinish finish, bool dontSave)
|
||||
: base(ctx, finish)
|
||||
{
|
||||
_ctx = ctx;
|
||||
_app = app;
|
||||
_password = password;
|
||||
_keyfile = keyfile;
|
||||
@@ -71,18 +73,18 @@ namespace keepass2android
|
||||
pm.MasterKey = newKey;
|
||||
|
||||
// Save Database
|
||||
_operationFinishedHandler = new AfterSave(_app, previousKey, previousMasterKeyChanged, pm, operationFinishedHandler);
|
||||
SaveDb save = new SaveDb(_app, _app.CurrentDb, operationFinishedHandler, _dontSave, null);
|
||||
_onFinishToRun = new AfterSave(ActiveActivity, previousKey, previousMasterKeyChanged, pm, OnFinishToRun);
|
||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun, _dontSave);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.Run();
|
||||
}
|
||||
|
||||
private class AfterSave : OnOperationFinishedHandler {
|
||||
private class AfterSave : OnFinish {
|
||||
private readonly CompositeKey _backup;
|
||||
private readonly DateTime _previousKeyChanged;
|
||||
private readonly PwDatabase _db;
|
||||
|
||||
public AfterSave(IActiveContextProvider activeContextProvider, CompositeKey backup, DateTime previousKeyChanged, PwDatabase db, OnOperationFinishedHandler operationFinishedHandler): base(activeContextProvider, operationFinishedHandler) {
|
||||
public AfterSave(Activity activity, CompositeKey backup, DateTime previousKeyChanged, PwDatabase db, OnFinish finish): base(activity, finish) {
|
||||
_previousKeyChanged = previousKeyChanged;
|
||||
_backup = backup;
|
||||
_db = db;
|
||||
|
@@ -22,29 +22,31 @@ using KeePassLib;
|
||||
namespace keepass2android
|
||||
{
|
||||
|
||||
public class UpdateEntry : OperationWithFinishHandler {
|
||||
public class UpdateEntry : RunnableOnFinish {
|
||||
private readonly IKp2aApp _app;
|
||||
private readonly Activity _ctx;
|
||||
|
||||
public UpdateEntry(Activity ctx, IKp2aApp app, PwEntry oldE, PwEntry newE, OnFinish finish):base(ctx, finish) {
|
||||
_ctx = ctx;
|
||||
_app = app;
|
||||
|
||||
public UpdateEntry(IKp2aApp app, PwEntry oldE, PwEntry newE, OnOperationFinishedHandler operationFinishedHandler):base(app, operationFinishedHandler) {
|
||||
_app = app;
|
||||
|
||||
_operationFinishedHandler = new AfterUpdate( oldE, newE, app, operationFinishedHandler);
|
||||
_onFinishToRun = new AfterUpdate(ctx, oldE, newE, app, finish);
|
||||
}
|
||||
|
||||
|
||||
public override void Run() {
|
||||
// Commit to disk
|
||||
SaveDb save = new SaveDb(_app, _app.CurrentDb, operationFinishedHandler);
|
||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.Run();
|
||||
}
|
||||
|
||||
private class AfterUpdate : OnOperationFinishedHandler {
|
||||
private class AfterUpdate : OnFinish {
|
||||
private readonly PwEntry _backup;
|
||||
private readonly PwEntry _updatedEntry;
|
||||
private readonly IKp2aApp _app;
|
||||
|
||||
public AfterUpdate(PwEntry backup, PwEntry updatedEntry, IKp2aApp app, OnOperationFinishedHandler operationFinishedHandler):base(app, operationFinishedHandler) {
|
||||
public AfterUpdate(Activity activity, PwEntry backup, PwEntry updatedEntry, IKp2aApp app, OnFinish finish):base(activity, finish) {
|
||||
_backup = backup;
|
||||
_updatedEntry = updatedEntry;
|
||||
_app = app;
|
||||
|
@@ -20,7 +20,6 @@ git clone --recurse-submodules https://github.com/PhilippC/keepass2android.git
|
||||
cd keepass2android/src/build-scripts
|
||||
./build-java.sh && ./build-native.sh
|
||||
cd ..
|
||||
cp Kp2aBusinessLogic/Io/DropboxFileStorageKeysDummy.cs Kp2aBusinessLogic/Io/DropboxFileStorageKeys.cs
|
||||
cd keepass2android-app
|
||||
ln -s Manifests/AndroidManifest_debug.xml AndroidManifest.xml
|
||||
dotnet workload restore
|
||||
|
22
src/build-scripts/rename-output-apks.sh
Normal file
22
src/build-scripts/rename-output-apks.sh
Normal file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
BASE_DIR="${1}"
|
||||
|
||||
for arch_dir in "$BASE_DIR"/android-*/; do
|
||||
arch=$(basename "$arch_dir")
|
||||
arch=${arch#android-}
|
||||
APK_DIR="${arch_dir}publish"
|
||||
if [[ -d "$APK_DIR" ]]; then
|
||||
apk_path=$(find "$APK_DIR" -maxdepth 1 -type f -name "*.apk" | head -n1)
|
||||
if [[ -n "$apk_path" ]]; then
|
||||
base=$(basename "$apk_path" .apk)
|
||||
new_path="$APK_DIR/${base}-${arch}.apk"
|
||||
mv "$apk_path" "$new_path"
|
||||
echo "Renamed $apk_path to $new_path"
|
||||
else
|
||||
echo "No APK found in $APK_DIR"
|
||||
fi
|
||||
else
|
||||
echo "Directory $APK_DIR does not exist"
|
||||
fi
|
||||
done
|
@@ -6,8 +6,7 @@
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
android:supportsRtl="true">
|
||||
<activity android:name="com.crocoapps.javafilestoragetest2.MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
|
@@ -56,15 +56,15 @@
|
||||
<string name="afc_title_sort_by">Ordina per…</string>
|
||||
<string name="afc_yesterday">Ieri</string>
|
||||
<plurals name="afc_title_choose_directories">
|
||||
<item quantity="one">Scegli la cartella…</item>
|
||||
<item quantity="other">Scegli le cartelle…</item>
|
||||
<item quantity="one">Scegli cartella...</item>
|
||||
<item quantity="other">Scegli le cartelle...</item>
|
||||
</plurals>
|
||||
<plurals name="afc_title_choose_files">
|
||||
<item quantity="one">Scegli il file…</item>
|
||||
<item quantity="other">Scegli i file…</item>
|
||||
<item quantity="one">Scegli il file</item>
|
||||
<item quantity="other">Scegli i file</item>
|
||||
</plurals>
|
||||
<plurals name="afc_title_choose_files_directories">
|
||||
<item quantity="one">Scegli file/ cartella…</item>
|
||||
<item quantity="other">Scegli file/ cartelle…</item>
|
||||
<item quantity="one">Scegli file/cartella</item>
|
||||
<item quantity="other">Scegli file/cartelle</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
|
@@ -14,7 +14,7 @@ using keepass2android;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
[Activity(Label = AppNames.AppName)]
|
||||
[Activity(Label = AppNames.AppName, Theme = "@style/Kp2aTheme_BlueNoActionBar")]
|
||||
public class AppKilledInfo : Activity, IDialogInterfaceOnDismissListener
|
||||
{
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
|
@@ -228,9 +228,9 @@ namespace keepass2android
|
||||
newEntry.SetUuid(new PwUuid(true), true); // Create new UUID
|
||||
string strTitle = newEntry.Strings.ReadSafe(PwDefs.TitleField);
|
||||
newEntry.Strings.Set(PwDefs.TitleField, new ProtectedString(false, strTitle + " (" + Android.OS.Build.Model + ")"));
|
||||
var addTask = new AddEntry( App.Kp2a.CurrentDb, App.Kp2a, newEntry,item.Entry.ParentGroup,new ActionInContextInstanceOnOperationFinished(ContextInstanceId, App.Kp2a, (success, message, context) => (context as ConfigureChildDatabasesActivity)?.Update()));
|
||||
var addTask = new AddEntry(this, App.Kp2a.CurrentDb, App.Kp2a, newEntry,item.Entry.ParentGroup,new ActionOnFinish(this, (success, message, activity) => ((ConfigureChildDatabasesActivity)activity).Update()));
|
||||
|
||||
BlockingOperationStarter pt = new BlockingOperationStarter(App.Kp2a, addTask);
|
||||
ProgressTask pt = new ProgressTask(App.Kp2a, this, addTask);
|
||||
pt.Run();
|
||||
|
||||
}
|
||||
@@ -260,9 +260,9 @@ namespace keepass2android
|
||||
|
||||
private void Save(AutoExecItem item)
|
||||
{
|
||||
var addTask = new SaveDb(App.Kp2a, App.Kp2a.FindDatabaseForElement(item.Entry), new ActionInContextInstanceOnOperationFinished(ContextInstanceId, App.Kp2a, (success, message, context) => (context as ConfigureChildDatabasesActivity)?.Update()));
|
||||
var addTask = new SaveDb(this, App.Kp2a, App.Kp2a.FindDatabaseForElement(item.Entry), new ActionOnFinish(this, (success, message, activity) => ((ConfigureChildDatabasesActivity)activity).Update()));
|
||||
|
||||
BlockingOperationStarter pt = new BlockingOperationStarter(App.Kp2a, addTask);
|
||||
ProgressTask pt = new ProgressTask(App.Kp2a, this, addTask);
|
||||
pt.Run();
|
||||
}
|
||||
|
||||
@@ -343,7 +343,7 @@ namespace keepass2android
|
||||
}
|
||||
if (autoOpenGroup == null)
|
||||
{
|
||||
AddGroup addGroupTask = AddGroup.GetInstance(App.Kp2a, "AutoOpen", 1, null, rootGroup, null, true);
|
||||
AddGroup addGroupTask = AddGroup.GetInstance(this, App.Kp2a, "AutoOpen", 1, null, rootGroup, null, true);
|
||||
addGroupTask.Run();
|
||||
autoOpenGroup = addGroupTask.Group;
|
||||
}
|
||||
@@ -367,9 +367,9 @@ namespace keepass2android
|
||||
{KeeAutoExecExt.ThisDeviceId, true}
|
||||
})));
|
||||
|
||||
var addTask = new AddEntry( db, App.Kp2a, newEntry, autoOpenGroup, new ActionInContextInstanceOnOperationFinished(ContextInstanceId, App.Kp2a, (success, message, context) => (context as ConfigureChildDatabasesActivity)?.Update()));
|
||||
var addTask = new AddEntry(this, db, App.Kp2a, newEntry, autoOpenGroup, new ActionOnFinish(this, (success, message, activity) => (activity as ConfigureChildDatabasesActivity)?.Update()));
|
||||
|
||||
BlockingOperationStarter pt = new BlockingOperationStarter(App.Kp2a, addTask);
|
||||
ProgressTask pt = new ProgressTask(App.Kp2a, this, addTask);
|
||||
pt.Run();
|
||||
}
|
||||
|
||||
|
@@ -213,9 +213,10 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
// Create the new database
|
||||
CreateDb create = new CreateDb(App.Kp2a, this, _ioc, new LaunchGroupActivity(_ioc, App.Kp2a, this), false, newKey, makeCurrent);
|
||||
BlockingOperationStarter createTask = new BlockingOperationStarter(
|
||||
App.Kp2a, create);
|
||||
CreateDb create = new CreateDb(App.Kp2a, this, _ioc, new LaunchGroupActivity(_ioc, this), false, newKey, makeCurrent);
|
||||
ProgressTask createTask = new ProgressTask(
|
||||
App.Kp2a,
|
||||
this, create);
|
||||
createTask.Run();
|
||||
}
|
||||
|
||||
@@ -316,7 +317,7 @@ namespace keepass2android
|
||||
|
||||
if (resultCode == KeePass.ResultOkPasswordGenerator)
|
||||
{
|
||||
String generatedPassword = data.GetStringExtra(GeneratePasswordActivity.GeneratedPasswordKey);
|
||||
String generatedPassword = data.GetStringExtra("keepass2android.password.generated_password");
|
||||
FindViewById<TextView>(Resource.Id.entry_password).Text = generatedPassword;
|
||||
FindViewById<TextView>(Resource.Id.entry_confpassword).Text = generatedPassword;
|
||||
}
|
||||
@@ -402,14 +403,14 @@ namespace keepass2android
|
||||
|
||||
private class LaunchGroupActivity : FileOnFinish
|
||||
{
|
||||
readonly CreateDatabaseActivity _activity;
|
||||
private readonly IOConnectionInfo _ioc;
|
||||
private readonly CreateDatabaseActivity _activity;
|
||||
|
||||
public LaunchGroupActivity(IOConnectionInfo ioc, IKp2aApp app, CreateDatabaseActivity activity)
|
||||
: base(app, null)
|
||||
public LaunchGroupActivity(IOConnectionInfo ioc, CreateDatabaseActivity activity)
|
||||
: base(activity, null)
|
||||
{
|
||||
_activity = activity;
|
||||
_ioc = ioc;
|
||||
_activity = activity;
|
||||
_ioc = ioc;
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
@@ -419,7 +420,7 @@ namespace keepass2android
|
||||
// Update the ongoing notification
|
||||
App.Kp2a.UpdateOngoingNotification();
|
||||
|
||||
if (PreferenceManager.GetDefaultSharedPreferences(App.Context).GetBoolean(App.Context.GetString(Resource.String.RememberRecentFiles_key), App.Context.Resources.GetBoolean(Resource.Boolean.RememberRecentFiles_default)))
|
||||
if (PreferenceManager.GetDefaultSharedPreferences(_activity).GetBoolean(_activity.GetString(Resource.String.RememberRecentFiles_key), _activity.Resources.GetBoolean(Resource.Boolean.RememberRecentFiles_default)))
|
||||
{
|
||||
// Add to recent files
|
||||
FileDbHelper dbHelper = App.Kp2a.FileDbHelper;
|
||||
|
@@ -4,12 +4,12 @@ using KeePassLib.Serialization;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
class CreateNewFilename : OperationWithFinishHandler
|
||||
class CreateNewFilename : RunnableOnFinish
|
||||
{
|
||||
private readonly string _filename;
|
||||
|
||||
public CreateNewFilename(IKp2aApp app, OnOperationFinishedHandler operationFinishedHandler, string filename)
|
||||
: base(app,operationFinishedHandler)
|
||||
public CreateNewFilename(Activity activity, OnFinish finish, string filename)
|
||||
: base(activity,finish)
|
||||
{
|
||||
_filename = filename;
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ using keepass2android.services.AutofillBase;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
[Activity(Label = "DisableAutofillForQueryActivity")]
|
||||
[Activity(Label = "DisableAutofillForQueryActivity", Theme = "@style/Kp2aTheme_ActionBar")]
|
||||
public class DisableAutofillForQueryActivity : Activity
|
||||
{
|
||||
public IAutofillIntentBuilder IntentBuilder = new Kp2aAutofillIntentBuilder();
|
||||
@@ -63,8 +63,6 @@ namespace keepass2android
|
||||
|
||||
prefs.Edit().PutStringSet("AutoFillDisabledQueries", disabledValues).Commit();
|
||||
|
||||
bool isManual = Intent.GetBooleanExtra(ChooseForAutofillActivityBase.ExtraIsManualRequest, false);
|
||||
|
||||
Intent reply = new Intent();
|
||||
FillResponse.Builder builder = new FillResponse.Builder();
|
||||
AssistStructure structure = (AssistStructure)Intent.GetParcelableExtra(AutofillManager.ExtraAssistStructure);
|
||||
@@ -77,7 +75,7 @@ namespace keepass2android
|
||||
StructureParser parser = new StructureParser(this, structure);
|
||||
try
|
||||
{
|
||||
parser.ParseForFill(isManual);
|
||||
parser.ParseForFill();
|
||||
|
||||
}
|
||||
catch (Java.Lang.SecurityException e)
|
||||
|
@@ -56,7 +56,6 @@ using Android.Util;
|
||||
using AndroidX.Core.Content;
|
||||
using Google.Android.Material.Dialog;
|
||||
using keepass2android;
|
||||
using keepass2android.views;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
@@ -64,7 +63,7 @@ namespace keepass2android
|
||||
{
|
||||
private readonly string _binaryToSave;
|
||||
|
||||
public ExportBinaryProcessManager(int requestCode, LifecycleAwareActivity activity, string key) : base(requestCode, activity)
|
||||
public ExportBinaryProcessManager(int requestCode, Activity activity, string key) : base(requestCode, activity)
|
||||
{
|
||||
_binaryToSave = key;
|
||||
}
|
||||
@@ -76,13 +75,13 @@ namespace keepass2android
|
||||
|
||||
protected override void SaveFile(IOConnectionInfo ioc)
|
||||
{
|
||||
var task = new EntryActivity.WriteBinaryTask(App.Kp2a, new ActionOnOperationFinished(App.Kp2a, (success, message, context) =>
|
||||
var task = new EntryActivity.WriteBinaryTask(_activity, App.Kp2a, new ActionOnFinish(_activity, (success, message, activity) =>
|
||||
{
|
||||
if (!success)
|
||||
App.Kp2a.ShowMessage(context, message, MessageSeverity.Error);
|
||||
App.Kp2a.ShowMessage(activity, message, MessageSeverity.Error);
|
||||
}
|
||||
), ((EntryActivity)_activity).Entry.Binaries.Get(_binaryToSave), ioc);
|
||||
BlockingOperationStarter pt = new BlockingOperationStarter(App.Kp2a, task);
|
||||
ProgressTask pt = new ProgressTask(App.Kp2a, _activity, task);
|
||||
pt.Run();
|
||||
|
||||
}
|
||||
@@ -90,7 +89,6 @@ namespace keepass2android
|
||||
public override void OnSaveInstanceState(Bundle outState)
|
||||
{
|
||||
outState.PutString("BinaryToSave", _binaryToSave);
|
||||
base.OnSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +97,7 @@ namespace keepass2android
|
||||
|
||||
[Activity (Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden,
|
||||
Theme = "@style/Kp2aTheme_ActionBar")]
|
||||
public class EntryActivity : LockCloseActivity, IProgressUiProvider
|
||||
public class EntryActivity : LockCloseActivity
|
||||
{
|
||||
public const String KeyEntry = "entry";
|
||||
public const String KeyRefreshPos = "refresh_pos";
|
||||
@@ -112,45 +110,6 @@ namespace keepass2android
|
||||
|
||||
protected override View? SnackbarAnchorView => FindViewById(Resource.Id.main_content);
|
||||
|
||||
public class UpdateEntryActivityBroadcastReceiver : BroadcastReceiver
|
||||
{
|
||||
private readonly EntryActivity _activity;
|
||||
|
||||
public UpdateEntryActivityBroadcastReceiver(EntryActivity activity)
|
||||
{
|
||||
_activity = activity;
|
||||
}
|
||||
|
||||
public override void OnReceive(Context? context, Intent? intent)
|
||||
{
|
||||
if (intent?.Action == Intents.DataUpdated)
|
||||
{
|
||||
_activity.OnDataUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDataUpdated()
|
||||
{
|
||||
if (Entry == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var entryUId = Entry.Uuid;
|
||||
if (!App.Kp2a.CurrentDb.EntriesById.ContainsKey(entryUId))
|
||||
{
|
||||
Finish();
|
||||
return;
|
||||
}
|
||||
var newEntry = App.Kp2a.CurrentDb.EntriesById[entryUId];
|
||||
if (!newEntry.EqualsEntry(Entry, PwCompareOptions.None, MemProtCmpMode.Full))
|
||||
{
|
||||
Recreate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void Launch(Activity act, PwEntry pw, int pos, AppTask appTask, ActivityFlags? flags = null, int historyIndex=-1)
|
||||
{
|
||||
Intent i = new Intent(act, typeof(EntryActivity));
|
||||
@@ -522,8 +481,8 @@ namespace keepass2android
|
||||
Entry.Expires = true;
|
||||
Entry.Touch(true);
|
||||
RequiresRefresh();
|
||||
UpdateEntry update = new UpdateEntry(App.Kp2a, backupEntry, Entry, null);
|
||||
BlockingOperationStarter pt = new BlockingOperationStarter(App.Kp2a, update);
|
||||
UpdateEntry update = new UpdateEntry(this, App.Kp2a, backupEntry, Entry, null);
|
||||
ProgressTask pt = new ProgressTask(App.Kp2a, this, update);
|
||||
pt.Run();
|
||||
}
|
||||
FillData();
|
||||
@@ -542,13 +501,7 @@ namespace keepass2android
|
||||
|
||||
//the rest of the things to do depends on the current app task:
|
||||
AppTask.CompleteOnCreateEntryActivity(this, notifyPluginsOnOpenThread);
|
||||
|
||||
_dataUpdatedIntentReceiver = new UpdateEntryActivityBroadcastReceiver(this);
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.AddAction(Intents.DataUpdated);
|
||||
ContextCompat.RegisterReceiver(this, _dataUpdatedIntentReceiver, filter, (int)ReceiverFlags.Exported);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveFromHistory()
|
||||
{
|
||||
@@ -572,17 +525,13 @@ namespace keepass2android
|
||||
App.Kp2a.DirtyGroups.Add(parent);
|
||||
}
|
||||
|
||||
var saveTask = new SaveDb( App.Kp2a, App.Kp2a.FindDatabaseForElement(Entry), new ActionInContextInstanceOnOperationFinished(ContextInstanceId, App.Kp2a, (success, message, context) =>
|
||||
var saveTask = new SaveDb(this, App.Kp2a, App.Kp2a.FindDatabaseForElement(Entry), new ActionOnFinish(this, (success, message, activity) =>
|
||||
{
|
||||
if (context is Activity activity)
|
||||
{
|
||||
activity.SetResult(KeePass.ExitRefresh);
|
||||
activity.Finish();
|
||||
}
|
||||
|
||||
activity.SetResult(KeePass.ExitRefresh);
|
||||
activity.Finish();
|
||||
}));
|
||||
|
||||
BlockingOperationStarter pt = new BlockingOperationStarter(App.Kp2a, saveTask);
|
||||
ProgressTask pt = new ProgressTask(App.Kp2a, this, saveTask);
|
||||
pt.Run();
|
||||
}
|
||||
|
||||
@@ -1129,9 +1078,7 @@ namespace keepass2android
|
||||
UnregisterReceiver(_pluginActionReceiver);
|
||||
if (_pluginFieldReceiver != null)
|
||||
UnregisterReceiver(_pluginFieldReceiver);
|
||||
if (_dataUpdatedIntentReceiver != null)
|
||||
UnregisterReceiver(_dataUpdatedIntentReceiver);
|
||||
base.OnDestroy();
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
private void NotifyPluginsOnClose()
|
||||
@@ -1313,13 +1260,13 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
|
||||
public class WriteBinaryTask : OperationWithFinishHandler
|
||||
public class WriteBinaryTask : RunnableOnFinish
|
||||
{
|
||||
private readonly IKp2aApp _app;
|
||||
private readonly ProtectedBinary _data;
|
||||
private IOConnectionInfo _targetIoc;
|
||||
|
||||
public WriteBinaryTask(IKp2aApp app, OnOperationFinishedHandler onOperationFinishedHandler, ProtectedBinary data, IOConnectionInfo targetIoc) : base(app, onOperationFinishedHandler)
|
||||
public WriteBinaryTask(Activity activity, IKp2aApp app, OnFinish onFinish, ProtectedBinary data, IOConnectionInfo targetIoc) : base(activity, onFinish)
|
||||
{
|
||||
_app = app;
|
||||
_data = data;
|
||||
@@ -1407,7 +1354,6 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
bool isPaused = false;
|
||||
private UpdateEntryActivityBroadcastReceiver _dataUpdatedIntentReceiver;
|
||||
|
||||
protected override void OnPause()
|
||||
{
|
||||
@@ -1494,8 +1440,8 @@ namespace keepass2android
|
||||
Finish();
|
||||
return true;
|
||||
case Resource.Id.menu_delete:
|
||||
DeleteEntry task = new DeleteEntry(App.Kp2a, Entry,
|
||||
new ActionOnOperationFinished(App.Kp2a, (success, message, context) => { if (success) { RequiresRefresh(); Finish();}}));
|
||||
DeleteEntry task = new DeleteEntry(this, App.Kp2a, Entry,
|
||||
new ActionOnFinish(this, (success, message, activity) => { if (success) { RequiresRefresh(); Finish();}}));
|
||||
task.Start();
|
||||
break;
|
||||
case Resource.Id.menu_toggle_pass:
|
||||
@@ -1558,16 +1504,16 @@ namespace keepass2android
|
||||
|
||||
//save the entry:
|
||||
|
||||
ActionOnOperationFinished closeOrShowError = new ActionInContextInstanceOnOperationFinished(ContextInstanceId, App.Kp2a, (success, message, context) =>
|
||||
ActionOnFinish closeOrShowError = new ActionOnFinish(this, (success, message, activity) =>
|
||||
{
|
||||
OnOperationFinishedHandler.DisplayMessage(this, message, true);
|
||||
finishAction(context as EntryActivity);
|
||||
OnFinish.DisplayMessage(this, message, true);
|
||||
finishAction((EntryActivity)activity);
|
||||
});
|
||||
|
||||
|
||||
OperationWithFinishHandler runnable = new UpdateEntry(App.Kp2a, initialEntry, newEntry, closeOrShowError);
|
||||
RunnableOnFinish runnable = new UpdateEntry(this, App.Kp2a, initialEntry, newEntry, closeOrShowError);
|
||||
|
||||
BlockingOperationStarter pt = new BlockingOperationStarter(App.Kp2a, runnable);
|
||||
ProgressTask pt = new ProgressTask(App.Kp2a, this, runnable);
|
||||
pt.Run();
|
||||
|
||||
}
|
||||
@@ -1657,7 +1603,5 @@ namespace keepass2android
|
||||
imageViewerIntent.PutExtra("EntryKey", key);
|
||||
StartActivity(imageViewerIntent);
|
||||
}
|
||||
|
||||
public IProgressUi? ProgressUi => FindViewById<BackgroundOperationContainer>(Resource.Id.background_ops_container);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -62,7 +62,7 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the state of the EntryEditActivity. This is required to be able to keep a partially modified entry in memory
|
||||
/// Holds the state of the EntrryEditActivity. This is required to be able to keep a partially modified entry in memory
|
||||
/// through the App variable. Serializing this state (especially the Entry/EntryInDatabase) can be a performance problem
|
||||
/// when there are big attachements.
|
||||
/// </summary>
|
||||
|
@@ -19,23 +19,23 @@ namespace keepass2android
|
||||
{
|
||||
private readonly FileFormatProvider _ffp;
|
||||
|
||||
public ExportDbProcessManager(int requestCode, LifecycleAwareActivity activity, FileFormatProvider ffp) : base(requestCode, activity)
|
||||
public ExportDbProcessManager(int requestCode, Activity activity, FileFormatProvider ffp) : base(requestCode, activity)
|
||||
{
|
||||
_ffp = ffp;
|
||||
}
|
||||
|
||||
protected override void SaveFile(IOConnectionInfo ioc)
|
||||
{
|
||||
var exportDb = new ExportDatabaseActivity.ExportDb(App.Kp2a, new ActionInContextInstanceOnOperationFinished(_activity.ContextInstanceId, App.Kp2a, (success, message, context) =>
|
||||
var exportDb = new ExportDatabaseActivity.ExportDb(_activity, App.Kp2a, new ActionOnFinish(_activity, (success, message, activity) =>
|
||||
{
|
||||
if (!success)
|
||||
App.Kp2a.ShowMessage(context, message, MessageSeverity.Error);
|
||||
App.Kp2a.ShowMessage(activity, message, MessageSeverity.Error);
|
||||
else
|
||||
App.Kp2a.ShowMessage(context, _activity.GetString(Resource.String.export_database_successful), MessageSeverity.Info);
|
||||
(context as Activity)?.Finish();
|
||||
App.Kp2a.ShowMessage(activity, _activity.GetString(Resource.String.export_database_successful), MessageSeverity.Info);
|
||||
activity.Finish();
|
||||
}
|
||||
), _ffp, ioc);
|
||||
BlockingOperationStarter pt = new BlockingOperationStarter(App.Kp2a, exportDb);
|
||||
ProgressTask pt = new ProgressTask(App.Kp2a, _activity, exportDb);
|
||||
pt.Run();
|
||||
|
||||
}
|
||||
@@ -93,13 +93,13 @@ namespace keepass2android
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public class ExportDb : OperationWithFinishHandler
|
||||
public class ExportDb : RunnableOnFinish
|
||||
{
|
||||
private readonly IKp2aApp _app;
|
||||
private readonly FileFormatProvider _fileFormat;
|
||||
private IOConnectionInfo _targetIoc;
|
||||
|
||||
public ExportDb(IKp2aApp app, OnOperationFinishedHandler onOperationFinishedHandler, FileFormatProvider fileFormat, IOConnectionInfo targetIoc) : base(app, onOperationFinishedHandler)
|
||||
public ExportDb(Activity activity, IKp2aApp app, OnFinish onFinish, FileFormatProvider fileFormat, IOConnectionInfo targetIoc) : base(activity, onFinish)
|
||||
{
|
||||
_app = app;
|
||||
this._fileFormat = fileFormat;
|
||||
|
@@ -12,9 +12,9 @@ namespace keepass2android
|
||||
{
|
||||
|
||||
protected readonly int _requestCode;
|
||||
protected readonly LifecycleAwareActivity _activity;
|
||||
protected readonly Activity _activity;
|
||||
|
||||
public FileSaveProcessManager(int requestCode, LifecycleAwareActivity activity)
|
||||
public FileSaveProcessManager(int requestCode, Activity activity)
|
||||
{
|
||||
_requestCode = requestCode;
|
||||
_activity = activity;
|
||||
@@ -103,7 +103,7 @@ namespace keepass2android
|
||||
}
|
||||
else
|
||||
{
|
||||
var task = new CreateNewFilename(App.Kp2a, new ActionOnOperationFinished(App.Kp2a, (success, messageOrFilename, activity) =>
|
||||
var task = new CreateNewFilename(_activity, new ActionOnFinish(_activity, (success, messageOrFilename, activity) =>
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
@@ -115,7 +115,7 @@ namespace keepass2android
|
||||
|
||||
}), filename);
|
||||
|
||||
new BlockingOperationStarter(App.Kp2a, task).Run();
|
||||
new ProgressTask(App.Kp2a, _activity, task).Run();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@@ -667,10 +667,10 @@ namespace keepass2android
|
||||
return true;
|
||||
}
|
||||
|
||||
private void IocSelected(Context context, IOConnectionInfo ioc)
|
||||
private void IocSelected(Activity activity, IOConnectionInfo ioc)
|
||||
{
|
||||
if (OnOpen != null)
|
||||
OnOpen(context, ioc);
|
||||
OnOpen(activity, ioc);
|
||||
}
|
||||
|
||||
public bool StartFileChooser(string defaultPath)
|
||||
@@ -781,7 +781,7 @@ namespace keepass2android
|
||||
}
|
||||
else
|
||||
{
|
||||
var task = new CreateNewFilename(App.Kp2a, new ActionOnOperationFinished(App.Kp2a, (success, messageOrFilename, newActivity) =>
|
||||
var task = new CreateNewFilename(activity, new ActionOnFinish(activity, (success, messageOrFilename, newActivity) =>
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
@@ -793,7 +793,7 @@ namespace keepass2android
|
||||
|
||||
}), filename);
|
||||
|
||||
new BlockingOperationStarter(App.Kp2a, task).Run();
|
||||
new ProgressTask(App.Kp2a, activity, task).Run();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -46,9 +46,7 @@ namespace keepass2android
|
||||
#endif
|
||||
|
||||
{
|
||||
public const string GeneratedPasswordKey = "keepass2android.password.generated_password";
|
||||
|
||||
private readonly int[] _buttonLengthButtonIds = new[] {Resource.Id.btn_length6,
|
||||
private readonly int[] _buttonLengthButtonIds = new[] {Resource.Id.btn_length6,
|
||||
Resource.Id.btn_length8,
|
||||
Resource.Id.btn_length12,
|
||||
Resource.Id.btn_length16,
|
||||
@@ -261,7 +259,7 @@ namespace keepass2android
|
||||
EditText password = (EditText) FindViewById(Resource.Id.password_edit);
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.PutExtra(GeneratedPasswordKey, password.Text);
|
||||
intent.PutExtra("keepass2android.password.generated_password", password.Text);
|
||||
|
||||
SetResult(KeePass.ResultOkPasswordGenerator, intent);
|
||||
|
||||
|
@@ -223,9 +223,9 @@ namespace keepass2android
|
||||
(o, args) =>
|
||||
{
|
||||
//yes
|
||||
BlockingOperationStarter pt = new BlockingOperationStarter(App.Kp2a,
|
||||
new AddTemplateEntries(App.Kp2a, new ActionInContextInstanceOnOperationFinished(ContextInstanceId, App.Kp2a,
|
||||
(success, message, context) => (context as GroupActivity)?.StartAddEntry())));
|
||||
ProgressTask pt = new ProgressTask(App.Kp2a, this,
|
||||
new AddTemplateEntries(this, App.Kp2a, new ActionOnFinish(this,
|
||||
(success, message, activity) => ((GroupActivity)activity)?.StartAddEntry())));
|
||||
pt.Run();
|
||||
},
|
||||
(o, args) =>
|
||||
@@ -235,7 +235,7 @@ namespace keepass2android
|
||||
edit.Commit();
|
||||
//no
|
||||
StartAddEntry();
|
||||
},null);
|
||||
},null, this);
|
||||
|
||||
}
|
||||
else
|
||||
|
@@ -43,13 +43,11 @@ using keepass2android;
|
||||
using KeeTrayTOTP.Libraries;
|
||||
using AndroidX.AppCompat.Widget;
|
||||
using Google.Android.Material.Dialog;
|
||||
using keepass2android.views;
|
||||
using SearchView = AndroidX.AppCompat.Widget.SearchView;
|
||||
using AndroidX.Core.Content;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public abstract class GroupBaseActivity : LockCloseActivity, IProgressUiProvider
|
||||
public abstract class GroupBaseActivity : LockCloseActivity
|
||||
{
|
||||
public const String KeyEntry = "entry";
|
||||
public const String KeyMode = "mode";
|
||||
@@ -203,18 +201,19 @@ namespace keepass2android
|
||||
new PwUuid(MemUtil.HexStringToByteArray(data.Extras.GetString(GroupEditActivity.KeyCustomIconId)));
|
||||
String strGroupUuid = data.Extras.GetString(GroupEditActivity.KeyGroupUuid);
|
||||
GroupBaseActivity act = this;
|
||||
OperationWithFinishHandler task;
|
||||
Handler handler = new Handler();
|
||||
RunnableOnFinish task;
|
||||
if (strGroupUuid == null)
|
||||
{
|
||||
task = AddGroup.GetInstance(App.Kp2a, groupName, groupIconId, groupCustomIconId, Group, CreateRefreshAction(), false);
|
||||
task = AddGroup.GetInstance(this, App.Kp2a, groupName, groupIconId, groupCustomIconId, Group, new RefreshTask(handler, this), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
PwUuid groupUuid = new PwUuid(MemUtil.HexStringToByteArray(strGroupUuid));
|
||||
task = new EditGroup(App.Kp2a, groupName, (PwIcon)groupIconId, groupCustomIconId, App.Kp2a.FindGroup(groupUuid),
|
||||
CreateRefreshAction());
|
||||
task = new EditGroup(this, App.Kp2a, groupName, (PwIcon)groupIconId, groupCustomIconId, App.Kp2a.FindGroup(groupUuid),
|
||||
new RefreshTask(handler, this));
|
||||
}
|
||||
BlockingOperationStarter pt = new BlockingOperationStarter(App.Kp2a, task);
|
||||
ProgressTask pt = new ProgressTask(App.Kp2a, act, task);
|
||||
pt.Run();
|
||||
}
|
||||
|
||||
@@ -275,7 +274,6 @@ namespace keepass2android
|
||||
private IMenuItem searchItem;
|
||||
private IMenuItem searchItemDummy;
|
||||
private bool isPaused;
|
||||
private UpdateGroupBaseActivityBroadcastReceiver _dataUpdatedIntentReceiver;
|
||||
|
||||
protected override void OnResume()
|
||||
{
|
||||
@@ -747,10 +745,9 @@ namespace keepass2android
|
||||
|
||||
|
||||
|
||||
_dataUpdatedIntentReceiver = new UpdateGroupBaseActivityBroadcastReceiver(this);
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.AddAction(Intents.DataUpdated);
|
||||
ContextCompat.RegisterReceiver(this, _dataUpdatedIntentReceiver, filter, (int)ReceiverFlags.Exported);
|
||||
|
||||
|
||||
|
||||
|
||||
SetResult(KeePass.ExitNormal);
|
||||
|
||||
@@ -897,9 +894,14 @@ namespace keepass2android
|
||||
RegisterInfoTextDisplay(
|
||||
"DbReadOnly"); //this ensures that we don't show the general info texts too soon
|
||||
|
||||
FindViewById<TextView>(Resource.Id.dbreadonly_infotext_text).Text =
|
||||
(GetString(Resource.String.FileReadOnlyMessagePre) + " " +
|
||||
App.Kp2a.GetResourceString(reason.Result));
|
||||
var infotext_view = FindViewById<TextView>(Resource.Id.dbreadonly_infotext_text);
|
||||
if (infotext_view != null)
|
||||
{
|
||||
infotext_view.Text =
|
||||
(GetString(Resource.String.FileReadOnlyMessagePre) + " " +
|
||||
App.Kp2a.GetResourceString(reason.Result));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
UpdateBottomBarElementVisibility(Resource.Id.dbreadonly_infotext, canShow);
|
||||
@@ -927,14 +929,14 @@ namespace keepass2android
|
||||
|
||||
|
||||
|
||||
var moveElement = new MoveElements(elementsToMove.ToList(), Group, App.Kp2a, new ActionInContextInstanceOnOperationFinished(ContextInstanceId, App.Kp2a,
|
||||
(success, message, context) =>
|
||||
var moveElement = new MoveElements(elementsToMove.ToList(), Group, this, App.Kp2a, new ActionOnFinish(this,
|
||||
(success, message, activity) =>
|
||||
{
|
||||
(context as GroupBaseActivity)?.StopMovingElements();
|
||||
((GroupBaseActivity)activity)?.StopMovingElements();
|
||||
if (!String.IsNullOrEmpty(message))
|
||||
App.Kp2a.ShowMessage(context, message, MessageSeverity.Error);
|
||||
App.Kp2a.ShowMessage(activity, message, MessageSeverity.Error);
|
||||
}));
|
||||
var progressTask = new BlockingOperationStarter(App.Kp2a, moveElement);
|
||||
var progressTask = new ProgressTask(App.Kp2a, this, moveElement);
|
||||
progressTask.Run();
|
||||
|
||||
}
|
||||
@@ -1036,13 +1038,6 @@ namespace keepass2android
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
UnregisterReceiver(_dataUpdatedIntentReceiver);
|
||||
base.OnDestroy();
|
||||
|
||||
}
|
||||
|
||||
public override bool OnCreateOptionsMenu(IMenu menu)
|
||||
{
|
||||
|
||||
@@ -1222,7 +1217,7 @@ namespace keepass2android
|
||||
return true;
|
||||
|
||||
case Resource.Id.menu_sync:
|
||||
new SyncUtil(this).StartSynchronizeDatabase(App.Kp2a.CurrentDb.Ioc);
|
||||
new SyncUtil(this).SynchronizeDatabase(() => { });
|
||||
return true;
|
||||
|
||||
case Resource.Id.menu_work_offline:
|
||||
@@ -1233,7 +1228,7 @@ namespace keepass2android
|
||||
case Resource.Id.menu_work_online:
|
||||
App.Kp2a.OfflineMode = App.Kp2a.OfflineModePreference = false;
|
||||
UpdateOfflineModeMenu();
|
||||
new SyncUtil(this).StartSynchronizeDatabase(App.Kp2a.CurrentDb.Ioc);
|
||||
new SyncUtil(this).SynchronizeDatabase(() => { });
|
||||
return true;
|
||||
case Resource.Id.menu_open_other_db:
|
||||
AppTask.SetActivityResult(this, KeePass.ExitLoadAnotherDb);
|
||||
@@ -1303,7 +1298,51 @@ namespace keepass2android
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class RefreshTask : OnFinish
|
||||
{
|
||||
public RefreshTask(Handler handler, GroupBaseActivity act)
|
||||
: base(act, handler)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
if (Success)
|
||||
{
|
||||
((GroupBaseActivity)ActiveActivity)?.RefreshIfDirty();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayMessage(ActiveActivity);
|
||||
}
|
||||
}
|
||||
}
|
||||
public class AfterDeleteGroup : OnFinish
|
||||
{
|
||||
public AfterDeleteGroup(Handler handler, GroupBaseActivity act)
|
||||
: base(act, handler)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
if (Success)
|
||||
{
|
||||
((GroupBaseActivity)ActiveActivity)?.RefreshIfDirty();
|
||||
}
|
||||
else
|
||||
{
|
||||
Handler.Post(() =>
|
||||
{
|
||||
App.Kp2a.ShowMessage(ActiveActivity ?? LocaleManager.LocalizedAppContext, "Unrecoverable error: " + Message, MessageSeverity.Error);
|
||||
});
|
||||
|
||||
App.Kp2a.Lock(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public bool IsBeingMoved(PwUuid uuid)
|
||||
{
|
||||
@@ -1374,79 +1413,6 @@ namespace keepass2android
|
||||
{
|
||||
GroupEditActivity.Launch(this, pwGroup.ParentGroup, pwGroup);
|
||||
}
|
||||
|
||||
public IProgressUi ProgressUi
|
||||
{
|
||||
get
|
||||
{
|
||||
return FindViewById<BackgroundOperationContainer>(Resource.Id.background_ops_container);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDataUpdated()
|
||||
{
|
||||
if (Group == null || FragmentManager.IsDestroyed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var groupId = Group.Uuid;
|
||||
if (!App.Kp2a.CurrentDb.GroupsById.ContainsKey(groupId))
|
||||
{
|
||||
Finish();
|
||||
return;
|
||||
}
|
||||
Group = App.Kp2a.CurrentDb.GroupsById[groupId];
|
||||
var fragment = FragmentManager.FindFragmentById<GroupListFragment>(Resource.Id.list_fragment);
|
||||
if (fragment == null)
|
||||
{
|
||||
throw new Exception("did not find fragment");
|
||||
}
|
||||
fragment.ListAdapter = new PwGroupListAdapter(this, Group);
|
||||
SetGroupIcon();
|
||||
SetGroupTitle();
|
||||
ListAdapter?.NotifyDataSetChanged();
|
||||
|
||||
}
|
||||
|
||||
public OnOperationFinishedHandler CreateRefreshAction()
|
||||
{
|
||||
return new ActionInContextInstanceOnOperationFinished(
|
||||
ContextInstanceId, App.Kp2a,
|
||||
(success, message, context) =>
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
RunOnUiThread(() =>
|
||||
{
|
||||
(context as GroupBaseActivity)?.RefreshIfDirty();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
App.Kp2a.ShowMessage(context, message, MessageSeverity.Error);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public class UpdateGroupBaseActivityBroadcastReceiver : BroadcastReceiver
|
||||
{
|
||||
private readonly GroupBaseActivity _groupBaseActivity;
|
||||
|
||||
public UpdateGroupBaseActivityBroadcastReceiver(GroupBaseActivity groupBaseActivity)
|
||||
{
|
||||
_groupBaseActivity = groupBaseActivity;
|
||||
}
|
||||
|
||||
public override void OnReceive(Context? context, Intent? intent)
|
||||
{
|
||||
if (intent?.Action == Intents.DataUpdated)
|
||||
{
|
||||
_groupBaseActivity.OnDataUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class GroupListFragment : ListFragment, AbsListView.IMultiChoiceModeListener
|
||||
@@ -1509,12 +1475,12 @@ namespace keepass2android
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Handler handler = new Handler();
|
||||
switch (item.ItemId)
|
||||
{
|
||||
|
||||
case Resource.Id.menu_delete:
|
||||
DeleteMultipleItems((GroupBaseActivity)Activity, checkedItems, ((GroupBaseActivity)Activity).CreateRefreshAction(), App.Kp2a);
|
||||
DeleteMultipleItems((GroupBaseActivity)Activity, checkedItems, new GroupBaseActivity.RefreshTask(handler, ((GroupBaseActivity)Activity)), App.Kp2a);
|
||||
break;
|
||||
case Resource.Id.menu_move:
|
||||
var navMove = new NavigateToFolderAndLaunchMoveElementTask(App.Kp2a.CurrentDb, checkedItems.First().ParentGroup, checkedItems.Select(i => i.Uuid).ToList(), ((GroupBaseActivity)Activity).IsSearchResult);
|
||||
@@ -1522,10 +1488,10 @@ namespace keepass2android
|
||||
break;
|
||||
case Resource.Id.menu_copy:
|
||||
|
||||
var copyTask = new CopyEntry(App.Kp2a, (PwEntry)checkedItems.First(),
|
||||
((GroupBaseActivity)Activity).CreateRefreshAction(), App.Kp2a.CurrentDb);
|
||||
var copyTask = new CopyEntry((GroupBaseActivity)Activity, App.Kp2a, (PwEntry)checkedItems.First(),
|
||||
new GroupBaseActivity.RefreshTask(handler, ((GroupBaseActivity)Activity)), App.Kp2a.CurrentDb);
|
||||
|
||||
BlockingOperationStarter pt = new BlockingOperationStarter(App.Kp2a, copyTask);
|
||||
ProgressTask pt = new ProgressTask(App.Kp2a, Activity, copyTask);
|
||||
pt.Run();
|
||||
break;
|
||||
|
||||
@@ -1670,7 +1636,7 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
|
||||
public void DeleteMultipleItems(GroupBaseActivity activity, List<IStructureItem> checkedItems, OnOperationFinishedHandler onOperationFinishedHandler, Kp2aApp app)
|
||||
public void DeleteMultipleItems(GroupBaseActivity activity, List<IStructureItem> checkedItems, OnFinish onFinish, Kp2aApp app)
|
||||
{
|
||||
if (checkedItems.Any() == false)
|
||||
return;
|
||||
@@ -1701,30 +1667,30 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
int dbIndex = 0;
|
||||
Action<bool, string, Context> action = null;
|
||||
action = (success, message, context) =>
|
||||
Action<bool, string, Activity> action = null;
|
||||
action = (success, message, activeActivity) =>
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
dbIndex++;
|
||||
if (dbIndex == itemsForDatabases.Count)
|
||||
{
|
||||
onOperationFinishedHandler.SetResult(true);
|
||||
onOperationFinishedHandler.Run();
|
||||
onFinish.SetResult(true);
|
||||
onFinish.Run();
|
||||
return;
|
||||
}
|
||||
new DeleteMultipleItemsFromOneDatabase(activity, itemsForDatabases[dbIndex].Key,
|
||||
itemsForDatabases[dbIndex].Value, new ActionOnOperationFinished(App.Kp2a, (b, s, activity1) => action(b, s, activity1)), app)
|
||||
itemsForDatabases[dbIndex].Value, new ActionOnFinish(activeActivity, (b, s, activity1) => action(b, s, activity1)), app)
|
||||
.Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
onOperationFinishedHandler.SetResult(false, message, true, null);
|
||||
onFinish.SetResult(false, message, true, null);
|
||||
}
|
||||
};
|
||||
|
||||
new DeleteMultipleItemsFromOneDatabase(activity, itemsForDatabases[dbIndex].Key,
|
||||
itemsForDatabases[dbIndex].Value, new ActionOnOperationFinished(App.Kp2a, (b, s, activity1) => action(b, s, activity1)), app)
|
||||
itemsForDatabases[dbIndex].Value, new ActionOnFinish(activity, (b, s, activity1) => action(b, s, activity1)), app)
|
||||
.Start();
|
||||
}
|
||||
|
||||
|
@@ -25,7 +25,7 @@ using Android.Runtime;
|
||||
namespace keepass2android
|
||||
{
|
||||
|
||||
public abstract class LifecycleAwareActivity : AndroidX.AppCompat.App.AppCompatActivity, IContextInstanceIdProvider
|
||||
public abstract class LifecycleAwareActivity : AndroidX.AppCompat.App.AppCompatActivity
|
||||
{
|
||||
protected override void AttachBaseContext(Context baseContext)
|
||||
{
|
||||
@@ -84,11 +84,12 @@ namespace keepass2android
|
||||
return baseRes;
|
||||
}
|
||||
|
||||
public Action? OnResumeListener { get; set; }
|
||||
|
||||
protected override void OnResume()
|
||||
{
|
||||
base.OnResume();
|
||||
App.Kp2a.PerformPendingActions(_instanceId);
|
||||
OnResumeListener?.Invoke();
|
||||
|
||||
Kp2aLog.Log(ClassName + ".OnResume " + ID);
|
||||
if (App.Kp2a.CurrentDb == null)
|
||||
@@ -103,38 +104,26 @@ namespace keepass2android
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
App.Kp2a.ActiveContext = this;
|
||||
ProgressTask.SetNewActiveActivity(this);
|
||||
base.OnStart();
|
||||
Kp2aLog.Log(ClassName + ".OnStart" + " " + ID);
|
||||
}
|
||||
|
||||
const string ID_KEY = "kp2a_context_instance_id";
|
||||
const int InvalidId = -1;
|
||||
|
||||
private int _instanceId;
|
||||
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
{
|
||||
|
||||
base.OnCreate(bundle);
|
||||
|
||||
_instanceId = bundle?.GetInt(ID_KEY, InvalidId) ?? InvalidId;
|
||||
if (_instanceId == InvalidId)
|
||||
{
|
||||
_instanceId = _nextContextInstanceId++;
|
||||
}
|
||||
|
||||
OnCreateListener?.Invoke(bundle);
|
||||
|
||||
Kp2aLog.Log(ClassName + ".OnCreate" + " " + ID + " (instance=" + _instanceId +")");
|
||||
Kp2aLog.Log(ClassName + ".OnCreate" + " " + ID);
|
||||
Kp2aLog.Log(ClassName + ":apptask=" + Intent.GetStringExtra("KP2A_APP_TASK_TYPE") + " " + ID);
|
||||
}
|
||||
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
Kp2aLog.Log(ClassName + ".OnDestroy " + IsFinishing.ToString() + " " + ID);
|
||||
Kp2aLog.Log(ClassName + ".OnDestroy" + IsFinishing.ToString() + " " + ID);
|
||||
}
|
||||
|
||||
protected override void OnPause()
|
||||
@@ -147,18 +136,14 @@ namespace keepass2android
|
||||
{
|
||||
base.OnStop();
|
||||
Kp2aLog.Log(ClassName + ".OnStop" + " " + ID);
|
||||
ProgressTask.RemoveActiveActivity(this);
|
||||
}
|
||||
|
||||
protected override void OnSaveInstanceState(Bundle outState)
|
||||
{
|
||||
base.OnSaveInstanceState(outState);
|
||||
outState.PutInt(ID_KEY, _instanceId);
|
||||
OnSaveInstanceStateListener?.Invoke(outState);
|
||||
}
|
||||
|
||||
static int _nextContextInstanceId = 0;
|
||||
|
||||
public int ContextInstanceId => _instanceId;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -38,7 +38,7 @@ namespace keepass2android
|
||||
protected const string NoLockCheck = "NO_LOCK_CHECK";
|
||||
|
||||
protected IOConnectionInfo _ioc;
|
||||
private BroadcastReceiver _lockCloseIntentReceiver;
|
||||
private BroadcastReceiver _intentReceiver;
|
||||
private ActivityDesign _design;
|
||||
|
||||
public LockCloseActivity()
|
||||
@@ -66,11 +66,11 @@ namespace keepass2android
|
||||
if (Intent.GetBooleanExtra(NoLockCheck, false))
|
||||
return;
|
||||
|
||||
_lockCloseIntentReceiver = new LockCloseActivityBroadcastReceiver(this);
|
||||
_intentReceiver = new LockCloseActivityBroadcastReceiver(this);
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.AddAction(Intents.DatabaseLocked);
|
||||
filter.AddAction(Intent.ActionScreenOff);
|
||||
ContextCompat.RegisterReceiver(this, _lockCloseIntentReceiver, filter, (int)ReceiverFlags.Exported);
|
||||
ContextCompat.RegisterReceiver(this, _intentReceiver, filter, (int)ReceiverFlags.Exported);
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
@@ -79,7 +79,7 @@ namespace keepass2android
|
||||
{
|
||||
try
|
||||
{
|
||||
UnregisterReceiver(_lockCloseIntentReceiver);
|
||||
UnregisterReceiver(_intentReceiver);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@@ -266,7 +266,6 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||
<uses-permission android:name="android.permission.USE_CREDENTIALS" android:maxSdkVersion="22" />
|
||||
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" android:maxSdkVersion="22" />
|
||||
<uses-permission android:name="keepass2android.keepass2android_debug.permission.KP2aInternalFileBrowsing" />
|
||||
|
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="206"
|
||||
android:versionName="1.12-r5"
|
||||
package="keepass2android.keepass2android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:installLocation="auto">
|
||||
android:versionCode="217"
|
||||
android:versionName="1.12-r9c"
|
||||
package="keepass2android.keepass2android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:installLocation="auto">
|
||||
|
||||
|
||||
<queries>
|
||||
@@ -46,13 +46,11 @@
|
||||
|
||||
<permission android:description="@string/permission_desc2" android:icon="@drawable/ic_launcher" android:label="KP2A entry search" android:name="keepass2android.keepass2android.permission.KP2aInternalSearch" android:protectionLevel="signature" />
|
||||
<permission android:description="@string/permission_desc3" android:icon="@drawable/ic_launcher" android:label="KP2A choose autofill dataset" android:name="keepass2android.keepass2android.permission.Kp2aChooseAutofill" android:protectionLevel="signature" />
|
||||
|
||||
<application android:label="keepass2android"
|
||||
android:icon="@mipmap/ic_launcher_online"
|
||||
android:roundIcon="@mipmap/ic_launcher_online_round"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
|
||||
>
|
||||
android:icon="@mipmap/ic_launcher_online"
|
||||
android:roundIcon="@mipmap/ic_launcher_online_round"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
>
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.mlkit.vision.DEPENDENCIES"
|
||||
@@ -107,16 +105,15 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="keepass2android.softkeyboard.InputLanguageSelection"
|
||||
|
||||
android:exported="true">
|
||||
<!-- android:label="@string/language_selection_title" TODO -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<action android:name="keepass2android.softkeyboard.INPUT_LANGUAGE_SELECTION"/>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:configChanges="orientation|keyboard|keyboardHidden" android:label="@string/app_name" android:theme="@style/Kp2aTheme_BlueNoActionBar" android:name="keepass2android.SelectCurrentDbActivity" android:windowSoftInputMode="adjustResize" android:exported="true">
|
||||
<activity android:configChanges="orientation|keyboard|keyboardHidden" android:label="@string/app_name" android:theme="@style/Kp2aTheme_BlueNoActionBar" android:name="keepass2android.SelectCurrentDbActivity" android:windowSoftInputMode="adjustResize"
|
||||
android:exported="true">
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
@@ -278,7 +275,6 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||
<uses-permission android:name="android.permission.USE_CREDENTIALS" android:maxSdkVersion="22" />
|
||||
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" android:maxSdkVersion="22" />
|
||||
<uses-permission android:name="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing" />
|
||||
|
@@ -1,24 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="200"
|
||||
android:versionName="1.11-r0"
|
||||
package="keepass2android.keepass2android_nonet"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:installLocation="auto">
|
||||
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="217"
|
||||
android:versionName="1.12-r9c"
|
||||
package="keepass2android.keepass2android_nonet"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:installLocation="auto">
|
||||
|
||||
|
||||
<queries>
|
||||
<!-- Specific intents and packages we query for (required since Android 11) -->
|
||||
<package android:name="keepass2android.plugin.keyboardswap2" />
|
||||
<package android:name="keepass2android.AncientIconSet" />
|
||||
<package android:name="com.dropbox.android" />
|
||||
<package android:name="keepass2android.plugin.qr" />
|
||||
<package android:name="it.andreacioni.kp2a.plugin.keelink" />
|
||||
<package android:name="com.inputstick.apps.kp2aplugin" />
|
||||
<package android:name="com.dropbox.android" />
|
||||
|
||||
<intent>
|
||||
<action android:name="android.intent.action.OPEN_DOCUMENT" />
|
||||
<data android:mimeType="*/*" />
|
||||
</intent>
|
||||
|
||||
<intent>
|
||||
<action android:name="android.intent.action.OPEN_DOCUMENT" />
|
||||
<data android:mimeType="*/*" />
|
||||
</intent>
|
||||
|
||||
<intent>
|
||||
<action android:name="android.intent.action.GET_DOCUMENT" />
|
||||
<data android:mimeType="*/*" />
|
||||
</intent>
|
||||
@@ -36,59 +39,57 @@
|
||||
</intent>
|
||||
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" />
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
</intent>
|
||||
</queries>
|
||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" />
|
||||
|
||||
<permission android:description="@string/permission_desc2" android:icon="@drawable/ic_launcher_offline" android:label="KP2A entry search" android:name="keepass2android.keepass2android_nonet.permission.KP2aInternalSearch" android:protectionLevel="signature" />
|
||||
<permission android:description="@string/permission_desc3" android:icon="@drawable/ic_launcher_offline" android:label="KP2A choose autofill dataset" android:name="keepass2android.keepass2android_nonet.permission.Kp2aChooseAutofill" android:protectionLevel="signature" />
|
||||
<application
|
||||
android:label="keepass2android"
|
||||
android:icon="@mipmap/ic_launcher_offline"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
>
|
||||
<application android:label="keepass2android"
|
||||
android:icon="@mipmap/ic_launcher_offline"
|
||||
android:roundIcon="@mipmap/ic_launcher_offline_round"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
>
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.mlkit.vision.DEPENDENCIES"
|
||||
android:value="barcode_ui"/>
|
||||
|
||||
<uses-library
|
||||
<uses-library
|
||||
android:name="org.apache.http.legacy"
|
||||
android:required="false"/>
|
||||
|
||||
<provider android:name="group.pals.android.lib.ui.filechooser.providers.localfile.LocalFileProvider" android:authorities="keepass2android.keepass2android_nonet.android-filechooser.localfile" android:exported="false" />
|
||||
<provider android:name="group.pals.android.lib.ui.filechooser.providers.history.HistoryProvider" android:authorities="keepass2android.keepass2android_nonet.android-filechooser.history" android:exported="false" />
|
||||
<activity android:name="group.pals.android.lib.ui.filechooser.FileChooserActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:screenOrientation="user" android:theme="@style/Afc.Theme.Light">
|
||||
</activity>
|
||||
|
||||
<provider android:name="group.pals.android.lib.ui.filechooser.providers.localfile.LocalFileProvider" android:authorities="keepass2android.keepass2android_nonet.android-filechooser.localfile" android:exported="false" />
|
||||
<provider android:name="group.pals.android.lib.ui.filechooser.providers.history.HistoryProvider" android:authorities="keepass2android.keepass2android_nonet.android-filechooser.history" android:exported="false" />
|
||||
<activity android:name="group.pals.android.lib.ui.filechooser.FileChooserActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:screenOrientation="user" android:theme="@style/Afc.Theme.Light">
|
||||
</activity>
|
||||
|
||||
<service android:name="keepass2android.softkeyboard.KP2AKeyboard" android:permission="android.permission.BIND_INPUT_METHOD" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.view.InputMethod" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.view.im" android:resource="@xml/method" />
|
||||
</service>
|
||||
<activity android:name="keepass2android.softkeyboard.LatinIMESettings" android:label="@string/english_ime_settings" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="keepass2android.softkeyboard.LatinIMESettings" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="keepass2android.softkeyboard.InputLanguageSelection"
|
||||
android:label="@string/language_selection_title"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<action android:name="keepass2android.softkeyboard.INPUT_LANGUAGE_SELECTION"/>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:configChanges="orientation|keyboard|keyboardHidden" android:label="@string/app_name" android:theme="@style/Kp2aTheme_BlueNoActionBar" android:name="keepass2android.SelectCurrentDbActivity" android:windowSoftInputMode="adjustResize"
|
||||
android:exported="true">
|
||||
<service android:name="keepass2android.softkeyboard.KP2AKeyboard" android:permission="android.permission.BIND_INPUT_METHOD" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.view.InputMethod" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.view.im" android:resource="@xml/method" />
|
||||
</service>
|
||||
<activity android:name="keepass2android.softkeyboard.LatinIMESettings" android:label="@string/english_ime_settings" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="keepass2android.softkeyboard.LatinIMESettings" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="keepass2android.softkeyboard.InputLanguageSelection"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<action android:name="keepass2android.softkeyboard.INPUT_LANGUAGE_SELECTION"/>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:configChanges="orientation|keyboard|keyboardHidden" android:label="@string/app_name" android:theme="@style/Kp2aTheme_BlueNoActionBar" android:name="keepass2android.SelectCurrentDbActivity" android:windowSoftInputMode="adjustResize"
|
||||
android:exported="true">
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
@@ -98,11 +99,11 @@
|
||||
<data android:host="*" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="kp2a.action.SelectCurrentDbActivity" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
|
||||
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||
@@ -112,7 +113,7 @@
|
||||
<data android:mimeType="application/*" />
|
||||
</intent-filter>
|
||||
|
||||
<!-- intent filter for opening database files
|
||||
<!-- intent filter for opening database files
|
||||
Note that this stopped working nicely with Android 7, see e.g. https://stackoverflow.com/a/26635162/292233
|
||||
KP2A was using
|
||||
<data android:scheme="content" />
|
||||
@@ -126,7 +127,7 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik
|
||||
-->
|
||||
|
||||
|
||||
<!-- This intent filter is for apps which use content with a URI containing the extension but no specific mimeType, e.g. ASTRO file manager -->
|
||||
<!-- This intent filter is for apps which use content with a URI containing the extension but no specific mimeType, e.g. ASTRO file manager -->
|
||||
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
@@ -168,7 +169,7 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik
|
||||
</intent-filter>
|
||||
|
||||
<!-- This intent filter is for apps which use content with a URI not containing the extension but at least specify mimeType=application/octet-stream, e.g. GoogleDrive or FolderSync -->
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
@@ -218,24 +219,15 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
<data
|
||||
android:scheme="https"
|
||||
android:host="my.yubico.com"
|
||||
android:pathPrefix="/neo"/>
|
||||
<intent-filter android:label="@string/kp2a_findUrl">
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="text/plain" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="keepass2android.ACTION_START_WITH_TASK" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter android:label="@string/kp2a_findUrl">
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="text/plain" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="keepass2android.ACTION_START_WITH_TASK" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
@@ -244,27 +236,28 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik
|
||||
<data android:host="totp"/>
|
||||
<data android:host="hotp"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<uses-library android:required="false" android:name="com.sec.android.app.multiwindow" />
|
||||
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.DEFAULT_SIZE_W" android:value="632.0dip" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.DEFAULT_SIZE_H" android:value="598.0dip" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.MINIMUM_SIZE_W" android:value="426.0dip" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.MINIMUM_SIZE_H" android:value="360.0dip" />
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
</activity>
|
||||
<uses-library android:required="false" android:name="com.sec.android.app.multiwindow" />
|
||||
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.DEFAULT_SIZE_W" android:value="632.0dip" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.DEFAULT_SIZE_H" android:value="598.0dip" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.MINIMUM_SIZE_W" android:value="426.0dip" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.MINIMUM_SIZE_H" android:value="360.0dip" />
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||
|
||||
<uses-permission android:name="keepass2android.keepass2android_nonet.permission.KP2aInternalFileBrowsing" />
|
||||
<uses-permission android:name="keepass2android.keepass2android_nonet.permission.KP2aInternalSearch" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||
|
||||
<!-- Samsung Pass permission -->
|
||||
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove" />
|
||||
|
||||
</manifest>
|
||||
|
@@ -66,7 +66,6 @@ using Exception = System.Exception;
|
||||
using String = System.String;
|
||||
using Toolbar = AndroidX.AppCompat.Widget.Toolbar;
|
||||
using AndroidX.Core.Content;
|
||||
using Google.Android.Material.Snackbar;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
@@ -132,7 +131,8 @@ namespace keepass2android
|
||||
ISharedPreferences _prefs;
|
||||
|
||||
private bool _starting;
|
||||
private OtpInfo _otpInfo;
|
||||
private bool _resumeCompleted;
|
||||
private OtpInfo _otpInfo;
|
||||
private IOConnectionInfo _otpAuxIoc;
|
||||
private ChallengeInfo _chalInfo;
|
||||
private byte[] _challengeSecret;
|
||||
@@ -222,7 +222,6 @@ namespace keepass2android
|
||||
//StackBaseActivity will launch the next activity
|
||||
Intent data = new Intent();
|
||||
data.PutExtra("ioc", IOConnectionInfo.SerializeToString(_ioConnection));
|
||||
data.PutExtra("requiresSubsequentSync", _lastLoadOperation?.RequiresSubsequentSync == true);
|
||||
|
||||
SetResult(Result.Ok, data);
|
||||
|
||||
@@ -421,8 +420,14 @@ namespace keepass2android
|
||||
try
|
||||
{
|
||||
var iocAux = GetDefaultAuxLocation();
|
||||
LoadFile(iocAux);
|
||||
}
|
||||
LoadFile(iocAux);
|
||||
|
||||
if (Activity._chalInfo == null)
|
||||
{
|
||||
throw new Java.Lang.Exception("Failed to load challenge aux file");
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//this can happen e.g. if the file storage does not support GetParentPath
|
||||
@@ -802,8 +807,6 @@ namespace keepass2android
|
||||
|
||||
_password = i.GetStringExtra(KeyPassword) ?? "";
|
||||
if (!KeyProviderTypes.Any())
|
||||
|
||||
|
||||
{
|
||||
SetKeyProviderFromString(LoadKeyProviderStringForIoc(_ioConnection.Path));
|
||||
}
|
||||
@@ -1256,7 +1259,7 @@ namespace keepass2android
|
||||
case 6:
|
||||
KeyProviderTypes.Add(KeyProviders.ChallengeXC);
|
||||
break;
|
||||
case 7:
|
||||
case 7:
|
||||
//don't set to "" to prevent losing the filename. (ItemSelected is also called during recreation!)
|
||||
Kp2aLog.Log("key file length before: " + _keyFile?.Length);
|
||||
_keyFile = (FindViewById(Resource.Id.label_keyfilename).Tag ?? "").ToString();
|
||||
@@ -1441,22 +1444,15 @@ namespace keepass2android
|
||||
MakePasswordMaskedOrVisible();
|
||||
|
||||
Handler handler = new Handler();
|
||||
OnOperationFinishedHandler onOperationFinishedHandler = new AfterLoad(handler, this, _ioConnection);
|
||||
LoadDb loadOperation = (KeyProviderTypes.Contains(KeyProviders.Otp))
|
||||
OnFinish onFinish = new AfterLoad(handler, this, _ioConnection);
|
||||
LoadDb task = (KeyProviderTypes.Contains(KeyProviders.Otp))
|
||||
? new SaveOtpAuxFileAndLoadDb(App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, GetKeyProviderString(),
|
||||
onOperationFinishedHandler, this, true, _makeCurrent)
|
||||
: new LoadDb(App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, GetKeyProviderString(), onOperationFinishedHandler,true, _makeCurrent);
|
||||
onFinish, this, true, _makeCurrent)
|
||||
: new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, GetKeyProviderString(), onFinish,true, _makeCurrent);
|
||||
_loadDbFileTask = null; // prevent accidental re-use
|
||||
|
||||
_lastLoadOperation = loadOperation;
|
||||
|
||||
|
||||
//Don't use BlockingOperationStarter as that would cancel running operations.
|
||||
//This is bad when used with AutoOpen: we might get here when one database has loaded and is now synced in the background.
|
||||
//We don't want to cancel this.
|
||||
OperationRunner.Instance.Run(App.Kp2a, loadOperation, true);
|
||||
|
||||
}
|
||||
new ProgressTask(App.Kp2a, this, task).Run();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Kp2aLog.LogUnexpectedError(new Exception("cannot load database: "+e + ", c: " + (compositeKey != null) + (_ioConnection != null) + (_keyFile != null), e));
|
||||
@@ -1580,7 +1576,7 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
private bool hasRequestedKeyboardActivation = false;
|
||||
private LoadDb _lastLoadOperation;
|
||||
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
@@ -1657,60 +1653,65 @@ namespace keepass2android
|
||||
if (intent != null)
|
||||
{
|
||||
if (intent.HasExtra(Intents.OtpExtraKey))
|
||||
{
|
||||
string otp = intent.GetStringExtra(Intents.OtpExtraKey);
|
||||
_keepPasswordInOnResume = true;
|
||||
if (KeyProviderTypes.Contains(KeyProviders.Otp))
|
||||
{
|
||||
string otp = intent.GetStringExtra(Intents.OtpExtraKey);
|
||||
_keepPasswordInOnResume = true;
|
||||
if (KeyProviderTypes.Contains(KeyProviders.Otp))
|
||||
{
|
||||
|
||||
if (_otpInfo == null)
|
||||
{
|
||||
//Entering OTPs not yet initialized:
|
||||
_pendingOtps.Add(otp);
|
||||
UpdateKeyProviderUiState();
|
||||
}
|
||||
else
|
||||
{
|
||||
//Entering OTPs is initialized. Write OTP into first empty field:
|
||||
bool foundEmptyField = false;
|
||||
foreach (int otpId in _otpTextViewIds)
|
||||
{
|
||||
EditText otpEdit = FindViewById<EditText>(otpId);
|
||||
if ((otpEdit.Visibility == ViewStates.Visible) && String.IsNullOrEmpty(otpEdit.Text))
|
||||
{
|
||||
otpEdit.Text = otp;
|
||||
foundEmptyField = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//did we find a field?
|
||||
if (!foundEmptyField)
|
||||
{
|
||||
App.Kp2a.ShowMessage(this, GetString(Resource.String.otp_discarded_no_space), MessageSeverity.Error);
|
||||
}
|
||||
}
|
||||
|
||||
Spinner passwordModeSpinner = FindViewById<Spinner>(Resource.Id.password_mode_spinner);
|
||||
if (passwordModeSpinner.SelectedItemPosition != (int)KeyProviders.Otp)
|
||||
{
|
||||
passwordModeSpinner.SetSelection((int)KeyProviders.Otp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//assume the key should be used as static password
|
||||
FindViewById<EditText>(Resource.Id.password_edit).Text += otp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the activity is launched twice and the first initialization hasn't even finished, we cannot
|
||||
// reset the state and re-initialize the activity.
|
||||
// This can happen with autofill in some cases (#2869)
|
||||
if (_resumeCompleted)
|
||||
{
|
||||
|
||||
if (_otpInfo == null)
|
||||
{
|
||||
//Entering OTPs not yet initialized:
|
||||
_pendingOtps.Add(otp);
|
||||
UpdateKeyProviderUiState();
|
||||
}
|
||||
else
|
||||
{
|
||||
//Entering OTPs is initialized. Write OTP into first empty field:
|
||||
bool foundEmptyField = false;
|
||||
foreach (int otpId in _otpTextViewIds)
|
||||
{
|
||||
EditText otpEdit = FindViewById<EditText>(otpId);
|
||||
if ((otpEdit.Visibility == ViewStates.Visible) && String.IsNullOrEmpty(otpEdit.Text))
|
||||
{
|
||||
otpEdit.Text = otp;
|
||||
foundEmptyField = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//did we find a field?
|
||||
if (!foundEmptyField)
|
||||
{
|
||||
App.Kp2a.ShowMessage(this, GetString(Resource.String.otp_discarded_no_space), MessageSeverity.Error);
|
||||
}
|
||||
}
|
||||
|
||||
Spinner passwordModeSpinner = FindViewById<Spinner>(Resource.Id.password_mode_spinner);
|
||||
if (passwordModeSpinner.SelectedItemPosition != (int)KeyProviders.Otp)
|
||||
{
|
||||
passwordModeSpinner.SetSelection((int)KeyProviders.Otp);
|
||||
}
|
||||
ResetState();
|
||||
GetIocFromLaunchIntent(intent);
|
||||
InitializeAfterSetIoc();
|
||||
OnStart();
|
||||
}
|
||||
else
|
||||
{
|
||||
//assume the key should be used as static password
|
||||
FindViewById<EditText>(Resource.Id.password_edit).Text += otp;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ResetState();
|
||||
GetIocFromLaunchIntent(intent);
|
||||
InitializeAfterSetIoc();
|
||||
OnStart();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1749,179 +1750,150 @@ namespace keepass2android
|
||||
|
||||
protected override View? SnackbarAnchorView => FindViewById(Resource.Id.main_content);
|
||||
|
||||
protected override void OnResume()
|
||||
{
|
||||
base.OnResume();
|
||||
|
||||
_activityDesign.ReapplyTheme();
|
||||
protected override void OnResume()
|
||||
{
|
||||
base.OnResume();
|
||||
|
||||
Kp2aLog.Log("starting: " + _starting + ", Finishing: " + IsFinishing + ", _performingLoad: " +
|
||||
_performingLoad);
|
||||
_activityDesign.ReapplyTheme();
|
||||
|
||||
CheckBox cbOfflineMode = (CheckBox)FindViewById(Resource.Id.work_offline);
|
||||
App.Kp2a.OfflineMode =
|
||||
cbOfflineMode.Checked =
|
||||
App.Kp2a
|
||||
.OfflineModePreference; //this won't overwrite new user settings because every change is directly saved in settings
|
||||
Kp2aLog.Log("starting: " + _starting + ", Finishing: " + IsFinishing + ", _performingLoad: " +
|
||||
_performingLoad);
|
||||
|
||||
CheckBox cbSyncInBackground = (CheckBox)FindViewById(Resource.Id.sync_in_background)!;
|
||||
cbSyncInBackground.Checked = App.Kp2a.SyncInBackgroundPreference;
|
||||
UpdateInternalCacheCheckboxesVisibility();
|
||||
|
||||
|
||||
|
||||
|
||||
View killButton = FindViewById(Resource.Id.kill_app);
|
||||
if (PreferenceManager.GetDefaultSharedPreferences(this)
|
||||
.GetBoolean(GetString(Resource.String.show_kill_app_key), false))
|
||||
{
|
||||
killButton.Click += (sender, args) =>
|
||||
{
|
||||
_killOnDestroy = true;
|
||||
SetResult(Result.Canceled);
|
||||
Finish();
|
||||
|
||||
};
|
||||
killButton.Visibility = ViewStates.Visible;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
killButton.Visibility = ViewStates.Gone;
|
||||
}
|
||||
|
||||
TryGetOtpFromClipboard();
|
||||
|
||||
if (!_keepPasswordInOnResume)
|
||||
{
|
||||
if (
|
||||
_lastOnPauseTime <
|
||||
DateTime.Now -
|
||||
TimeSpan.FromSeconds(
|
||||
5) //only clear when user left the app for more than 5 seconds (allows to use Yubiclip, also allows to switch shortly to another app)
|
||||
&&
|
||||
PreferenceManager.GetDefaultSharedPreferences(this)
|
||||
.GetBoolean(GetString(Resource.String.ClearPasswordOnLeave_key), true))
|
||||
{
|
||||
ClearEnteredPassword();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
_keepPasswordInOnResume = false;
|
||||
|
||||
MakePasswordMaskedOrVisible();
|
||||
|
||||
UpdateOkButtonState();
|
||||
|
||||
if (KeyProviderTypes.Contains(KeyProviders.Challenge))
|
||||
{
|
||||
FindViewById(Resource.Id.otpInitView).Visibility =
|
||||
_challengeSecret == null ? ViewStates.Visible : ViewStates.Gone;
|
||||
}
|
||||
/*
|
||||
Snackbar snackbar = Snackbar
|
||||
.Make(FindViewById(Resource.Id.main_content),
|
||||
"snack snack snack snack snack snack snack snack snack snack snack snack snack snack snacksnack snack snacksnack snack snacksnack snack snack snack snack snack snack snack snack snack snack snack snack snack snack snacksnack snack snacksnack snack snacksnack snack snack snack snack snacksnack snack snack ",
|
||||
Snackbar.LengthLong);
|
||||
snackbar.SetTextMaxLines(5);
|
||||
snackbar.SetBackgroundTint(GetColor(Resource.Color.md_theme_secondaryContainer));
|
||||
snackbar.SetTextColor(GetColor(Resource.Color.md_theme_onSecondaryContainer));
|
||||
snackbar.SetAction("dismiss",
|
||||
view => snackbar.SetBackgroundTint(GetColor(Resource.Color.md_theme_surfaceContainer)));
|
||||
|
||||
snackbar.Show();
|
||||
|
||||
new Handler().PostDelayed(() =>
|
||||
{
|
||||
|
||||
Snackbar snackbar2 = Snackbar
|
||||
.Make(FindViewById(Resource.Id.main_content), "snack snack snack ",
|
||||
Snackbar.LengthLong);
|
||||
snackbar2.SetTextMaxLines(5);
|
||||
snackbar2.SetBackgroundTint(GetColor(Resource.Color.md_theme_errorContainer));
|
||||
snackbar2.SetTextColor(GetColor(Resource.Color.md_theme_onErrorContainer));
|
||||
snackbar2.Show();
|
||||
}, 1500);
|
||||
|
||||
|
||||
new Handler().PostDelayed(() =>
|
||||
{
|
||||
|
||||
Snackbar snackbar2 = Snackbar
|
||||
.Make(FindViewById(Resource.Id.main_content), "snack snack warn ",
|
||||
Snackbar.LengthLong);
|
||||
snackbar2.SetTextMaxLines(5);
|
||||
snackbar2.SetBackgroundTint(GetColor(Resource.Color.md_theme_inverseSurface));
|
||||
snackbar2.SetTextColor(GetColor(Resource.Color.md_theme_inverseOnSurface));
|
||||
snackbar2.Show();
|
||||
}, 2500);*/
|
||||
|
||||
//use !IsFinishing to make sure we're not starting another activity when we're already finishing (e.g. due to TaskComplete in OnActivityResult)
|
||||
//use !performingLoad to make sure we're not already loading the database (after ActivityResult from File-Prepare-Activity; this would cause _loadDbFileTask to exist when we reload later!)
|
||||
if ( !IsFinishing && !_performingLoad)
|
||||
CheckBox cbOfflineMode = (CheckBox)FindViewById(Resource.Id.work_offline);
|
||||
App.Kp2a.OfflineMode =
|
||||
cbOfflineMode.Checked =
|
||||
App.Kp2a
|
||||
.OfflineModePreference; //this won't overwrite new user settings because every change is directly saved in settings
|
||||
LinearLayout offlineModeContainer = FindViewById<LinearLayout>(Resource.Id.work_offline_container);
|
||||
var cachingFileStorage = App.Kp2a.GetFileStorage(_ioConnection) as CachingFileStorage;
|
||||
if ((cachingFileStorage != null) && cachingFileStorage.IsCached(_ioConnection))
|
||||
{
|
||||
|
||||
|
||||
// OnResume is run every time the activity comes to the foreground. This code should only run when the activity is started (OnStart), but must
|
||||
// be run in OnResume rather than OnStart so that it always occurrs after OnActivityResult (when re-creating a killed activity, OnStart occurs before OnActivityResult)
|
||||
if (_starting)
|
||||
{
|
||||
offlineModeContainer.Visibility = ViewStates.Visible;
|
||||
}
|
||||
else
|
||||
{
|
||||
offlineModeContainer.Visibility = ViewStates.Gone;
|
||||
App.Kp2a.OfflineMode = false;
|
||||
}
|
||||
|
||||
_starting = false;
|
||||
|
||||
//database not yet loaded.
|
||||
|
||||
//check if pre-loading is enabled but wasn't started yet:
|
||||
if (_loadDbFileTask == null &&
|
||||
_prefs.GetBoolean(GetString(Resource.String.PreloadDatabaseEnabled_key), true))
|
||||
{
|
||||
// Create task to kick off file loading while the user enters the password
|
||||
_loadDbFileTask = Task.Factory.StartNew(PreloadDbFile);
|
||||
_loadDbTaskOffline = App.Kp2a.OfflineMode;
|
||||
}
|
||||
}
|
||||
|
||||
View killButton = FindViewById(Resource.Id.kill_app);
|
||||
if (PreferenceManager.GetDefaultSharedPreferences(this)
|
||||
.GetBoolean(GetString(Resource.String.show_kill_app_key), false))
|
||||
{
|
||||
killButton.Click += (sender, args) =>
|
||||
{
|
||||
_killOnDestroy = true;
|
||||
SetResult(Result.Canceled);
|
||||
Finish();
|
||||
|
||||
};
|
||||
killButton.Visibility = ViewStates.Visible;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
killButton.Visibility = ViewStates.Gone;
|
||||
}
|
||||
|
||||
TryGetOtpFromClipboard();
|
||||
|
||||
if (!_keepPasswordInOnResume)
|
||||
{
|
||||
if (
|
||||
_lastOnPauseTime <
|
||||
DateTime.Now -
|
||||
TimeSpan.FromSeconds(
|
||||
5) //only clear when user left the app for more than 5 seconds (allows to use Yubiclip, also allows to switch shortly to another app)
|
||||
&&
|
||||
PreferenceManager.GetDefaultSharedPreferences(this)
|
||||
.GetBoolean(GetString(Resource.String.ClearPasswordOnLeave_key), true))
|
||||
{
|
||||
ClearEnteredPassword();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (compositeKeyForImmediateLoad != null)
|
||||
{
|
||||
//reload the database (without most other stuff performed in PerformLoadDatabase.
|
||||
// We're assuming that the db file (and if appropriate also the key file) are still available
|
||||
// and there's no need to re-init the file storage. if it is, loading will fail and the user has
|
||||
// to retry with typing the full password, but that's intended to avoid showing the password to a
|
||||
// a potentially unauthorized user (feature request https://keepass2android.codeplex.com/workitem/274)
|
||||
Handler handler = new Handler();
|
||||
OnOperationFinishedHandler onOperationFinishedHandler = new AfterLoad(handler, this, _ioConnection);
|
||||
_performingLoad = true;
|
||||
LoadDb loadOperation = new LoadDb(App.Kp2a, _ioConnection, _loadDbFileTask, compositeKeyForImmediateLoad, GetKeyProviderString(),
|
||||
onOperationFinishedHandler, false, _makeCurrent);
|
||||
_loadDbFileTask = null; // prevent accidental re-use
|
||||
_lastLoadOperation = loadOperation;
|
||||
OperationRunner.Instance.Run(App.Kp2a, loadOperation, true);
|
||||
compositeKeyForImmediateLoad = null; //don't reuse or keep in memory
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
bool showKeyboard = true;
|
||||
|
||||
|
||||
EditText pwd = (EditText) FindViewById(Resource.Id.password_edit);
|
||||
pwd.PostDelayed(() =>
|
||||
{
|
||||
InputMethodManager keyboard = (InputMethodManager) GetSystemService(InputMethodService);
|
||||
if (showKeyboard)
|
||||
{
|
||||
pwd.RequestFocus();
|
||||
keyboard.ShowSoftInput(pwd, 0);
|
||||
}
|
||||
else
|
||||
keyboard.HideSoftInputFromWindow(pwd.WindowToken, HideSoftInputFlags.ImplicitOnly);
|
||||
}, 50);
|
||||
}
|
||||
_keepPasswordInOnResume = false;
|
||||
|
||||
MakePasswordMaskedOrVisible();
|
||||
|
||||
UpdateOkButtonState();
|
||||
|
||||
if (KeyProviderTypes.Contains(KeyProviders.Challenge))
|
||||
{
|
||||
FindViewById(Resource.Id.otpInitView).Visibility =
|
||||
_challengeSecret == null ? ViewStates.Visible : ViewStates.Gone;
|
||||
}
|
||||
|
||||
//use !IsFinishing to make sure we're not starting another activity when we're already finishing (e.g. due to TaskComplete in OnActivityResult)
|
||||
//use !performingLoad to make sure we're not already loading the database (after ActivityResult from File-Prepare-Activity; this would cause _loadDbFileTask to exist when we reload later!)
|
||||
if (!IsFinishing && !_performingLoad)
|
||||
{
|
||||
|
||||
|
||||
// OnResume is run every time the activity comes to the foreground. This code should only run when the activity is started (OnStart), but must
|
||||
// be run in OnResume rather than OnStart so that it always occurrs after OnActivityResult (when re-creating a killed activity, OnStart occurs before OnActivityResult)
|
||||
if (_starting)
|
||||
{
|
||||
|
||||
_starting = false;
|
||||
|
||||
//database not yet loaded.
|
||||
|
||||
//check if pre-loading is enabled but wasn't started yet:
|
||||
if (_loadDbFileTask == null &&
|
||||
_prefs.GetBoolean(GetString(Resource.String.PreloadDatabaseEnabled_key), true))
|
||||
{
|
||||
// Create task to kick off file loading while the user enters the password
|
||||
_loadDbFileTask = Task.Factory.StartNew(PreloadDbFile);
|
||||
_loadDbTaskOffline = App.Kp2a.OfflineMode;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (compositeKeyForImmediateLoad != null)
|
||||
{
|
||||
//reload the database (without most other stuff performed in PerformLoadDatabase.
|
||||
// We're assuming that the db file (and if appropriate also the key file) are still available
|
||||
// and there's no need to re-init the file storage. if it is, loading will fail and the user has
|
||||
// to retry with typing the full password, but that's intended to avoid showing the password to a
|
||||
// a potentially unauthorized user (feature request https://keepass2android.codeplex.com/workitem/274)
|
||||
Handler handler = new Handler();
|
||||
OnFinish onFinish = new AfterLoad(handler, this, _ioConnection);
|
||||
_performingLoad = true;
|
||||
LoadDb task = new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKeyForImmediateLoad, GetKeyProviderString(),
|
||||
onFinish, false, _makeCurrent);
|
||||
_loadDbFileTask = null; // prevent accidental re-use
|
||||
new ProgressTask(App.Kp2a, this, task).Run();
|
||||
compositeKeyForImmediateLoad = null; //don't reuse or keep in memory
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
bool showKeyboard = true;
|
||||
|
||||
|
||||
EditText pwd = (EditText)FindViewById(Resource.Id.password_edit);
|
||||
pwd.PostDelayed(() =>
|
||||
{
|
||||
InputMethodManager keyboard = (InputMethodManager)GetSystemService(InputMethodService);
|
||||
if (showKeyboard)
|
||||
{
|
||||
pwd.RequestFocus();
|
||||
keyboard.ShowSoftInput(pwd, 0);
|
||||
}
|
||||
else
|
||||
keyboard.HideSoftInputFromWindow(pwd.WindowToken, HideSoftInputFlags.ImplicitOnly);
|
||||
}, 50);
|
||||
}
|
||||
|
||||
_resumeCompleted = true;
|
||||
}
|
||||
|
||||
private void TryGetOtpFromClipboard()
|
||||
@@ -2043,38 +2015,10 @@ namespace keepass2android
|
||||
{
|
||||
App.Kp2a.OfflineModePreference = App.Kp2a.OfflineMode = args.IsChecked;
|
||||
};
|
||||
|
||||
CheckBox cbSyncInBackground = (CheckBox)FindViewById(Resource.Id.sync_in_background);
|
||||
cbSyncInBackground.CheckedChange += (sender, args) =>
|
||||
{
|
||||
App.Kp2a.SyncInBackgroundPreference = args.IsChecked;
|
||||
UpdateInternalCacheCheckboxesVisibility();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private void UpdateInternalCacheCheckboxesVisibility()
|
||||
{
|
||||
|
||||
LinearLayout syncInBackgroundContainer = FindViewById<LinearLayout>(Resource.Id.sync_in_background_container)!;
|
||||
|
||||
LinearLayout offlineModeContainer = FindViewById<LinearLayout>(Resource.Id.work_offline_container)!;
|
||||
var cachingFileStorage = App.Kp2a.GetFileStorage(_ioConnection) as CachingFileStorage;
|
||||
if ((cachingFileStorage != null) && cachingFileStorage.IsCached(_ioConnection))
|
||||
{
|
||||
syncInBackgroundContainer.Visibility = ViewStates.Visible;
|
||||
offlineModeContainer.Visibility =
|
||||
App.Kp2a.SyncInBackgroundPreference ? ViewStates.Gone : ViewStates.Visible;
|
||||
}
|
||||
else
|
||||
{
|
||||
syncInBackgroundContainer.Visibility = offlineModeContainer.Visibility = ViewStates.Gone;
|
||||
App.Kp2a.OfflineMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
private String LoadKeyProviderStringForIoc(String filename) {
|
||||
|
||||
}
|
||||
|
||||
private String LoadKeyProviderStringForIoc(String filename) {
|
||||
if ( _rememberKeyfile ) {
|
||||
string keyfile = App.Kp2a.FileDbHelper.GetKeyFileForFile(filename);
|
||||
if (String.IsNullOrEmpty(keyfile))
|
||||
@@ -2142,11 +2086,11 @@ namespace keepass2android
|
||||
Finish();
|
||||
}
|
||||
|
||||
private class AfterLoad : OnOperationFinishedHandler {
|
||||
private class AfterLoad : OnFinish {
|
||||
readonly PasswordActivity _act;
|
||||
private readonly IOConnectionInfo _ioConnection;
|
||||
|
||||
public AfterLoad(Handler handler, PasswordActivity act, IOConnectionInfo ioConnection):base(App.Kp2a, handler)
|
||||
public AfterLoad(Handler handler, PasswordActivity act, IOConnectionInfo ioConnection):base(act, handler)
|
||||
{
|
||||
_act = act;
|
||||
_ioConnection = ioConnection;
|
||||
@@ -2253,7 +2197,7 @@ namespace keepass2android
|
||||
if (!Success)
|
||||
_act.InitFingerprintUnlock();
|
||||
|
||||
_act._lastLoadOperation = null;
|
||||
|
||||
_act._performingLoad = false;
|
||||
|
||||
}
|
||||
@@ -2287,7 +2231,7 @@ namespace keepass2android
|
||||
private readonly PasswordActivity _act;
|
||||
|
||||
|
||||
public SaveOtpAuxFileAndLoadDb(IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, CompositeKey compositeKey, string keyfileOrProvider, OnOperationFinishedHandler operationFinishedHandler, PasswordActivity act, bool updateLastUsageTimestamp, bool makeCurrent) : base(app, ioc, databaseData, compositeKey, keyfileOrProvider, operationFinishedHandler,updateLastUsageTimestamp,makeCurrent)
|
||||
public SaveOtpAuxFileAndLoadDb(IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, CompositeKey compositeKey, string keyfileOrProvider, OnFinish finish, PasswordActivity act, bool updateLastUsageTimestamp, bool makeCurrent) : base(act, app, ioc, databaseData, compositeKey, keyfileOrProvider, finish,updateLastUsageTimestamp,makeCurrent)
|
||||
{
|
||||
_act = act;
|
||||
}
|
||||
|
@@ -339,10 +339,10 @@ namespace keepass2android
|
||||
if (PreferenceManager.GetDefaultSharedPreferences(this)
|
||||
.GetBoolean(GetString(Resource.String.SyncAfterQuickUnlock_key), false))
|
||||
{
|
||||
new SyncUtil(this).StartSynchronizeDatabase(App.Kp2a.CurrentDb.Ioc);
|
||||
new SyncUtil(this).SynchronizeDatabase(Finish);
|
||||
}
|
||||
|
||||
Finish();
|
||||
else
|
||||
Finish();
|
||||
|
||||
|
||||
|
||||
|
@@ -1,65 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/background_ops_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/md_theme_surfaceVariant"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
|
||||
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/background_ops_message"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_marginBottom="3dp"
|
||||
android:text="" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/background_ops_submessage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_marginBottom="3dp"
|
||||
android:textSize="12sp"
|
||||
android:text="" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/cancel_background"
|
||||
style="?attr/materialIconButtonStyle"
|
||||
app:icon="@drawable/baseline_close_24"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="6dip"
|
||||
android:layout_margin="6dip"
|
||||
android:layout_weight="0"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
@@ -43,6 +43,7 @@
|
||||
style="@style/EntryEditSingleLine_EditText"
|
||||
android:layout_marginRight="0dip" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/protection"
|
||||
|
@@ -75,11 +75,6 @@ android:layout_height="wrap_content">
|
||||
android:layout_marginRight="0dip"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
<CheckBox
|
||||
android:id="@+id/protection"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="0dip"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
@@ -4,35 +4,18 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
<LinearLayout android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
||||
|
||||
|
||||
<keepass2android.views.BackgroundOperationContainer
|
||||
android:visibility="gone"
|
||||
android:id="@+id/background_ops_container"
|
||||
android:layout_below="@id/top"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
/>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/entry_scroll"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:fillViewport="true"
|
||||
android:background="?android:attr/colorBackground"
|
||||
android:scrollbarStyle="insideOverlay">
|
||||
|
||||
<keepass2android.view.EntryContentsView
|
||||
android:id="@+id/entry_contents"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent" />
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/entry_edit"
|
||||
android:layout_width="wrap_content"
|
||||
|
@@ -354,22 +354,13 @@
|
||||
android:layout_height="1dp"
|
||||
android:layout_above="@id/bottom_bar"
|
||||
android:background="#b8b8b8" />
|
||||
|
||||
<keepass2android.views.BackgroundOperationContainer
|
||||
android:visibility="gone"
|
||||
android:id="@+id/background_ops_container"
|
||||
android:layout_below="@id/top"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
/>
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/main_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@id/divider2"
|
||||
android:layout_below="@id/background_ops_container"
|
||||
android:layout_below="@id/top"
|
||||
android:fitsSystemWindows="true">
|
||||
<fragment
|
||||
android:name="keepass2android.GroupListFragment"
|
||||
|
@@ -318,30 +318,6 @@
|
||||
android:text="@string/help_quickunlock"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/sync_in_background_container"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/sync_in_background"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/SyncOfflineCacheInBackground_title" />
|
||||
<keepass2android.views.Kp2aShortHelpView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/TextAppearance_Help_Dense"
|
||||
|
||||
app:help_text="@string/SyncOfflineCacheInBackground_summary"
|
||||
app:title_text="@string/SyncOfflineCacheInBackground_title"
|
||||
android:text="@string/SyncOfflineCacheInBackground_summary"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/work_offline_container"
|
||||
android:orientation="horizontal"
|
||||
@@ -352,7 +328,7 @@
|
||||
android:id="@+id/work_offline"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/UseOfflineMode" />
|
||||
<keepass2android.views.Kp2aShortHelpView
|
||||
android:layout_width="wrap_content"
|
||||
@@ -365,7 +341,6 @@
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/kill_app"
|
||||
android:text="@string/kill_app_label"
|
||||
|
@@ -1169,4 +1169,8 @@ První veřejné vydání
|
||||
<string name="kp2a_switch_on_sendgodone_summary">Přepnout zpět při stisknutí tlačítka odeslat/pokračovat/ukončit</string>
|
||||
<string name="qr_scanning_error_no_google_play_services">Skenování QR kódu vyžaduje služby Google Play. Nainstalujte nebo aktualizujte služby Google Play ve svém zařízení.</string>
|
||||
<string name="english_ime_settings">Nastavení klávesnice Keepass2Android</string>
|
||||
<string name="autoswitch_enabled_but_not_setup">Poznámka: Máte povoleno Aplikace - Nastavení - Přístup k heslu - Přepínání klávesnice - Automatické přepínání klávesnice, ale nezdá se, že je správně nakonfigurováno.</string>
|
||||
<string name="switch_keyboard_for_totp_enabled">Poznámka: Máte povoleno Aplikace - Přístup k heslu - Služba automatického vyplňování - Automatické vyplňování pro položky TOTP. To může způsobit, že se toto okno zobrazí, když otevřete položku s TOTP.</string>
|
||||
<string name="switch_keyboard_inside_kp2a_enabled">Poznámka: V aplikaci Keepass2Android jste povolili možnost Aplikace - Zabezpečení - Použít vestavěnou klávesnici. To může způsobit, že se toto okno zobrazí při otevření aplikace nebo úpravě položky.</string>
|
||||
<string name="switch_keyboard_on_search_enabled">Poznámka: Máte povoleno Aplikace - Zabezpečení - Přístup k heslu - Přepínání klávesnice - Přepínání klávesnice. To může způsobit, že se toto okno zobrazí při vyhledávání položky z prohlížeče.</string>
|
||||
</resources>
|
||||
|
@@ -164,7 +164,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die
|
||||
<string name="invalid_db_sig">Datenbank-Format wurde nicht erkannt.</string>
|
||||
<string name="keyfile_does_not_exist">Schlüssel-Datei existiert nicht.</string>
|
||||
<string name="no_keyfile_selected">Keine Schlüsseldatei ausgewählt.</string>
|
||||
<string name="keyfile_is_empty">Schlüssel-Datei ist leer.</string>
|
||||
<string name="keyfile_is_empty">Schlüsseldatei ist leer.</string>
|
||||
<string name="length">Länge</string>
|
||||
<string name="list_size_title">Größe der Gruppenliste</string>
|
||||
<string name="list_size_summary">Schriftgröße in der Gruppenliste</string>
|
||||
@@ -378,7 +378,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die
|
||||
<string name="ActivateSearchViewOnStart_summary">Aktiviert das Suchfeld in der Gruppenansicht nach dem Entsperren oder wenn ein Eintrag gesucht wird.</string>
|
||||
<string name="NoDonateOption_title">Spenden-Option ausblenden</string>
|
||||
<string name="NoDonateOption_summary">Diese Einstellung ist ein Dankeschön an alle, die gespendet haben. Sie steht erst nach einer gewissen Zeit der Benutzung von Keepass2Android zur Verfügung.</string>
|
||||
<string name="NoDonateOption_question">Ohne Spenden gäbe es diese App nicht und sie könnte nicht ständig verbessert werden! Wenn Sie noch nicht gespendet haben, sollten Sie dies jetzt in Betracht ziehen.</string>
|
||||
<string name="NoDonateOption_question">Ohne Spenden würde diese App nicht existieren und ständig verbessert werden! Wenn du noch nicht gespendet hast, erwäge bitte, dies jetzt zu tun</string>
|
||||
<string name="NoDonationReminder_title">Nie um eine Spende bitten</string>
|
||||
<string name="NoDonationReminder_summary">Ich werde keinen Cent spenden oder habe bereits gespendet. Bitte niemals um eine Spende, nicht einmal am Geburtstag des Autors.</string>
|
||||
<string name="UseOfflineCache_title">Datenbank-Caching</string>
|
||||
@@ -717,12 +717,12 @@ Anbei einige Tipps, die bei der Diagnose des Problems helfen können:\n
|
||||
<string name="CloseDbAfterFailedAttempts">Datenbank nach drei fehlgeschlagenen biometrischen Entsperrversuchen schließen.</string>
|
||||
<string name="WarnFingerprintInvalidated">Achtung! Die biometrische Authentifizierung kann von Android ungültig gemacht werden, z. B. nach dem Hinzufügen eines neuen Fingerabdrucks in den Geräteeinstellungen. Bitte sicherstellen, dass jederzeit klar ist, wie mit dem eigenen Hauptpasswort entsperrt werden kann!</string>
|
||||
<string-array name="ChangeLog_1_12">
|
||||
<item>Upgraded from Xamarin Android to .net 8</item>
|
||||
<item>Von Xamarin Android auf .NET 8 upgegradet</item>
|
||||
<item>Upgrade auf Target-SDK 34</item>
|
||||
<item>Upgraded to Material 3 user interface</item>
|
||||
<item>Improve autofill to work with Compose apps</item>
|
||||
<item>Fix hostname matching in autofill and search</item>
|
||||
<item>Fix issue with password generator</item>
|
||||
<item>Auf MUI 3 upgegradet</item>
|
||||
<item>Verbessertes automatisches Ausfüllen damit Compose-Apps funktionieren</item>
|
||||
<item>Hostnamen-vergleiche im automatischen Ausfüllen und der Suche gefixt</item>
|
||||
<item>Probleme mit dem Passwort Generator behoben</item>
|
||||
</string-array>
|
||||
<string-array name="ChangeLog_1_12_net">
|
||||
<item>OneDrive SDK auf Version 5.68 aktualisiert</item>
|
||||
@@ -1145,7 +1145,7 @@ Erstes öffentliches Release</string>
|
||||
<string name="masterkey_infotext_head">Kennst du dein Master-Passwort?</string>
|
||||
<string name="masterkey_infotext_main">Bitte beachte, dass du deine Datenbank ohne den Hauptschlüssel nicht öffnen kannst. Es gibt keine Möglichkeit, das Hauptpasswort „zurückzusetzen“.</string>
|
||||
<string name="masterkey_infotext_fingerprint_note">Bitte auch bedenken, dass das Biometrische Entsperren über das Speichern des Hauptschlüssels im sicheren Speicher von Android funktioniert. Dieser Speicher kann von Android jederzeit gelöscht werden, z. B. wenn ein neuer Fingerabdruck in den Systemeinstellungen hinzugefügt wird. Daher sich nicht auf das biometrische Entsperren verlassen, sondern sich bitte das eigene Hauptpasswort merken!</string>
|
||||
<string name="backup_infotext_head">Gibt es eine Sicherung der Datenbank?</string>
|
||||
<string name="backup_infotext_head">Ist deine Datenbank gesichert?</string>
|
||||
<string name="backup_infotext_main">Keepass2Android speichert die Passwörter in einer Datei an einem frei wählbarem Speicherort.Ist sichergestellt, dass die Datei auch dann noch verfügbar ist, wenn das Telefon verloren geht oder gestohlen wird, oder wenn die Datei zerstört oder gelöscht wird? Bitte sicherstellen, dass immer eine aktuelle Kopie an einem sichern Ort aufbewahrt wird!</string>
|
||||
<string name="backup_infotext_note">Um jetzt eine Sicherung zu erstellen, nach %1$s > %2$s > %3$s gehen.</string>
|
||||
<string name="emergency_infotext_head">Hast du für Notfälle vorgesorgt?</string>
|
||||
@@ -1162,4 +1162,5 @@ Erstes öffentliches Release</string>
|
||||
<string name="kp2a_switch_on_sendgodone_summary">Beim Drücken von Senden/Los/Fertig zurückschalten</string>
|
||||
<string name="qr_scanning_error_no_google_play_services">QR-Code-Scannen erfordert Google Play-Dienste. Bitte installiere oder aktualisiere Google Play-Dienste auf deinem Gerät.</string>
|
||||
<string name="english_ime_settings">Android-Tastatureinstellungen</string>
|
||||
<string name="autoswitch_enabled_but_not_setup">Notiz: Du hast Einstellungen - Anwendung - Passwortzugriff - Wechsel der Eingabemethode - Auto-Umschalten der Tastatur eingeschaltet, aber sieht aus als würde es nicht funktionieren</string>
|
||||
</resources>
|
||||
|
@@ -1178,4 +1178,5 @@
|
||||
<string name="kp2a_switch_on_sendgodone">Volver cuando termine</string>
|
||||
<string name="kp2a_switch_on_sendgodone_summary">Volver cuando se presione enviar/ir/finalizado</string>
|
||||
<string name="english_ime_settings">Ajustes del teclado de Keepass2Android</string>
|
||||
<string name="switch_keyboard_on_search_enabled">Nota: Ha habilitado la aplicación - Seguridad - Acceso a la contraseña - Interruptor de teclado - Cambiar teclado. Esto puede causar que esta ventana se muestre cuando busque una entrada desde el navegador.</string>
|
||||
</resources>
|
||||
|
@@ -546,6 +546,7 @@
|
||||
<string name="filestoragename_dropboxKP2A">Dropbox (dossier KP2A)</string>
|
||||
<string name="filestoragehelp_dropboxKP2A">Si vous ne voulez pas donner l\'accès KP2A à votre espace Dropbox complet, vous pouvez sélectionner cette option. Seul l\'accès au dossier Apps/Keepass2Android sera demandé. Ceci est particulièrement adapté lorsque vous créez une nouvelle base de données. Si vous avez déjà une base de données, cliquez sur cette option pour créer le dossier, puis placez votre fichier dans le dossier (à partir de votre PC) et puis sélectionnez à nouveau cette option pour ouvrir le fichier.</string>
|
||||
<string name="filestoragename_gdrive">Google Drive</string>
|
||||
<string name="filestoragehelp_gdrive">Attention : Google restreint l\'accès à Google Drive depuis les applications pour un nombre grandissant d\'utilisateurs. Si l\'intégration de Google Drive ne fonctionne pas, utilisez plutôt le sélecteur de fichiers système et sélectionnez Google Drive !</string>
|
||||
<string name="filestoragename_gdriveKP2A">Google Drive (fichiers KP2A)</string>
|
||||
<string name="filestoragehelp_gdriveKP2A">Si vous ne voulez pas donner à KP2A un accès complet à Google Drive, vous pouvez sélectionner cette option. Notez que vous devez d\'abord créer un fichier de base de données, les fichiers existants ne sont pas visibles pour l\'application. Choisissez cette option dans l\'écran Créer une base de données ou, si vous avez déjà ouvert une base de données, en exportant la base de données en choisissant cette option.</string>
|
||||
<string name="filestoragename_pcloud">PCloud (dossier KP2A)</string>
|
||||
@@ -723,9 +724,15 @@
|
||||
<item>Mise à niveau de Xamarin Android vers. net 8</item>
|
||||
<item>Mise à niveau vers Target SDK 34</item>
|
||||
<item>Mise à niveau vers l\'interface utilisateur Material 3</item>
|
||||
<item>Improve autofill to work with Compose apps</item>
|
||||
<item>Amélioration de la saisie automatique pour fonctionner avec les applications Compose</item>
|
||||
<item>Fix hostname matching in autofill and search</item>
|
||||
<item>Fix issue with password generator</item>
|
||||
<item>Corriger le problème avec le générateur de mot de passe</item>
|
||||
</string-array>
|
||||
<string-array name="ChangeLog_1_12_net">
|
||||
<item>Mise à jour de OneDrive SDK vers la version 5.68</item>
|
||||
<item>Mise à jour du SDK Dropbox vers la version 7.0.0</item>
|
||||
<item>Mise à jour Gradle, NewtonsoftJson, FluentFTP, MegaApiClient et okhttp</item>
|
||||
<item>Correction de bugs dans la sélection de fichiers WebDav</item>
|
||||
</string-array>
|
||||
<string-array name="ChangeLog_1_11">
|
||||
<item>Ajout de boutons d\'action flottants pour la recherche et l\'aperçu TOTP (si des entrées TOTP sont présentes).</item>
|
||||
@@ -821,6 +828,89 @@
|
||||
* Nouvelle implémentation pour OneDrive : inclut la prise en charge de OneDrive Entreprise, des fichiers partagés, des périmètres d\'accès sélectionnables, des comptes multiples et des corrections de problèmes d\'accès en mode hors-ligne\n
|
||||
* Corrections d\'anomalies
|
||||
</string>
|
||||
<string name="ChangeLog_1_07"> Version 1.07\n
|
||||
* Corrige les crashs sur les Samsung avec Android 9\n
|
||||
* Permet d\'ouvrir plus d\'une base de données, compatible avec KeeAutoExec\n
|
||||
* SFTP : permet l\'authentification avec clé publique, vérifie si la clé de l\'hôte a changé\n
|
||||
* Introduction du support pCloud - merci à gilbsgilbs !\n
|
||||
* Mise en place explicite du support Nextcloud\n
|
||||
* Améliore l\'enregistrement et la mise à jour des pièces jointes des entrées\n
|
||||
* Plus d\'options pour adapter le comportement aux préférences personnelles\n
|
||||
* SSL : acceptation et confiance avec les certificats utilisateur\n
|
||||
* Améliore la saisie automatique (fonctionne maintenant avec Firefox, permet de réduire les popups)\n
|
||||
* Résolution de bugs\n
|
||||
</string>
|
||||
<string name="ChangeLog_1_06">Version 1.06\n
|
||||
* Changement vers ykDroid au lieu de YubiChallenge comme application pour le défi-réponse de Yubikey.\n
|
||||
* implémentation du support de défi-réponse compatible KeepassXC. Note : Le format de base de données doit être KDBX4 !\n
|
||||
* Blocage du chargement de fichiers supprimés depuis Google Drive\n
|
||||
* Changement d\'implémentation TLS pour FTPS, ajout d\'un contournement du bug JSch avec les serveurs compatibles avec gssapi-with-mic\n
|
||||
* Correction de bugs\n </string>
|
||||
<string name="ChangeLog_1_05"> Version 1.05\n * Utilisation des canaux de notification Android 8, ce qui permet la configuration via les paramètres système\n * Affichage de l’icône entrée dans la notification\n * Utilisation d\'icônes adaptatifs pour Android 8, utilisez l\'icône arrondi du lanceur pour Android 7\n * Permet d’activer la recherche au déverrouillage (voir réglages) \n * Modification de comment les fichiers sont écrits en utilisant le framework Storage Access, corrections de problèmes sur les mises à jour des fichiers ouvert sur Google Drive avec le sélecteur du système fichier\n * Ajout de textes d’informations afin d’éviter certaines incompréhensions commune \n * Création de sauvegardes locales pour les bases ouvertes avec succès pour réduire le risque de perte de donnée\n * Mise à jour de JSch pour supporté les derniers chiffrements SSH\n * Permettre la modification des paramètres de connexion, par exemple lorsque le mot de passe WebDav a changé\n * Ajout du support pour mot de passe statique Yubikey Neo\n * Permettre de désactiver les suggestions automatiques\n * Correction des fuites de données vers logcat\n * Corrections d\'anomalies\n
|
||||
</string>
|
||||
<string name="ChangeLog_1_04b"> Version 1.04b\n * Évite les plantages lorsque l’utilisateur essaie d’activer la fonctionnalité de remplissage automatique sur les appareils Huawei.\n
|
||||
</string>
|
||||
<string name="ChangeLog_1_04">Version 1.04
|
||||
* Ajout du service de saisie automatique pour Android 8.0 et plus.
|
||||
* Mise à niveau des librairies, des outils de build et de la version du sdk cible
|
||||
</string>
|
||||
<string name="ChangeLog_1_03">Version 1.03
|
||||
* Suppression du service d\'accessibilité pour le remplissage automatique tel que demandé par Google. Voir les paramètres d’accès mot de passe pour trouver un plugin reproduisant la fonctionnalité précédente.
|
||||
* Ajout d\'applications tierces comme option de stockage
|
||||
* Visionneuse intégrée pour le voir des images jointes sans les transférer sur d’autres applications
|
||||
* OkHttp mis à jour pour résoudre certains problèmes de connexion
|
||||
* Support des entrées de KeeTrayTOTP, supporte désormais les entrées Steam</string>
|
||||
<string name="ChangeLog_1_02"> Version 1.02\n
|
||||
* Quelques améliorations liées à la sécurité. Merci beaucoup pour le rapport jean-baptiste.cayrou@thalesgroup.com et vincent.fargues@thalesgroup.com et aussi pour votre collaboration !\n
|
||||
* Support de KeyboardSwapPlugin (voir les paramètres d\'accès aux mots de passe) : permet de changer de méthode de saisie automatiquement sur les appareils sans « root ». Merci à Mishaal Rahman d\'XDA-Developers de l\'avoir rendu possible.\n
|
||||
* Correction pour les services d’accessibilité avec les versions récentes de Chrome\n
|
||||
* Correction pour les nettoyages non nécessaires des données d\'empreintes digitales\n
|
||||
* Correction de plantages mineurs\n
|
||||
* Mise à jour du kit de développement Dropbox pour s\'assurer de la compatibilité future\n
|
||||
* Suppression des rapports d\'erreur en utilisant Xamarin Insights\n
|
||||
* Mise à jour des outils de compilation\n
|
||||
</string>
|
||||
<string name="ChangeLog_1_01g"> Version 1. 1-g\n
|
||||
* Correction pour un plantage lorsque vous essayez de travailler hors ligne\n
|
||||
* Correction pour un codage incorrect des identifiants FTP(S)\n
|
||||
* Correction pour les plantages lors de l\'utilisation de OneDrive et des anciennes versions d\'Android\n
|
||||
* Affiche les temps en temps local dans l\'écran d\'entrée\n
|
||||
</string>
|
||||
<string name="ChangeLog_1_01d">Version 1.01-d\n * Correction pour le listing des fichiers OneDrive\n * Possibilité d’ignorer les erreurs de certificat lorsque la vérification du nom de l’hôte échoue (non recommandé pour une utilisation en production) \n * Correction pour QuickUnlock qui parfois ne fonctionnait malgré la saisie correcte du code\n </string>
|
||||
<string name="ChangeLog_0_9_8c">Version 0.9.8c\n
|
||||
* Correctif pour la vulnérabilité SSL dans Microsoft Live SDK (utilisé lorsque vous accédez à des fichiers via OneDrive)\n
|
||||
* Bug fix : la version précédente contenait deux méthodes de saisie (l\'une des deux plante)\n </string>
|
||||
<string name="ChangeLog_1_01">Version 1.01\n * Ajout du support pour le nouveau format KDBX-4 (compatible avec Keepass 2.35) y compris la dérivation de clés Argon2 et ChaCha20 cryptage.\n * Nouvelle implémentation du stockage WebDav, il est maintenant possible de parcourir les fichiers et le stockage prend en charge un chiffrement moderne.\n * Nouvelle implémentation du stockage FTP qui permet maintenant de parcourir les fichiers et de prendre en charge le cryptage (FTPS).\n * Mise à jour du SDK OneDrive (le SDK Live précédemment utilisé n’est plus mis à jour).\n * Mise à jour du SDK Dropbox vers la version 2 (la version 1 n\'est plus supportée).\n * Ajout du support pour OwnCloud.\n *Demande d’autorisation de stockage avant d’ouvrir les fichiers locaux. </string>
|
||||
<string name="ChangeLog_1_0_0e">Version 1.0.0e\n
|
||||
* Règle un problème avec le scaneur d\'empreintes digitales sur les anciens appareils Samsung tournant avec Android 6.\n
|
||||
* Ajout d\'un support natif pour les processeurs x86.\n
|
||||
* Permet d\'afficher ou cacher les caractères dans les champs texte de saisie si le scanner d\'empreinte digital a été activé. \n
|
||||
* Construction de mise à jour système </string>
|
||||
<string name="ChangeLog_1_0_0">Version 1.0.0\n * Déverrouiller par empreinte digitale (nécessite Android 6.0+ ou un appareil Samsung)\n * Ajout du service de saisie automatique (nécessite Android 5.0+)\n * Ajout du support pour l\'entrée templates\n * Ajout d\'un mode \"hors connexion\"\n * Possibilité de copier les entrées\n * Mode semi-automatique pour les champs noms\n * Possibilité de supprimer des éléments de liste des fichiers récents\n * Demande des autorisations à l\'exécution pour Android 6.0\n * Corrections de bugs (dans le clavier intégré, lorsque vous sélectionnez les icônes)\n * Ajout d\'une option pour envoyer des rapports d\'erreur\n * Ajouts de plusieurs messages d\'aide\n </string>
|
||||
<string name="ChangeLog_0_9_9">Version 0.9.9\n
|
||||
* Refonte complète de l\'interface utilisateur. Merci beaucoup à Stefano Pignataro (http://www.spstudio.at) pour son aide!\n
|
||||
* Permet l\'ajout d\'icônes personnalisées\n
|
||||
* Support pour l\'affichage fractionné sur les appareils Samsung\n
|
||||
* Nombre de rotation par défaut pour le chiffrement de nouvelle base de données\n
|
||||
* Vérification des clés dupliquées des champs supplémentaires pour éviter la perte de données\n
|
||||
</string>
|
||||
<string name="ChangeLog_0_9_9c"> Version 0.9.9c
|
||||
* Retour du thème sombre
|
||||
* Vous pouvez installer d\'autres pack d\'icones (Icones Windows ancien sont disponibles sur le Play Store)
|
||||
* Ajout d\'une confirmation lors d\'une suppression d\'éléments sans passer par la corbeille
|
||||
* Correction de bugs (mauvais affichage de l\'encodage secret OTP, mauvaise icone de l\'application dans certains endroits)
|
||||
</string>
|
||||
<string name="ChangeLog_0_9_8b">Version 0.9.8b\n
|
||||
* corrections de bugs (Sauvegarde a échoué pour certaines bases, exporter vers le périphérique local ne fonctionne pas, sélectionner certaines options de préférence crash l\'app)\n</string>
|
||||
<string name="ChangeLog_0_9_8">Version 0.9.8\n
|
||||
* Support du Storage Access Framework (permet l\'écriture sur carte SD et Google Drive dans KP2A Offline)\n
|
||||
* Essai de détecter les erreurs de saisie dans les URL WebDAV (répertoire au lieu du fichier)\n
|
||||
* Police de mot de passe modifié\n
|
||||
* Autorise le changement de compte Dropbox\n
|
||||
* correction de bug: maintenant se souvient du mot de passe OTP\n</string>
|
||||
<string name="ChangeLog_0_9_7b">Version 0.9.7b\n
|
||||
* traductions actualisées\n
|
||||
* corrections de bugs : polices de mot de passe était manquant dans 0.9.7, trie par nom ne trie pas les groupes\n</string>
|
||||
<string name="ChangeLog_keptDonate">Possibilité élargie de faire un don d\'une bière ou autre chose</string>
|
||||
<string-array name="clipboard_timeout_options">
|
||||
<item>30 secondes</item>
|
||||
@@ -912,5 +1002,10 @@
|
||||
<string name="AutofillWarning_Intro">Vous êtes sur le point d\'insérer des identifiants pour le domaine \"%1$s\" dans l\'application \"%2$s\".</string>
|
||||
<string name="AutofillWarning_FillDomainInUntrustedApp">Si vous faites confiance à \"%2$s\" pour appartenir à \"%1$s\" ou que vous faites confiance à l\'application \"%2$s\" pour ne pas abuser des identifiants (ex. parce que c\'est une application de navigateur de confiance), il est possible de continuer. Si ce n\'est pas le cas, veuillez annuler.</string>
|
||||
<string name="AutofillWarning_trustAsBrowser">Accepter toujours dans \"%1$s\"</string>
|
||||
<string name="qr_scanning_error_no_google_play_services">Le scan de QR Code requiert les Services Google Play. Veuillez installer ou mettre à jour les Services Google Play sur votre périphérique.</string>
|
||||
<string name="english_ime_settings">Paramètres du clavier Keepass2Android</string>
|
||||
<string name="autoswitch_enabled_but_not_setup">Note : Vous avez activé le changement automatique de clavier, mais il ne semble pas être correctement configuré (Paramètres - Appli - Accès aux mots de passe - Changement de clavier).</string>
|
||||
<string name="switch_keyboard_for_totp_enabled">Note : Vous avez activé le remplissage automatique des entrées TOTP. Cela peut entrainer l\'apparition de cette fenêtre lorsque vous ouvrez une entrée avec un TOTP (Paramètres - Appli - Accès aux mots de passe - Service de saisie automatique).</string>
|
||||
<string name="switch_keyboard_inside_kp2a_enabled">Note : Vous avez activé le clavier intégré dans Keepass2Android. Cela peut faire apparaitre cette fenêtre quand vous ouvrez l\'application, ou que vous éditez une entrée (Paramètres - Appli - Sécurité).</string>
|
||||
<string name="switch_keyboard_on_search_enabled">Note : Vous avez activé le changement de clavier. Cela peut faire apparaitre cette fenêtre lorsque vous recherchez une entrée depuis le navigateur (Paramètres - Appli - Accès aux mots de passe - Changement de clavier).</string>
|
||||
</resources>
|
||||
|
@@ -722,7 +722,7 @@ Ecco alcuni suggerimenti che ti potrebbero aiutare a diagnosticare il problema:\
|
||||
<item>Aggiornato all\'interfaccia utente Material 3</item>
|
||||
<item>Migliora l\'autofill per funzionare con le app Compose</item>
|
||||
<item>Corretta la corrispondenza con l\' hostname in riempimento automatico e ricerca</item>
|
||||
<item>Fix issue with password generator</item>
|
||||
<item>Corretto problema con il generatore di password</item>
|
||||
</string-array>
|
||||
<string-array name="ChangeLog_1_12_net">
|
||||
<item>Aggiornato OneDrive SDK alla versione 5.68</item>
|
||||
@@ -944,7 +944,142 @@ Ecco alcuni suggerimenti che ti potrebbero aiutare a diagnosticare il problema:\
|
||||
<string name="ChangeLog_0_9_7b">Versione 0.9.7b\n
|
||||
* aggiornate le traduzioni\n
|
||||
* bugfix: font Password mancante nella versione 0.9.7; ordina per nome non ordinava i gruppi\n</string>
|
||||
<string name="ChangeLog_0_9_7"> Versione 0.9.\n
|
||||
* scrivere il supporto per i database di Keepass 1 (kdb) (beta!\n
|
||||
* meglio tornare alla tastiera precedente (funziona anche su dispositivi non rootati)\n
|
||||
* supporto per KeeChallenge con sfide di lunghezza variabile\n
|
||||
* evitare di prendere screenshot dalle schermate di QuickUnlock e password\n
|
||||
* ordine inverso per Ordina per Modifica Data (ora discendente)\n
|
||||
* correzioni di bug: Note ora aggiornate correttamente dopo le modifiche, Viste password ora nascondere correttamente la password su (si spera) tutti i dispositivi, problema fisso che ha permesso di aggiungere una voce due volte, problema fisso con la visualizzazione di un avviso UUID duplicato anche dopo aver risolto il database\n
|
||||
</string>
|
||||
<string name="ChangeLog_0_9_6"> Versione 0.9.\n
|
||||
* consente di importare file chiave e/o file di database locale nella directory interna dell\'app (vedi impostazioni)\n
|
||||
* consente diverse opzioni di ordinamento\n
|
||||
* preferenze migliorate per il cambio automatico della tastiera\n
|
||||
* logo e design di notifica aggiornati, design di Stefano Pignataro (http://www. pstudio. t)\n
|
||||
* generatore di password ricorda le ultime impostazioni\n
|
||||
* imposta visibilità di notifica per Android 5 schermata di blocco\n
|
||||
* ora cancellare il campo password principale quando esce dall\'app senza toccare OK\n
|
||||
* problema fisso con i linguaggi di input mancanti nell\'impostazione della tastiera su alcuni dispositivi\n
|
||||
* problema fisso con l\'accensione automatica della tastiera su dispositivi radicati\n
|
||||
* aggiunto controllo per database corrotti (UUID duplicati)\n
|
||||
* ricaricare automaticamente il database quando è stato rilevato, risolve i timori di sicurezza per la rivelazione della master password\n
|
||||
* migliore lucido piccolo layout della tastiera, tema impostazioni tastiera fissa (grazie a Wiktor Ławski)\n
|
||||
</string>
|
||||
<string name="ChangeLog_0_9_5"><b>Versione 0.9.5</b>\n
|
||||
* corregge i problemi con la navigazione delle cartelle (in particolare su Android 4.4)\n
|
||||
* risolve il problema con il caricamento dei file .kdb (Keepass 1) su Nexus 5 con Android Lollipop\n
|
||||
* aggiunge un\'opzione per impedire la cattura delle schermate e nascondere KP2A dalla lista delle App Recenti\n
|
||||
* risolve il problema con l\'archiviazione su Google Drive (edizione normale)\n
|
||||
* permette i file chiave sui tipi di storage voluti (edizione normale)\n
|
||||
* aggiornato SDK di Dropbox per includere un aggiornamento di sicurezza (edizione normale)\n
|
||||
* aggiornati i tool di sviluppo --> aumentata dimensione apk :-(\n
|
||||
Avevo promesso alcune altre modifiche. Arriveranno con la prossima release - scusate. Ho voluto pubblicare queste correzioni il più presto possibile.</string>
|
||||
<string name="ChangeLog_0_9_4"><b>Versione 0.9.4</b>\n
|
||||
* aggiunto supporto ai plug-in: guarda nelle impostazioni per scoprire come ottenerli!\n
|
||||
* pubblicato QR plug-in (scansiona password, mostra password come QR-code, trasferisci voci ad altri dispositivi KP2A)\n
|
||||
* pubblicato InputStick plug-in (trasferisci credenziali al PC via bluetooth - richiede chiavetta InputStick USB)\n
|
||||
* le applicazioni di terze parti ora possono interrogare facilmente KP2A per ottenere le credenziali. Sei uno sviluppatore? Per favore aggiungi il supporto alle tue applicazioni se ti sembra conveniente!\n
|
||||
* aggiunto supporto a TOTP (compatibile con KeeOTP e TrayTotp)\n
|
||||
* l\'app non dovrebbe più essere chiusa da Android quando il database è aperto\n
|
||||
* il database non viene più chiuso quando si abbandona l\'app tramite il pulsante \"indietro\" (vedi impostazioni)\n
|
||||
* mostra i nomi dei gruppi nei risultati di ricerca (*)\n
|
||||
* aggiungo un menu contestuale nei risultati di ricerca con l\'opzione \"Passa al gruppo superiore\" (*)\n
|
||||
* aggiunta un\'opzione per mostrare, nella visualizzazione di una voce, il nome del gruppo a cui la voce appartiene (*)\n
|
||||
* (*) un grazie a Matthieu per aver implementato queste funzioni!\n
|
||||
* aggiunto supporto a KeeChallenge (con Yubikey NEO). Grazie a Ben Rush per l\'implementazione del connettore!\n
|
||||
* migliorata l\'interfaccia utente\n
|
||||
* corretto un bug nell\'interfaccia di Google Drive\n
|
||||
* aggiunta un\'opzione per disabilitare la funzione \"donazione\"\n
|
||||
* l\'icona QuickUnlock ora è nascosta di default su dispositivi Android 4.2+\n</string>
|
||||
<string name="ChangeLog_0_9_3_r5"><b>Versione 0.9.3 r5</b>\n
|
||||
* Incorporate correzioni da Xamarin: Keepass2Android è ora compatibile con ART su Android 4.4.2. Finalmente!\n
|
||||
* Correzioni di errori: errori in sincronizzazione (aggiornamento visualizzazione, corretto controllo per modifiche in http), errori su dispositivi Android 2.x, errori nelle implementazioni di archiviazione con Google Drive e OneDrive, pulizia degli appunti alla chiusura del database, errori in apertura allegati, problemi di visualizzazione della tastiera\n</string>
|
||||
<string name="ChangeLog_0_9_3"><b>Versione 0.9.3</b>\n
|
||||
* Nuova tastiera con molti miglioramenti. Vedi le Impostazioni.\n
|
||||
* Supporto in sola lettura per file kdb (Keepass 1). Sperimentale!\n
|
||||
* Aggiunto supporto SFTP\n
|
||||
* Aggiunto soluzione temporanea per il bug con ART (Android 4.4.2)\n
|
||||
* Bugfix\n</string>
|
||||
<string name="ChangeLog_0_9_2"><b>Versione 0.9.2</b>\n
|
||||
* Aggiunto supporto OTP (compatibile con il plugin OtpKeyProv)\n
|
||||
* Integrato supporto NFC per le OTP dal NEO YubiKey\n
|
||||
* Aggiornata l\'interfaccia utente\n
|
||||
* Integrata la libreria di Keepass 2.24\n
|
||||
* Aggiunta un\'opzione per terminare il processo dell\'app (vedi le Impostazioni)\n
|
||||
* Migliorata la validazione del certificato SSL\n
|
||||
* Corretti alcuni errori\n</string>
|
||||
<string name="ChangeLog_0_9_1"><b>Versione 0.9.1</b>\n
|
||||
* Aggiunto il supporto per SkyDrive (solo nell\'edizione normale di Keepass2Android)\n
|
||||
* Corretti i problemi di integrazione con Google Drive\n
|
||||
* Aggiunto supporto NTLM</string>
|
||||
<string name="ChangeLog_0_9"><b>Versione 0.9</b> \n
|
||||
* integrato supporto per Dropbox e Google Drive (database in lettura/scrittura; solo per Keepass2Android edizione regolare)\n
|
||||
* integrata la selezione dei file (basata su android-filechooser di HBA)\n
|
||||
* migliorata l\'interfaccia per la creazione di nuovi database\n
|
||||
* incluso il font DejaVu Sans Mono per la visualizzazione passwords\n
|
||||
* corretti alcuni errori</string>
|
||||
<string name="ChangeLog_0_8_6"><b>Versione 0.8.6</b>\n
|
||||
* Supporto per cifratura Twofish\n
|
||||
* Consentita la modifica dei gruppi\n
|
||||
* Consentito lo spostamento di voci e gruppi\n
|
||||
* L\'icona QuickUnlock può essere resa trasparente (vedi le impostazioni)\n
|
||||
* Correzioni di errori</string>
|
||||
<string name="ChangeLog_0_8_5"><b>Versione 0.8.5</b>\n
|
||||
* i file remoti vengono mantenuti nella cache locale dell\'applicazione per permetterne l\'uso offline (compresa la modifica e la successiva sincronizzazione). Vedi le impostazioni. \n
|
||||
* Icona di notifica per visualizzare lo stato del blocco del database (vedi Impostazioni)\n
|
||||
* Migliorato il rilevamento dello stato del blocco del database in alcune circostanze \n
|
||||
* I file dei database vengono caricati in memoria mentre stai digitando la password per aumentare la velocità di caricamento (vedi Impostazioni) \n
|
||||
* Le voci possono essere aggiunte al gruppo principale \n
|
||||
* Correzione di errori (risoluzione campi con riferimenti, problemi con la tastiera su dispositivi italiani e cinesi)</string>
|
||||
<string name="ChangeLog_0_8_4"><b>Versione 0.8.4</b>\n
|
||||
* Le modifiche al database esterno vengono rilevate ed unite durante il salvataggio\n
|
||||
* Migliorate le performance durante il caricamento\n
|
||||
* Migliorata la barra di ricerca con suggerimenti\n
|
||||
* Nuovo logo dell\'App!\n
|
||||
* Aggiunto supporto al formato .kdbp per apertura e salvataggio più veloci\n
|
||||
* Migliorata la modifica delle stringhe aggiuntive e la visualizzazione nascosta quando sono protette\n
|
||||
Grazie ad Alex Vallat per il suo contributo al codice!\n
|
||||
Grazie a Niki Hüttner (www.close-cut.de) per il logo!\n</string>
|
||||
<string name="ChangeLog_0_8_3"><b> Versione 0.8.3 </b>\n
|
||||
* Le voci nome utente e indice TAN vengono visualizzati nella lista delle voci di immissione (vedi le impostazioni)\n
|
||||
* Le voci possono essere create se la ricerca da browser non restituisce alcun risultato\n
|
||||
* La tastiera KP2A offre possibilità di ricercare le credenziali per l\'applicazione attuale\n
|
||||
* L\'applicazione si chiude automaticamente dopo aver selezionato una voce per l\'uso dalla tastiera\n
|
||||
* La finestra di selezione della tastiera si apre automaticamente dopo la ricerca di URL (vedi le impostazioni)\n
|
||||
* I segnaposto nei campi di immissione vengono sostituiti prima della copia (la maggior parte dei segnaposto sono supportati)\n
|
||||
* Correzioni di errori minori </string>
|
||||
<string name="ChangeLog_0_8_2"><b>Versione 0.8.2</b>\n
|
||||
* Supporto per la Digest Authentication in WebDAV\n
|
||||
* Correzione di errori (OI File manager, Open URL)</string>
|
||||
<string name="ChangeLog_0_8_1"><b>Versione 0.8.1</b>\n
|
||||
* KP2A Offline e \"Online\" possono di nuovo essere installati insieme\n
|
||||
* Aggiunte nuove traduzioni (grazie a tutti i collaboratori!)</string>
|
||||
<string name="ChangeLog_0_8"><b>Versione 0.8</b>\n
|
||||
* Migliorata l\'interfaccia utente in particolare per i dispositivi con Android 4.x\n
|
||||
* Consentito l\'utilizzo di gestori di file personali per selezionare file esistenti\n
|
||||
* Aggiunto un modo più sicuro per l\'apertura degli allegati (tramite cartella di cache)\n
|
||||
* sistemati alcuni errori nella finestra di modifica\n
|
||||
* probabilmente aggiunti nuovi errori :-)</string>
|
||||
<string name="ChangeLog_keptDonate">Estesa la possibilità di donare una birra o qualcos\'altro</string>
|
||||
<string name="ChangeLog_0_7"><b>Versione 0.7</b>\n
|
||||
* Aumentata la velocità di caricamento: l\'elaborazione delle chiavi ora è 10 volte più veloce!\n
|
||||
* Aggiunta la tastiera virtuale di Keepass2Android: usa questa tastiera quando inserisci le credenziali. Ti metterà al riparo dagli sniffer delle password basati sugli appunti (disabilita le vecchie notifiche degli appunti nelle impostazioni)\n
|
||||
* Aggiunta l\'opzione per donare una birra o qualcos\'altro (vedi menu)</string>
|
||||
<string name="ChangeLog"><b>Versione 0.6.2</b>\n
|
||||
* Integrazione con Google Drive/Dropbox/... : usa l\'app ufficiale di Google Drive o Dropbox App e apri un qualunque file \".kdbx\". In questo modo si aprirà KP2A.\n
|
||||
* Migliorato il dialogo di ricerca\n
|
||||
* Migliorati i risultati di ricerca per le URL condivise con sottodomini\n
|
||||
* Aggiunte al menu le opzioni per inviare feedback, valutazioni e per tradurre l\'app\n
|
||||
\n
|
||||
<b>Versione 0.6.1</b>\n
|
||||
* Aggiunto il rilevamento di modifiche in background (es.: dovute ad un\'app di sincronizzazione)\n
|
||||
* Migliorata la ricerca delle URL dal browser\n
|
||||
* Aggiunta una richiesta di conferma prima di annullare le modifiche\n
|
||||
\n
|
||||
<b>Versione 0.6</b>\n
|
||||
Prima release pubblica
|
||||
</string>
|
||||
<string-array name="clipboard_timeout_options">
|
||||
<item>30 secondi</item>
|
||||
<item>1 minuto</item>
|
||||
@@ -1039,4 +1174,7 @@ Ecco alcuni suggerimenti che ti potrebbero aiutare a diagnosticare il problema:\
|
||||
<string name="kp2a_switch_on_sendgodone_summary">Torna indietro quando premi invia/vai/fatto</string>
|
||||
<string name="qr_scanning_error_no_google_play_services">La scansione del codice QR richiede Google Play Services. Installa o aggiorna Google Play Services sul tuo dispositivo.</string>
|
||||
<string name="english_ime_settings">Impostazioni tastiera Keepass2Android</string>
|
||||
<string name="autoswitch_enabled_but_not_setup">Nota: Hai abilitato App - Impostazioni - Accesso password - Cambio di tastiera - Tastiera automatica, ma non sembra essere configurata correttamente.</string>
|
||||
<string name="switch_keyboard_for_totp_enabled">Nota: Hai abilitato App - Accesso password - Servizio di autocompilazione - Autocompilazione per le voci TOTP. Questo può causare la visualizzazione di questa finestra quando si apre una voce con un TOTP.</string>
|
||||
<string name="switch_keyboard_inside_kp2a_enabled">Nota: Hai abilitato App - Sicurezza - Usa la tastiera integrata all\'interno di Keepass2Android. Questo può causare la visualizzazione di questa finestra quando si apre l\'app o si modifica una voce.</string>
|
||||
</resources>
|
||||
|
@@ -1203,4 +1203,8 @@
|
||||
<string name="kp2a_switch_on_sendgodone_summary">Voltar ao pressionar enviar/ir/concluído</string>
|
||||
<string name="qr_scanning_error_no_google_play_services">A leitura de código QR requer o Google Play Services. Instale ou atualize o Google Play Services no seu dispositivo.</string>
|
||||
<string name="english_ime_settings">Configurações do teclado Android</string>
|
||||
<string name="autoswitch_enabled_but_not_setup">Nota: Você ativou o Aplicativo - Configurações - Acesso por senha - Troca de teclado - Troca automática de teclado, mas não parece estar configurado corretamente.</string>
|
||||
<string name="switch_keyboard_for_totp_enabled">Nota: você ativou o Aplicativo - Acesso por senha - Serviço de preenchimento automático - Preenchimento automático para entradas TOTP. Isso pode fazer com que essa janela seja exibida quando você abre uma entrada com um TOTP.</string>
|
||||
<string name="switch_keyboard_inside_kp2a_enabled">Nota: Você ativou o Aplicativo - Segurança - Usar o teclado embutido dentro do Keepass2Android. Isso pode fazer com que essa janela seja exibida quando você abre o aplicativo ou edita uma entrada.</string>
|
||||
<string name="switch_keyboard_on_search_enabled">Nota: Você ativou o Aplicativo - Segurança - Acesso por senha - Troca de teclado - Alternar teclado. Isso pode fazer com que essa janela seja exibida quando você pesquisar uma entrada no navegador.</string>
|
||||
</resources>
|
||||
|
@@ -468,6 +468,7 @@
|
||||
<string name="NoOverwrite">Nu, suprascrie</string>
|
||||
<string name="UseOfflineMode">Funcționare doar cu cache intern</string>
|
||||
<string name="UseOnlineMode">Sincronizează copia cache cu sursa</string>
|
||||
<string name="UseOfflineMode_Info">Baza de date este încărcată din memoria cache internă. Modificările sunt stocate doar în cache-ul intern și vor fi sincronizate numai atunci când selectezi Sincronizare copie cache cu sursa.</string>
|
||||
<string name="InOfflineMode">Funcționare doar cu cache intern.</string>
|
||||
<string name="SynchronizingCachedDatabase">Sincronizează baza de date din cache…</string>
|
||||
<string name="DownloadingRemoteFile">Se încarcă fișierul sursă…</string>
|
||||
@@ -476,15 +477,21 @@
|
||||
<string name="FilesInSync">Fişierele sunt sincronizate.</string>
|
||||
<string name="SynchronizedDatabaseSuccessfully">Baza de date s-a sincronizat cu succes!</string>
|
||||
<string name="CheckingDatabaseForChanges">Se verifică baza de date pentru modificări…</string>
|
||||
<string name="CouldNotSaveToRemote">Nu s-a putut salva în fișierul sursă: %1$s. Salvează din nou sau utilizează meniul Sincronizare atunci când fișierul este accesibil din nou.</string>
|
||||
<string name="CouldNotLoadFromRemote">Nu s-a putut accesa fișierul sursă: %1$s. Fișier încărcat din cache-ul intern. Poți face în continuare modificări în baza de date și să le sincronizezi mai târziu.</string>
|
||||
<string name="UpdatedRemoteFileOnLoad">Fișier sursă actualizat.</string>
|
||||
<string name="NotifyOpenFromLocalDueToConflict">S-a deschis fișierul cache intern din cauza conflictului cu modificările din fișierul sursă. Utilizează meniul Sincronizare pentru a fuziona.</string>
|
||||
<string name="LoadedFromRemoteInSync">Fișierul sursă și cache-ul sunt sincronizate.</string>
|
||||
<string name="UpdatedCachedFileOnLoad">S-a actualizat copia internă a cache-ului %1$s.</string>
|
||||
<string name="RemoteDatabaseUnchanged">Nu s-au detectat modificări.</string>
|
||||
<string name="ResolvedCacheConflictByUsingRemoteOtpAux">S-a actualizat fișierul auxiliar OTP din cache : Contorul sursă a fost mai mare.</string>
|
||||
<string name="ResolvedCacheConflictByUsingLocalOtpAux">S-a actualizat fișierul auxiliar OTP sursă: Contorul local a fost mai mare.</string>
|
||||
<string name="SynchronizingOtpAuxFile">Se sincronizează fișierul auxiliar OTP…</string>
|
||||
<string name="database_file">fișier bază de date</string>
|
||||
<string name="otp_aux_file">Fişier auxiliar OTP</string>
|
||||
<string name="ErrorOcurred">A apărut o eroare:</string>
|
||||
<string name="DuplicateUuidsError">Baza de date este coruptă: ID-uri duplicate au fost găsite. (Ai salvat cu Minikeepass?) Te rog să reimporți o bază de date nouă cu Keepass 2 pentru PC selectând \'Create new IDs\'.</string>
|
||||
<string name="DuplicateUuidsErrorAdditional">Poți dezactiva acest mesaj de eroare în Setări/Setările aplicației/Gestionare fișiere/Verificare duplicat UUID-uri. Reține că este posibil te confrunți cu un comportament neașteptat. Este recomandat să repari baza de date.</string>
|
||||
<string name="synchronize_database_menu">Sincronizează baza de date…</string>
|
||||
<string name="CannotMoveGroupHere">Nu se poate muta grupul în acest grup.</string>
|
||||
<string name="donate_question">Astăzi este Oktoberfest! Dacă vă place Keepass2Android: nu ar fi azi o zi potrivită să-mi cumpăraţi o bere?</string>
|
||||
@@ -518,6 +525,7 @@
|
||||
<string name="private_key_select">Selectează cheia privată</string>
|
||||
<string name="private_key_create_new">[Adaugă nou...]</string>
|
||||
<string name="hint_sftp_key_passphrase">Frază de acces pentru cheie (opțională)</string>
|
||||
<string name="sftp_kex_title">Algoritmi de schimb de chei (KEX) (opțional)</string>
|
||||
<string name="enter_ftp_login_title">Introdu datele de conectare FTP:</string>
|
||||
<string name="select_storage_type">Selectaţi tipul de stocare:</string>
|
||||
<string name="filestoragename_file">Fişier local</string>
|
||||
|
@@ -726,7 +726,7 @@
|
||||
<item>Aktualizované na používateľské rozhranie Material 3</item>
|
||||
<item>Vylepšené automatické dopĺňanie kvôli fungovaniu s aplikáciami Compose</item>
|
||||
<item>Oprava zhody mena hostiteľa v automatickom dopĺňaní a vyhľadávaní</item>
|
||||
<item>Fix issue with password generator</item>
|
||||
<item>Oprava problému s generátorom hesiel</item>
|
||||
</string-array>
|
||||
<string-array name="ChangeLog_1_12_net">
|
||||
<item>Aktualizované na OneDrive SDK, verziu 5.68</item>
|
||||
@@ -1203,4 +1203,8 @@
|
||||
<string name="kp2a_switch_on_sendgodone_summary">Po stlačení Odoslať/Prejsť/Hotovo prejsť späť</string>
|
||||
<string name="qr_scanning_error_no_google_play_services">Na skenovanie QR kódov sú potrebné služby Google Play. Nainštalujte alebo aktualizujte si ich vo vašom zariadení.</string>
|
||||
<string name="english_ime_settings">Nastavenia klávesnice Keepass2Android</string>
|
||||
<string name="autoswitch_enabled_but_not_setup">Poznámka: aktivovali ste automatické prepínanie klávesnice v sekcii Nastavenia aplikácie - Prístup k záznamu s heslom - Prepínanie klávesnice, ale zdá sa, že táto funkcia nie je správne nakonfigurovaná.</string>
|
||||
<string name="switch_keyboard_for_totp_enabled">Poznámka: aktivovali ste automatické dopĺňanie pre záznamy TOTP, v sekcii Apl. - Prístup k záznamu s heslom - Služba automatického dopĺňania. Môže to spôsobiť zobrazenie tohto okna pri otvorení záznamu s TOTP.</string>
|
||||
<string name="switch_keyboard_inside_kp2a_enabled">Poznámka: aktivovali ste použitie klávesnice integrovanej v Keepass2Android, v sekcii Apl. - Zabezpečenie. Môže to spôsobiť zobrazenie tohto okna pri otvorení aplikácie alebo pri úprave záznamu.</string>
|
||||
<string name="switch_keyboard_on_search_enabled">Poznámka: aktivovali ste prepínanie klávesnice v sekcii Apl. - Zabezpečenie - Prístup k záznamu s heslom - Prepínanie klávesnice. Môže to spôsobovať zobrazenie tohto okna pri vyhľadávaní nejakého záznamu z prehliadača.</string>
|
||||
</resources>
|
||||
|
@@ -1201,4 +1201,8 @@
|
||||
<string name="kp2a_switch_on_sendgodone_summary">Preklopi nazaj, ko pritisnete gumb za pošiljanje/prehajanje/končano</string>
|
||||
<string name="qr_scanning_error_no_google_play_services">Za optično branje kode QR so potrebne storitve Google Play. V svojo napravo namestite ali posodobite storitve Google Play.</string>
|
||||
<string name="english_ime_settings">Nastavitve tipkovnice Keepass2Android</string>
|
||||
<string name="autoswitch_enabled_but_not_setup">Opomba: Omogočili ste Aplikacije - Nastavitve - Dostop z geslom - Preklop tipkovnice - Samodejni preklop tipkovnice, vendar se zdi, da ta ni pravilno konfigurirana.</string>
|
||||
<string name="switch_keyboard_for_totp_enabled">Opomba: Omogočili ste Aplikacije - Dostop do gesla - Storitev samodejnega izpolnjevanja - Samodejno izpolnjevanje za vnose TOTP. To lahko povzroči, da se to okno prikaže, ko odprete vnos s TOTP.</string>
|
||||
<string name="switch_keyboard_inside_kp2a_enabled">Opomba: Omogočili ste Aplikacije - Varnost - Uporabi vgrajeno tipkovnico znotraj Keepass2Android. To lahko povzroči, da se to okno prikaže, ko odprete aplikacijo ali urejate vnos.</string>
|
||||
<string name="switch_keyboard_on_search_enabled">Opomba: Omogočili ste možnost Aplikacija - Varnost - Dostop z geslom - Preklop tipkovnice - Preklop tipkovnice. To lahko povzroči, da se to okno prikaže, ko iščete vnos v brskalniku.</string>
|
||||
</resources>
|
||||
|
@@ -151,6 +151,7 @@
|
||||
<string name="hint_keyfile">Anahtar dosyası</string>
|
||||
<string name="hint_length">Uzunluk</string>
|
||||
<string name="hint_pass">parola</string>
|
||||
<string name="hint_keyfile_path">SSH özel anahtar yolu</string>
|
||||
<string name="hint_login_pass">Parola</string>
|
||||
<string name="hint_title">Başlık</string>
|
||||
<string name="hint_url">URL</string>
|
||||
@@ -300,6 +301,8 @@
|
||||
<string name="NoDalVerification_summary">Etki alanı ve uygulama paketinin eşleşip eşleşmediğini kontrol etmeyi devre dışı bırakır</string>
|
||||
<string name="InlineSuggestions_title">Klavye ile entegre et</string>
|
||||
<string name="InlineSuggestions_summary">Otomatik doldurma önerilerini klavyede satır içi seçenekler olarak gösterir (giriş yöntemi tarafından destekleniyorsa)</string>
|
||||
<string name="LogAutofillView_title">Günlük otomatik doldurma görünümü</string>
|
||||
<string name="LogAutofillView_summary">Otomatik doldurma görünümü hakkında ayrıntıları hata ayıklama günlüğüne yaz (eğer hata ayıklama günlüğü etkinse). Eğer otomatik doldurma beklendiği gibi çalışmıyorsa bu ayrıntılar geliştiriciye gönderilebilir.</string>
|
||||
<string name="requires_android11">Android 11 veya sonraki bir sürümünü gerektirir</string>
|
||||
<string name="kp2a_findUrl">Parola bul</string>
|
||||
<string name="excludeExpiredEntries">Hızlı aramalara süresi dolmuş kayıtlar katılmasın</string>
|
||||
@@ -398,6 +401,11 @@
|
||||
<string name="ShowSeparateNotifications_summary">Kullanıcı adıyla parolayı panoya kopyalamak ve klavyeyi etkinleştirmek için bildirimleri göster.</string>
|
||||
<string name="AccServiceAutoFill_prefs">Otomatik Doldurma Erişilebilirlik Hizmeti</string>
|
||||
<string name="AutoFill_prefs">Otomatik Doldurma Hizmeti</string>
|
||||
<string name="AutoFillTotp_prefs_ShowNotification_summary">Bir girişi TOTP ile otomatik doldururken, giriş bildirimini TOTP Kopyala düğmesiyle göster</string>
|
||||
<string name="AutoFillTotp_prefs_ShowNotification_title">Giriş bildirimlerini göster</string>
|
||||
<string name="AutoFillTotp_prefs_CopyTotpToClipboard_title">TOTP \'yi panoya kopyala</string>
|
||||
<string name="AutoFillTotp_prefs_ActivateKeyboard_title">Yerleşik klavyeyi etkinleştir</string>
|
||||
<string name="TotpCopiedToClipboard">TOTP panoya kopyalandı</string>
|
||||
<string name="ShowKp2aKeyboardNotification_title">KP2A klavye bildirimi</string>
|
||||
<string name="ShowKp2aKeyboardNotification_summary">Tam girişi KP2A klavyesinden erişilebilir yapın (önerilir).</string>
|
||||
<string name="OpenKp2aKeyboardAutomatically_title">Klavyeyi değiştir</string>
|
||||
@@ -414,6 +422,7 @@
|
||||
<string name="ShowUnlockedNotification_summary">Veritabanı kilitli değilken devam eden bir bildirim gösterir.</string>
|
||||
<string name="IconVisibilityInfo_Android8_text">Android 8, bildirimler için yeni davranışlar getirdi. Keepass2Android\'in bildirimleri için simgeyi gizlemek istiyorsanız, lütfen bunu sistem ayarlarından yapılandırın. Bildirim kategorisinin önemini Minimum olarak ayarlayın.</string>
|
||||
<string name="IconVisibilityInfo_Android8_btnSettings">Ayarları aç</string>
|
||||
<string name="PostNotificationsPermissionInfo_text">Keepass2Android bilgi bankanız kilitli değilken size bir sistem uyarısı görüntüler. Bunun çalışması için lütfen izin verin.</string>
|
||||
<string name="DontCare">Umrumda değil</string>
|
||||
<string name="DocumentAccessRevoked">Keepass2Android artık dosyaya erişemiyor. Dosya ya silindi yada erişim izinleri iptal edildi. Lütfen Veritabanını değiştir seçeneğiyle dosyayı yeniden açın.</string>
|
||||
<string name="PreloadDatabaseEnabled_title">Veritabanı dosyasını önceden yükleme</string>
|
||||
@@ -498,9 +507,15 @@
|
||||
<string name="hint_sftp_host">sunucu (ör: 192.168.0.1)</string>
|
||||
<string name="hint_sftp_port">bağlantı noktası</string>
|
||||
<string name="initial_directory">Başlangıç dizini (isteğe bağlı):</string>
|
||||
<string name="connect_timeout">Bağlantı zaman aşımı saniyesi (isteğe bağlı)</string>
|
||||
<string name="enter_sftp_login_title">SFTP oturum açma verilerini girin:</string>
|
||||
<string name="sftp_auth_mode">Kimlik doğrulama modu</string>
|
||||
<string name="send_public_key">Ortak anahtar gönder...</string>
|
||||
<string name="select_private_keyfile">Özel anahtarı seç...</string>
|
||||
<string name="hint_sftp_key_name">Yeni anahtar adı</string>
|
||||
<string name="hint_sftp_key_content">Yeni anahtar içeriği</string>
|
||||
<string name="private_key_saved">Özel anahtar kaydedildi</string>
|
||||
<string name="private_key_save_failed">Özel anahtar kayıt edilemedi: %1$s</string>
|
||||
<string name="enter_ftp_login_title">FTP oturum açma verilerini girin:</string>
|
||||
<string name="enter_mega_login_title">MEGA hesap bilgilerinizi girin:</string>
|
||||
<string name="select_storage_type">Depolama türünü seçin:</string>
|
||||
|
@@ -720,6 +720,14 @@
|
||||
<string name="EntryChannel_desc">选定条目快速进入通知</string>
|
||||
<string name="CloseDbAfterFailedAttempts">三次失败的生物识别解锁后关闭数据库。</string>
|
||||
<string name="WarnFingerprintInvalidated">警告!生物识别认证可能会被Android系统作废,例如在你的设备设置中添加一个新的指纹后。确保你总是知道如何用你的主密码解锁!</string>
|
||||
<string-array name="ChangeLog_1_12">
|
||||
<item>Upgraded from Xamarin Android to .net 8</item>
|
||||
<item></item>
|
||||
<item>Upgraded to Material 3 user interface</item>
|
||||
<item>Improve autofill to work with Compose apps</item>
|
||||
<item>Fix hostname matching in autofill and search</item>
|
||||
<item>Fix issue with password generator</item>
|
||||
</string-array>
|
||||
<string-array name="ChangeLog_1_11">
|
||||
<item>添加了用于搜索和概览 TOTP 的浮动按钮(如果存在TOTP条目)</item>
|
||||
<item>通过添加超时指示器并突出显示,改进 TOTP 字段的显示效果</item>
|
||||
@@ -1161,4 +1169,8 @@ Initial public release
|
||||
<string name="kp2a_switch_on_sendgodone_summary">按下发送/转到/完成时切换回来</string>
|
||||
<string name="qr_scanning_error_no_google_play_services">二维码扫描需要 Google Play 服务。请在您的设备上安装或更新 Google Play 服务。</string>
|
||||
<string name="english_ime_settings">键盘设置</string>
|
||||
<string name="autoswitch_enabled_but_not_setup">注意:您已启用应用-设置-密码访问-键盘切换-自动切换键盘,但它似乎配置不正确。</string>
|
||||
<string name="switch_keyboard_for_totp_enabled">注意:您已启用应用 - 密码访问-自动填充服务 - TOTP 条目自动填充。 当您打开一条有TOTP的条目时,这会导致此窗口显示。</string>
|
||||
<string name="switch_keyboard_inside_kp2a_enabled">注意:您已经启用了应用 - 安全性 - 使用 Keepass2Android 中的内置键盘。 当您打开应用或编辑条目时,这会导致此窗口显示。</string>
|
||||
<string name="switch_keyboard_on_search_enabled">注意: 您已经启用了应用-安全性-密码访问-键盘切换-切换键盘。当您从浏览器搜索条目时,这会导致此窗口显示。</string>
|
||||
</resources>
|
||||
|
@@ -137,7 +137,6 @@
|
||||
<string name="NoDonationReminder_key">NoDonationReminder</string>
|
||||
|
||||
<string name="UseOfflineCache_key">UseOfflineCache</string>
|
||||
<string name="SyncOfflineCacheInBackground_key">SyncOfflineCacheInBackground_key</string>
|
||||
<string name="CreateBackups_key">CreateBackups_key</string>
|
||||
<string name="AcceptAllServerCertificates_key">AcceptAllServerCertificates</string>
|
||||
<string name="CheckForFileChangesOnSave_key">CheckForFileChangesOnSave</string>
|
||||
|
@@ -382,8 +382,6 @@
|
||||
<string name="NoDonationReminder_summary">I won\'t give you a dime or I have already donated. Don\'t ask for a donation, not even at the author\'s birthday.</string>
|
||||
<string name="UseOfflineCache_title">Database caching</string>
|
||||
<string name="UseOfflineCache_summary">Keep a copy of the database files in the app\'s cache directory. This allows to use databases even while the database file is not accessible.</string>
|
||||
<string name="SyncOfflineCacheInBackground_summary">When saving or loading, use the internal cache. Then synchronize with remote storage in a background process.</string>
|
||||
<string name="SyncOfflineCacheInBackground_title">Synchronize in background</string>
|
||||
<string name="CreateBackups_title">Local backups</string>
|
||||
<string name="CreateBackups_summary">Create a local backup copy after successfully loading a database.</string>
|
||||
<string name="UpdatingBackup">Updating local backup...</string>
|
||||
@@ -726,9 +724,6 @@
|
||||
<string name="DbQuicklockedChannel_desc">Notification about the database being locked with QuickUnlock</string>
|
||||
<string name="EntryChannel_name">Entry notifications</string>
|
||||
<string name="EntryChannel_desc">Notification to simplify access to the currently selected entry.</string>
|
||||
<string name="BackgroundSyncChannel_name">Synchronization operation</string>
|
||||
<string name="BackgroundSyncChannel_desc">Notification to indicate that a synchronization is performed in the background.</string>
|
||||
|
||||
<string name="CloseDbAfterFailedAttempts">Close database after three failed biometric unlock attempts.</string>
|
||||
<string name="WarnFingerprintInvalidated">Warning! Biometric authentication can be invalidated by Android, e.g. after adding a new fingerprint in your device settings. Make sure you always know how to unlock with your master password!</string>
|
||||
|
||||
@@ -1258,6 +1253,5 @@
|
||||
<string name="switch_keyboard_for_totp_enabled">Note: You have enabled App - Password access - Autofill-Service - Autofill for TOTP entries. This can cause this window to show when you open an entry with a TOTP.</string>
|
||||
<string name="switch_keyboard_inside_kp2a_enabled">Note: You have enabled App - Security - Use built-in keyboard inside Keepass2Android. This can cause this window to show when you open the app or edit an entry.</string>
|
||||
<string name="switch_keyboard_on_search_enabled">Note: You have enabled App - Security - Password access - Keyboard switching - Switch keyboard. This can cause this window to show when you search for an entry from the browser.</string>
|
||||
<string name="user_interaction_required">User interaction required. Please open the app.</string>
|
||||
<string name="failed_to_access_database">Database is currently in use and cannot be accessed.</string>
|
||||
|
||||
</resources>
|
@@ -12,17 +12,7 @@
|
||||
android:title="@string/UseOfflineCache_title"
|
||||
android:key="@string/UseOfflineCache_key" />
|
||||
|
||||
|
||||
<CheckBoxPreference
|
||||
android:enabled="true"
|
||||
android:persistent="true"
|
||||
android:summary="@string/SyncOfflineCacheInBackground_summary"
|
||||
android:defaultValue="true"
|
||||
android:title="@string/SyncOfflineCacheInBackground_title"
|
||||
android:key="@string/SyncOfflineCacheInBackground_key" />
|
||||
|
||||
|
||||
<CheckBoxPreference
|
||||
<CheckBoxPreference
|
||||
android:enabled="true"
|
||||
android:persistent="true"
|
||||
android:summary="@string/CreateBackups_summary"
|
||||
|
@@ -558,7 +558,6 @@ namespace keepass2android
|
||||
private OpenDatabaseAdapter _adapter;
|
||||
private MyBroadcastReceiver _intentReceiver;
|
||||
private bool _isForeground;
|
||||
private readonly List<IOConnectionInfo> _pendingBackgroundSyncs = new List<IOConnectionInfo>();
|
||||
|
||||
public override void OnBackPressed()
|
||||
{
|
||||
@@ -599,36 +598,11 @@ namespace keepass2android
|
||||
|
||||
string iocString = data?.GetStringExtra("ioc");
|
||||
IOConnectionInfo ioc = IOConnectionInfo.UnserializeFromString(iocString);
|
||||
|
||||
//we first store the required sync operation and delay its execution until we loaded all AutoOpen entries (from local file)
|
||||
//if required
|
||||
bool requiresSubsequentSync = data?.GetBooleanExtra("requiresSubsequentSync", false) ?? false;
|
||||
if (requiresSubsequentSync)
|
||||
{
|
||||
_pendingBackgroundSyncs.Add(ioc);
|
||||
}
|
||||
|
||||
if (App.Kp2a.TrySelectCurrentDb(ioc))
|
||||
{
|
||||
if (OpenAutoExecEntries(App.Kp2a.CurrentDb)) return;
|
||||
LaunchingOther = true;
|
||||
AppTask.CanActivateSearchViewOnStart = true;
|
||||
|
||||
foreach (var pendingSyncIoc in _pendingBackgroundSyncs)
|
||||
{
|
||||
try
|
||||
{
|
||||
new SyncUtil(this).StartSynchronizeDatabase(pendingSyncIoc);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
App.Kp2a.ShowMessage(this, "Failed to synchronize database", MessageSeverity.Error);
|
||||
Kp2aLog.LogUnexpectedError(e);
|
||||
}
|
||||
}
|
||||
|
||||
_pendingBackgroundSyncs.Clear();
|
||||
|
||||
AppTask.LaunchFirstGroupActivity(this);
|
||||
}
|
||||
|
||||
|
@@ -72,8 +72,8 @@ namespace keepass2android
|
||||
|
||||
}
|
||||
|
||||
SetPassword sp = new SetPassword(App.Kp2a, pass, keyfile, new AfterSave(_activity, this, null, new Handler()));
|
||||
BlockingOperationStarter pt = new BlockingOperationStarter(App.Kp2a, sp);
|
||||
SetPassword sp = new SetPassword(_activity, App.Kp2a, pass, keyfile, new AfterSave(_activity, this, null, new Handler()));
|
||||
ProgressTask pt = new ProgressTask(App.Kp2a, _activity, sp);
|
||||
pt.Run();
|
||||
};
|
||||
|
||||
@@ -88,21 +88,21 @@ namespace keepass2android
|
||||
|
||||
|
||||
|
||||
class AfterSave : OnOperationFinishedHandler {
|
||||
private readonly FileOnFinish _operationFinishedHandler;
|
||||
class AfterSave : OnFinish {
|
||||
private readonly FileOnFinish _finish;
|
||||
|
||||
readonly SetPasswordDialog _dlg;
|
||||
|
||||
public AfterSave(Activity activity, SetPasswordDialog dlg, FileOnFinish operationFinishedHandler, Handler handler): base(App.Kp2a, operationFinishedHandler, handler) {
|
||||
_operationFinishedHandler = operationFinishedHandler;
|
||||
public AfterSave(Activity activity, SetPasswordDialog dlg, FileOnFinish finish, Handler handler): base(activity, finish, handler) {
|
||||
_finish = finish;
|
||||
_dlg = dlg;
|
||||
}
|
||||
|
||||
|
||||
public override void Run() {
|
||||
if ( Success ) {
|
||||
if ( _operationFinishedHandler != null ) {
|
||||
_operationFinishedHandler.Filename = _dlg.Keyfile;
|
||||
if ( _finish != null ) {
|
||||
_finish.Filename = _dlg.Keyfile;
|
||||
}
|
||||
FingerprintUnlockMode um;
|
||||
Enum.TryParse(PreferenceManager.GetDefaultSharedPreferences(_dlg.Context).GetString(App.Kp2a.CurrentDb.CurrentFingerprintModePrefKey, ""), out um);
|
||||
|
@@ -78,15 +78,7 @@ namespace keepass2android
|
||||
|
||||
protected override void OnCreate(Bundle savedInstanceState)
|
||||
{
|
||||
//we don't want any background thread to update/reload the database while we're in this activity.
|
||||
if (!App.Kp2a.DatabasesBackgroundModificationLock.TryEnterReadLock(TimeSpan.FromSeconds(5)))
|
||||
{
|
||||
App.Kp2a.ShowMessage(this, GetString(Resource.String.failed_to_access_database), MessageSeverity.Error);
|
||||
Finish();
|
||||
return;
|
||||
}
|
||||
|
||||
base.OnCreate(savedInstanceState);
|
||||
base.OnCreate(savedInstanceState);
|
||||
|
||||
//if user presses back to leave this activity:
|
||||
SetResult(Result.Canceled);
|
||||
@@ -296,12 +288,5 @@ namespace keepass2android
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
App.Kp2a.DatabasesBackgroundModificationLock.ExitReadLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
|
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using Android.App;
|
||||
using Android.OS;
|
||||
using Android.Widget;
|
||||
using keepass2android.Io;
|
||||
using KeePassLib.Serialization;
|
||||
@@ -9,19 +8,19 @@ namespace keepass2android
|
||||
{
|
||||
public class SyncUtil
|
||||
{
|
||||
private LifecycleAwareActivity _activity;
|
||||
private Activity _activity;
|
||||
|
||||
public SyncUtil(LifecycleAwareActivity activity)
|
||||
public SyncUtil(Activity activity)
|
||||
{
|
||||
_activity = activity;
|
||||
}
|
||||
|
||||
public class SyncOtpAuxFile : OperationWithFinishHandler
|
||||
public class SyncOtpAuxFile : RunnableOnFinish
|
||||
{
|
||||
private readonly IOConnectionInfo _ioc;
|
||||
|
||||
public SyncOtpAuxFile(Activity activity, IOConnectionInfo ioc)
|
||||
: base(App.Kp2a, null)
|
||||
: base(activity, null)
|
||||
{
|
||||
_ioc = ioc;
|
||||
}
|
||||
@@ -50,45 +49,50 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
|
||||
public void StartSynchronizeDatabase(IOConnectionInfo ioc)
|
||||
public void SynchronizeDatabase(Action runAfterSuccess)
|
||||
{
|
||||
var filestorage = App.Kp2a.GetFileStorage(ioc);
|
||||
var databaseForIoc = App.Kp2a.GetDatabase(ioc);
|
||||
|
||||
OperationWithFinishHandler task;
|
||||
OnOperationFinishedHandler onOperationFinishedHandler = new ActionInContextInstanceOnOperationFinished(_activity.ContextInstanceId, App.Kp2a, (success, message, context) =>
|
||||
var filestorage = App.Kp2a.GetFileStorage(App.Kp2a.CurrentDb.Ioc);
|
||||
RunnableOnFinish task;
|
||||
OnFinish onFinish = new ActionOnFinish(_activity, (success, message, activity) =>
|
||||
{
|
||||
App.Kp2a.UiThreadHandler.Post(() =>
|
||||
if (!String.IsNullOrEmpty(message))
|
||||
App.Kp2a.ShowMessage(activity, message, success ? MessageSeverity.Info : MessageSeverity.Error);
|
||||
|
||||
// Tell the adapter to refresh it's list
|
||||
BaseAdapter adapter = (activity as GroupBaseActivity)?.ListAdapter;
|
||||
adapter?.NotifyDataSetChanged();
|
||||
|
||||
if (App.Kp2a.CurrentDb?.OtpAuxFileIoc != null)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(message))
|
||||
App.Kp2a.ShowMessage(context, message, success ? MessageSeverity.Info : MessageSeverity.Error);
|
||||
|
||||
// Tell the adapter to refresh it's list
|
||||
BaseAdapter adapter = (context as GroupBaseActivity)?.ListAdapter;
|
||||
|
||||
adapter?.NotifyDataSetChanged();
|
||||
});
|
||||
|
||||
if (databaseForIoc?.OtpAuxFileIoc != null)
|
||||
{
|
||||
var task2 = new SyncOtpAuxFile(_activity, databaseForIoc.OtpAuxFileIoc);
|
||||
|
||||
OperationRunner.Instance.Run(App.Kp2a, task2);
|
||||
var task2 = new SyncOtpAuxFile(_activity, App.Kp2a.CurrentDb.OtpAuxFileIoc);
|
||||
task2.OnFinishToRun = new ActionOnFinish(_activity, (b, s, activeActivity) =>
|
||||
{
|
||||
runAfterSuccess();
|
||||
});
|
||||
new ProgressTask(App.Kp2a, activity, task2).Run(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
runAfterSuccess();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (filestorage is CachingFileStorage)
|
||||
{
|
||||
|
||||
task = new SynchronizeCachedDatabase(App.Kp2a, databaseForIoc, onOperationFinishedHandler, new BackgroundDatabaseModificationLocker(App.Kp2a));
|
||||
task = new SynchronizeCachedDatabase(_activity, App.Kp2a, onFinish);
|
||||
}
|
||||
else
|
||||
{
|
||||
task = new CheckDatabaseForChanges( App.Kp2a, onOperationFinishedHandler);
|
||||
|
||||
task = new CheckDatabaseForChanges(_activity, App.Kp2a, onFinish);
|
||||
}
|
||||
|
||||
OperationRunner.Instance.Run(App.Kp2a, task);
|
||||
|
||||
|
||||
|
||||
var progressTask = new ProgressTask(App.Kp2a, _activity, task);
|
||||
progressTask.Run();
|
||||
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user