Compare commits

...

37 Commits

Author SHA1 Message Date
Philipp Crocoll
288539b902 make output more verbose 2025-07-05 11:09:55 +02:00
Philipp Crocoll
61fd32f121 avoid building the "full" apk when calling apk_split 2025-07-05 09:39:54 +02:00
Philipp Crocoll
43108ec4a6 remove ls step in release 2025-07-05 08:35:58 +02:00
Philipp Crocoll
51089c6b98 change build artifact release paths. make archive name depend on matrix variables. 2025-07-05 08:16:30 +02:00
Philipp Crocoll
cf18fcf91c remove distclean from build 2025-07-05 08:15:58 +02:00
Philipp Crocoll
da0513c768 don't create release but only list files to test the release workflow without polluting github releases 2025-07-05 07:49:39 +02:00
Philipp Crocoll
37f520cdbe manifest for r9c 2025-07-05 07:40:21 +02:00
Philipp Crocoll
c98572bee0 fix wildcard for selecting files to upload to release 2025-07-05 07:39:44 +02:00
Philipp Crocoll
b1774ffc4b increase version number ot r9b 2025-07-05 07:19:26 +02:00
Philipp Crocoll
57aaa0c4cd start release action by pushing version tags instead of when release is created on Github 2025-07-05 07:18:21 +02:00
Philipp Crocoll
b961ae1b33 make sure AndroidManifest.xml exists before running nuget 2025-07-05 07:12:17 +02:00
Philipp Crocoll
5e418e2b1b run workload update before any dotnet/nuget calls in github actions 2025-07-05 06:57:00 +02:00
Philipp Crocoll
6d22a213f3 add build target apk_split; build all combinations in a Github action when creating the release 2025-07-05 06:44:28 +02:00
Philipp Crocoll
a76addc43f manifest for 1.12-r9 2025-07-05 06:43:39 +02:00
Philipp Crocoll
1d96217713 remove GooglePlayServices Auth and Base from apk in NoNet build 2025-07-05 06:42:42 +02:00
Philipp Crocoll
d2b8fdcfff allow using Dropbox secrets from environment (better suited for Github action builds) 2025-07-05 06:34:23 +02:00
Philipp Crocoll
507b671448 exclude Mega and OneDrive from NoNet build. Manifest for 1.12-r8c 2025-07-02 21:39:37 +02:00
Philipp Crocoll
3118ffaeb5 update version code and name => r8b (to distinguish from previously incorrect r8 build) 2025-07-02 21:04:22 +02:00
Philipp Crocoll
0abe29bd77 restore NoNet build, including removal of MLKit for that Flavor as it adds internet permission 2025-07-02 21:03:20 +02:00
Philipp Crocoll
f3a7831390 upload release artifacts before rebuilding 2025-06-30 22:29:31 +02:00
Philipp Crocoll
37cd58f7ba Merge branch 'v1.12' 2025-06-30 21:59:46 +02:00
Philipp Crocoll
7dd80a8ef7 remove "net" where no longer appropriate from workflow file 2025-06-30 16:16:55 +02:00
Philipp Crocoll
c78636264b align net and nonet manifests 2025-06-30 16:05:02 +02:00
Philipp Crocoll
035506a5a3 add nonet to release workflow 2025-06-30 16:04:38 +02:00
PhilippC
4cf46ef062 Merge pull request #2933 from PhilippC/v1.12
several updates for V1.12
2025-06-30 15:48:57 +02:00
Philipp Crocoll
c7b8063171 add previously forgotten changes 2025-06-30 14:36:59 +02:00
Philipp Crocoll
0a8b149c9a fix failing AutofillTest by adjusting to changed policy 2025-06-30 14:05:26 +02:00
Philipp Crocoll
9240a27791 run workload update before running tests, otherwise dotnet test can fail 2025-06-30 13:38:54 +02:00
PhilippC
e90d5b903c Merge pull request #2932 from PhilippC/2915-bug-exporting-the-key-file-broken-android-file-browser-doesnt-open
Fix crash when exporting key file
2025-06-30 12:43:08 +02:00
Philipp Crocoll
50b4a9f1b9 add missing Theme attributes 2025-06-30 12:42:05 +02:00
Philipp Crocoll
9783c3b5fe manifest for 1.12-r7 2025-06-24 17:12:22 +02:00
Philipp Crocoll
7a837e3237 show autofill more often without requiring manual requests, might mitigate issues in https://github.com/PhilippC/keepass2android/issues/2898 2025-06-24 17:10:50 +02:00
Philipp Crocoll
c8f6714373 refactoring: simplify autofill code 2025-06-24 17:10:08 +02:00
Philipp Crocoll
bc0313aa6a remove no-longer-needed step in release workflow 2025-06-24 15:41:46 +02:00
Philipp Crocoll
0f98668bcd improve app stability and refactor to get better logs 2025-06-24 15:41:11 +02:00
PhilippC
0aa78ffd66 Merge pull request #2862 from Gian-Fr/fix-makefile
Fixed MakeFile for Linux
2025-06-17 16:52:04 +02:00
Gian-Fr
c1dbf171f5 Fixed MakeFile for Linux 2025-05-01 16:21:02 +02:00
28 changed files with 344 additions and 264 deletions

View File

@@ -309,6 +309,14 @@ jobs:
run: | run: |
make java make java
- name: Update dotnet workloads
run: |
dotnet workload update
- name: Select the manifest
run: |
make manifestlink Flavor=Net
- name: Install NuGet dependencies (net) - name: Install NuGet dependencies (net)
run: make nuget Flavor=Net run: make nuget Flavor=Net
@@ -327,12 +335,17 @@ jobs:
path: | path: |
src/keepass2android/bin/*/*-Signed.apk src/keepass2android/bin/*/*-Signed.apk
- name: Select the manifest
run: |
make manifestlink Flavor=NoNet
- name: Install NuGet dependencies (nonet) - name: Install NuGet dependencies (nonet)
run: make nuget Flavor=NoNet run: make nuget Flavor=NoNet
- name: Build keepass2android (nonet) - name: Build keepass2android (nonet)
run: | run: |
make msbuild Flavor=NoNet make msbuild Flavor=NoNet
- name: Test Autofill - name: Test Autofill
working-directory: ./src/Kp2aAutofillParser.Tests working-directory: ./src/Kp2aAutofillParser.Tests
run: dotnet test run: dotnet test
@@ -348,5 +361,3 @@ jobs:
path: | path: |
src/keepass2android/bin/*/*-Signed.apk src/keepass2android/bin/*/*-Signed.apk
- name: Perform "make distclean"
run: make distclean

View File

@@ -1,19 +1,21 @@
name: Create keepass2android release name: Create keepass2android release
env: env:
NAME: 'ReleaseNet' NAME: 'Release'
on: on:
release: push:
types: [published] # Trigger when a new GitHub release is published tags:
workflow_dispatch: # For manual testing - "v1.*"
jobs: jobs:
build-release: build-release:
runs-on: windows-2022 runs-on: windows-2022
strategy:
matrix:
flavor: [Net, NoNet]
target: [apk, apk_split]
steps: steps:
@@ -76,49 +78,50 @@ jobs:
run: | run: |
make java make java
- name: Install NuGet dependencies (net) - name: Update dotnet workloads
run: make nuget Flavor=Net
- name: Use the _net manifest
run: | run: |
make manifestlink Flavor=Net dotnet workload update
- name: Select the manifest
run: |
make manifestlink Flavor=${{ matrix.flavor }}
- name: Install NuGet dependencies
run: make nuget Flavor=${{ matrix.flavor }}
- name: List apks
run: find . -type f -name "*.apk"
- name: Build APK (net) - name: Build APK (net)
env: env:
KeyStore: "${{ github.workspace }}/kp2a.keystore" KeyStore: "${{ github.workspace }}/kp2a.keystore"
MyAndroidSigningStorePass: ${{ secrets.KEY_STORE_PASSWORD }} MyAndroidSigningStorePass: ${{ secrets.KEY_STORE_PASSWORD }}
MyAndroidSigningKeyPass: ${{ secrets.KEY_PASSWORD }} MyAndroidSigningKeyPass: ${{ secrets.KEY_PASSWORD }}
run: | DropboxAppKey: ${{ secrets.DROPBOX_APP_KEY }}
make Configuration=Release Flavor=Net DropboxAppSecret: ${{ secrets.DROPBOX_APP_SECRET }}
DropboxAppFolderAppKey: ${{ secrets.DROPBOX_APP_FOLDER_APP_KEY }}
DropboxAppFolderAppSecret: ${{ secrets.DROPBOX_APP_FOLDER_APP_SECRET }}
- name: List files
shell: bash
run: | run: |
ls src/keepass2android-app/bin/**/*.* make ${{ matrix.target }} Configuration=Release Flavor=${{ matrix.flavor }}
- name: Archive production artifacts (net) - name: List apks
run: find . -type f -name "*.apk"
- name: Archive production artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: signed APK ('net' built on ${{ github.job }}) name: keepass2android_${{ matrix.target }}_${{ matrix.flavor }}
path: | path: |
src/keepass2android-app/bin/Release/net8.0-android/*-Signed.apk src/keepass2android-app/bin/Release/net8.0-android/publish/*.apk
src/keepass2android-app/bin/Release/net8.0-android/*/publish/*.apk
- name: Upload APK to GitHub Release - name: List apks
uses: softprops/action-gh-release@v2 run: find . -type f -name "*.apk"
if: github.ref_type == 'tag'
with:
files: |
src/keepass2android-app/bin/Release/net8.0-android/*-Signed.apk
- name: Run checksum action #- name: Upload APK to GitHub Release
uses: thewh1teagle/checksum@v2 # uses: softprops/action-gh-release@v2
with: # if: github.ref_type == 'tag'
pre-release: true # with:
file-name: 'apk-checksum-sha256.txt' # files: |
patterns: | # src/keepass2android-app/bin/Release/net8.0-android/*/publish/*.apk src/keepass2android-app/bin/Release/net8.0-android/publish/*.apk
src/keepass2android-app/bin/Release/net8.0-android/*-Signed.apk
algorithm: sha256
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

2
.gitignore vendored
View File

@@ -64,7 +64,7 @@ Thumbs.db
/src/java/android-filechooser/code/projectzip/project.zip /src/java/android-filechooser/code/projectzip/project.zip
/src/java/android-filechooser/code/unused.txt /src/java/android-filechooser/code/unused.txt
/src/Kp2aBusinessLogic/Io/DropboxFileStorageKeys.cs /src/Kp2aBusinessLogic/Io/DropboxFileStorage.g.cs
/src/java/workspace/DriveTest /src/java/workspace/DriveTest

View File

@@ -62,11 +62,11 @@ $(info )
# On linux use xabuild, on Windows use MSBuild.exe, otherwise (macos?) use msbuild. # On linux use xabuild, on Windows use MSBuild.exe, otherwise (macos?) use msbuild.
ifeq ($(detected_OS),Linux) ifeq ($(detected_OS),Linux)
MSBUILD_binary := xabuild MSBUILD_binary := dotnet
MSBUILD := $(shell $(WHICH) $(MSBUILD_binary)) MSBUILD := $(shell $(WHICH) $(MSBUILD_binary)) publish
else ifeq ($(detected_OS),Windows) else ifeq ($(detected_OS),Windows)
MSBUILD_binary := MSBuild.exe MSBUILD_binary := dotnet
MSBUILD := $(shell $(WHICH) $(MSBUILD_binary) 2> nul) MSBUILD := $(shell $(WHICH) $(MSBUILD_binary) 2> nul) publish
ifeq ($(MSBUILD),) ifeq ($(MSBUILD),)
# Additional heuristic to find MSBUILD_BINARY on Windows # Additional heuristic to find MSBUILD_BINARY on Windows
VSWHERE := "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" VSWHERE := "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
@@ -312,19 +312,20 @@ manifestlink:
$(CREATE_MANIFEST_LINK) $(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 $(MSBUILD) src/KeePass.sln -target:keepass2android-app -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -p:BuildProjectReferences=true $(MSBUILD_PARAM) -p:Platform="Any CPU" -m
apk: msbuild apk: manifestlink native java nuget
$(MSBUILD) src/keepass2android-app/keepass2android-app.csproj -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -t:SignAndroidPackage $(MSBUILD_PARAM) -p:Platform=AnyCPU -m $(MSBUILD) src/keepass2android-app/keepass2android-app.csproj -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -t:SignAndroidPackage $(MSBUILD_PARAM) -p:Platform=AnyCPU -m
apk_split: manifestlink native java nuget
$(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 build_all: msbuild
##### Cleanup targets ##### Cleanup targets

View File

@@ -95,7 +95,7 @@ namespace Kp2aAutofillParserTest
StructureParserBase<TestInputField> parser = StructureParserBase<TestInputField> parser =
new StructureParserBase<TestInputField>(new TestLogger(), new TestDalSourceTrustAll()); new StructureParserBase<TestInputField>(new TestLogger(), new TestDalSourceTrustAll());
var result = parser.ParseForFill(false, autofillView); var result = parser.ParseForFill(autofillView);
if (expectedPackageName != null) if (expectedPackageName != null)
Assert.Equal(expectedPackageName, result.PackageName); Assert.Equal(expectedPackageName, result.PackageName);
if (expectedWebDomain != null) if (expectedWebDomain != null)

View File

@@ -58,7 +58,8 @@
"IsFocused": false, "IsFocused": false,
"InputType": 97, "InputType": 97,
"HtmlInfoTag": null, "HtmlInfoTag": null,
"HtmlInfoTypeAttribute": null "HtmlInfoTypeAttribute": null,
"ExpectedAssignedHints": [ "username" ]
}, },
{ {
"IdEntry": "password_text_input_layout", "IdEntry": "password_text_input_layout",
@@ -81,6 +82,7 @@
"InputType": 129, "InputType": 129,
"HtmlInfoTag": null, "HtmlInfoTag": null,
"HtmlInfoTypeAttribute": null, "HtmlInfoTypeAttribute": null,
"ExpectedAssignedHints": [ "password" ]
}, },
{ {

View File

@@ -476,8 +476,16 @@ namespace Kp2aAutofillParser
foreach (var field in autofillFields.HintMap.Values.Distinct()) foreach (var field in autofillFields.HintMap.Values.Distinct())
{ {
if (field == null || field.AutofillHints == null)
{
continue;
}
foreach (var hint in field.AutofillHints) foreach (var hint in field.AutofillHints)
{ {
if (hint == null)
{
continue;
}
if (GetPartitionIndex(hint) == partitionIndex) if (GetPartitionIndex(hint) == partitionIndex)
{ {
filteredCollection.Add(field); 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) public AutofillTargetId ParseForSave(AutofillView<FieldT> autofillView)
{ {
return Parse(false, true, autofillView); return Parse(false, autofillView);
} }
/// <summary> /// <summary>
@@ -808,8 +816,7 @@ namespace Kp2aAutofillParser
/// </summary> /// </summary>
/// <returns>The parse.</returns> /// <returns>The parse.</returns>
/// <param name="forFill">If set to <c>true</c> for fill.</param> /// <param name="forFill">If set to <c>true</c> for fill.</param>
/// <param name="isManualRequest"></param> protected virtual AutofillTargetId Parse(bool forFill, AutofillView<FieldT> autofillView)
protected virtual AutofillTargetId Parse(bool forFill, bool isManualRequest, AutofillView<FieldT> autofillView)
{ {
AutofillTargetId result = new AutofillTargetId() AutofillTargetId result = new AutofillTargetId()
{ {
@@ -876,8 +883,9 @@ namespace Kp2aAutofillParser
} }
//for "heuristic determination" we demand that one of the filled fields is focused: //for "heuristic determination" we demand that there is a password field or one of the username fields is focused:
if (passwordFields.Concat(usernameFields).Any(f => f.IsFocused)) //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) foreach (var uf in usernameFields)
AddFieldToHintMap(uf, new string[] { AutofillHintsHelper.AutofillHintUsername }); AddFieldToHintMap(uf, new string[] { AutofillHintsHelper.AutofillHintUsername });

View File

@@ -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";
}
}

View 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>

View File

@@ -4,30 +4,43 @@
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion> <SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<DefineConstants Condition="'$(Flavor)'=='NoNet'">NO_QR_SCANNER;EXCLUDE_JAVAFILESTORAGE;NoNet</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Resources\" /> <Folder Include="Resources\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentFTP" Version="51.1.0" /> <PackageReference Include="FluentFTP" Version="51.1.0" Condition="'$(Flavor)'!='NoNet'"/>
<PackageReference Include="MegaApiClient" Version="1.10.4" /> <PackageReference Include="MegaApiClient" Version="1.10.4" Condition="'$(Flavor)'!='NoNet'"/>
<PackageReference Include="Microsoft.Graph" Version="5.68.0" /> <PackageReference Include="Microsoft.Graph" Version="5.68.0" Condition="'$(Flavor)'!='NoNet'"/>
<PackageReference Include="Microsoft.Identity.Client" Version="4.67.1" /> <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.Browser" Version="1.8.0" />
<PackageReference Include="Xamarin.AndroidX.Core" Version="1.13.1.5" /> <PackageReference Include="Xamarin.AndroidX.Core" Version="1.13.1.5" />
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.11.0.3" /> <PackageReference Include="Xamarin.Google.Android.Material" Version="1.11.0.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\AndroidFileChooserBinding\AndroidFileChooserBinding.csproj" /> <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="..\KeePassLib2Android\KeePassLib2Android.csproj" />
<ProjectReference Include="..\KP2AKdbLibraryBinding\KP2AKdbLibraryBinding.csproj" /> <ProjectReference Include="..\KP2AKdbLibraryBinding\KP2AKdbLibraryBinding.csproj" />
<ProjectReference Include="..\TwofishCipher\TwofishCipher.csproj" /> <ProjectReference Include="..\TwofishCipher\TwofishCipher.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Remove="Io/DropboxFileStorageKeysDummy.cs" />
<Compile Remove="Io/DropboxFileStorageKeysDummy.cs" /> </ItemGroup>
<Content Remove="Io/DropboxFileStorageKeysDummy.cs" /> <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> </ItemGroup>
<Import Project="Io/GenerateSecrets.targets" />
<ItemGroup>
<Compile Include="Io/DropboxFileStorage.g.cs" />
</ItemGroup>
</Project> </Project>

View File

@@ -14,9 +14,16 @@ namespace KeePass.Util
{ {
string errorMessage = e.Message; string errorMessage = e.Message;
if (e is Java.Lang.Exception javaException) if (e is Java.Lang.Exception javaException)
{
try
{ {
errorMessage = javaException.LocalizedMessage ?? javaException.Message ?? errorMessage; errorMessage = javaException.LocalizedMessage ?? javaException.Message ?? errorMessage;
} }
finally
{
}
}
return errorMessage; return errorMessage;
} }

View File

@@ -20,7 +20,6 @@ git clone --recurse-submodules https://github.com/PhilippC/keepass2android.git
cd keepass2android/src/build-scripts cd keepass2android/src/build-scripts
./build-java.sh && ./build-native.sh ./build-java.sh && ./build-native.sh
cd .. cd ..
cp Kp2aBusinessLogic/Io/DropboxFileStorageKeysDummy.cs Kp2aBusinessLogic/Io/DropboxFileStorageKeys.cs
cd keepass2android-app cd keepass2android-app
ln -s Manifests/AndroidManifest_debug.xml AndroidManifest.xml ln -s Manifests/AndroidManifest_debug.xml AndroidManifest.xml
dotnet workload restore dotnet workload restore

View 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

View File

@@ -6,8 +6,7 @@
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true">
android:theme="@style/AppTheme">
<activity android:name="com.crocoapps.javafilestoragetest2.MainActivity" <activity android:name="com.crocoapps.javafilestoragetest2.MainActivity"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>

View File

@@ -14,7 +14,7 @@ using keepass2android;
namespace keepass2android namespace keepass2android
{ {
[Activity(Label = AppNames.AppName)] [Activity(Label = AppNames.AppName, Theme = "@style/Kp2aTheme_BlueNoActionBar")]
public class AppKilledInfo : Activity, IDialogInterfaceOnDismissListener public class AppKilledInfo : Activity, IDialogInterfaceOnDismissListener
{ {
protected override void OnCreate(Bundle bundle) protected override void OnCreate(Bundle bundle)

View File

@@ -19,7 +19,7 @@ using keepass2android.services.AutofillBase;
namespace keepass2android namespace keepass2android
{ {
[Activity(Label = "DisableAutofillForQueryActivity")] [Activity(Label = "DisableAutofillForQueryActivity", Theme = "@style/Kp2aTheme_ActionBar")]
public class DisableAutofillForQueryActivity : Activity public class DisableAutofillForQueryActivity : Activity
{ {
public IAutofillIntentBuilder IntentBuilder = new Kp2aAutofillIntentBuilder(); public IAutofillIntentBuilder IntentBuilder = new Kp2aAutofillIntentBuilder();
@@ -63,8 +63,6 @@ namespace keepass2android
prefs.Edit().PutStringSet("AutoFillDisabledQueries", disabledValues).Commit(); prefs.Edit().PutStringSet("AutoFillDisabledQueries", disabledValues).Commit();
bool isManual = Intent.GetBooleanExtra(ChooseForAutofillActivityBase.ExtraIsManualRequest, false);
Intent reply = new Intent(); Intent reply = new Intent();
FillResponse.Builder builder = new FillResponse.Builder(); FillResponse.Builder builder = new FillResponse.Builder();
AssistStructure structure = (AssistStructure)Intent.GetParcelableExtra(AutofillManager.ExtraAssistStructure); AssistStructure structure = (AssistStructure)Intent.GetParcelableExtra(AutofillManager.ExtraAssistStructure);
@@ -77,7 +75,7 @@ namespace keepass2android
StructureParser parser = new StructureParser(this, structure); StructureParser parser = new StructureParser(this, structure);
try try
{ {
parser.ParseForFill(isManual); parser.ParseForFill();
} }
catch (Java.Lang.SecurityException e) catch (Java.Lang.SecurityException e)

View File

@@ -37,8 +37,10 @@ using System.Net;
using System.Text; using System.Text;
using Android.Content.Res; using Android.Content.Res;
using Android.Database; using Android.Database;
#if !NO_QR_SCANNER
using Android.Gms.Common; using Android.Gms.Common;
using Android.Gms.Tasks; using Android.Gms.Tasks;
#endif
using Android.Graphics; using Android.Graphics;
using Android.Graphics.Drawables; using Android.Graphics.Drawables;
using Android.Runtime; using Android.Runtime;
@@ -55,10 +57,11 @@ using Object = Java.Lang.Object;
using Uri = Android.Net.Uri; using Uri = Android.Net.Uri;
using Resource = keepass2android.Resource; using Resource = keepass2android.Resource;
using Google.Android.Material.TextField; using Google.Android.Material.TextField;
#if !NO_QR_SCANNER
using Xamarin.Google.MLKit.Vision.Barcode.Common; using Xamarin.Google.MLKit.Vision.Barcode.Common;
using Xamarin.Google.MLKit.Vision.CodeScanner; using Xamarin.Google.MLKit.Vision.CodeScanner;
#endif
using Console = System.Console; using Console = System.Console;
using Task = Android.Gms.Tasks.Task;
namespace keepass2android namespace keepass2android
{ {
@@ -1158,7 +1161,9 @@ namespace keepass2android
{ {
dlgView.FindViewById(Resource.Id.totp_custom_settings_group).Visibility = args.IsChecked ? ViewStates.Visible : ViewStates.Gone; dlgView.FindViewById(Resource.Id.totp_custom_settings_group).Visibility = args.IsChecked ? ViewStates.Visible : ViewStates.Gone;
}; };
#if NO_QR_SCANNER
dlgView.FindViewById<Button>(Resource.Id.totp_scan).Visibility = ViewStates.Gone;
#else
dlgView.FindViewById<Button>(Resource.Id.totp_scan).Click += async (object o, EventArgs args) => dlgView.FindViewById<Button>(Resource.Id.totp_scan).Click += async (object o, EventArgs args) =>
{ {
if (GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this) != ConnectionResult.Success) if (GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this) != ConnectionResult.Success)
@@ -1194,6 +1199,7 @@ namespace keepass2android
}; };
#endif
//copy values from entry into dialog //copy values from entry into dialog
View ees = (View)sender.Parent; View ees = (View)sender.Parent;
@@ -1572,6 +1578,7 @@ namespace keepass2android
} }
} }
#if !NO_QR_SCANNER
public class SuccessListener : Object, IOnSuccessListener public class SuccessListener : Object, IOnSuccessListener
{ {
private readonly Action<Barcode> _onSuccess; private readonly Action<Barcode> _onSuccess;
@@ -1601,6 +1608,7 @@ namespace keepass2android
_onFailure?.Invoke(e); _onFailure?.Invoke(e);
} }
} }
#endif
public class DefaultEdit : EditModeBase public class DefaultEdit : EditModeBase
{ {

View File

@@ -894,10 +894,15 @@ namespace keepass2android
RegisterInfoTextDisplay( RegisterInfoTextDisplay(
"DbReadOnly"); //this ensures that we don't show the general info texts too soon "DbReadOnly"); //this ensures that we don't show the general info texts too soon
FindViewById<TextView>(Resource.Id.dbreadonly_infotext_text).Text = var infotext_view = FindViewById<TextView>(Resource.Id.dbreadonly_infotext_text);
if (infotext_view != null)
{
infotext_view.Text =
(GetString(Resource.String.FileReadOnlyMessagePre) + " " + (GetString(Resource.String.FileReadOnlyMessagePre) + " " +
App.Kp2a.GetResourceString(reason.Result)); App.Kp2a.GetResourceString(reason.Result));
} }
}
} }
UpdateBottomBarElementVisibility(Resource.Id.dbreadonly_infotext, canShow); UpdateBottomBarElementVisibility(Resource.Id.dbreadonly_infotext, canShow);
} }

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="210" android:versionCode="217"
android:versionName="1.12-r6b" android:versionName="1.12-r9c"
package="keepass2android.keepass2android" package="keepass2android.keepass2android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:installLocation="auto"> android:installLocation="auto">
@@ -46,12 +46,10 @@
<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_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" /> <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" <application android:label="keepass2android"
android:icon="@mipmap/ic_launcher_online" android:icon="@mipmap/ic_launcher_online"
android:roundIcon="@mipmap/ic_launcher_online_round" android:roundIcon="@mipmap/ic_launcher_online_round"
android:networkSecurityConfig="@xml/network_security_config" android:networkSecurityConfig="@xml/network_security_config"
> >
<meta-data <meta-data
@@ -107,16 +105,15 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="keepass2android.softkeyboard.InputLanguageSelection" <activity android:name="keepass2android.softkeyboard.InputLanguageSelection"
android:exported="true"> android:exported="true">
<!-- android:label="@string/language_selection_title" TODO -->
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
<action android:name="keepass2android.softkeyboard.INPUT_LANGUAGE_SELECTION"/> <action android:name="keepass2android.softkeyboard.INPUT_LANGUAGE_SELECTION"/>
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</activity> </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"> <intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="200" android:versionCode="217"
android:versionName="1.11-r0" android:versionName="1.12-r9c"
package="keepass2android.keepass2android_nonet" package="keepass2android.keepass2android_nonet"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:installLocation="auto"> android:installLocation="auto">
@@ -11,6 +11,9 @@
<!-- Specific intents and packages we query for (required since Android 11) --> <!-- Specific intents and packages we query for (required since Android 11) -->
<package android:name="keepass2android.plugin.keyboardswap2" /> <package android:name="keepass2android.plugin.keyboardswap2" />
<package android:name="keepass2android.AncientIconSet" /> <package android:name="keepass2android.AncientIconSet" />
<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" /> <package android:name="com.dropbox.android" />
<intent> <intent>
@@ -39,13 +42,13 @@
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
</intent> </intent>
</queries> </queries>
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" /> <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_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" /> <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 <application android:label="keepass2android"
android:label="keepass2android"
android:icon="@mipmap/ic_launcher_offline" android:icon="@mipmap/ic_launcher_offline"
android:roundIcon="@mipmap/ic_launcher_offline_round"
android:networkSecurityConfig="@xml/network_security_config" android:networkSecurityConfig="@xml/network_security_config"
> >
@@ -78,7 +81,6 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="keepass2android.softkeyboard.InputLanguageSelection" <activity android:name="keepass2android.softkeyboard.InputLanguageSelection"
android:label="@string/language_selection_title"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
@@ -86,7 +88,6 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:configChanges="orientation|keyboard|keyboardHidden" android:label="@string/app_name" android:theme="@style/Kp2aTheme_BlueNoActionBar" android:name="keepass2android.SelectCurrentDbActivity" android:windowSoftInputMode="adjustResize" <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"> android:exported="true">
<intent-filter android:label="@string/app_name"> <intent-filter android:label="@string/app_name">
@@ -112,7 +113,7 @@
<data android:mimeType="application/*" /> <data android:mimeType="application/*" />
</intent-filter> </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 Note that this stopped working nicely with Android 7, see e.g. https://stackoverflow.com/a/26635162/292233
KP2A was using KP2A was using
<data android:scheme="content" /> <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"> <intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" /> <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> </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 --> <!-- 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" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
@@ -218,15 +219,6 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" /> <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
</intent-filter> </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>
<intent-filter android:label="@string/kp2a_findUrl"> <intent-filter android:label="@string/kp2a_findUrl">
<action android:name="android.intent.action.SEND" /> <action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
@@ -254,14 +246,18 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik
</application> </application>
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <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="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_FINGERPRINT" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" /> <uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-feature android:name="android.hardware.camera" android:required="false" /> <uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-permission android:name="keepass2android.keepass2android_nonet.permission.KP2aInternalFileBrowsing" /> <!-- Samsung Pass permission -->
<uses-permission android:name="keepass2android.keepass2android_nonet.permission.KP2aInternalSearch" /> <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" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove" />
</manifest> </manifest>

View File

@@ -1245,7 +1245,7 @@ namespace keepass2android
{ {
var db = TryFindDatabaseForElement(element); var db = TryFindDatabaseForElement(element);
if (db == null) if (db == null)
throw new Exception("Database element not found!"); throw new Exception($"Database element {element.Uuid} not found in any of {OpenDatabases.Count()} databases!");
return db; return db;
} }

View File

@@ -15,6 +15,7 @@ using Android.Content.Res;
using Android.Preferences; using Android.Preferences;
using Google.Android.Material.Dialog; using Google.Android.Material.Dialog;
using keepass2android; using keepass2android;
using PluginTOTP;
namespace keepass2android namespace keepass2android
{ {
@@ -638,19 +639,7 @@ namespace keepass2android
if (CopyTotpToClipboard && isTotpEntry) if (CopyTotpToClipboard && isTotpEntry)
{ {
Dictionary<string, string> entryFields = pwEntryOutput.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString()); DoCopyTotpToClipboard(activity, pwEntryOutput, totpPluginAdapter);
var totpData= totpPluginAdapter.GetTotpData(entryFields, activity, true);
if (totpData.IsTotpEntry)
{
TOTPProvider prov = new TOTPProvider(totpData);
string totp = prov.GenerateByByte(totpData.TotpSecret);
CopyToClipboardService.CopyValueToClipboardWithTimeout(activity, totp, true);
App.Kp2a.ShowMessage(activity, activity.GetString(Resource.String.TotpCopiedToClipboard),
MessageSeverity.Info);
}
} }
if (CloseAfterCreate) if (CloseAfterCreate)
@@ -661,6 +650,22 @@ namespace keepass2android
activity.CloseAfterTaskComplete(); activity.CloseAfterTaskComplete();
} }
} }
private static void DoCopyTotpToClipboard(EntryActivity activity, PwEntryOutput pwEntryOutput,
ITotpPluginAdapter? totpPluginAdapter)
{
Dictionary<string, string> entryFields = pwEntryOutput.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString());
var totpData = totpPluginAdapter.GetTotpData(entryFields, activity, true);
if (totpData.IsTotpEntry)
{
TOTPProvider prov = new TOTPProvider(totpData);
string totp = prov.GenerateByByte(totpData.TotpSecret);
CopyToClipboardService.CopyValueToClipboardWithTimeout(activity, totp, true);
App.Kp2a.ShowMessage(activity, activity.GetString(Resource.String.TotpCopiedToClipboard),
MessageSeverity.Info);
}
}
} }

View File

@@ -10,6 +10,7 @@
<ApplicationVersion>1</ApplicationVersion> <ApplicationVersion>1</ApplicationVersion>
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion> <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants Condition="'$(Flavor)'=='NoNet'">NO_QR_SCANNER;EXCLUDE_JAVAFILESTORAGE;NoNet</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<None Remove="Assets\fontawesome-webfont.ttf" /> <None Remove="Assets\fontawesome-webfont.ttf" />
@@ -750,18 +751,18 @@
<PackageReference Include="Xamarin.AndroidX.Preference" Version="1.2.1.12" /> <PackageReference Include="Xamarin.AndroidX.Preference" Version="1.2.1.12" />
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.12.0.2" /> <PackageReference Include="Xamarin.Google.Android.Material" Version="1.12.0.2" />
<PackageReference Include="Xamarin.Google.Guava" Version="33.4.0.1" /> <PackageReference Include="Xamarin.Google.Guava" Version="33.4.0.1" />
<PackageReference Include="Xamarin.GooglePlayServices.Auth" Version="121.3.0.1" /> <PackageReference Include="Xamarin.GooglePlayServices.Auth" Version="121.3.0.1" Condition="'$(Flavor)'!='NoNet'" />
<PackageReference Include="Xamarin.GooglePlayServices.Base" Version="118.5.0.4" /> <PackageReference Include="Xamarin.GooglePlayServices.Base" Version="118.5.0.4" Condition="'$(Flavor)'!='NoNet'" />
<PackageReference Include="Xamarin.GooglePlayServices.Code.Scanner" Version="116.1.0.10" /> <PackageReference Include="Xamarin.GooglePlayServices.Code.Scanner" Version="116.1.0.10" Condition="'$(Flavor)'!='NoNet'" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\AndroidFileChooserBinding\AndroidFileChooserBinding.csproj" /> <ProjectReference Include="..\AndroidFileChooserBinding\AndroidFileChooserBinding.csproj" />
<ProjectReference Include="..\DropboxBinding\DropboxBinding.csproj" /> <ProjectReference Include="..\DropboxBinding\DropboxBinding.csproj" Condition="'$(Flavor)'!='NoNet'" />
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj" /> <ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj" Condition="'$(Flavor)'!='NoNet'" />
<ProjectReference Include="..\Kp2aAutofillParser\Kp2aAutofillParser.csproj" /> <ProjectReference Include="..\Kp2aAutofillParser\Kp2aAutofillParser.csproj" />
<ProjectReference Include="..\KP2AKdbLibraryBinding\KP2AKdbLibraryBinding.csproj" /> <ProjectReference Include="..\KP2AKdbLibraryBinding\KP2AKdbLibraryBinding.csproj" />
<ProjectReference Include="..\Kp2aKeyboardBinding\Kp2aKeyboardBinding.csproj" /> <ProjectReference Include="..\Kp2aKeyboardBinding\Kp2aKeyboardBinding.csproj" />
<ProjectReference Include="..\PCloudBindings\PCloudBindings.csproj" /> <ProjectReference Include="..\PCloudBindings\PCloudBindings.csproj" Condition="'$(Flavor)'!='NoNet'" />
<ProjectReference Include="..\PluginSdkBinding\PluginSdkBinding.csproj" /> <ProjectReference Include="..\PluginSdkBinding\PluginSdkBinding.csproj" />
<ProjectReference Include="..\ZlibAndroid\ZlibAndroid.csproj" /> <ProjectReference Include="..\ZlibAndroid\ZlibAndroid.csproj" />
<ProjectReference Include="..\TwofishCipher\TwofishCipher.csproj" /> <ProjectReference Include="..\TwofishCipher\TwofishCipher.csproj" />

View File

@@ -28,13 +28,11 @@ namespace keepass2android.services.AutofillBase
{ {
public interface IAutofillIntentBuilder public interface IAutofillIntentBuilder
{ {
PendingIntent GetAuthPendingIntentForResponse(Context context, string query, string queryDomain, string queryPackage, PendingIntent GetAuthPendingIntentForResponse(Context context, string query, string queryDomain, string queryPackage, bool autoReturnFromQuery, AutofillServiceBase.DisplayWarning warning);
bool isManualRequest, bool autoReturnFromQuery, AutofillServiceBase.DisplayWarning warning);
PendingIntent GetAuthPendingIntentForWarning(Context context, PwUuid entryUuid, AutofillServiceBase.DisplayWarning warning); PendingIntent GetAuthPendingIntentForWarning(Context context, PwUuid entryUuid, AutofillServiceBase.DisplayWarning warning);
PendingIntent GetDisablePendingIntentForResponse(Context context, string query, PendingIntent GetDisablePendingIntentForResponse(Context context, string query, bool isDisable);
bool isManualRequest, bool isDisable);
Intent GetRestartAppIntent(Context context); Intent GetRestartAppIntent(Context context);
int AppIconResource { get; } int AppIconResource { get; }
@@ -150,7 +148,7 @@ namespace keepass2android.services.AutofillBase
var parser = new StructureParser(this, structure); var parser = new StructureParser(this, structure);
try try
{ {
query = parser.ParseForFill(isManual); query = parser.ParseForFill();
} }
catch (Java.Lang.SecurityException e) catch (Java.Lang.SecurityException e)
@@ -213,16 +211,14 @@ namespace keepass2android.services.AutofillBase
{ {
if (query.WebDomain != null) if (query.WebDomain != null)
AddQueryDataset(query.WebDomain, AddQueryDataset(query.WebDomain,
query.WebDomain, query.PackageName, query.WebDomain, query.PackageName, autofillIds, responseBuilder, !hasEntryDataset,
isManual, autofillIds, responseBuilder, !hasEntryDataset,
query.IncompatiblePackageAndDomain query.IncompatiblePackageAndDomain
? DisplayWarning.FillDomainInUntrustedApp ? DisplayWarning.FillDomainInUntrustedApp
: DisplayWarning.None, : DisplayWarning.None,
AutofillHelper.ExtractSpec(inlinePresentationSpecs, entryDatasets.Count)); AutofillHelper.ExtractSpec(inlinePresentationSpecs, entryDatasets.Count));
else else
AddQueryDataset(query.PackageNameWithPseudoSchema, AddQueryDataset(query.PackageNameWithPseudoSchema,
query.WebDomain, query.PackageName, query.WebDomain, query.PackageName, autofillIds, responseBuilder, !hasEntryDataset, DisplayWarning.None,
isManual, autofillIds, responseBuilder, !hasEntryDataset, DisplayWarning.None,
AutofillHelper.ExtractSpec(inlinePresentationSpecs, entryDatasets.Count)); AutofillHelper.ExtractSpec(inlinePresentationSpecs, entryDatasets.Count));
} }
@@ -340,9 +336,9 @@ namespace keepass2android.services.AutofillBase
} }
private void AddQueryDataset(string query, string queryDomain, string queryPackage, bool isManual, AutofillId[] autofillIds, FillResponse.Builder responseBuilder, bool autoReturnFromQuery, DisplayWarning warning, InlinePresentationSpec inlinePresentationSpec) private void AddQueryDataset(string query, string queryDomain, string queryPackage, AutofillId[] autofillIds, FillResponse.Builder responseBuilder, bool autoReturnFromQuery, DisplayWarning warning, InlinePresentationSpec inlinePresentationSpec)
{ {
PendingIntent pendingIntent = IntentBuilder.GetAuthPendingIntentForResponse(this, query, queryDomain, queryPackage, isManual, autoReturnFromQuery, warning); PendingIntent pendingIntent = IntentBuilder.GetAuthPendingIntentForResponse(this, query, queryDomain, queryPackage, autoReturnFromQuery, warning);
string text = GetString(Resource.String.autofill_sign_in_prompt); string text = GetString(Resource.String.autofill_sign_in_prompt);
RemoteViews overlayPresentation = AutofillHelper.NewRemoteViews(base.PackageName, RemoteViews overlayPresentation = AutofillHelper.NewRemoteViews(base.PackageName,
text, AppNames.LauncherIcon); text, AppNames.LauncherIcon);
@@ -396,7 +392,7 @@ namespace keepass2android.services.AutofillBase
if (isQueryDisabled && !isManual) if (isQueryDisabled && !isManual)
return; return;
bool isForDisable = !isQueryDisabled; bool isForDisable = !isQueryDisabled;
var pendingIntent = IntentBuilder.GetDisablePendingIntentForResponse(this, query, isManual, isForDisable); var pendingIntent = IntentBuilder.GetDisablePendingIntentForResponse(this, query, isForDisable);
string text = GetString(isForDisable ? Resource.String.autofill_disable : Resource.String.autofill_enable_for, new Java.Lang.Object[] { GetDisplayNameForQuery(query, this) }); string text = GetString(isForDisable ? Resource.String.autofill_disable : Resource.String.autofill_enable_for, new Java.Lang.Object[] { GetDisplayNameForQuery(query, this) });
RemoteViews presentation = AutofillHelper.NewRemoteViews(base.PackageName, RemoteViews presentation = AutofillHelper.NewRemoteViews(base.PackageName,

View File

@@ -27,7 +27,6 @@ namespace keepass2android.services.AutofillBase
public static string ExtraQueryPackageString => "EXTRA_QUERY_PACKAGE_STRING"; public static string ExtraQueryPackageString => "EXTRA_QUERY_PACKAGE_STRING";
public static string ExtraQueryDomainString => "EXTRA_QUERY_DOMAIN_STRING"; public static string ExtraQueryDomainString => "EXTRA_QUERY_DOMAIN_STRING";
public static string ExtraUseLastOpenedEntry => "EXTRA_USE_LAST_OPENED_ENTRY"; //if set to true, no query UI is displayed. Can be used to just show a warning public static string ExtraUseLastOpenedEntry => "EXTRA_USE_LAST_OPENED_ENTRY"; //if set to true, no query UI is displayed. Can be used to just show a warning
public static string ExtraIsManualRequest => "EXTRA_IS_MANUAL_REQUEST";
public static string ExtraAutoReturnFromQuery => "EXTRA_AUTO_RETURN_FROM_QUERY"; public static string ExtraAutoReturnFromQuery => "EXTRA_AUTO_RETURN_FROM_QUERY";
public static string ExtraDisplayWarning => "EXTRA_DISPLAY_WARNING"; public static string ExtraDisplayWarning => "EXTRA_DISPLAY_WARNING";
@@ -185,18 +184,18 @@ namespace keepass2android.services.AutofillBase
ReplyIntent = null; ReplyIntent = null;
} }
protected void OnSuccess(FilledAutofillFieldCollection<ViewNodeInputField> clientFormDataMap, bool isManual) protected void OnSuccess(FilledAutofillFieldCollection<ViewNodeInputField> clientFormDataMap)
{ {
var intent = Intent; var intent = Intent;
AssistStructure structure = (AssistStructure)intent.GetParcelableExtra(AutofillManager.ExtraAssistStructure); AssistStructure structure = (AssistStructure)intent.GetParcelableExtra(AutofillManager.ExtraAssistStructure);
if (structure == null) if (structure == null || clientFormDataMap == null)
{ {
SetResult(Result.Canceled); SetResult(Result.Canceled);
Finish(); Finish();
return; return;
} }
StructureParser parser = new StructureParser(this, structure); StructureParser parser = new StructureParser(this, structure);
parser.ParseForFill(isManual); parser.ParseForFill();
AutofillFieldMetadataCollection autofillFields = parser.AutofillFields; AutofillFieldMetadataCollection autofillFields = parser.AutofillFields;
var partitionData = AutofillHintsHelper.FilterForPartition(clientFormDataMap, parser.AutofillFields.FocusedAutofillCanonicalHints); var partitionData = AutofillHintsHelper.FilterForPartition(clientFormDataMap, parser.AutofillFields.FocusedAutofillCanonicalHints);
@@ -229,7 +228,7 @@ namespace keepass2android.services.AutofillBase
private void ReturnSuccess() private void ReturnSuccess()
{ {
OnSuccess(GetDataset(), Intent.GetBooleanExtra(ExtraIsManualRequest, false)); OnSuccess(GetDataset());
Finish(); Finish();
} }

View File

@@ -72,7 +72,7 @@ namespace keepass2android.services.AutofillBase
domainSuffixParserCache = new PublicSuffixRuleCache(context); domainSuffixParserCache = new PublicSuffixRuleCache(context);
} }
public AutofillView<ViewNodeInputField> GetAutofillView(bool isManualRequest) public AutofillView<ViewNodeInputField> GetAutofillView()
{ {
AutofillView<ViewNodeInputField> autofillView = new AutofillView<ViewNodeInputField>(); AutofillView<ViewNodeInputField> autofillView = new AutofillView<ViewNodeInputField>();
@@ -83,7 +83,7 @@ namespace keepass2android.services.AutofillBase
var node = _structure.GetWindowNodeAt(i); var node = _structure.GetWindowNodeAt(i);
var view = node.RootViewNode; var view = node.RootViewNode;
ParseRecursive(autofillView, view, isManualRequest); ParseRecursive(autofillView, view);
} }
autofillView.PackageId = autofillView.PackageId ?? _structure.ActivityComponent.PackageName; autofillView.PackageId = autofillView.PackageId ?? _structure.ActivityComponent.PackageName;
@@ -93,7 +93,7 @@ namespace keepass2android.services.AutofillBase
} }
void ParseRecursive(AutofillView<ViewNodeInputField> autofillView, AssistStructure.ViewNode viewNode, bool isManualRequest) void ParseRecursive(AutofillView<ViewNodeInputField> autofillView, AssistStructure.ViewNode viewNode)
{ {
String webDomain = viewNode.WebDomain; String webDomain = viewNode.WebDomain;
if ((autofillView.PackageId == null) && (!string.IsNullOrWhiteSpace(viewNode.IdPackage)) && if ((autofillView.PackageId == null) && (!string.IsNullOrWhiteSpace(viewNode.IdPackage)) &&
@@ -129,7 +129,7 @@ namespace keepass2android.services.AutofillBase
{ {
for (int i = 0; i < childrenSize; i++) for (int i = 0; i < childrenSize; i++)
{ {
ParseRecursive(autofillView, viewNode.GetChildAt(i), isManualRequest); ParseRecursive(autofillView, viewNode.GetChildAt(i));
} }
} }
} }
@@ -159,11 +159,11 @@ namespace keepass2android.services.AutofillBase
} }
protected override AutofillTargetId Parse(bool forFill, bool isManualRequest, AutofillView<ViewNodeInputField> autofillView) protected override AutofillTargetId Parse(bool forFill, AutofillView<ViewNodeInputField> autofillView)
{ {
if (autofillView == null) if (autofillView == null)
Kp2aLog.Log("Received null autofill view!"); Kp2aLog.Log("Received null autofill view!");
var result = base.Parse(forFill, isManualRequest, autofillView); var result = base.Parse(forFill, autofillView);
Kp2aLog.Log("Parsing done"); Kp2aLog.Log("Parsing done");
@@ -185,14 +185,14 @@ namespace keepass2android.services.AutofillBase
public AutofillTargetId ParseForSave() public AutofillTargetId ParseForSave()
{ {
var autofillView = new AutofillViewFromAssistStructureFinder(_context, _structure).GetAutofillView(true); var autofillView = new AutofillViewFromAssistStructureFinder(_context, _structure).GetAutofillView();
return Parse(false, true, autofillView); return Parse(false, autofillView);
} }
public StructureParserBase<ViewNodeInputField>.AutofillTargetId ParseForFill(bool isManual) public StructureParserBase<ViewNodeInputField>.AutofillTargetId ParseForFill()
{ {
var autofillView = new AutofillViewFromAssistStructureFinder(_context, _structure).GetAutofillView(isManual); var autofillView = new AutofillViewFromAssistStructureFinder(_context, _structure).GetAutofillView();
return Parse(true, isManual, autofillView); return Parse(true, autofillView);
} }

View File

@@ -17,14 +17,12 @@ namespace keepass2android.services
{ {
private static int _pendingIntentRequestCode = 0; private static int _pendingIntentRequestCode = 0;
public PendingIntent GetAuthPendingIntentForResponse(Context context, string query, string queryDomain, string queryPackage, public PendingIntent GetAuthPendingIntentForResponse(Context context, string query, string queryDomain, string queryPackage, bool autoReturnFromQuery, AutofillServiceBase.DisplayWarning warning)
bool isManualRequest, bool autoReturnFromQuery, AutofillServiceBase.DisplayWarning warning)
{ {
Intent intent = new Intent(context, typeof(ChooseForAutofillActivity)); Intent intent = new Intent(context, typeof(ChooseForAutofillActivity));
intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryString, query); intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryString, query);
intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryDomainString, queryDomain); intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryDomainString, queryDomain);
intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryPackageString, queryPackage); intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryPackageString, queryPackage);
intent.PutExtra(ChooseForAutofillActivityBase.ExtraIsManualRequest, isManualRequest);
intent.PutExtra(ChooseForAutofillActivityBase.ExtraAutoReturnFromQuery, autoReturnFromQuery); intent.PutExtra(ChooseForAutofillActivityBase.ExtraAutoReturnFromQuery, autoReturnFromQuery);
intent.PutExtra(ChooseForAutofillActivityBase.ExtraDisplayWarning, (int)warning); intent.PutExtra(ChooseForAutofillActivityBase.ExtraDisplayWarning, (int)warning);
return PendingIntent.GetActivity(context, _pendingIntentRequestCode++, intent, Util.AddMutabilityFlag(PendingIntentFlags.CancelCurrent, PendingIntentFlags.Mutable)); return PendingIntent.GetActivity(context, _pendingIntentRequestCode++, intent, Util.AddMutabilityFlag(PendingIntentFlags.CancelCurrent, PendingIntentFlags.Mutable));
@@ -40,12 +38,10 @@ namespace keepass2android.services
return PendingIntent.GetActivity(context, _pendingIntentRequestCode++, intent, Util.AddMutabilityFlag(PendingIntentFlags.CancelCurrent, PendingIntentFlags.Mutable)); return PendingIntent.GetActivity(context, _pendingIntentRequestCode++, intent, Util.AddMutabilityFlag(PendingIntentFlags.CancelCurrent, PendingIntentFlags.Mutable));
} }
public PendingIntent GetDisablePendingIntentForResponse(Context context, string query, public PendingIntent GetDisablePendingIntentForResponse(Context context, string query, bool isDisable)
bool isManualRequest, bool isDisable)
{ {
Intent intent = new Intent(context, typeof(DisableAutofillForQueryActivity)); Intent intent = new Intent(context, typeof(DisableAutofillForQueryActivity));
intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryString, query); intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryString, query);
intent.PutExtra(ChooseForAutofillActivityBase.ExtraIsManualRequest, isManualRequest);
intent.PutExtra(DisableAutofillForQueryActivity.ExtraIsDisable, isDisable); intent.PutExtra(DisableAutofillForQueryActivity.ExtraIsDisable, isDisable);
return PendingIntent.GetActivity(context, _pendingIntentRequestCode++, intent, Util.AddMutabilityFlag(PendingIntentFlags.CancelCurrent, PendingIntentFlags.Immutable)); return PendingIntent.GetActivity(context, _pendingIntentRequestCode++, intent, Util.AddMutabilityFlag(PendingIntentFlags.CancelCurrent, PendingIntentFlags.Immutable));

View File

@@ -9,7 +9,7 @@ using KeePassLib.Serialization;
namespace keepass2android namespace keepass2android
{ {
[Activity] [Activity(Theme = "@style/Kp2aTheme_ActionBar")]
public class ExportKeyfileActivity : LockCloseActivity public class ExportKeyfileActivity : LockCloseActivity
{ {