Compare commits

...

260 Commits

Author SHA1 Message Date
Philipp Crocoll
bb74305b26 remove accidentally commited code, was for testing only (into 1.08-pre3) 2019-11-06 20:52:55 +01:00
Philipp Crocoll
32549c9eff make sure biometric prompt does not show up directly after authentication (into 1.08-pre3) 2019-11-06 19:31:57 +01:00
Philipp Crocoll
83b5aa7d7b don't require confirmation for face unlock, as suggested in #795; makes it into pre3 2019-11-06 18:52:34 +01:00
Philipp Crocoll
640a2c7e88 manifest for 1.08-pre3 2019-11-06 18:28:04 +01:00
Philipp Crocoll
31aad963d6 Merge branch 'master' of https://github.com/PhilippC/keepass2android 2019-11-06 18:27:37 +01:00
Philipp Crocoll
326f4282d7 fix potential crash (opening an activity without NewTask flag) 2019-11-06 18:27:24 +01:00
Philipp Crocoll
e5b3cf3db6 trust more Opera browsers 2019-11-06 17:46:26 +01:00
PhilippC
ca3e4a5135 Merge pull request #1023 from squabbi/patch-1
Update How-to-create-a-plug-in_.md
2019-11-06 11:37:50 -05:00
Jayden
c1607bbfb3 Update How-to-create-a-plug-in_.md
Fix malformed link for QR code Play Store link
2019-11-06 16:05:24 +11:00
Philipp Crocoll
0639201b4c add compatibility with steam encoding for OTPs (e.g. otpauth://totp/test:test@example.com?secret=63BEDWCQZKTQWPESARIERL5DTTQFCJTK&issuer=Valve&algorithm=SHA1&digits=5&period=30&encoder=steam) 2019-11-06 04:50:29 +01:00
Philipp Crocoll
b5fe3b8ce4 Merge branch 'master' of https://github.com/PhilippC/keepass2android 2019-11-05 22:41:10 +01:00
Philipp Crocoll
2362efe5fc fix SelectCurrentDbActivity not correctly forwarding to PasswordActivity 2019-11-05 22:40:59 +01:00
Philipp Crocoll
308d8889e4 add missing permission and fix app version for 1.08-pre2 (142 was already used for pre1) 2019-11-05 21:33:14 +01:00
Philipp Crocoll
5e4ea21377 Merge branch 'master' of https://github.com/PhilippC/keepass2android 2019-11-05 20:56:53 +01:00
Philipp Crocoll
45489ad600 changelog and manifest for 1.08-pre2 2019-11-05 20:56:45 +01:00
Philipp Crocoll
683cde5a8b update targetSdkVersion to 29 (Android 10/Q). Change canvas clipping in Soft keyboard to adhere to behavior changes in Android 10. Migrate to AndroidX. Migrate to using BiometricPrompt instead of FingerprintManager, keeping compatibility to SamsungPass API for devices like SGS5. Closes #795, should close #626, closes #910 2019-11-05 20:55:02 +01:00
Philipp Crocoll
8a9c781de2 packages.config to .csproj 2019-11-01 20:35:25 +01:00
PhilippC
6812998c8d Update README.md 2019-10-29 19:43:41 +01:00
Philipp Crocoll
89fda1eee5 update to target Android Q (build tools and targetSdkVersion) 2019-10-28 20:24:20 +01:00
Philipp Crocoll
0cf0170144 changelog and manifest for 1.08-pre1 2019-10-27 22:30:02 +01:00
Philipp Crocoll
cb79c8b1ff Merge branch 'master' of https://github.com/PhilippC/keepass2android 2019-10-27 22:19:57 +01:00
Philipp Crocoll
658dd6a0ec add kiwi browser to list of support autofill browsers 2019-10-27 22:11:36 +01:00
Philipp Crocoll
e6049eca2c upgrade OkHttp to 4.2.2 2019-10-27 22:11:03 +01:00
Philipp Crocoll
efcaa36325 no donate notice in changelog when using the app for one of the first times 2019-10-21 10:33:31 +02:00
Philipp Crocoll
905efd0454 Merge branch 'master' of https://github.com/PhilippC/keepass2android
# Resolved Conflicts:
#	src/keepass2android/Resources/values/strings.xml
2019-10-21 10:24:15 +02:00
Philipp Crocoll
3ce1c04cf2 Merge branch 'Branch_1.07'
# Resolved Conflicts:
#	src/keepass2android/Resources/values/strings.xml
2019-10-10 03:25:02 +02:00
Philipp Crocoll
cb979f8975 Merge remote-tracking branch 'remotes/origin/master' 2019-10-10 03:22:31 +02:00
PhilippC
8fe549fc55 Merge pull request #768 from PhilippC/l10n_master
New Crowdin translations
2019-10-10 02:44:27 +02:00
PhilippC
a99e55e884 New translations strings.xml (Portuguese, Brazilian) 2019-10-10 02:41:12 +02:00
PhilippC
e361f770e8 New translations strings.xml (Portuguese) 2019-10-10 02:41:09 +02:00
PhilippC
a27e13bcb3 New translations strings.xml (French) 2019-10-10 02:34:34 +02:00
PhilippC
03cf25766b New translations strings.xml (Swedish) 2019-10-10 02:33:44 +02:00
PhilippC
9ce42a8e98 New translations strings.xml (Spanish) 2019-10-10 02:33:39 +02:00
PhilippC
c03a5b08fd New translations strings.xml (Portuguese, Brazilian) 2019-10-10 02:33:16 +02:00
PhilippC
9b5853d3f9 New translations strings.xml (Portuguese) 2019-10-10 02:33:11 +02:00
PhilippC
8a3735dc01 New translations strings.xml (German) 2019-10-09 22:30:13 +02:00
PhilippC
aae662ab5e New translations strings.xml (Swedish) 2019-10-09 10:10:14 +02:00
PhilippC
d051f02a43 New translations strings.xml (Swedish) 2019-10-09 10:00:15 +02:00
PhilippC
2e4cf0dfc6 New translations strings.xml (Swedish) 2019-10-09 09:50:09 +02:00
PhilippC
d7f462d21f New translations strings.xml (Czech) 2019-10-08 21:00:11 +02:00
PhilippC
2b61598c21 New translations strings.xml (Czech) 2019-10-08 20:50:12 +02:00
Philipp Crocoll
799dc3a38f switch to FluentFTP to close #825 2019-10-08 07:11:34 +02:00
PhilippC
9c76dce17d New translations strings.xml (Polish) 2019-10-07 21:50:13 +02:00
PhilippC
28ac79bbe5 New translations strings.xml (Catalan) 2019-10-07 21:50:08 +02:00
PhilippC
bdf825a2b5 New translations strings.xml (Catalan) 2019-10-07 21:40:09 +02:00
PhilippC
37d03a2735 New translations strings.xml (Catalan) 2019-10-07 21:20:08 +02:00
PhilippC
e8fde4ad0a New translations strings.xml (Dutch) 2019-10-07 20:50:08 +02:00
PhilippC
1aa29a82fb New translations strings.xml (Ukrainian) 2019-10-07 18:10:09 +02:00
PhilippC
60f292a5a7 New translations strings.xml (German) 2019-10-07 17:30:10 +02:00
PhilippC
1f956ab1db New translations strings.xml (German) 2019-10-07 17:20:12 +02:00
PhilippC
df39fa5545 New translations strings.xml (Russian) 2019-10-07 17:00:12 +02:00
PhilippC
dd0800f543 New translations strings.xml (Chinese Traditional) 2019-10-07 16:50:14 +02:00
PhilippC
8b3c6eb1ff New translations strings.xml (Danish) 2019-10-07 16:30:13 +02:00
PhilippC
88b35c0051 New translations strings.xml (Danish) 2019-10-07 15:00:10 +02:00
PhilippC
2f83169ddd New translations strings.xml (Italian) 2019-10-07 13:50:08 +02:00
PhilippC
ce4b301f5c New translations strings.xml (Italian) 2019-10-07 13:40:13 +02:00
PhilippC
433f46b8f1 New translations strings.xml (Danish) 2019-10-07 13:40:10 +02:00
PhilippC
03eb52dc14 New translations strings.xml (Japanese) 2019-10-07 13:30:19 +02:00
PhilippC
9d785679c5 New translations strings.xml (Danish) 2019-10-07 13:30:14 +02:00
PhilippC
699a4f96b0 New translations strings.xml (Chinese Traditional) 2019-10-07 13:30:09 +02:00
PhilippC
afd6f0f4d6 New translations strings.xml (Dutch) 2019-10-07 12:40:15 +02:00
PhilippC
eaadc45fce New translations strings.xml (Chinese Traditional) 2019-10-07 12:40:13 +02:00
PhilippC
e9852a6d98 New translations strings.xml (Spanish) 2019-10-07 12:30:17 +02:00
PhilippC
e1b3e769d8 New translations strings.xml (Slovenian) 2019-10-07 12:30:12 +02:00
PhilippC
501535a9a4 New translations strings.xml (Spanish) 2019-10-07 12:20:10 +02:00
PhilippC
fb8608e467 New translations strings.xml (Slovak) 2019-10-07 12:10:29 +02:00
PhilippC
e9eb8c250a New translations strings.xml (Italian) 2019-10-07 12:10:22 +02:00
PhilippC
eaa5a9d375 New translations strings.xml (French) 2019-10-07 12:10:15 +02:00
PhilippC
d28834591a New translations strings.xml (Danish) 2019-10-07 12:02:12 +02:00
PhilippC
49aa0a20cd New translations strings.xml (Slovak) 2019-10-07 12:01:17 +02:00
PhilippC
8d611bd6c6 New translations strings.xml (Portuguese, Brazilian) 2019-10-07 12:01:01 +02:00
PhilippC
bfe8650ec9 New translations strings.xml (Portuguese) 2019-10-07 12:00:56 +02:00
PhilippC
fd52a5f388 New translations strings.xml (Spanish) 2019-10-07 11:40:13 +02:00
PhilippC
6b8c5ea1fb New translations strings.xml (Japanese) 2019-10-07 11:40:09 +02:00
PhilippC
8347feceff New translations strings.xml (Japanese) 2019-10-07 11:30:10 +02:00
PhilippC
626b7fc6b3 New translations strings.xml (Spanish) 2019-10-07 11:20:08 +02:00
Philipp Crocoll
1701c9142b allow to activate search field also after QuickUnlock, not only full unlock. Closes #858 2019-10-07 11:19:34 +02:00
Philipp Crocoll
245794ed53 add Copy TOTP notification, closes #110 2019-10-07 11:18:48 +02:00
PhilippC
24aba30fa8 New translations strings.xml (French) 2019-10-07 10:30:10 +02:00
Philipp Crocoll
6338472e73 order group list with culture-aware sorting, closes #922 2019-10-07 10:30:08 +02:00
Philipp Crocoll
580b46a394 detect if FLAG_SECURE cannot be set and display an explanation, combined with a button to access the app settings to disable screen protection if desired. closes #272. 2019-10-07 10:29:54 +02:00
PhilippC
ea1a34353c New translations strings.xml (Spanish) 2019-10-07 09:50:08 +02:00
PhilippC
f9790e0e3e New translations strings.xml (Chinese Traditional) 2019-10-07 09:30:14 +02:00
PhilippC
540c4a72a2 New translations strings.xml (Chinese Traditional) 2019-10-07 09:20:10 +02:00
PhilippC
bc905304e7 New translations strings.xml (Chinese Traditional) 2019-10-07 09:10:08 +02:00
PhilippC
ad04309f9d New translations strings.xml (Slovenian) 2019-10-07 07:20:07 +02:00
Philipp Crocoll
684ffb8525 show toast in correct thread, closes #371 2019-10-07 07:13:59 +02:00
Philipp Crocoll
049764fe67 don't save files in a file version lower than what was read, closes #791 2019-10-07 02:30:38 +02:00
Philipp Crocoll
a048c45b32 improve clearing of clipboard, closes #936 2019-10-07 02:29:00 +02:00
PhilippC
60c78642b1 New translations strings.xml (Danish) 2019-10-07 00:10:09 +02:00
PhilippC
5c7f551922 New translations strings.xml (German) 2019-10-07 00:00:15 +02:00
PhilippC
ceac7841a0 New translations strings.xml (Danish) 2019-10-07 00:00:11 +02:00
PhilippC
a29fc9d3cc New translations strings.xml (Danish) 2019-10-06 23:50:10 +02:00
PhilippC
f5dbc85450 New translations strings.xml (Polish) 2019-10-06 22:50:10 +02:00
PhilippC
6a86a6906c New translations strings.xml (Italian) 2019-10-06 22:40:12 +02:00
PhilippC
2b4bd1a79d New translations strings.xml (Czech) 2019-10-06 22:40:08 +02:00
PhilippC
2b2ce4eb29 New translations strings.xml (French) 2019-10-06 22:20:10 +02:00
PhilippC
6ac875aeb5 New translations strings.xml (Portuguese, Brazilian) 2019-10-06 22:10:24 +02:00
PhilippC
f43c6d3899 New translations strings.xml (Turkish) 2019-10-06 22:00:26 +02:00
PhilippC
3f240868d0 New translations strings.xml (Italian) 2019-10-06 22:00:22 +02:00
PhilippC
5ccea973ee New translations strings.xml (Portuguese) 2019-10-06 21:51:33 +02:00
PhilippC
c1d59d9203 New translations strings.xml (Dutch) 2019-10-06 21:50:33 +02:00
Philipp Crocoll
c6d3eb7131 Merge branch 'master' of https://github.com/PhilippC/keepass2android 2019-10-06 21:48:35 +02:00
Philipp Crocoll
f462bbe98b remove "pre" from changelog 2019-10-06 21:48:10 +02:00
PhilippC
c6be5fcf84 New translations strings.xml (Hungarian) 2019-10-06 21:40:10 +02:00
PhilippC
023d9e194f New translations strings.xml (Turkish) 2019-10-06 21:30:10 +02:00
PhilippC
78ad964481 New translations strings.xml (Dutch) 2019-10-06 21:20:08 +02:00
PhilippC
9c9a8277a9 New translations strings.xml (Dutch) 2019-10-06 21:10:13 +02:00
PhilippC
3f414ded5b New translations strings.xml (Czech) 2019-10-06 21:10:11 +02:00
PhilippC
5906824ffc New translations strings.xml (German) 2019-10-06 21:00:09 +02:00
PhilippC
737c87bdf8 New translations strings.xml (Vietnamese) 2019-10-06 20:53:11 +02:00
PhilippC
bb27734a07 New translations strings.xml (Hungarian) 2019-10-06 20:53:07 +02:00
PhilippC
a9e6880add New translations strings.xml (Greek) 2019-10-06 20:52:57 +02:00
PhilippC
a1c3bf19ae New translations strings.xml (German) 2019-10-06 20:52:53 +02:00
PhilippC
0dc86e8662 New translations strings.xml (Galician) 2019-10-06 20:52:50 +02:00
PhilippC
bddc731390 New translations strings.xml (French) 2019-10-06 20:52:46 +02:00
PhilippC
2521aa2621 New translations strings.xml (Finnish) 2019-10-06 20:52:42 +02:00
PhilippC
23af6f3031 New translations strings.xml (Indonesian) 2019-10-06 20:52:39 +02:00
PhilippC
89ac5af115 New translations strings.xml (Dutch) 2019-10-06 20:52:36 +02:00
PhilippC
1f1ac04640 New translations strings.xml (Czech) 2019-10-06 20:52:32 +02:00
PhilippC
67d2eeaaff New translations strings.xml (Croatian) 2019-10-06 20:52:28 +02:00
PhilippC
0788af941e New translations strings.xml (Chinese Traditional) 2019-10-06 20:52:24 +02:00
PhilippC
484cea229c New translations strings.xml (Chinese Simplified) 2019-10-06 20:52:22 +02:00
PhilippC
827a680f81 New translations strings.xml (Catalan) 2019-10-06 20:52:20 +02:00
PhilippC
8b5c170409 New translations strings.xml (Bulgarian) 2019-10-06 20:52:16 +02:00
PhilippC
9ec76c2738 New translations strings.xml (Basque) 2019-10-06 20:52:11 +02:00
PhilippC
ea9539ad0a New translations strings.xml (Danish) 2019-10-06 20:52:06 +02:00
PhilippC
03f4040c09 New translations strings.xml (Italian) 2019-10-06 20:51:58 +02:00
PhilippC
869f5d35bd New translations strings.xml (Korean) 2019-10-06 20:51:54 +02:00
PhilippC
01ac1c601f New translations strings.xml (Ukrainian) 2019-10-06 20:51:50 +02:00
PhilippC
22f3f5ce59 New translations strings.xml (Turkish) 2019-10-06 20:51:47 +02:00
PhilippC
0b430c90f4 New translations strings.xml (Swedish) 2019-10-06 20:51:41 +02:00
PhilippC
080483b2d0 New translations strings.xml (Spanish) 2019-10-06 20:51:35 +02:00
PhilippC
2da645f25b New translations strings.xml (Slovenian) 2019-10-06 20:51:32 +02:00
PhilippC
3ff6c35e35 New translations strings.xml (Slovak) 2019-10-06 20:51:30 +02:00
PhilippC
5f3fb52833 New translations strings.xml (Japanese) 2019-10-06 20:51:23 +02:00
PhilippC
6117053dd7 New translations strings.xml (Russian) 2019-10-06 20:51:18 +02:00
PhilippC
c3a1faffca New translations strings.xml (Portuguese, Brazilian) 2019-10-06 20:51:12 +02:00
PhilippC
5d85fdda46 New translations strings.xml (Portuguese) 2019-10-06 20:51:10 +02:00
PhilippC
907705b657 New translations strings.xml (Polish) 2019-10-06 20:51:04 +02:00
PhilippC
22e460d7bf New translations strings.xml (Persian) 2019-10-06 20:51:00 +02:00
PhilippC
3a81ebfcd9 New translations strings.xml (Norwegian Bokmal) 2019-10-06 20:50:52 +02:00
PhilippC
ec92225e50 New translations strings.xml (Romanian) 2019-10-06 20:50:49 +02:00
PhilippC
5163d472b3 New translations strings.xml (Arabic) 2019-10-06 20:50:46 +02:00
Philipp Crocoll
069a2d287c catch bad paths passed to search activity. closes #801. 2019-10-06 20:36:37 +02:00
Philipp Crocoll
01b8469fbb fix crash when copying entries, closes #920 2019-10-06 20:25:25 +02:00
PhilippC
421a590514 Update Documentation.md 2019-10-06 07:53:37 +02:00
PhilippC
c3898245ce New translations strings.xml (French) 2019-07-22 17:30:13 +02:00
PhilippC
f15748b4e9 New translations strings.xml (Chinese Traditional) 2019-07-22 14:00:18 +02:00
PhilippC
d11c871526 New translations strings.xml (French) 2019-07-22 13:00:11 +02:00
PhilippC
6944d842c3 New translations strings.xml (Turkish) 2019-07-22 11:40:15 +02:00
PhilippC
183087b441 New translations strings.xml (Italian) 2019-07-22 11:30:13 +02:00
PhilippC
5e081805f1 New translations strings.xml (Spanish) 2019-07-22 11:10:22 +02:00
PhilippC
e1addd1485 New translations strings.xml (Japanese) 2019-07-22 11:10:14 +02:00
PhilippC
801f13c2d3 New translations strings.xml (Chinese Traditional) 2019-07-22 10:50:11 +02:00
PhilippC
6dcb22dfc2 New translations strings.xml (Portuguese) 2019-07-22 09:50:30 +02:00
PhilippC
014f238f6c New translations strings.xml (Dutch) 2019-07-03 10:30:13 +02:00
PhilippC
9482b37672 New translations strings.xml (Dutch) 2019-07-03 10:20:13 +02:00
PhilippC
69c5601de4 New translations strings.xml (Dutch) 2019-07-03 10:10:13 +02:00
PhilippC
856ba36a20 New translations strings.xml (Norwegian Bokmal) 2019-06-27 23:10:10 +02:00
PhilippC
396cf51794 New translations strings.xml (Dutch) 2019-06-26 13:30:10 +02:00
PhilippC
8138790396 New translations strings.xml (Dutch) 2019-06-26 13:20:10 +02:00
PhilippC
e698468c39 New translations strings.xml (Dutch) 2019-06-26 13:10:12 +02:00
PhilippC
da005a35bf New translations strings.xml (Polish) 2019-06-21 02:40:11 +02:00
PhilippC
9b62f28e93 New translations strings.xml (Polish) 2019-06-21 02:30:13 +02:00
PhilippC
5adc738c03 New translations strings.xml (Korean) 2019-06-18 10:10:14 +02:00
PhilippC
d784394ea9 New translations strings.xml (Swedish) 2019-06-02 18:00:11 +02:00
PhilippC
b1cbb7893c New translations strings.xml (Swedish) 2019-06-02 17:50:09 +02:00
PhilippC
51b2049429 New translations strings.xml (Swedish) 2019-06-02 17:40:09 +02:00
PhilippC
84c8af7357 New translations strings.xml (Swedish) 2019-06-02 17:30:10 +02:00
PhilippC
69cbda8a39 New translations strings.xml (Swedish) 2019-06-02 17:20:09 +02:00
PhilippC
48f351ba0d New translations strings.xml (Swedish) 2019-06-02 17:10:11 +02:00
PhilippC
0a7fac77ff New translations strings.xml (Vietnamese) 2019-05-26 13:32:22 +02:00
PhilippC
ff336b40ae New translations strings.xml (Basque) 2019-05-26 13:32:16 +02:00
PhilippC
86a8da3ef3 New translations strings.xml (Bulgarian) 2019-05-26 13:32:12 +02:00
PhilippC
a72b681205 New translations strings.xml (Catalan) 2019-05-26 13:32:07 +02:00
PhilippC
3c75a4a012 New translations strings.xml (Chinese Simplified) 2019-05-26 13:32:01 +02:00
PhilippC
f9fc4b9a06 New translations strings.xml (Croatian) 2019-05-26 13:31:56 +02:00
PhilippC
6869f940ac New translations strings.xml (Czech) 2019-05-26 13:31:52 +02:00
PhilippC
79f0f90f3e New translations strings.xml (Danish) 2019-05-26 13:31:47 +02:00
PhilippC
1119610a10 New translations strings.xml (Dutch) 2019-05-26 13:31:42 +02:00
PhilippC
90fe3f04c0 New translations strings.xml (Finnish) 2019-05-26 13:31:37 +02:00
PhilippC
aca0aef285 New translations strings.xml (French) 2019-05-26 13:31:32 +02:00
PhilippC
8134b73902 New translations strings.xml (Galician) 2019-05-26 13:31:28 +02:00
PhilippC
57414cd0b8 New translations strings.xml (German) 2019-05-26 13:31:23 +02:00
PhilippC
6792eb53f0 New translations strings.xml (Arabic) 2019-05-26 13:31:19 +02:00
PhilippC
a6d4814980 New translations strings.xml (Greek) 2019-05-26 13:31:15 +02:00
PhilippC
3ef0afa6bc New translations strings.xml (Hungarian) 2019-05-26 13:31:10 +02:00
PhilippC
942be17e61 New translations strings.xml (Indonesian) 2019-05-26 13:31:06 +02:00
PhilippC
37e8f14e3b New translations strings.xml (Italian) 2019-05-26 13:31:00 +02:00
PhilippC
64ca771c51 New translations strings.xml (Japanese) 2019-05-26 13:30:54 +02:00
PhilippC
df2c2cd827 New translations strings.xml (Romanian) 2019-05-26 13:30:50 +02:00
PhilippC
4b692e4697 New translations strings.xml (Russian) 2019-05-26 13:30:45 +02:00
PhilippC
a0fa5ff4c2 New translations strings.xml (Serbian (Cyrillic)) 2019-05-26 13:30:42 +02:00
PhilippC
32df0ae8fe New translations strings.xml (Slovak) 2019-05-26 13:30:36 +02:00
PhilippC
73b9bcac7a New translations strings.xml (Slovenian) 2019-05-26 13:30:31 +02:00
PhilippC
11f606631c New translations strings.xml (Spanish) 2019-05-26 13:30:28 +02:00
PhilippC
9f696441e3 New translations strings.xml (Swedish) 2019-05-26 13:30:23 +02:00
PhilippC
118d18613f New translations strings.xml (Turkish) 2019-05-26 13:30:19 +02:00
PhilippC
a39bc9b7f7 New translations strings.xml (Chinese Traditional) 2019-05-26 13:30:12 +02:00
PhilippC
e0e17359c9 New translations strings.xml (Polish) 2019-05-25 21:50:41 +02:00
PhilippC
5ab25b0bc8 New translations strings.xml (Persian) 2019-05-25 21:50:37 +02:00
PhilippC
686e7eb6c1 New translations strings.xml (Norwegian Bokmal) 2019-05-25 21:50:29 +02:00
PhilippC
c3ba8662b9 New translations strings.xml (Korean) 2019-05-25 21:50:25 +02:00
PhilippC
b7e23fd046 New translations strings.xml (Portuguese, Brazilian) 2019-05-25 21:50:20 +02:00
PhilippC
9ff89ba263 New translations strings.xml (Ukrainian) 2019-05-25 21:50:16 +02:00
PhilippC
f470606af0 New translations strings.xml (Vietnamese) 2019-05-21 15:43:03 +02:00
PhilippC
4a7b3f17c2 New translations strings.xml (Basque) 2019-05-21 15:42:54 +02:00
PhilippC
788df21115 New translations strings.xml (Bulgarian) 2019-05-21 15:42:48 +02:00
PhilippC
2aaaa8b416 New translations strings.xml (Catalan) 2019-05-21 15:42:43 +02:00
PhilippC
2660084401 New translations strings.xml (Chinese Simplified) 2019-05-21 15:42:37 +02:00
PhilippC
e0dfb888c1 New translations strings.xml (Croatian) 2019-05-21 15:42:31 +02:00
PhilippC
ab66b5585d New translations strings.xml (Czech) 2019-05-21 15:42:25 +02:00
PhilippC
bf8b9f32df New translations strings.xml (Danish) 2019-05-21 15:42:20 +02:00
PhilippC
d259143736 New translations strings.xml (Dutch) 2019-05-21 15:42:15 +02:00
PhilippC
83dc82a308 New translations strings.xml (Finnish) 2019-05-21 15:42:09 +02:00
PhilippC
233f4bb04f New translations strings.xml (French) 2019-05-21 15:42:04 +02:00
PhilippC
8183d17706 New translations strings.xml (Galician) 2019-05-21 15:41:57 +02:00
PhilippC
feedcae410 New translations strings.xml (German) 2019-05-21 15:41:52 +02:00
PhilippC
3157ea741e New translations strings.xml (Arabic) 2019-05-21 15:41:47 +02:00
PhilippC
623040bf3e New translations strings.xml (Greek) 2019-05-21 15:41:40 +02:00
PhilippC
6a394f697a New translations strings.xml (Hungarian) 2019-05-21 15:41:34 +02:00
PhilippC
3908f4b5ce New translations strings.xml (Indonesian) 2019-05-21 15:41:29 +02:00
PhilippC
ad21ee1e64 New translations strings.xml (Italian) 2019-05-21 15:41:21 +02:00
PhilippC
6c69796248 New translations strings.xml (Japanese) 2019-05-21 15:41:16 +02:00
PhilippC
e6f79562dc New translations strings.xml (Romanian) 2019-05-21 15:41:10 +02:00
PhilippC
5e9c655672 New translations strings.xml (Russian) 2019-05-21 15:41:06 +02:00
PhilippC
6b01100ca4 New translations strings.xml (Serbian (Cyrillic)) 2019-05-21 15:41:01 +02:00
PhilippC
838382ea0a New translations strings.xml (Slovak) 2019-05-21 15:40:55 +02:00
PhilippC
3c62c22f3a New translations strings.xml (Slovenian) 2019-05-21 15:40:50 +02:00
PhilippC
bc1197b4a0 New translations strings.xml (Spanish) 2019-05-21 15:40:44 +02:00
PhilippC
d691570099 New translations strings.xml (Swedish) 2019-05-21 15:40:35 +02:00
PhilippC
772d55fa45 New translations strings.xml (Turkish) 2019-05-21 15:40:29 +02:00
PhilippC
676072e96b New translations strings.xml (Chinese Traditional) 2019-05-21 15:40:17 +02:00
PhilippC
29dec2d9f7 New translations strings.xml (Polish) 2019-05-21 11:50:55 +02:00
PhilippC
b1d6099e2c New translations strings.xml (Persian) 2019-05-21 11:50:51 +02:00
PhilippC
e5cbf010a3 New translations strings.xml (Norwegian Bokmal) 2019-05-21 11:50:41 +02:00
PhilippC
023364f968 New translations strings.xml (Korean) 2019-05-21 11:50:34 +02:00
PhilippC
26fe7f610d New translations strings.xml (Portuguese, Brazilian) 2019-05-21 11:50:29 +02:00
PhilippC
37d6e54e70 New translations strings.xml (Ukrainian) 2019-05-21 11:50:23 +02:00
PhilippC
adc4c59a99 New translations strings.xml (Chinese Traditional) 2019-05-17 05:20:11 +02:00
PhilippC
16fd528e95 New translations strings.xml (Ukrainian) 2019-05-07 13:30:13 +02:00
PhilippC
efdfdac6cb New translations strings.xml (Polish) 2019-05-05 02:40:09 +02:00
PhilippC
03ebe6b176 New translations strings.xml (Polish) 2019-05-05 02:30:11 +02:00
PhilippC
477c36d880 New translations strings.xml (Polish) 2019-04-10 01:00:11 +02:00
PhilippC
d4a99ce9b2 New translations strings.xml (Czech) 2019-04-07 15:30:10 +02:00
PhilippC
025c5fe301 New translations strings.xml (Czech) 2019-04-07 15:20:09 +02:00
PhilippC
422f5deafb New translations strings.xml (Czech) 2019-04-07 15:10:09 +02:00
PhilippC
00b5473a7a New translations strings.xml (Czech) 2019-04-07 15:00:09 +02:00
PhilippC
945264d927 New translations strings.xml (Catalan) 2019-04-07 10:50:11 +02:00
PhilippC
74848cd015 New translations strings.xml (Catalan) 2019-04-07 10:40:09 +02:00
PhilippC
c583e3238a New translations strings.xml (Turkish) 2019-04-06 12:20:09 +02:00
PhilippC
0cc7abf322 New translations strings.xml (Chinese Simplified) 2019-04-06 10:20:12 +02:00
PhilippC
8f3b9c532c New translations strings.xml (Chinese Simplified) 2019-04-06 10:10:10 +02:00
PhilippC
4ce35de276 New translations strings.xml (Chinese Simplified) 2019-04-06 10:00:10 +02:00
PhilippC
7c05aa625f New translations strings.xml (Swedish) 2019-04-05 11:20:11 +02:00
PhilippC
139ac0b269 New translations strings.xml (Swedish) 2019-04-05 11:10:12 +02:00
PhilippC
8ba35083d8 New translations strings.xml (Danish) 2019-04-04 01:10:11 +02:00
PhilippC
02003abf1d New translations strings.xml (Chinese Traditional) 2019-04-01 16:12:30 +02:00
PhilippC
88ce729351 New translations strings.xml (Portuguese, Brazilian) 2019-04-01 16:11:53 +02:00
79 changed files with 7103 additions and 1255 deletions

View File

@@ -77,6 +77,10 @@ The KP2A keyboard is meant to quickly "paste" or "type" values from your databas
## Is it safe to store my kdbx file in the cloud?
While it may happen that someone gets access to your kdbx file in the cloud, there is still no need to worry: the purpose of encryption is to protect the data even in case someone gets the kdbx file! As long as you are using a safe master key, you're safe! [Key files](https://keepass.info/help/base/keys.html#keyfiles) can help with securing the database even more.
## Doesn't Keepass2Android create automatic backups?
Yes and no. Yes: Keepass2Android stores the last successfully opened file as a read-only backup locally on the phone (unless you disable this is in the settings). This should make sure that even if the file gets destroyed during a save operation or gets deleted by accident, you should always have a version that can be opened. (Don't mix this up with the internal file cache which is not meant as a backup and can easily be overwritten even with a corrupt file. This internal file cache is meant for providing writable access even when the original file is not reachable, e.g. when you're offline.)
No: The local backup has two shortcomings: It is only one backup and does not allow to revert to older versions. So if you deleted an entry from the database, it might be deleted in the local backup soon as well. The even more important shortcoming is that it is just a local backup. It won't help when your phone gets lost or broken. Please create additional backups on seperate storage!
## How do I backup the database?
If you have stored your database on the cloud, you might rely on your cloud storage providers backups. Make sure they allow you to revert to older revisions in case the file gets corrupted for some reason.
If you are working with a local database file, make sure you create regular backups. I suggest you have an aumotated mechanism, e.g. with FolderSync (Lite) which can copy local files from your device to other locations, e.g. your PC in a local network. You can also use USB or tools like MyPhoneExploror to transfer data to your PC. Or, you use a removable storage like an SD card which you keep in a safe place after making the backup.

View File

@@ -54,7 +54,7 @@ Please also add a few strings in your resource files (e.g. strings.xml) with the
These strings will be displayed to the user when KP2A asks if access should be granted.
## Modifying the entry view
You can add menu options for the full entry or for individual fields of the entry when displayed to the user. This is done, for example, by the QR plugin ([https://play.google.com/store/apps/details?id=keepass2android.plugin.qr](https___play.google.com_store_apps_details_id=keepass2android.plugin.qr)).
You can add menu options for the full entry or for individual fields of the entry when displayed to the user. This is done, for example, by the QR plugin ([https://play.google.com/store/apps/details?id=keepass2android.plugin.qr](https://play.google.com/store/apps/details?id=keepass2android.plugin.qr)).
In addition, it is even possible to add new fields or modify existing fields. Please see the sample plugin "PluginA" in the KP2A repository for a simple example on how to do this:
[https://keepass2android.codeplex.com/SourceControl/latest#src/java/PluginA/src/keepass2android/plugina/PluginAActionReceiver.java](https://keepass2android.codeplex.com/SourceControl/latest#src/java/PluginA/src/keepass2android/plugina/PluginAActionReceiver.java)

View File

@@ -13,6 +13,7 @@ Beta-releases can be obtained by opting in to the [Beta testing channel](https:/
# How can I contribute?
* Help to translate Keepass2Android into your language or improve translations at [our Crowdin page](http://crowdin.net/project/keepass2android)
* Add features by [creating a plugin](How-to-create-a-plug-in_.md) or creating a pull request. You might want to contact me before you start working so I can coordinate efforts.
* [Become a GitHub sponsor to boost 🚀 development](https://github.com/sponsors/PhilippC)
* [Make a donation](http://philipp.crocoll.net/donate.php)
# How do I learn more?

View File

@@ -12,6 +12,7 @@
<FileAlignment>512</FileAlignment>
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>

View File

@@ -0,0 +1,48 @@
Additions allow you to add arbitrary C# to the generated classes
before they are compiled. This can be helpful for providing convenience
methods or adding pure C# classes.
== Adding Methods to Generated Classes ==
Let's say the library being bound has a Rectangle class with a constructor
that takes an x and y position, and a width and length size. It will look like
this:
public partial class Rectangle
{
public Rectangle (int x, int y, int width, int height)
{
// JNI bindings
}
}
Imagine we want to add a constructor to this class that takes a Point and
Size structure instead of 4 ints. We can add a new file called Rectangle.cs
with a partial class containing our new method:
public partial class Rectangle
{
public Rectangle (Point location, Size size) :
this (location.X, location.Y, size.Width, size.Height)
{
}
}
At compile time, the additions class will be added to the generated class
and the final assembly will a Rectangle class with both constructors.
== Adding C# Classes ==
Another thing that can be done is adding fully C# managed classes to the
generated library. In the above example, let's assume that there isn't a
Point class available in Java or our library. The one we create doesn't need
to interact with Java, so we'll create it like a normal class in C#.
By adding a Point.cs file with this class, it will end up in the binding library:
public class Point
{
public int X { get; set; }
public int Y { get; set; }
}

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}</ProjectGuid>
<ProjectTypeGuids>{10368E6C-D01B-4462-8E8B-01FC667A7035};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TemplateGuid>{77efb91c-a7e9-4b0e-a7c5-31eeec3c6d46}</TemplateGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>BiometricBinding</RootNamespace>
<AssemblyName>BiometricBinding</AssemblyName>
<FileAlignment>512</FileAlignment>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
<AndroidClassParser>class-parse</AndroidClassParser>
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>portable</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>portable</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Jars\AboutJars.txt" />
<None Include="Additions\AboutAdditions.txt" />
<LibraryProjectZip Include="Jars\biometric-1.0.0-rc02.aar" />
</ItemGroup>
<ItemGroup>
<TransformFile Include="Transforms\Metadata.xml" />
<TransformFile Include="Transforms\EnumFields.xml" />
<TransformFile Include="Transforms\EnumMethods.xml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.AndroidX.Fragment">
<Version>1.0.0-preview02</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,24 @@
This directory is for Android .jars.
There are 2 types of jars that are supported:
== Input Jar ==
This is the jar that bindings should be generated for.
For example, if you were binding the Google Maps library, this would
be Google's "maps.jar".
Set the build action for these jars in the properties page to "InputJar".
== Reference Jars ==
These are jars that are referenced by the input jar. C# bindings will
not be created for these jars. These jars will be used to resolve
types used by the input jar.
NOTE: Do not add "android.jar" as a reference jar. It will be added automatically
based on the Target Framework selected.
Set the build action for these jars in the properties page to "ReferenceJar".

Binary file not shown.

View File

@@ -0,0 +1,30 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Android.App;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("BiometricBinding")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BiometricBinding")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,14 @@
<enum-field-mappings>
<!--
This example converts the constants Fragment_id, Fragment_name,
and Fragment_tag from android.support.v4.app.FragmentActivity.FragmentTag
to an enum called Android.Support.V4.App.FragmentTagType with values
Id, Name, and Tag.
<mapping jni-class="android/support/v4/app/FragmentActivity$FragmentTag" clr-enum-type="Android.Support.V4.App.FragmentTagType">
<field jni-name="Fragment_name" clr-name="Name" value="0" />
<field jni-name="Fragment_id" clr-name="Id" value="1" />
<field jni-name="Fragment_tag" clr-name="Tag" value="2" />
</mapping>
-->
</enum-field-mappings>

View File

@@ -0,0 +1,13 @@
<enum-method-mappings>
<!--
This example changes the Java method:
android.support.v4.app.Fragment.SavedState.writeToParcel (int flags)
to be:
android.support.v4.app.Fragment.SavedState.writeToParcel (Android.OS.ParcelableWriteFlags flags)
when bound in C#.
<mapping jni-class="android/support/v4/app/Fragment.SavedState">
<method jni-name="writeToParcel" parameter="flags" clr-enum-type="Android.OS.ParcelableWriteFlags" />
</mapping>
-->
</enum-method-mappings>

View File

@@ -0,0 +1,9 @@
<metadata>
<!--
This sample removes the class: android.support.v4.content.AsyncTaskLoader.LoadTask:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='AsyncTaskLoader.LoadTask']" />
This sample removes the method: android.support.v4.content.CursorLoader.loadInBackground:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='CursorLoader']/method[@name='loadInBackground']" />
-->
</metadata>

Binary file not shown.

Binary file not shown.

View File

@@ -13,6 +13,7 @@
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
<AndroidClassParser>class-parse</AndroidClassParser>
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -84,9 +85,6 @@
<ItemGroup>
<ProjectReference Include="..\PCloudBindings\PCloudBindings.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\okhttp-digest-1.7.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\msa-auth-0.8.6\classes-msa-auth.jar" />
</ItemGroup>
@@ -141,16 +139,19 @@
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\jackson-core-2.7.4.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\okhttp-3.9.0.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\okio-1.13.0.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedJar Include="Jars\dropbox-core-sdk-3.1.1.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gson-2.8.1.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\okhttp-4.2.2.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\okhttp-digest-1.15.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\okio-2.2.2.jar" />
</ItemGroup>
</Project>

View File

@@ -12,6 +12,7 @@
<FileAlignment>512</FileAlignment>
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>

View File

@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27004.2009
# Visual Studio Version 16
VisualStudioVersion = 16.0.29418.71
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePassLib2Android", "KeePassLib2Android\KeePassLib2Android.csproj", "{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}"
EndProject
@@ -29,6 +29,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamsungPass", "SamsungPass\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PCloudBindings", "PCloudBindings\PCloudBindings.csproj", "{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BiometricBinding", "BiometricBinding\BiometricBinding.csproj", "{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -315,6 +317,30 @@ Global
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Win32.Build.0 = ReleaseNoNet|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|x64.Build.0 = ReleaseNoNet|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Win32.ActiveCfg = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Win32.Build.0 = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|x64.ActiveCfg = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|x64.Build.0 = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Any CPU.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Win32.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Win32.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|x64.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|x64.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Win32.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -375,13 +375,16 @@ namespace KeePassLib.Serialization
// See also KeePassKdb2x3.Export (KDBX 3.1 export module)
uint minVersionForKeys = m_pwDatabase.MasterKey.UserKeys.Select(key => key.GetMinKdbxVersion()).Max();
uint minRequiredVersion = Math.Max(minVersionForKeys, m_uFileVersion); //don't save a version lower than what we read
AesKdf kdfAes = new AesKdf();
if(!kdfAes.Uuid.Equals(m_pwDatabase.KdfParameters.KdfUuid))
return Math.Max(FileVersion32, minVersionForKeys);
return Math.Max(FileVersion32, minRequiredVersion);
if(m_pwDatabase.PublicCustomData.Count > 0)
return Math.Max(FileVersion32, minVersionForKeys);
return Math.Max(FileVersion32, minRequiredVersion);
@@ -401,9 +404,9 @@ namespace KeePassLib.Serialization
gh(m_pwDatabase.RootGroup);
m_pwDatabase.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh);
if(bCustomData)
return Math.Max(FileVersion32, minVersionForKeys);
return Math.Max(FileVersion32, minRequiredVersion);
return Math.Max(FileVersion32_3, minVersionForKeys); ; // KDBX 3.1 is sufficient
return Math.Max(FileVersion32_3, minRequiredVersion); ; // KDBX 3.1 is sufficient
}
private void ComputeKeys(out byte[] pbCipherKey, int cbCipherKey,

View File

@@ -3,12 +3,12 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.FtpClient;
using System.Reflection;
using System.Threading;
using Android.Content;
using Android.OS;
using Android.Preferences;
using FluentFTP;
using KeePassLib;
using KeePassLib.Serialization;
using KeePassLib.Utility;
@@ -17,73 +17,6 @@ namespace keepass2android.Io
{
public class NetFtpFileStorage: IFileStorage
{
class RetryConnectFtpClient : FtpClient
{
protected override FtpClient CloneConnection()
{
RetryConnectFtpClient conn = new RetryConnectFtpClient();
conn.m_isClone = true;
foreach (PropertyInfo prop in GetType().GetProperties())
{
object[] attributes = prop.GetCustomAttributes(typeof(FtpControlConnectionClone), true);
if (attributes != null && attributes.Length > 0)
{
prop.SetValue(conn, prop.GetValue(this, null), null);
}
}
// always accept certficate no matter what because if code execution ever
// gets here it means the certificate on the control connection object being
// cloned was already accepted.
conn.ValidateCertificate += new FtpSslValidation(
delegate(FtpClient obj, FtpSslValidationEventArgs e)
{
e.Accept = true;
});
return conn;
}
private static T DoInRetryLoop<T>(Func<T> func)
{
double timeout = 30.0;
double timePerRequest = 1.0;
var startTime = DateTime.Now;
while (true)
{
var attemptStartTime = DateTime.Now;
try
{
return func();
}
catch (System.Net.Sockets.SocketException e)
{
if ((e.ErrorCode != 10061) || (DateTime.Now > startTime.AddSeconds(timeout)))
{
throw;
}
double secondsSinceAttemptStart = (DateTime.Now - attemptStartTime).TotalSeconds;
if (secondsSinceAttemptStart < timePerRequest)
{
Thread.Sleep(TimeSpan.FromSeconds(timePerRequest - secondsSinceAttemptStart));
}
}
}
}
public override void Connect()
{
DoInRetryLoop(() =>
{
base.Connect();
return true;
}
);
}
}
public struct ConnectionSettings
{
public FtpEncryptionMode EncryptionMode {get; set; }
@@ -149,7 +82,6 @@ namespace keepass2android.Io
{
_app = app;
traceStream = new MemoryStream();
FtpTrace.AddListener(new System.Diagnostics.TextWriterTraceListener(traceStream));
}
@@ -174,7 +106,7 @@ namespace keepass2android.Io
{
string localPath = IocToUri(ioc).PathAndQuery;
if (client.DirectoryExists(localPath))
client.DeleteDirectory(localPath, true);
client.DeleteDirectory(localPath);
else
client.DeleteFile(localPath);
}
@@ -205,7 +137,8 @@ namespace keepass2android.Io
{
var settings = ConnectionSettings.FromIoc(ioc);
FtpClient client = new RetryConnectFtpClient();
FtpClient client = new FtpClient();
client.RetryAttempts = 3;
if ((settings.Username.Length > 0) || (settings.Password.Length > 0))
client.Credentials = new NetworkCredential(settings.Username, settings.Password);
else

View File

@@ -12,7 +12,7 @@
<FileAlignment>512</FileAlignment>
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<TargetFrameworkVersion>v9.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
@@ -141,10 +141,6 @@
<Project>{70D3844A-D9FA-4A64-B205-A84C6A822196}</Project>
<Name>KP2AKdbLibraryBinding</Name>
</ProjectReference>
<ProjectReference Include="..\netftpandroid\System.Net.FtpClient\System.Net.FtpClient.Android.csproj">
<Project>{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}</Project>
<Name>System.Net.FtpClient.Android</Name>
</ProjectReference>
<ProjectReference Include="..\TwofishCipher\TwofishCipher.csproj">
<Project>{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}</Project>
<Name>TwofishCipher</Name>
@@ -157,6 +153,9 @@
<None Include="app.config" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentFTP">
<Version>27.1.3</Version>
</PackageReference>
<PackageReference Include="Microsoft.Graph">
<Version>1.17.0</Version>
</PackageReference>

File diff suppressed because it is too large Load Diff

View File

@@ -31,15 +31,17 @@ namespace keepass2android
private readonly PwEntry _entry;
private readonly PwGroup _parentGroup;
private readonly Activity _ctx;
public static AddEntry GetInstance(Activity ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish) {
private readonly Database _db;
return new AddEntry(ctx, app, entry, parentGroup, finish);
public static AddEntry GetInstance(Activity ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish, Database db) {
return new AddEntry(ctx, db, app, entry, parentGroup, finish);
}
public AddEntry(Activity ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish):base(ctx, finish) {
public AddEntry(Activity ctx, Database db, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish):base(ctx, finish) {
_ctx = ctx;
_parentGroup = parentGroup;
_db = db;
_parentGroup = parentGroup;
_app = app;
_entry = entry;
@@ -57,10 +59,13 @@ namespace keepass2android
{
_parentGroup.AddEntry(_entry, true);
}
// Commit to disk
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
// Add entry to global
_db.EntriesById[_entry.Uuid] = _entry;
_db.Elements.Add(_entry);
// Commit to disk
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
save.SetStatusLogger(StatusLogger);
save.Run();
}
@@ -86,9 +91,7 @@ namespace keepass2android
// Mark parent group dirty
_app.DirtyGroups.Add(parent);
// Add entry to global
_db.EntriesById[_entry.Uuid] = _entry;
_db.Elements.Add(_entry);
} else
{

View File

@@ -16,8 +16,8 @@ namespace keepass2android.database.edit
{
public class CopyEntry: AddEntry
{
public CopyEntry(Activity ctx, IKp2aApp app, PwEntry entry, OnFinish finish)
: base(ctx, app, CreateCopy(entry, app), entry.ParentGroup, finish)
public CopyEntry(Activity ctx, IKp2aApp app, PwEntry entry, OnFinish finish, Database db)
: base(ctx, db, app, CreateCopy(entry, app), entry.ParentGroup, finish)
{
}

View File

@@ -11,7 +11,8 @@
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
<AssemblyName>Kp2aKeyboardBinding</AssemblyName>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>True</DebugSymbols>

View File

@@ -12,6 +12,7 @@
<FileAlignment>512</FileAlignment>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>

View File

@@ -12,6 +12,7 @@
<FileAlignment>512</FileAlignment>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>

View File

@@ -26,8 +26,8 @@ NOTE: If you change dependencies here, don't forget to update the jar files in J
*/
dependencies {
compile 'com.squareup.okhttp3:okhttp:3.9.0'
compile 'com.burgstaller:okhttp-digest:1.7'
compile 'com.squareup.okhttp3:okhttp:4.2.2'
compile 'com.burgstaller:okhttp-digest:1.15'
compile 'com.google.android.gms:play-services:4.0.30'
compile 'com.google.http-client:google-http-client-gson:1.20.0'
compile('com.google.api-client:google-api-client-android:1.16.0-rc') {

View File

@@ -26,6 +26,7 @@ import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region.Op;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
@@ -774,7 +775,9 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
mKeyboardChanged = false;
}
final Canvas canvas = mCanvas;
canvas.clipRect(mDirtyRect, Op.REPLACE);
canvas.save();
canvas.clipRect(new RectF(mDirtyRect));
if (mKeyboard == null) return;
@@ -907,6 +910,8 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
}
}
canvas.restore();
mDrawPending = false;
mDirtyRect.setEmpty();
}

View File

@@ -0,0 +1,550 @@
using System;
using Android.Content;
using Javax.Crypto;
using Java.Security;
using Java.Lang;
using Android.Views.InputMethods;
using Android.App;
using Android.OS;
using Android.Security.Keystore;
using Android.Preferences;
using Android.Util;
using Android.Widget;
using Androidx.Biometric;
using AndroidX.Fragment.App;
using Java.IO;
using Java.Security.Cert;
using Java.Util.Concurrent;
using Javax.Crypto.Spec;
using Exception = System.Exception;
using File = System.IO.File;
namespace keepass2android
{
public static class Kp2aLog
{
private static bool? _logToFile;
private static object _fileLocker = new object();
public static void Log(string message)
{
if (message != null)
Android.Util.Log.Debug("KP2A", message);
if (LogToFile)
{
lock (_fileLocker)
{
try
{
using (var streamWriter = System.IO.File.AppendText(LogFilename))
{
string stringToLog = DateTime.Now + ":" + DateTime.Now.Millisecond + " -- " + message;
streamWriter.WriteLine(stringToLog);
}
}
catch (Exception e)
{
Android.Util.Log.Debug("KP2A", "Couldn't write to log file. " + e);
}
}
}
}
private static string LogFilename
{
get { return Application.Context.FilesDir.CanonicalPath + "/keepass2android.log"; }
}
private static bool LogToFile
{
get
{
if (_logToFile == null)
_logToFile = System.IO.File.Exists(LogFilename);
return (bool)_logToFile;
}
}
public static event EventHandler<Exception> OnUnexpectedError;
public static void LogUnexpectedError(Exception exception)
{
Log(exception.ToString());
if (OnUnexpectedError != null)
OnUnexpectedError(null, exception);
}
public static void CreateLogFile()
{
if (!System.IO.File.Exists(LogFilename))
{
System.IO.File.Create(LogFilename).Dispose();
_logToFile = true;
}
}
public static void FinishLogFile()
{
if (System.IO.File.Exists(LogFilename))
{
_logToFile = false;
int count = 0;
while (System.IO.File.Exists(LogFilename + "." + count))
count++;
System.IO.File.Move(LogFilename, LogFilename + "." + count);
}
}
public static void SendLog(Context ctx)
{
if (!System.IO.File.Exists(LogFilename))
return;
Intent sendIntent = new Intent();
sendIntent.SetAction(Intent.ActionSend);
sendIntent.PutExtra(Intent.ExtraText, File.ReadAllText(LogFilename));
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..."));
}
}
public interface IBiometricAuthCallback
{
void OnBiometricAuthSucceeded();
void OnBiometricError(string toString);
}
public class BiometricModule
{
public AndroidX.Fragment.App.FragmentActivity Activity { get; set; }
public BiometricModule(AndroidX.Fragment.App.FragmentActivity activity)
{
Activity = activity;
}
public KeyguardManager KeyguardManager
{
get
{
return (KeyguardManager)Activity.GetSystemService("keyguard");
}
}
public KeyStore Keystore
{
get
{
try
{
return KeyStore.GetInstance("AndroidKeyStore");
}
catch (KeyStoreException e)
{
throw new RuntimeException("Failed to get an instance of KeyStore", e);
}
}
}
public KeyGenerator KeyGenerator
{
get
{
try
{
return KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, "AndroidKeyStore");
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
}
catch (NoSuchProviderException e)
{
throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
}
}
}
public Cipher Cipher
{
get
{
try
{
return Cipher.GetInstance(KeyProperties.KeyAlgorithmAes + "/"
+ KeyProperties.BlockModeCbc + "/"
+ KeyProperties.EncryptionPaddingPkcs7);
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException("Failed to get an instance of Cipher", e);
}
catch (NoSuchPaddingException e)
{
throw new RuntimeException("Failed to get an instance of Cipher", e);
}
}
}
public ISharedPreferences SharedPreferences
{
get { return PreferenceManager.GetDefaultSharedPreferences(Activity); }
}
public bool IsAvailable
{
get
{
return BiometricManager.From(Activity).CanAuthenticate() ==
BiometricManager.BiometricSuccess;
}
}
public bool IsHardwareAvailable
{
get
{
var result = BiometricManager.From(Activity).CanAuthenticate();
return result == BiometricManager.BiometricSuccess
|| result == BiometricManager.BiometricErrorNoneEnrolled;
}
}
}
public abstract class BiometricCrypt : IBiometricIdentifier
{
protected const string FailedToInitCipher = "Failed to init Cipher";
protected readonly string _keyId;
protected Cipher _cipher;
private CancellationSignal _cancellationSignal;
protected BiometricPrompt.CryptoObject _cryptoObject;
protected KeyStore _keystore;
private BiometricPrompt _biometricPrompt;
private FragmentActivity _activity;
public BiometricCrypt(BiometricModule biometric, string keyId)
{
Kp2aLog.Log("FP: Create " + this.GetType().Name);
_keyId = keyId;
_cipher = biometric.Cipher;
_keystore = biometric.Keystore;
_activity = biometric.Activity;
}
public abstract bool Init();
protected static string GetAlias(string keyId)
{
return "keepass2android." + keyId;
}
protected static string GetIvPrefKey(string prefKey)
{
return prefKey + "_iv";
}
public void StartListening(IBiometricAuthCallback callback)
{
StartListening(new BiometricAuthCallbackAdapter(callback, _activity));
}
public void StopListening()
{
}
public bool HasUserInterface
{
get { return true; }
}
public void StartListening(BiometricPrompt.AuthenticationCallback callback)
{
Kp2aLog.Log("Fingerprint: StartListening ");
var executor = Executors.NewSingleThreadExecutor();
_biometricPrompt = new Androidx.Biometric.BiometricPrompt(_activity, executor, callback);
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
.SetTitle(_activity.GetString(AppNames.AppNameResource))
.SetSubtitle(_activity.GetString(Resource.String.unlock_database_title))
.SetNegativeButtonText(_activity.GetString(Android.Resource.String.Cancel))
.SetConfirmationRequired(false)
.Build();
_biometricPrompt.Authenticate(promptInfo, _cryptoObject);
}
public string Encrypt(string textToEncrypt)
{
Kp2aLog.Log("FP: Encrypting");
return Base64.EncodeToString(_cipher.DoFinal(System.Text.Encoding.UTF8.GetBytes(textToEncrypt)), 0);
}
public void StoreEncrypted(string textToEncrypt, string prefKey, Context context)
{
var edit = PreferenceManager.GetDefaultSharedPreferences(context).Edit();
StoreEncrypted(textToEncrypt, prefKey, edit);
edit.Commit();
}
public void StoreEncrypted(string textToEncrypt, string prefKey, ISharedPreferencesEditor edit)
{
edit.PutString(prefKey, Encrypt(textToEncrypt));
edit.PutString(GetIvPrefKey(prefKey), Base64.EncodeToString(CipherIv, 0));
}
private byte[] CipherIv
{
get { return _cipher.GetIV(); }
}
}
public interface IBiometricIdentifier
{
bool Init();
void StartListening(IBiometricAuthCallback callback);
void StopListening();
bool HasUserInterface { get; }
}
public class BiometricDecryption : BiometricCrypt
{
private readonly Context _context;
private readonly byte[] _iv;
public BiometricDecryption(BiometricModule biometric, string keyId, byte[] iv) : base(biometric, keyId)
{
_iv = iv;
}
public BiometricDecryption(BiometricModule biometric, string keyId, Context context, string prefKey)
: base(biometric, keyId)
{
_context = context;
_iv = Base64.Decode(PreferenceManager.GetDefaultSharedPreferences(context).GetString(GetIvPrefKey(prefKey), null), 0);
}
public static bool IsSetUp(Context context, string prefKey)
{
return PreferenceManager.GetDefaultSharedPreferences(context).GetString(GetIvPrefKey(prefKey), null) != null;
}
public override bool Init()
{
Kp2aLog.Log("FP: Init for Dec");
try
{
_keystore.Load(null);
var key = _keystore.GetKey(GetAlias(_keyId), null);
var ivParams = new IvParameterSpec(_iv);
_cipher.Init(CipherMode.DecryptMode, key, ivParams);
_cryptoObject = new BiometricPrompt.CryptoObject(_cipher);
return true;
}
catch (KeyPermanentlyInvalidatedException e)
{
Kp2aLog.Log("FP: KeyPermanentlyInvalidatedException." + e.ToString());
return false;
}
catch (KeyStoreException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (CertificateException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (UnrecoverableKeyException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (IOException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (InvalidKeyException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
}
public string Decrypt(string encryted)
{
Kp2aLog.Log("FP: Decrypting ");
byte[] encryptedBytes = Base64.Decode(encryted, 0);
return System.Text.Encoding.UTF8.GetString(_cipher.DoFinal(encryptedBytes));
}
public string DecryptStored(string prefKey)
{
string enc = PreferenceManager.GetDefaultSharedPreferences(_context).GetString(prefKey, null);
return Decrypt(enc);
}
}
public class BiometricEncryption : BiometricCrypt
{
private KeyGenerator _keyGen;
public BiometricEncryption(BiometricModule biometric, string keyId) :
base(biometric, keyId)
{
_keyGen = biometric.KeyGenerator;
Kp2aLog.Log("FP: CreateKey ");
CreateKey();
}
/// <summary>
/// Creates a symmetric key in the Android Key Store which can only be used after the user
/// has authenticated with biometry.
/// </summary>
private void CreateKey()
{
try
{
_keystore.Load(null);
_keyGen.Init(new KeyGenParameterSpec.Builder(GetAlias(_keyId),
KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
.SetBlockModes(KeyProperties.BlockModeCbc)
// Require the user to authenticate with biometry to authorize every use
// of the key
.SetEncryptionPaddings(KeyProperties.EncryptionPaddingPkcs7)
.SetUserAuthenticationRequired(true)
.Build());
_keyGen.GenerateKey();
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException(e);
}
catch (InvalidAlgorithmParameterException e)
{
throw new RuntimeException(e);
}
catch (CertificateException e)
{
throw new RuntimeException(e);
}
catch (IOException e)
{
throw new RuntimeException(e);
}
catch (System.Exception e)
{
Kp2aLog.LogUnexpectedError(e);
}
}
public override bool Init()
{
Kp2aLog.Log("FP: Init for Enc ");
try
{
_keystore.Load(null);
var key = _keystore.GetKey(GetAlias(_keyId), null);
_cipher.Init(CipherMode.EncryptMode, key);
_cryptoObject = new BiometricPrompt.CryptoObject(_cipher);
return true;
}
catch (KeyPermanentlyInvalidatedException)
{
return false;
}
catch (KeyStoreException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (CertificateException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (UnrecoverableKeyException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (IOException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (InvalidKeyException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
}
}
public class BiometricAuthCallbackAdapter : BiometricPrompt.AuthenticationCallback
{
private readonly IBiometricAuthCallback _callback;
private readonly Context _context;
public BiometricAuthCallbackAdapter(IBiometricAuthCallback callback, Context context)
{
_callback = callback;
_context = context;
}
public override void OnAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result)
{
new Handler(Looper.MainLooper).Post(() => _callback.OnBiometricAuthSucceeded());
}
public override void OnAuthenticationError(int errorCode, ICharSequence errString)
{
new Handler(Looper.MainLooper).Post(() => _callback.OnBiometricError(errString.ToString()));
}
public override void OnAuthenticationFailed()
{
new Handler(Looper.MainLooper).Post(() => _callback.OnBiometricError(_context.Resources.GetString(Resource.String.fingerprint_not_recognized)));
}
}
}

View File

@@ -9,6 +9,7 @@ using Android.Content.PM;
using Android.Content.Res;
using Android.Graphics;
using Android.OS;
using Android.Preferences;
using Android.Runtime;
using Android.Text;
using Android.Text.Method;
@@ -26,6 +27,7 @@ namespace keepass2android
AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(ctx, Android.Resource.Style.ThemeHoloLightDialog));
builder.SetTitle(ctx.GetString(Resource.String.ChangeLog_title));
List<string> changeLog = new List<string>{
BuildChangelogString(ctx, Resource.Array.ChangeLog_1_08, "1.08-pre"),
ctx.GetString(Resource.String.ChangeLog_1_07b),
ctx.GetString(Resource.String.ChangeLog_1_07),
ctx.GetString(Resource.String.ChangeLog_1_06),
@@ -110,7 +112,18 @@ namespace keepass2android
}
private const string HtmlStart = @"<html>
private static string BuildChangelogString(Context ctx, int changeLogResId, string version)
{
string result = "Version " + version + "\n";
foreach (var item in ctx.Resources.GetStringArray(changeLogResId))
{
result += " * " + item + "\n";
}
return result;
}
private const string HtmlStart = @"<html>
<head>
<style type='text/css'>
a { color:#000000 }
@@ -146,21 +159,36 @@ namespace keepass2android
{
string versionLog2 = versionLog;
bool title = true;
if (isFirst)
{
if (versionLog2.EndsWith("\n") == false)
versionLog2 += "\n";
string donateUrl = ctx.GetString(Resource.String.donate_url,
new Java.Lang.Object[]{ctx.Resources.Configuration.Locale.Language,
ctx.PackageName
});
versionLog2 += " * <a href=\"" + donateUrl
+ "\">" +
ctx.GetString(Resource.String.ChangeLog_keptDonate)
+ "<a/>";
isFirst = false;
}
foreach (string line in versionLog2.Split('\n'))
if (isFirst)
{
bool showDonateOption = true;
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(ctx);
if (prefs.GetBoolean(ctx.GetString(Resource.String.NoDonationReminder_key), false))
showDonateOption = false;
long usageCount = prefs.GetLong(ctx.GetString(Resource.String.UsageCount_key), 0);
if (usageCount <= 5)
showDonateOption = false;
if (showDonateOption)
{
if (versionLog2.EndsWith("\n") == false)
versionLog2 += "\n";
string donateUrl = ctx.GetString(Resource.String.donate_url,
new Java.Lang.Object[]{ctx.Resources.Configuration.Locale.Language,
ctx.PackageName
});
versionLog2 += " * <a href=\"" + donateUrl
+ "\">" +
ctx.GetString(Resource.String.ChangeLog_keptDonate)
+ "<a/>";
}
isFirst = false;
}
foreach (string line in versionLog2.Split('\n'))
{
string w = line.Trim();
if (title)

View File

@@ -15,7 +15,7 @@ using Android.Widget;
namespace keepass2android
{
[Activity(Label = AppNames.AppName, Theme = "@style/MyTheme_ActionBar", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden)]
public class CloseImmediatelyActivity : AppCompatActivity
public class CloseImmediatelyActivity : AndroidX.AppCompat.App.AppCompatActivity
{
protected override void OnResume()
{

View File

@@ -227,7 +227,7 @@ 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(this, App.Kp2a, newEntry,item.Entry.ParentGroup,new ActionOnFinish(this, (success, message, activity) => ((ConfigureChildDatabasesActivity)activity).Update()));
var addTask = new AddEntry(this, App.Kp2a.CurrentDb, App.Kp2a, newEntry,item.Entry.ParentGroup,new ActionOnFinish(this, (success, message, activity) => ((ConfigureChildDatabasesActivity)activity).Update()));
ProgressTask pt = new ProgressTask(App.Kp2a, this, addTask);
pt.Run();
@@ -284,7 +284,7 @@ namespace keepass2android
var listView = FindViewById<ListView>(Android.Resource.Id.List);
listView.Adapter = _adapter;
SetSupportActionBar(FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.mytoolbar));
SetSupportActionBar(FindViewById<AndroidX.AppCompat.Widget.Toolbar>(Resource.Id.mytoolbar));
FindViewById<Button>(Resource.Id.add_child_db_button).Click += (sender, args) =>
{
@@ -366,7 +366,7 @@ namespace keepass2android
{KeeAutoExecExt.ThisDeviceId, true}
})));
var addTask = new AddEntry(this, App.Kp2a, newEntry, autoOpenGroup, new ActionOnFinish(this, (success, message, activity) => (activity as ConfigureChildDatabasesActivity)?.Update()));
var addTask = new AddEntry(this, db, App.Kp2a, newEntry, autoOpenGroup, new ActionOnFinish(this, (success, message, activity) => (activity as ConfigureChildDatabasesActivity)?.Update()));
ProgressTask pt = new ProgressTask(App.Kp2a, this, addTask);
pt.Run();

View File

@@ -21,7 +21,7 @@ namespace keepass2android
[Activity(Label = "@string/app_name",
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
Theme = "@style/MyTheme_ActionBar")]
public class CreateDatabaseActivity : AppCompatActivity
public class CreateDatabaseActivity : AndroidX.AppCompat.App.AppCompatActivity
{
private IOConnectionInfo _ioc;
private string _keyfileFilename;

View File

@@ -506,7 +506,7 @@ namespace keepass2android
},closeOrShowError);
if ( State.IsNew ) {
runnable = AddEntry.GetInstance(this, App.Kp2a, newEntry, State.ParentGroup, afterAddEntry);
runnable = AddEntry.GetInstance(this, App.Kp2a, newEntry, State.ParentGroup, afterAddEntry, db);
} else {
runnable = new UpdateEntry(this, App.Kp2a, initialEntry, newEntry, closeOrShowError);
}

View File

@@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
#if !NoNet
using System.Net.FtpClient;
using FluentFTP;
#endif
using System.Text;
@@ -12,6 +12,7 @@ using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Java.IO;
using keepass2android.Io;
using Keepass2android.Javafilestorage;

View File

@@ -23,7 +23,7 @@ using Object = Java.Lang.Object;
namespace keepass2android
{
[Activity(Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden, Theme = "@style/MyTheme_Blue")]
public class FileStorageSelectionActivity : AppCompatActivity
public class FileStorageSelectionActivity : AndroidX.AppCompat.App.AppCompatActivity
{
private readonly ActivityDesign _design;
@@ -238,7 +238,7 @@ namespace keepass2android
SetContentView(Resource.Layout.filestorage_selection);
var toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.mytoolbar);
var toolbar = FindViewById<AndroidX.AppCompat.Widget.Toolbar>(Resource.Id.mytoolbar);
SetSupportActionBar(toolbar);

View File

@@ -1,472 +0,0 @@
using System;
using Android.Content;
using Javax.Crypto;
using Java.Security;
using Java.Lang;
using Android.Views.InputMethods;
using Android.App;
using Android.Hardware.Fingerprints;
using Android.OS;
using Android.Security.Keystore;
using Android.Preferences;
using Android.Util;
using Android.Widget;
using Java.IO;
using Java.Security.Cert;
using Javax.Crypto.Spec;
namespace keepass2android
{
public interface IFingerprintAuthCallback
{
void OnFingerprintAuthSucceeded();
void OnFingerprintError(string toString);
}
public class FingerprintModule
{
public Context Context { get; set; }
public FingerprintModule (Context context)
{
Context = context;
}
public FingerprintManager FingerprintManager
{
get { return Context.GetSystemService(Context.FingerprintService) as FingerprintManager; }
}
public KeyguardManager KeyguardManager
{
get
{
return (KeyguardManager) Context.GetSystemService("keyguard");
}
}
public KeyStore Keystore
{
get
{
try
{
return KeyStore.GetInstance("AndroidKeyStore");
}
catch (KeyStoreException e)
{
throw new RuntimeException("Failed to get an instance of KeyStore", e);
}
}
}
public KeyGenerator KeyGenerator
{
get
{
try
{
return KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, "AndroidKeyStore");
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
}
catch (NoSuchProviderException e)
{
throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
}
}
}
public Cipher Cipher
{
get
{
try
{
return Cipher.GetInstance(KeyProperties.KeyAlgorithmAes + "/"
+ KeyProperties.BlockModeCbc + "/"
+ KeyProperties.EncryptionPaddingPkcs7);
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException("Failed to get an instance of Cipher", e);
}
catch (NoSuchPaddingException e)
{
throw new RuntimeException("Failed to get an instance of Cipher", e);
}
}
}
public InputMethodManager InputMethodManager
{
get { return (InputMethodManager) Context.GetSystemService(Context.InputMethodService); }
}
public ISharedPreferences SharedPreferences
{
get { return PreferenceManager.GetDefaultSharedPreferences(Context); }
}
}
public abstract class FingerprintCrypt: FingerprintManager.AuthenticationCallback, IFingerprintIdentifier
{
protected const string FailedToInitCipher = "Failed to init Cipher";
public override void OnAuthenticationError(FingerprintState errorCode, ICharSequence errString)
{
Kp2aLog.Log("FP: OnAuthenticationError: " + errString + ", " + _selfCancelled);
if (!_selfCancelled)
_callback.OnAuthenticationError(errorCode, errString);
}
public override void OnAuthenticationFailed()
{
Kp2aLog.Log("FP: OnAuthenticationFailed " + _selfCancelled);
_callback.OnAuthenticationFailed();
}
public override void OnAuthenticationHelp(FingerprintState helpCode, ICharSequence helpString)
{
_callback.OnAuthenticationHelp(helpCode, helpString);
}
public override void OnAuthenticationSucceeded(FingerprintManager.AuthenticationResult result)
{
Kp2aLog.Log("FP: OnAuthenticationSucceeded ");
StopListening();
_callback.OnAuthenticationSucceeded(result);
}
protected readonly string _keyId;
protected Cipher _cipher;
private bool _selfCancelled;
private CancellationSignal _cancellationSignal;
protected FingerprintManager.CryptoObject _cryptoObject;
private FingerprintManager.AuthenticationCallback _callback;
protected KeyStore _keystore;
private FingerprintManager _fingerprintManager;
public FingerprintCrypt(FingerprintModule fingerprint, string keyId)
{
Kp2aLog.Log("FP: Create " + this.GetType().Name);
_keyId = keyId;
_cipher = fingerprint.Cipher;
_keystore = fingerprint.Keystore;
_fingerprintManager = fingerprint.FingerprintManager;
}
public abstract bool Init();
protected static string GetAlias(string keyId)
{
return "keepass2android." + keyId;
}
protected static string GetIvPrefKey(string prefKey)
{
return prefKey + "_iv";
}
public bool IsFingerprintAuthAvailable
{
get
{
return _fingerprintManager.IsHardwareDetected
&& _fingerprintManager.HasEnrolledFingerprints;
}
}
public void StartListening(Context ctx, IFingerprintAuthCallback callback)
{
StartListening(new FingerprintAuthCallbackAdapter(callback, ctx));
}
public void StartListening(FingerprintManager.AuthenticationCallback callback)
{
if (!IsFingerprintAuthAvailable)
return;
Kp2aLog.Log("FP: StartListening ");
var thisSignal = new CancellationSignal();
_cancellationSignal = thisSignal;
_cancellationSignal.CancelEvent += (sender, args) =>
{
if (_cancellationSignal == thisSignal) _cancellationSignal = null;
};
_selfCancelled = false;
_callback = callback;
_fingerprintManager.Authenticate(_cryptoObject, _cancellationSignal, 0 /* flags */, this, null);
}
public void StopListening()
{
if (_cancellationSignal != null)
{
Kp2aLog.Log("FP: StopListening ");
_selfCancelled = true;
try
{
_cancellationSignal.Cancel();
}
catch (System.Exception e)
{
Kp2aLog.LogUnexpectedError(e);
}
_cancellationSignal = null;
}
}
public string Encrypt(string textToEncrypt)
{
Kp2aLog.Log("FP: Encrypting");
return Base64.EncodeToString(_cipher.DoFinal(System.Text.Encoding.UTF8.GetBytes(textToEncrypt)), 0);
}
public void StoreEncrypted(string textToEncrypt, string prefKey, Context context)
{
var edit = PreferenceManager.GetDefaultSharedPreferences(context).Edit();
StoreEncrypted(textToEncrypt, prefKey, edit);
edit.Commit();
}
public void StoreEncrypted(string textToEncrypt, string prefKey, ISharedPreferencesEditor edit)
{
edit.PutString(prefKey, Encrypt(textToEncrypt));
edit.PutString(GetIvPrefKey(prefKey), Base64.EncodeToString(CipherIv, 0));
}
private byte[] CipherIv
{
get { return _cipher.GetIV(); }
}
}
public interface IFingerprintIdentifier
{
bool Init();
void StartListening(Context ctx, IFingerprintAuthCallback callback);
void StopListening();
}
public class FingerprintDecryption : FingerprintCrypt
{
private readonly Context _context;
private readonly byte[] _iv;
public FingerprintDecryption(FingerprintModule fingerprint, string keyId, byte[] iv) : base(fingerprint, keyId)
{
_iv = iv;
}
public FingerprintDecryption(FingerprintModule fingerprint, string keyId, Context context, string prefKey)
: base(fingerprint, keyId)
{
_context = context;
_iv = Base64.Decode(PreferenceManager.GetDefaultSharedPreferences(context).GetString(GetIvPrefKey(prefKey), null), 0);
}
public static bool IsSetUp(Context context, string prefKey)
{
return PreferenceManager.GetDefaultSharedPreferences(context).GetString(GetIvPrefKey(prefKey), null) != null;
}
public override bool Init()
{
Kp2aLog.Log("FP: Init for Dec");
try
{
_keystore.Load(null);
var key = _keystore.GetKey(GetAlias(_keyId), null);
var ivParams = new IvParameterSpec(_iv);
_cipher.Init(CipherMode.DecryptMode, key, ivParams);
_cryptoObject = new FingerprintManager.CryptoObject(_cipher);
return true;
}
catch (KeyPermanentlyInvalidatedException e)
{
Kp2aLog.Log("FP: KeyPermanentlyInvalidatedException." + e.ToString());
return false;
}
catch (KeyStoreException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (CertificateException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (UnrecoverableKeyException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (IOException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (InvalidKeyException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
}
public string Decrypt(string encryted)
{
Kp2aLog.Log("FP: Decrypting ");
byte[] encryptedBytes = Base64.Decode(encryted, 0);
return System.Text.Encoding.UTF8.GetString(_cipher.DoFinal(encryptedBytes));
}
public string DecryptStored(string prefKey)
{
string enc = PreferenceManager.GetDefaultSharedPreferences(_context).GetString(prefKey, null);
return Decrypt(enc);
}
}
public class FingerprintEncryption : FingerprintCrypt
{
private KeyGenerator _keyGen;
public FingerprintEncryption(FingerprintModule fingerprint, string keyId) :
base(fingerprint, keyId)
{
_keyGen = fingerprint.KeyGenerator;
Kp2aLog.Log("FP: CreateKey ");
CreateKey();
}
/// <summary>
/// Creates a symmetric key in the Android Key Store which can only be used after the user
/// has authenticated with fingerprint.
/// </summary>
private void CreateKey()
{
try
{
_keystore.Load(null);
_keyGen.Init(new KeyGenParameterSpec.Builder(GetAlias(_keyId),
KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
.SetBlockModes(KeyProperties.BlockModeCbc)
// Require the user to authenticate with a fingerprint to authorize every use
// of the key
.SetUserAuthenticationRequired(true)
.SetEncryptionPaddings(KeyProperties.EncryptionPaddingPkcs7)
.Build());
_keyGen.GenerateKey();
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException(e);
}
catch (InvalidAlgorithmParameterException e)
{
throw new RuntimeException(e);
}
catch (CertificateException e)
{
throw new RuntimeException(e);
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
public override bool Init()
{
Kp2aLog.Log("FP: Init for Enc ");
try
{
_keystore.Load(null);
var key = _keystore.GetKey(GetAlias(_keyId), null);
_cipher.Init(CipherMode.EncryptMode, key);
_cryptoObject = new FingerprintManager.CryptoObject(_cipher);
return true;
}
catch (KeyPermanentlyInvalidatedException)
{
return false;
}
catch (KeyStoreException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (CertificateException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (UnrecoverableKeyException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (IOException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
catch (InvalidKeyException e)
{
throw new RuntimeException(FailedToInitCipher, e);
}
}
}
public class FingerprintAuthCallbackAdapter : FingerprintManager.AuthenticationCallback
{
private readonly IFingerprintAuthCallback _callback;
private readonly Context _context;
public FingerprintAuthCallbackAdapter(IFingerprintAuthCallback callback, Context context)
{
_callback = callback;
_context = context;
}
public override void OnAuthenticationSucceeded(FingerprintManager.AuthenticationResult result)
{
_callback.OnFingerprintAuthSucceeded();
}
public override void OnAuthenticationError(FingerprintState errorCode, ICharSequence errString)
{
_callback.OnFingerprintError(errString.ToString());
}
public override void OnAuthenticationHelp(FingerprintState helpCode, ICharSequence helpString)
{
_callback.OnFingerprintError(helpString.ToString());
}
public override void OnAuthenticationFailed()
{
_callback.OnFingerprintError(
_context.Resources.GetString(Resource.String.fingerprint_not_recognized));
}
}
}

View File

@@ -5,6 +5,7 @@ using System.Text;
using Android.App;
using Android.Content;
using Android.Hardware.Biometrics;
using Android.OS;
using Android.Runtime;
using Android.Util;
@@ -16,13 +17,15 @@ using Java.Lang;
namespace keepass2android
{
class FingerprintSamsungIdentifier: IFingerprintIdentifier
class BiometrySamsungIdentifier: IBiometricIdentifier
{
SpassFingerprint _spassFingerprint;
private readonly Context _context;
SpassFingerprint _spassFingerprint;
Spass _spass;
public FingerprintSamsungIdentifier(Context context)
public BiometrySamsungIdentifier(Context context)
{
_spass = new Spass();
_context = context;
_spass = new Spass();
try
{
@@ -61,12 +64,12 @@ namespace keepass2android
}
class IdentifyListener : Java.Lang.Object, IIdentifyListener
{
private readonly IFingerprintAuthCallback _callback;
private readonly IBiometricAuthCallback _callback;
private readonly Context _context;
private readonly FingerprintSamsungIdentifier _id;
private readonly BiometrySamsungIdentifier _id;
public IdentifyListener(IFingerprintAuthCallback callback, Context context, FingerprintSamsungIdentifier id)
public IdentifyListener(IBiometricAuthCallback callback, Context context, BiometrySamsungIdentifier id)
{
_callback = callback;
_context = context;
@@ -80,11 +83,11 @@ namespace keepass2android
_id.Listening = false;
if (responseCode == SpassFingerprint.StatusAuthentificationSuccess)
{
_callback.OnFingerprintAuthSucceeded();
_callback.OnBiometricAuthSucceeded();
}
else if (responseCode == SpassFingerprint.StatusAuthentificationPasswordSuccess)
{
_callback.OnFingerprintAuthSucceeded();
_callback.OnBiometricAuthSucceeded();
}
}
@@ -106,22 +109,22 @@ namespace keepass2android
}
public void StartListening(Context ctx, IFingerprintAuthCallback callback)
public void StartListening(IBiometricAuthCallback callback)
{
if (Listening) return;
try
{
_spassFingerprint.StartIdentifyWithDialog(ctx, new IdentifyListener(callback, ctx, this), false);
_spassFingerprint.StartIdentifyWithDialog(_context, new IdentifyListener(callback, _context, this), false);
Listening = true;
}
catch (SpassInvalidStateException m)
{
callback.OnFingerprintError(m.Message);
callback.OnBiometricError(m.Message);
}
catch (IllegalStateException ex)
{
callback.OnFingerprintError(ex.Message);
callback.OnBiometricError(ex.Message);
}
}
@@ -141,5 +144,10 @@ namespace keepass2android
Kp2aLog.LogUnexpectedError(e);
}
}
}
public bool HasUserInterface
{
get { return false; }
}
}
}

View File

@@ -15,6 +15,7 @@ using Android.Widget;
using Java.Lang;
using KeePassLib.Keys;
using KeePassLib.Utility;
using Kotlin.Text;
using Enum = System.Enum;
using Exception = System.Exception;
@@ -24,16 +25,16 @@ namespace keepass2android
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden,
Theme = "@style/MyTheme_ActionBar", MainLauncher = false)]
[IntentFilter(new[] { "kp2a.action.FingerprintSetupActivity" }, Categories = new[] { Intent.CategoryDefault })]
public class FingerprintSetupActivity : LockCloseActivity, IFingerprintAuthCallback
public class BiometricSetupActivity : LockCloseActivity, IBiometricAuthCallback
{
private readonly ActivityDesign _activityDesign;
public FingerprintSetupActivity(IntPtr javaReference, JniHandleOwnership transfer)
public BiometricSetupActivity(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
_activityDesign = new ActivityDesign(this);
}
public FingerprintSetupActivity()
public BiometricSetupActivity()
{
_activityDesign = new ActivityDesign(this);
}
@@ -42,7 +43,7 @@ namespace keepass2android
private FingerprintUnlockMode _unlockMode = FingerprintUnlockMode.Disabled;
private FingerprintUnlockMode _desiredUnlockMode;
private FingerprintEncryption _enc;
private BiometricEncryption _enc;
private RadioButton[] _radioButtons;
public override bool OnOptionsItemSelected(IMenuItem item)
{
@@ -70,6 +71,7 @@ namespace keepass2android
_fpIcon = FindViewById<ImageView>(Resource.Id.fingerprint_icon);
_fpTextView = FindViewById<TextView>(Resource.Id.fingerprint_status);
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.SetHomeButtonEnabled(true);
@@ -128,14 +130,8 @@ namespace keepass2android
.PutBoolean(GetString(Resource.String.ShowKeyboardWhileFingerprint_key), args.IsChecked)
.Commit();
};
if ((int)Build.VERSION.SdkInt >= 23)
RequestPermissions(new[] {Manifest.Permission.UseFingerprint}, FingerprintPermissionRequestCode);
else
{
TrySetupSamsung();
}
UpdateKeyboardCheckboxVisibility();
@@ -143,10 +139,7 @@ namespace keepass2android
private void UpdateKeyboardCheckboxVisibility()
{
FindViewById(Resource.Id.show_keyboard_while_fingerprint).Visibility = (_unlockMode == FingerprintUnlockMode.Disabled) ||
(_samsungFingerprint != null)
? ViewStates.Gone
: ViewStates.Visible;
FindViewById(Resource.Id.show_keyboard_while_fingerprint).Visibility = ViewStates.Gone;
}
private bool TrySetupSamsung()
@@ -154,20 +147,20 @@ namespace keepass2android
try
{
//try to create a Samsung ID object
_samsungFingerprint = new FingerprintSamsungIdentifier(this);
if (!_samsungFingerprint.Init())
_samsungBiometry = new BiometrySamsungIdentifier(this);
if (!_samsungBiometry.Init())
{
SetError(Resource.String.fingerprint_no_enrolled);
}
ShowRadioButtons();
FindViewById(Resource.Id.container_fingerprint_unlock).Visibility = _samsungFingerprint == null
FindViewById(Resource.Id.container_fingerprint_unlock).Visibility = _samsungBiometry == null
? ViewStates.Visible
: ViewStates.Gone;
return true;
}
catch (Exception)
{
_samsungFingerprint = null;
_samsungBiometry = null;
return false;
}
}
@@ -231,30 +224,7 @@ namespace keepass2android
tv.Visibility = ViewStates.Visible;
}
const int FingerprintPermissionRequestCode = 0;
public override void OnRequestPermissionsResult (int requestCode, string[] permissions, Permission[] grantResults)
{
if (requestCode == FingerprintPermissionRequestCode && grantResults[0] == Permission.Granted)
{
FingerprintModule fpModule = new FingerprintModule(this);
if (fpModule.FingerprintManager == null || (!fpModule.FingerprintManager.IsHardwareDetected))
{
//seems like not all Samsung Devices (e.g. Note 4) don't support the Android 6 fingerprint API
if (!TrySetupSamsung())
SetError(Resource.String.fingerprint_hardware_error);
UpdateKeyboardCheckboxVisibility();
return;
}
if (!fpModule.FingerprintManager.HasEnrolledFingerprints)
{
SetError(Resource.String.fingerprint_no_enrolled);
return;
}
ShowRadioButtons();
UpdateKeyboardCheckboxVisibility();
}
}
private void ShowRadioButtons()
{
FindViewById<TextView>(Resource.Id.tvFatalError).Visibility = ViewStates.Gone;
@@ -262,14 +232,21 @@ namespace keepass2android
FindViewById(Resource.Id.fingerprint_auth_container).Visibility = ViewStates.Gone;
}
private void HideRadioButtons()
{
FindViewById<TextView>(Resource.Id.tvFatalError).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.radio_buttons).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fingerprint_auth_container).Visibility = ViewStates.Gone;
}
private void ChangeUnlockMode(FingerprintUnlockMode oldMode, FingerprintUnlockMode newMode)
private void ChangeUnlockMode(FingerprintUnlockMode oldMode, FingerprintUnlockMode newMode)
{
if (oldMode == newMode)
return;
if (_samsungFingerprint != null)
if (_samsungBiometry != null)
{
_unlockMode = newMode;
UpdateKeyboardCheckboxVisibility();
@@ -294,14 +271,15 @@ namespace keepass2android
FindViewById(Resource.Id.show_keyboard_while_fingerprint).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fingerprint_auth_container).Visibility = ViewStates.Visible;
_enc = new FingerprintEncryption(new FingerprintModule(this), CurrentPreferenceKey);
try
try
{
if (!_enc.Init())
_enc = new BiometricEncryption(new BiometricModule(this), CurrentPreferenceKey);
if (!_enc.Init())
throw new Exception("Failed to initialize cipher");
ResetErrorTextRunnable();
_enc.StartListening(new FingerprintAuthCallbackAdapter(this, this));
}
_enc.StartListening(new BiometricAuthCallbackAdapter(this, this));
}
catch (Exception e)
{
CheckCurrentRadioButton();
@@ -318,9 +296,9 @@ namespace keepass2android
private ImageView _fpIcon;
private TextView _fpTextView;
private FingerprintSamsungIdentifier _samsungFingerprint;
private BiometrySamsungIdentifier _samsungBiometry;
public void OnFingerprintAuthSucceeded()
public void OnBiometricAuthSucceeded()
{
_unlockMode = _desiredUnlockMode;
@@ -344,7 +322,7 @@ namespace keepass2android
public void OnFingerprintError(string error)
public void OnBiometricError(string error)
{
_fpIcon.SetImageResource(Resource.Drawable.ic_fingerprint_error);
_fpTextView.Text = error;
@@ -365,9 +343,26 @@ namespace keepass2android
protected override void OnResume()
{
base.OnResume();
if (_enc != null)
_enc.StartListening(new FingerprintAuthCallbackAdapter(this, this));
}
BiometricModule fpModule = new BiometricModule(this);
HideRadioButtons();
if (!fpModule.IsHardwareAvailable)
{
//seems like not all Samsung Devices (e.g. Note 4) don't support the Android 6 fingerprint API
if (!TrySetupSamsung())
SetError(Resource.String.fingerprint_hardware_error);
UpdateKeyboardCheckboxVisibility();
return;
}
if (!fpModule.IsAvailable)
{
SetError(Resource.String.fingerprint_no_enrolled);
return;
}
ShowRadioButtons();
UpdateKeyboardCheckboxVisibility();
}
protected override void OnPause()
{

View File

@@ -495,7 +495,7 @@ namespace keepass2android
{
FindViewById(Resource.Id.enable_fingerprint).Click += (sender, args) =>
{
StartActivity(typeof(FingerprintSetupActivity));
StartActivity(typeof(BiometricSetupActivity));
};
}
@@ -689,8 +689,8 @@ namespace keepass2android
if (!disabledForAll && !disabledForDatabase && !App.Kp2a.IsChildDatabase(App.Kp2a.CurrentDb))
{
FingerprintModule fpModule = new FingerprintModule(this);
if (fpModule.FingerprintManager != null && fpModule.FingerprintManager.IsHardwareDetected)
BiometricModule biometricModule = new BiometricModule(this);
if (biometricModule.IsAvailable)
{
FingerprintUnlockMode um;
Enum.TryParse(_prefs.GetString(Database.GetFingerprintModePrefKey(App.Kp2a.CurrentDb.Ioc), ""), out um);
@@ -1390,7 +1390,7 @@ namespace keepass2android
case Resource.Id.menu_copy:
var copyTask = new CopyEntry((GroupBaseActivity)Activity, App.Kp2a, (PwEntry)checkedItems.First(),
new GroupBaseActivity.RefreshTask(handler, ((GroupBaseActivity)Activity)));
new GroupBaseActivity.RefreshTask(handler, ((GroupBaseActivity)Activity)), App.Kp2a.CurrentDb);
ProgressTask pt = new ProgressTask(App.Kp2a, Activity, copyTask);
pt.Run();

View File

@@ -24,8 +24,8 @@ using Android.Support.V7.App;
namespace keepass2android
{
public abstract class LifecycleAwareActivity : AppCompatActivity
{
public abstract class LifecycleAwareActivity : AndroidX.AppCompat.App.AppCompatActivity
{
protected LifecycleAwareActivity (IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{

View File

@@ -54,13 +54,9 @@ namespace keepass2android
{
_design.ApplyTheme();
base.OnCreate(savedInstanceState);
if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(
GetString(Resource.String.ViewDatabaseSecure_key), true))
{
Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
}
Util.MakeSecureDisplay(this);
_ioc = App.Kp2a.CurrentDb?.Ioc;

View File

@@ -43,13 +43,9 @@ namespace keepass2android
{
_design.ApplyTheme();
base.OnCreate(savedInstanceState);
if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(
GetString(Resource.String.ViewDatabaseSecure_key), true))
{
Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
}
Util.MakeSecureDisplay(this);
_ioc = App.Kp2a.CurrentDb.Ioc;

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Runtime;
using Android.Support.V7.App;
using Android.Views;
using Android.Widget;
namespace keepass2android
{
[Activity(Label = AppNames.AppName, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden, Theme = "@style/MyTheme_Blue",
LaunchMode = LaunchMode.SingleInstance)]
public class NoSecureDisplayActivity : AndroidX.AppCompat.App.AppCompatActivity
{
private readonly ActivityDesign _design;
public NoSecureDisplayActivity()
{
_design = new ActivityDesign(this);
}
protected override void OnCreate(Bundle savedInstanceState)
{
_design.ApplyTheme();
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.no_secure_display_layout);
FindViewById<Button>(Resource.Id.btn_goto_settings).Click += (sender, args) =>
{
AppSettingsActivity.Launch(this);
};
var toolbar = FindViewById<AndroidX.AppCompat.Widget.Toolbar>(Resource.Id.mytoolbar);
SetSupportActionBar(toolbar);
SupportActionBar.Title = AppNames.AppName;
}
protected override void OnResume()
{
base.OnResume();
_design.ReapplyTheme();
//close if displays changed
if (!Util.SecureDisplayConfigured(this) || !Util.HasUnsecureDisplay(this))
Finish();
}
}
}

View File

@@ -69,7 +69,7 @@ namespace keepass2android
LaunchMode = LaunchMode.SingleInstance,
WindowSoftInputMode = SoftInput.AdjustResize,
Theme = "@style/MyTheme_Blue")]
public class PasswordActivity : LockingActivity, IFingerprintAuthCallback
public class PasswordActivity : LockingActivity, IBiometricAuthCallback
{
enum KeyProviders
@@ -86,8 +86,10 @@ namespace keepass2android
public const String KeyKeyfile = "keyFile";
public const String KeyPassword = "password";
public const String LaunchImmediately = "launchImmediately";
private const string ShowpasswordKey = "ShowPassword";
private const string ShowpasswordKey = "ShowPassword";
private const string KeyProviderIdOtp = "KP2A-OTP";
private const string KeyProviderIdOtpRecovery = "KP2A-OTPSecret";
private const string KeyProviderIdChallenge = "KP2A-Chal";
@@ -579,7 +581,7 @@ namespace keepass2android
private string mDrawerTitle;
private MeasuringRelativeLayout.MeasureArgs _measureArgs;
private ActivityDesign _activityDesign;
private FingerprintDecryption _fingerprintDec;
private BiometricDecryption _biometricDec;
private bool _fingerprintPermissionGranted;
private PasswordActivityBroadcastReceiver _intentReceiver;
private int _appnameclickCount;
@@ -646,16 +648,12 @@ namespace keepass2android
IntentFilter filter = new IntentFilter();
filter.AddAction(Intent.ActionScreenOff);
RegisterReceiver(_intentReceiver, filter);
//use FlagSecure to make sure the last (revealed) character of the master password is not visible in recent apps
if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(
GetString(Resource.String.ViewDatabaseSecure_key), true))
{
Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
}
Intent i = Intent;
//use FlagSecure to make sure the last (revealed) character of the master password is not visible in recent apps
Util.MakeSecureDisplay(this);
Intent i = Intent;
String action = i.Action;
@@ -763,11 +761,15 @@ namespace keepass2android
mDrawerTitle = Title;
InitializeToolbarCollapsing();
if ((int)Build.VERSION.SdkInt >= 23)
RequestPermissions(new[] { Manifest.Permission.UseFingerprint }, FingerprintPermissionRequestCode);
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
btn.Click += (sender, args) =>
{
_biometricDec?.StartListening(this);
if (App.Kp2a.TrySelectCurrentDb(_ioConnection))
};
if (App.Kp2a.TrySelectCurrentDb(_ioConnection))
{
//database already opened. return the ioc and we're good.
LaunchNextActivity();
@@ -891,41 +893,8 @@ namespace keepass2android
}
}
const int FingerprintPermissionRequestCode = 99;
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
if ((requestCode == FingerprintPermissionRequestCode) && (grantResults.Length > 0) && (grantResults[0] == Permission.Granted))
{
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
btn.Click += (sender, args) =>
{
AlertDialog.Builder b = new AlertDialog.Builder(this);
b.SetTitle(Resource.String.fingerprint_prefs);
b.SetMessage(btn.Tag.ToString());
b.SetPositiveButton(Android.Resource.String.Ok, (o, eventArgs) => ((Dialog)o).Dismiss());
if (_fingerprintDec != null)
{
b.SetNegativeButton(Resource.String.disable_sensor, (senderAlert, alertArgs) =>
{
btn.SetImageResource(Resource.Drawable.ic_fingerprint_error);
_fingerprintDec?.StopListening();
_fingerprintDec = null;
});
}
else
{
b.SetNegativeButton(Resource.String.enable_sensor, (senderAlert, alertArgs) =>
{
InitFingerprintUnlock();
});
}
b.Show();
};
_fingerprintPermissionGranted = true;
}
}
private void ClearFingerprintUnlockData()
{
@@ -935,7 +904,7 @@ namespace keepass2android
edit.Commit();
}
public void OnFingerprintError(string message)
public void OnBiometricError(string message)
{
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
@@ -948,7 +917,7 @@ namespace keepass2android
Toast.MakeText(this, message, ToastLength.Long).Show();
}
public void OnFingerprintAuthSucceeded()
public void OnBiometricAuthSucceeded()
{
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
@@ -956,7 +925,7 @@ namespace keepass2android
try
{
var masterPassword = _fingerprintDec.DecryptStored(Database.GetFingerprintPrefKey(_ioConnection));
var masterPassword = _biometricDec.DecryptStored(Database.GetFingerprintPrefKey(_ioConnection));
_password = FindViewById<EditText>(Resource.Id.password_edit).Text = masterPassword;
FindViewById<EditText>(Resource.Id.password_edit).Enabled = false; //prevent accidental modification of password
@@ -1024,7 +993,7 @@ namespace keepass2android
private void InitializeToolbar()
{
var toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.mytoolbar);
var toolbar = FindViewById<AndroidX.AppCompat.Widget.Toolbar>(Resource.Id.mytoolbar);
SetSupportActionBar(toolbar);
@@ -1528,13 +1497,16 @@ namespace keepass2android
protected override void OnPause()
{
_fingerprintDec?.StopListening();
_biometricDec?.StopListening();
_lastOnPauseTime = DateTime.Now;
base.OnPause();
}
protected override void OnStart()
private bool fingerprintInitialized;
protected override void OnStart()
{
base.OnStart();
_starting = true;
@@ -1546,9 +1518,14 @@ namespace keepass2android
}
DonateReminder.ShowDonateReminderIfAppropriate(this);
}
if (compositeKeyForImmediateLoad == null && !fingerprintInitialized)
{
fingerprintInitialized = InitFingerprintUnlock();
}
}
private MemoryStream PreloadDbFile()
{
@@ -1778,16 +1755,10 @@ namespace keepass2android
bool showKeyboard = (Util.GetShowKeyboardDuringFingerprintUnlock(this));
if (_fingerprintPermissionGranted)
{
if (!InitFingerprintUnlock())
showKeyboard = true;
}
else
{
FindViewById<ImageButton>(Resource.Id.fingerprintbtn).Visibility = ViewStates.Gone;
if (!fingerprintInitialized)
showKeyboard = true;
}
EditText pwd = (EditText) FindViewById(Resource.Id.password_edit);
@@ -1865,16 +1836,16 @@ namespace keepass2android
return false;
}
FingerprintModule fpModule = new FingerprintModule(this);
_fingerprintDec = new FingerprintDecryption(fpModule, Database.GetFingerprintPrefKey(_ioConnection), this,
BiometricModule fpModule = new BiometricModule(this);
_biometricDec = new BiometricDecryption(fpModule, Database.GetFingerprintPrefKey(_ioConnection), this,
Database.GetFingerprintPrefKey(_ioConnection));
btn.Tag = GetString(Resource.String.fingerprint_unlock_hint);
if (_fingerprintDec.Init())
if (_biometricDec.Init())
{
btn.SetImageResource(Resource.Drawable.ic_fp_40px);
_fingerprintDec.StartListening(new FingerprintAuthCallbackAdapter(this, this));
_biometricDec.StartListening(new BiometricAuthCallbackAdapter(this, this));
return true;
}
else
@@ -1895,7 +1866,7 @@ namespace keepass2android
Toast.MakeText(this, Resource.String.fingerprint_reenable2, ToastLength.Long).Show();
_fingerprintDec = null;
_biometricDec = null;
return false;
}
@@ -1908,7 +1879,7 @@ namespace keepass2android
//key invalidated permanently
btn.SetImageResource(Resource.Drawable.ic_fingerprint_error);
btn.Tag = GetString(Resource.String.fingerprint_unlock_failed) + " " + GetString(Resource.String.fingerprint_reenable2);
_fingerprintDec = null;
_biometricDec = null;
ClearFingerprintUnlockData();
}
@@ -2147,7 +2118,7 @@ namespace keepass2android
KeyProviderQueryContext ctx = new KeyProviderQueryContext(_act._ioConnection, false, false);
if (!OathHotpKeyProv.CreateAuxFile(_act._otpInfo, ctx, _act._otpAuxIoc))
Toast.MakeText(_act, _act.GetString(Resource.String.ErrorUpdatingOtpAuxFile), ToastLength.Long).Show();
ShowError(_act.GetString(Resource.String.ErrorUpdatingOtpAuxFile));
}
@@ -2155,8 +2126,7 @@ namespace keepass2android
{
Kp2aLog.LogUnexpectedError(e);
Toast.MakeText(_act, _act.GetString(Resource.String.ErrorUpdatingOtpAuxFile) + " " + e.Message,
ToastLength.Long).Show();
ShowError( _act.GetString(Resource.String.ErrorUpdatingOtpAuxFile) + " " + e.Message);
}
@@ -2169,7 +2139,11 @@ namespace keepass2android
}
private void ShowError(string message)
{
App.Kp2a.ShowToast(message);
}
}
private class PasswordActivityBroadcastReceiver : BroadcastReceiver
{
@@ -2192,8 +2166,8 @@ namespace keepass2android
private void OnScreenLocked()
{
if (_fingerprintDec != null)
_fingerprintDec.StopListening();
if (_biometricDec != null)
_biometricDec.StopListening();
}

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="46" android:versionName="0.9.3-release-3" package="keepass2android.keepass2android_debug" android:installLocation="auto">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26" />
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="29" />
<permission android:description="@string/permission_desc2" android:icon="@drawable/ic_notify_locked" android:label="KP2A entry search" android:name="keepass2android.keepass2android_debug.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_debug.permission.Kp2aChooseAutofill" android:protectionLevel="signature" />
<application android:label="keepass2android"
@@ -135,6 +135,7 @@
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="keepass2android.keepass2android_debug.permission.KP2aInternalFileBrowsing" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<!-- Samsung Pass permission -->
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />

View File

@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="141"
android:versionName="1.07b-r0"
android:versionCode="144"
android:versionName="1.08-pre3"
package="keepass2android.keepass2android"
android:installLocation="auto">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26" />
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="29" />
<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" />
@@ -163,6 +163,7 @@
<uses-permission android:name="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing" />
<uses-permission android:name="keepass2android.keepass2android.permission.KP2aInternalSearch" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<!-- Samsung Pass permission -->
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />

View File

@@ -4,7 +4,7 @@
android:versionName="1.01-g"
package="keepass2android.keepass2android_nonet"
android:installLocation="auto">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" />
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="29" />
<permission android:description="@string/permission_desc2" android:icon="@drawable/ic_launcher" 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" android:label="KP2A choose autofill dataset" android:name="keepass2android.keepass2android_nonet.permission.Kp2aChooseAutofill" android:protectionLevel="signature" />
<application
@@ -137,6 +137,8 @@
<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="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing" />
<uses-permission android:name="keepass2android.keepass2android.permission.KP2aInternalSearch" />

View File

@@ -120,7 +120,7 @@ namespace keepass2android
String nameX = x.Strings.ReadSafe(PwDefs.TitleField);
String nameY = y.Strings.ReadSafe(PwDefs.TitleField);
if (nameX.ToLower() != nameY.ToLower())
return String.Compare(nameX, nameY, StringComparison.OrdinalIgnoreCase);
return String.Compare(nameX, nameY, StringComparison.CurrentCultureIgnoreCase);
else
{
if (PwDefs.IsTanEntry(x) && PwDefs.IsTanEntry(y))
@@ -138,7 +138,7 @@ namespace keepass2android
{
//ignore
}
return String.Compare(userX, userY, StringComparison.OrdinalIgnoreCase);
return String.Compare(userX, userY, StringComparison.CurrentCultureIgnoreCase);
}
}
@@ -150,7 +150,7 @@ namespace keepass2android
public int CompareGroups(PwGroup a, PwGroup b)
{
return String.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase);
return String.Compare(a.Name, b.Name, StringComparison.CurrentCultureIgnoreCase);
}
}

View File

@@ -38,13 +38,13 @@ namespace keepass2android
WindowSoftInputMode = SoftInput.AdjustResize,
MainLauncher = false,
Theme = "@style/MyTheme_Blue")]
public class QuickUnlock : LifecycleAwareActivity, IFingerprintAuthCallback
public class QuickUnlock : LifecycleAwareActivity, IBiometricAuthCallback
{
private IOConnectionInfo _ioc;
private QuickUnlockBroadcastReceiver _intentReceiver;
private ActivityDesign _design;
private bool _fingerprintPermissionGranted;
private IFingerprintIdentifier _fingerprintIdentifier;
private IBiometricIdentifier _biometryIdentifier;
private int _quickUnlockLength;
private const int FingerprintPermissionRequestCode = 0;
@@ -59,11 +59,7 @@ namespace keepass2android
base.OnCreate(bundle);
//use FlagSecure to make sure the last (revealed) character of the password is not visible in recent apps
if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(
GetString(Resource.String.ViewDatabaseSecure_key), true))
{
Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
}
Util.MakeSecureDisplay(this);
_ioc = App.Kp2a.GetDbForQuickUnlock()?.Ioc;
@@ -75,7 +71,7 @@ namespace keepass2android
SetContentView(Resource.Layout.QuickUnlock);
var toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.mytoolbar);
var toolbar = FindViewById<AndroidX.AppCompat.Widget.Toolbar>(Resource.Id.mytoolbar);
SetSupportActionBar(toolbar);
@@ -149,15 +145,7 @@ namespace keepass2android
filter.AddAction(Intents.DatabaseLocked);
RegisterReceiver(_intentReceiver, filter);
if ((int) Build.VERSION.SdkInt >= 23)
{
Kp2aLog.Log("requesting fingerprint permission");
RequestPermissions(new[] { Manifest.Permission.UseFingerprint }, FingerprintPermissionRequestCode);
}
else
{
}
}
@@ -168,51 +156,9 @@ namespace keepass2android
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
Kp2aLog.Log("OnRequestPermissionsResult " + (requestCode == FingerprintPermissionRequestCode) +
((grantResults.Length > 0) && (grantResults[0] == Permission.Granted)));
if ((requestCode == FingerprintPermissionRequestCode) && (grantResults.Length > 0) && (grantResults[0] == Permission.Granted))
{
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
btn.Click += (sender, args) =>
{
AlertDialog.Builder b = new AlertDialog.Builder(this);
b.SetTitle(Resource.String.fingerprint_prefs);
b.SetMessage(btn.Tag.ToString());
b.SetPositiveButton(Android.Resource.String.Ok, (o, eventArgs) => ((Dialog)o).Dismiss());
if (_fingerprintIdentifier != null)
{
b.SetNegativeButton(Resource.String.disable_sensor, (senderAlert, alertArgs) =>
{
btn.SetImageResource(Resource.Drawable.ic_fingerprint_error);
_fingerprintIdentifier?.StopListening();
_fingerprintIdentifier = null;
});
}
else
{
b.SetNegativeButton(Resource.String.enable_sensor, (senderAlert, alertArgs) =>
{
InitFingerprintUnlock();
});
}
b.Show();
};
_fingerprintPermissionGranted = true;
Kp2aLog.Log("_fingerprintPermissionGranted");
if (_onResumeDone)
{
//it seems the permission result is called after onResume sometimes. Repeat fingerprint unlock then.
InitFingerprintUnlock();
}
}
}
bool _onResumeDone = false;
public void OnFingerprintError(string message)
public void OnBiometricError(string message)
{
Kp2aLog.Log("fingerprint error: " + message);
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
@@ -226,10 +172,10 @@ namespace keepass2android
Toast.MakeText(this, message, ToastLength.Long).Show();
}
public void OnFingerprintAuthSucceeded()
public void OnBiometricAuthSucceeded()
{
Kp2aLog.Log("OnFingerprintAuthSucceeded");
_fingerprintIdentifier.StopListening();
_biometryIdentifier.StopListening();
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
btn.SetImageResource(Resource.Drawable.ic_fingerprint_success);
@@ -250,7 +196,7 @@ namespace keepass2android
{
Kp2aLog.Log("InitFingerprintUnlock");
if (_fingerprintIdentifier != null)
if (_biometryIdentifier != null)
{
Kp2aLog.Log("Already listening for fingerprint!");
return true;
@@ -266,49 +212,47 @@ namespace keepass2android
if (um == FingerprintUnlockMode.Disabled)
{
_fingerprintIdentifier = null;
_biometryIdentifier = null;
return false;
}
if (_fingerprintPermissionGranted)
{
FingerprintModule fpModule = new FingerprintModule(this);
Kp2aLog.Log("fpModule.FingerprintManager.IsHardwareDetected=" + fpModule.FingerprintManager.IsHardwareDetected);
if (fpModule.FingerprintManager.IsHardwareDetected) //see FingerprintSetupActivity
_fingerprintIdentifier = new FingerprintDecryption(fpModule, App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey, this,
App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey);
}
if ((_fingerprintIdentifier == null) && (!FingerprintDecryption.IsSetUp(this, App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey)))
BiometricModule fpModule = new BiometricModule(this);
Kp2aLog.Log("fpModule.IsHardwareAvailable=" + fpModule.IsHardwareAvailable);
if (fpModule.IsHardwareAvailable) //see FingerprintSetupActivity
_biometryIdentifier = new BiometricDecryption(fpModule, App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey, this,
App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey);
if ((_biometryIdentifier == null) && (!BiometricDecryption.IsSetUp(this, App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey)))
{
try
{
Kp2aLog.Log("trying Samsung Fingerprint API...");
_fingerprintIdentifier = new FingerprintSamsungIdentifier(this);
_biometryIdentifier = new BiometrySamsungIdentifier(this);
btn.Click += (sender, args) =>
{
if (_fingerprintIdentifier.Init())
_fingerprintIdentifier.StartListening(this, this);
if (_biometryIdentifier.Init())
_biometryIdentifier.StartListening(this);
};
Kp2aLog.Log("trying Samsung Fingerprint API...Seems to work!");
}
catch (Exception)
{
Kp2aLog.Log("trying Samsung Fingerprint API...failed.");
_fingerprintIdentifier = null;
_biometryIdentifier = null;
}
}
if (_fingerprintIdentifier == null)
if (_biometryIdentifier == null)
{
FindViewById<ImageButton>(Resource.Id.fingerprintbtn).Visibility = ViewStates.Gone;
return false;
}
btn.Tag = GetString(Resource.String.fingerprint_unlock_hint);
if (_fingerprintIdentifier.Init())
if (_biometryIdentifier.Init())
{
Kp2aLog.Log("successfully initialized fingerprint.");
btn.SetImageResource(Resource.Drawable.ic_fp_40px);
_fingerprintIdentifier.StartListening(this, this);
_biometryIdentifier.StartListening(this);
return true;
}
else
@@ -323,7 +267,7 @@ namespace keepass2android
btn.SetImageResource(Resource.Drawable.ic_fingerprint_error);
btn.Tag = "Error initializing Fingerprint Unlock: " + e;
_fingerprintIdentifier = null;
_biometryIdentifier = null;
}
return false;
@@ -335,7 +279,7 @@ namespace keepass2android
//key invalidated permanently
btn.SetImageResource(Resource.Drawable.ic_fingerprint_error);
btn.Tag = GetString(Resource.String.fingerprint_unlock_failed) + " " + GetString(Resource.String.fingerprint_reenable2);
_fingerprintIdentifier = null;
_biometryIdentifier = null;
}
private void OnUnlock(int quickUnlockLength, EditText pwd)
@@ -397,25 +341,59 @@ namespace keepass2android
keyboard.HideSoftInputFromWindow(pwd.WindowToken, HideSoftInputFlags.ImplicitOnly);
}, 50);
_onResumeDone = true;
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
btn.Click += (sender, args) =>
{
if (_biometryIdentifier.HasUserInterface)
{
_biometryIdentifier.StartListening(this);
}
else
{
AlertDialog.Builder b = new AlertDialog.Builder(this);
b.SetTitle(Resource.String.fingerprint_prefs);
b.SetMessage(btn.Tag.ToString());
b.SetPositiveButton(Android.Resource.String.Ok, (o, eventArgs) => ((Dialog)o).Dismiss());
if (_biometryIdentifier != null)
{
b.SetNegativeButton(Resource.String.disable_sensor, (senderAlert, alertArgs) =>
{
btn.SetImageResource(Resource.Drawable.ic_fingerprint_error);
_biometryIdentifier?.StopListening();
_biometryIdentifier = null;
});
}
else
{
b.SetNegativeButton(Resource.String.enable_sensor, (senderAlert, alertArgs) =>
{
InitFingerprintUnlock();
});
}
b.Show();
}
};
}
}
protected override void OnPause()
{
if (_fingerprintIdentifier != null)
if (_biometryIdentifier != null && !_biometryIdentifier.HasUserInterface)
{
Kp2aLog.Log("FP: Stop listening");
_fingerprintIdentifier.StopListening();
_fingerprintIdentifier = null;
}
_biometryIdentifier.StopListening();
}
base.OnPause();
}

View File

@@ -92,7 +92,7 @@ android:fitsSystemWindows="true">
android:textSize="10sp"
android:text="/storage/emulated/0/keepass/keepass/database.kdbx" />
</RelativeLayout>
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/mytoolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"

View File

@@ -6,7 +6,7 @@
android:fitsSystemWindows="true"
android:layout_height="fill_parent"
android:gravity="center_horizontal">
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/mytoolbar"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"

View File

@@ -7,7 +7,7 @@
android:fitsSystemWindows="true"
android:layout_height="fill_parent"
android:gravity="center_horizontal">
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/mytoolbar"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"

View File

@@ -0,0 +1,25 @@
<?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"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="16dp"
android:paddingStart="24dp"
android:paddingEnd="24dp"
android:paddingTop="16dp">
<androidx.appcompat.widget.Toolbar android:id="@+id/mytoolbar"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:titleTextStyle="@style/MyTitleTextStyle"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:minHeight="?attr/actionBarSize"
android:background="#00000000" />
<TextView android:text="@string/no_secure_display" android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button android:id="@+id/btn_goto_settings" android:text="@string/IconVisibilityInfo_Android8_btnSettings" android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@@ -7,7 +7,7 @@
android:fitsSystemWindows="true"
android:layout_height="fill_parent"
android:gravity="center_horizontal">
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/mytoolbar"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"

View File

@@ -89,7 +89,7 @@
android:textSize="10sp"
android:text="/storage/emulated/0/keepass/keepass/database.kdbx" />
</RelativeLayout>
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/mytoolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="@+id/mytoolbar"

View File

@@ -781,7 +781,16 @@
<string name="EntryChannel_desc">Notification to simplify access to the currently selected entry.</string>
<string name="ShowKeyboardDuringFingerprintAuth">Show soft keyboard for password input when fingerprint scan is active.</string>
<string name="ChangeLog_1_07b">
<string-array name="ChangeLog_1_08">
<item>Add notification button for copying TOTP to clipboard</item>
<item>Switch to using FluentFTP to provide support for TLS 1.2</item>
<item>Switch to BiometricPrompt API to improve user experience with fingerprint unlock and allow to use face unlock, e.g. on Pixel 4.</item>
<item>Bug fixes</item>
</string-array>
<string name="ChangeLog_1_07b">
Version 1.07b\n
* Improve Argon2 performance by using native implementation (Thanks to Chih-Hsuan Yen!)\n
* Allow to disable fingerprint by clicking on the fingerprint icon (avoids issue with underscreen fingerprint readers, thanks to marcoDallas!)\n
@@ -1217,6 +1226,7 @@ Initial public release
<string name="emergency_infotext_head">Are you prepared for emergency cases?</string>
<string name="emergency_infotext_main">Did you ever consider what happens if you are no longer able to access your password database? What if you have an accident? It is good practice to pass your master key to some trusted person for emergency cases. Nobody will have access to your passwords otherwise.</string>
<string name="no_secure_display">The currently valid display is not marked as secure. This means that screenshots might be taken by other apps. Keepass2Android is configured to display sensitive information on secure displays only. Please change to a secure display (e.g. by detaching an HDMI monitor) or change the app settings.</string>
<string name="no_secure_display">The currently valid display is not marked as secure. This means that screenshots might be taken by other apps. Keepass2Android is configured to display sensitive information on secure displays only. Please change to a secure display (e.g. by detaching an HDMI monitor) or change the app settings.</string>
</resources>

View File

@@ -29,7 +29,7 @@ using Object = Java.Lang.Object;
namespace keepass2android
{
[Activity(Label = AppNames.AppName, MainLauncher = false, Theme = "@style/MyTheme_Blue", LaunchMode = LaunchMode.SingleInstance)] //caution, see manifest file
public class SelectCurrentDbActivity : AppCompatActivity
public class SelectCurrentDbActivity : AndroidX.AppCompat.App.AppCompatActivity
{
private int ReqCodeOpenNewDb = 1;
@@ -188,7 +188,7 @@ namespace keepass2android
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.open_db_selection);
var toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.mytoolbar);
var toolbar = FindViewById<AndroidX.AppCompat.Widget.Toolbar>(Resource.Id.mytoolbar);
SetSupportActionBar(toolbar);
@@ -232,8 +232,9 @@ namespace keepass2android
//forward to password activity
Intent i = new Intent(this, typeof(PasswordActivity));
Util.PutIoConnectionToIntent(ioc, i);
i.PutExtra(PasswordActivity.KeyKeyfile, i.GetStringExtra(PasswordActivity.KeyKeyfile));
i.PutExtra(PasswordActivity.KeyPassword, i.GetStringExtra(PasswordActivity.KeyPassword));
i.PutExtra(PasswordActivity.KeyKeyfile, Intent.GetStringExtra(PasswordActivity.KeyKeyfile));
i.PutExtra(PasswordActivity.KeyPassword, Intent.GetStringExtra(PasswordActivity.KeyPassword));
i.PutExtra(PasswordActivity.LaunchImmediately, Intent.GetBooleanExtra(PasswordActivity.LaunchImmediately, false));
LaunchingOther = true;
StartActivityForResult(i, ReqCodeOpenNewDb);
}
@@ -329,6 +330,7 @@ namespace keepass2android
//database loaded
if (App.Kp2a.QuickLocked)
{
AppTask.CanActivateSearchViewOnStart = true;
var i = new Intent(this, typeof(QuickUnlock));
Util.PutIoConnectionToIntent(App.Kp2a.GetDbForQuickUnlock().Ioc, i);
Kp2aLog.Log("Starting QuickUnlock");

View File

@@ -114,7 +114,7 @@ namespace keepass2android
edit.Commit();
Toast.MakeText(_dlg.Context, Resource.String.fingerprint_reenable, ToastLength.Long).Show();
_dlg.Context.StartActivity(typeof(FingerprintSetupActivity));
_dlg.Context.StartActivity(typeof(BiometricSetupActivity));
}
_dlg.Dismiss();

View File

@@ -30,13 +30,18 @@ namespace keepass2android
res.TotpSeed = parsedQuery.Get("secret");
res.Length = parsedQuery.Get("digits");
res.Duration = parsedQuery.Get("period");
res.Encoder = parsedQuery.Get("encoder");
//set defaults according to https://github.com/google/google-authenticator/wiki/Key-Uri-Format
if (res.Length == null)
res.Length = "6";
if (res.Duration == null)
res.Duration = "30";
if (res.Encoder == null)
res.Encoder = TotpData.EncoderRfc6238;
}
catch (Exception)
catch (Exception e)
{
return res;
}

View File

@@ -3,18 +3,22 @@ using System.Collections.Generic;
namespace PluginTOTP
{
struct TotpData
{
public bool IsTotpEnry { get; set; }
{
public const string EncoderSteam = "steam";
public const string EncoderRfc6238 = "rfc6238";
public bool IsTotpEnry { get; set; }
public string TotpSeed { get; set; }
public string Duration { get; set; }
public string Length { get; set; }
public string Encoder { get; set; }
public string Length { get; set; }
public string Url { get; set; }
public string[] Settings
{
get
{
List<string> settings = new List<string>() { Duration, Length};
List<string> settings = new List<string>() { Duration, Encoder == EncoderSteam ? "S" : Length};
if (Url != null)
settings.Add(Url);
return settings.ToArray();

View File

@@ -13,7 +13,7 @@ namespace PluginTOTP
{
class UpdateTotpTimerTask: TimerTask
{
private const string _totp = "TOTP";
public const string TotpKey = "TOTP";
private readonly Context _context;
private readonly ITotpPluginAdapter _adapter;
@@ -49,7 +49,7 @@ namespace PluginTOTP
}
catch (Exception e)
{
Android.Util.Log.Debug(_totp, e.ToString());
Android.Util.Log.Debug(TotpKey, e.ToString());
}
@@ -58,7 +58,7 @@ namespace PluginTOTP
private void UpdateEntryData(string totp)
{
//update the Entry output in the App database and notify the CopyToClipboard service
App.Kp2a.LastOpenedEntry.OutputStrings.Set(_totp, new ProtectedString(true, totp));
App.Kp2a.LastOpenedEntry.OutputStrings.Set(TotpKey, new ProtectedString(true, totp));
Intent updateKeyboardIntent = new Intent(_context, typeof(CopyToClipboardService));
updateKeyboardIntent.SetAction(Intents.UpdateKeyboard);
updateKeyboardIntent.PutExtra(EntryActivity.KeyEntry, new ElementAndDatabaseId(App.Kp2a.FindDatabaseForElement(App.Kp2a.LastOpenedEntry.Entry), App.Kp2a.LastOpenedEntry.Entry).FullId);
@@ -74,7 +74,7 @@ namespace PluginTOTP
i.PutExtra(Strings.ExtraSender, _context.PackageName);
i.PutExtra(Strings.ExtraFieldValue, totp);
i.PutExtra(Strings.ExtraEntryId, App.Kp2a.LastOpenedEntry.Entry.Uuid.ToHexString());
i.PutExtra(Strings.ExtraFieldId, _totp);
i.PutExtra(Strings.ExtraFieldId, TotpKey);
i.PutExtra(Strings.ExtraFieldProtected, true);
_context.SendBroadcast(i);

View File

@@ -19,6 +19,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using Android.App;
using Android.Content;
using Android.Database;
@@ -31,6 +32,7 @@ using Android.Content.PM;
using Android.Content.Res;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Hardware.Display;
using Android.Util;
using KeePassLib.Serialization;
using Uri = Android.Net.Uri;
@@ -129,13 +131,41 @@ namespace keepass2android
public static void CopyToClipboard(Context context, String text) {
Android.Content.ClipboardManager clipboardManager = (ClipboardManager)context.GetSystemService(Context.ClipboardService);
if (text == "")
text = "***";
ClipData clipData = Android.Content.ClipData.NewPlainText("KP2A", text);
clipboardManager.PrimaryClip = clipData;
}
public static void GotoUrl(Context context, String url) {
if (text == "")
{
//on some devices, adding empty text does not seem to work. Try again with some garbage.
clipData = Android.Content.ClipData.NewPlainText("KP2A", "***");
clipboardManager.PrimaryClip = clipData;
//seems to work better on some devices:
try
{
clipboardManager.Text = text;
}
catch (Exception exception)
{
Kp2aLog.LogUnexpectedError(exception);
}
}
}
private static readonly Regex ARC_DEVICE_PATTERN = new Regex(".+_cheets|cheets_.+");
public static bool IsChromeOS(Context context)
{
return
context.PackageManager.HasSystemFeature(
"org.chromium.arc.device_management") // https://stackoverflow.com/a/39843396/292233
|| (Build.Device != null && ARC_DEVICE_PATTERN.IsMatch(Build.Device))
;
}
public static void GotoUrl(Context context, String url) {
if ( !string.IsNullOrEmpty(url) ) {
if (url.StartsWith("androidapp://"))
@@ -567,6 +597,43 @@ namespace keepass2android
"file" : displayPath.Substring(0, protocolSeparatorPos);
return protocolId;
}
public static void MakeSecureDisplay(Activity context)
{
if (SecureDisplayConfigured(context))
{
var hasUnsecureDisplay = HasUnsecureDisplay(context);
if (hasUnsecureDisplay)
{
var intent = new Intent(context, typeof(NoSecureDisplayActivity));
intent.AddFlags(ActivityFlags.SingleTop | ActivityFlags.ClearTop);
context.StartActivityForResult(intent,9999);
}
context.Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
}
}
public static bool SecureDisplayConfigured(Activity context)
{
return PreferenceManager.GetDefaultSharedPreferences(context).GetBoolean(
context.GetString(Resource.String.ViewDatabaseSecure_key), true);
}
public static bool HasUnsecureDisplay(Activity context)
{
bool hasUnsecureDisplay = false;
if ((int) Build.VERSION.SdkInt >= 17)
{
foreach (var display in ((DisplayManager) context.GetSystemService(Context.DisplayService)).GetDisplays())
{
if ((display.Flags & DisplayFlags.Secure) == 0)
{
hasUnsecureDisplay = true;
}
}
}
return hasUnsecureDisplay;
}
}
}

View File

@@ -44,7 +44,7 @@ namespace keepass2android
ConfigurationChanges=ConfigChanges.Orientation|
ConfigChanges.KeyboardHidden,
Theme = "@style/MyTheme_Blue")]
public class FileSelectActivity : AppCompatActivity
public class FileSelectActivity : AndroidX.AppCompat.App.AppCompatActivity
{
private readonly ActivityDesign _design;
public FileSelectActivity (IntPtr javaReference, JniHandleOwnership transfer)

View File

@@ -39,7 +39,8 @@ namespace keepass2android
public const String CopyUsername = "keepass2android.copy_username";
public const String CopyPassword = "keepass2android.copy_password";
public const String CheckKeyboard = "keepass2android.check_keyboard";
public const String CopyTotp = "keepass2android.copy_totp";
public const String CheckKeyboard = "keepass2android.check_keyboard";
public const String StartWithOtp = "keepass2android.startWithOtp";
public const String OtpExtraKey = "keepass2android.Otp";

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Xamarin.Build.Download.0.4.2\build\Xamarin.Build.Download.props" Condition="Exists('..\packages\Xamarin.Build.Download.0.4.2\build\Xamarin.Build.Download.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -16,7 +15,7 @@
<AssemblyName>keepass2android</AssemblyName>
<newfilesearch>OnLoad</newfilesearch>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<TargetFrameworkVersion>v9.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
<MandroidI18n />
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
@@ -50,6 +49,8 @@
<AotAssemblies>false</AotAssemblies>
<EnableLLVM>false</EnableLLVM>
<JavaMaximumHeapSize>2G</JavaMaximumHeapSize>
<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
<MandroidI18n />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>full</DebugType>
@@ -82,6 +83,7 @@
<AndroidTlsProvider>btls</AndroidTlsProvider>
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
<JavaMaximumHeapSize>2G</JavaMaximumHeapSize>
<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseNoNet|AnyCPU' ">
<DebugType>none</DebugType>
@@ -105,159 +107,24 @@
<ItemGroup>
<Reference Include="Java.Interop" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Graph, Version=1.17.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Graph.1.17.0\lib\netstandard1.3\Microsoft.Graph.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Graph.Auth, Version=0.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Graph.Auth.1.0.0-preview.1\lib\netstandard1.3\Microsoft.Graph.Auth.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Graph.Core, Version=1.17.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Graph.Core.1.17.0\lib\monoandroid70\Microsoft.Graph.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Identity.Client, Version=4.4.0.0, Culture=neutral, PublicKeyToken=0a613f4dd989e8ae, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Identity.Client.4.4.0\lib\monoandroid90\Microsoft.Identity.Client.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.11.0.1\lib\netstandard2.0\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.IdentityModel" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Web.Services" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Mono.Android" />
<Reference Include="System.Xml.Linq" />
<Reference Include="Xamarin.Android.Arch.Core.Common, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Arch.Core.Common.1.1.1.1\lib\monoandroid90\Xamarin.Android.Arch.Core.Common.dll</HintPath>
<Reference Include="Xamarin.Jetbrains.Annotations, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Jetbrains.Annotations.13.0.0.1\lib\monoandroid90\Xamarin.Jetbrains.Annotations.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Arch.Core.Runtime, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Arch.Core.Runtime.1.1.1.1\lib\monoandroid90\Xamarin.Android.Arch.Core.Runtime.dll</HintPath>
<Reference Include="Xamarin.Kotlin.StdLib, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Kotlin.StdLib.1.3.50.1\lib\monoandroid90\Xamarin.Kotlin.StdLib.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Arch.Lifecycle.Common, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Arch.Lifecycle.Common.1.1.1.1\lib\monoandroid90\Xamarin.Android.Arch.Lifecycle.Common.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Arch.Lifecycle.LiveData, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Arch.Lifecycle.LiveData.1.1.1.1\lib\monoandroid90\Xamarin.Android.Arch.Lifecycle.LiveData.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Arch.Lifecycle.LiveData.Core, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Arch.Lifecycle.LiveData.Core.1.1.1.1\lib\monoandroid90\Xamarin.Android.Arch.Lifecycle.LiveData.Core.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Arch.Lifecycle.Runtime, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Arch.Lifecycle.Runtime.1.1.1.1\lib\monoandroid90\Xamarin.Android.Arch.Lifecycle.Runtime.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Arch.Lifecycle.ViewModel, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Arch.Lifecycle.ViewModel.1.1.1.1\lib\monoandroid90\Xamarin.Android.Arch.Lifecycle.ViewModel.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Animated.Vector.Drawable, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.Animated.Vector.Drawable.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Annotations, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Annotations.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.Annotations.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.AsyncLayoutInflater, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.AsyncLayoutInflater.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.AsyncLayoutInflater.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Collections, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Collections.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.Collections.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Compat, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Compat.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.Compat.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.CoordinaterLayout, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.CoordinaterLayout.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.CoordinaterLayout.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Core.UI, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Core.UI.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.Core.UI.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Core.Utils, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Core.Utils.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.Core.Utils.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.CursorAdapter, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.CursorAdapter.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.CursorAdapter.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.CustomTabs, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.CustomTabs.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.CustomTabs.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.CustomView, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.CustomView.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.CustomView.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Design, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Design.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.Design.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.DocumentFile, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.DocumentFile.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.DocumentFile.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.DrawerLayout, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.DrawerLayout.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.DrawerLayout.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Fragment, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Fragment.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.Fragment.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Interpolator, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Interpolator.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.Interpolator.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Loader, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Loader.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.Loader.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.LocalBroadcastManager, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.LocalBroadcastManager.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.LocalBroadcastManager.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Media.Compat, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Media.Compat.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.Media.Compat.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Print, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Print.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.Print.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.SlidingPaneLayout, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.SlidingPaneLayout.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.SlidingPaneLayout.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.SwipeRefreshLayout, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.SwipeRefreshLayout.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.SwipeRefreshLayout.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Transition, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Transition.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.Transition.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v13, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.v13.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.v13.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v4, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.v4.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.v4.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.AppCompat, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.v7.AppCompat.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.v7.AppCompat.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.CardView, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.v7.CardView.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.v7.CardView.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.RecyclerView, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.v7.RecyclerView.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.v7.RecyclerView.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Vector.Drawable, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Vector.Drawable.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.Vector.Drawable.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.VersionedParcelable, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.VersionedParcelable.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.VersionedParcelable.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.ViewPager, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.ViewPager.28.0.0.1\lib\monoandroid90\Xamarin.Android.Support.ViewPager.dll</HintPath>
</Reference>
<Reference Include="Xamarin.GooglePlayServices.Base">
<HintPath>..\packages\Xamarin.GooglePlayServices.Base.27.0.0.0\lib\MonoAndroid41\Xamarin.GooglePlayServices.Base.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.GooglePlayServices.Basement">
<HintPath>..\packages\Xamarin.GooglePlayServices.Basement.27.0.0.0\lib\MonoAndroid41\Xamarin.GooglePlayServices.Basement.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.GooglePlayServices.Drive">
<HintPath>..\packages\Xamarin.GooglePlayServices.Drive.27.0.0.0\lib\MonoAndroid41\Xamarin.GooglePlayServices.Drive.dll</HintPath>
<Private>True</Private>
<Reference Include="Xamarin.Kotlin.StdLib.Common, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Kotlin.StdLib.Common.1.3.50.1\lib\monoandroid90\Xamarin.Kotlin.StdLib.Common.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@@ -296,7 +163,7 @@
<Compile Include="EntryActivityClasses\ToggleVisibilityPopupMenuItem.cs" />
<Compile Include="EntryActivityClasses\WriteBinaryToFilePopupItem.cs" />
<Compile Include="FileSelectHelper.cs" />
<Compile Include="FingerprintModule.cs" />
<Compile Include="BiometricModule.cs" />
<Compile Include="FingerprintSamsungIdentifier.cs" />
<Compile Include="FingerprintSetupActivity.cs" />
<Compile Include="ExportDatabaseActivity.cs" />
@@ -315,6 +182,7 @@
<Compile Include="KpEntryTemplatedEdit.cs" />
<Compile Include="MeasuringRelativeLayout.cs" />
<Compile Include="NfcOtpActivity.cs" />
<Compile Include="NoSecureDisplayActivity.cs" />
<Compile Include="PasswordFont.cs" />
<Compile Include="pluginhost\PluginArrayAdapter.cs" />
<Compile Include="pluginhost\PluginDatabase.cs" />
@@ -758,7 +626,6 @@
<AndroidResource Include="Resources\drawable-mdpi-v4\ic_launcher.png" />
<AndroidResource Include="Resources\drawable-hdpi-v4\ic_launcher.png" />
<AndroidResource Include="Resources\drawable-xhdpi-v4\ic_launcher.png" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\ic99_blank.png" />
@@ -942,6 +809,10 @@
<Folder Include="SupportLib\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BiometricBinding\BiometricBinding.csproj">
<Project>{2b1de455-bf8e-4f8a-87be-ae7ea354f3e4}</Project>
<Name>BiometricBinding</Name>
</ProjectReference>
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj">
<Project>{48574278-4779-4B3A-A9E4-9CF1BC285D0B}</Project>
<Name>JavaFileStorageBindings</Name>
@@ -966,10 +837,6 @@
<Project>{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}</Project>
<Name>Kp2aKeyboardBinding</Name>
</ProjectReference>
<ProjectReference Include="..\netftpandroid\System.Net.FtpClient\System.Net.FtpClient.Android.csproj">
<Project>{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}</Project>
<Name>System.Net.FtpClient.Android</Name>
</ProjectReference>
<ProjectReference Include="..\PluginSdkBinding\PluginSdkBinding.csproj">
<Project>{3DA3911E-36DE-465E-8F15-F1991B6437E5}</Project>
<Name>PluginSdkBinding</Name>
@@ -2021,94 +1888,170 @@
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_storage_onedrive2.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\no_secure_display_layout.axml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentFTP">
<Version>27.1.3</Version>
</PackageReference>
<PackageReference Include="Microsoft.Bcl">
<Version>1.1.10</Version>
</PackageReference>
<PackageReference Include="Microsoft.Graph">
<Version>1.17.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.Graph.Auth">
<Version>1.0.0-preview.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.Identity.Client">
<Version>4.4.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Core.Common">
<Version>1.1.1.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Core.Runtime">
<Version>1.1.1.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.Common">
<Version>1.1.1.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.LiveData">
<Version>1.1.1.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.LiveData.Core">
<Version>1.1.1.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.Runtime">
<Version>1.1.1.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.ViewModel">
<Version>1.1.1.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Animated.Vector.Drawable">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Annotations">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.AsyncLayoutInflater">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Collections">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Compat">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CoordinaterLayout">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Core.UI">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Core.Utils">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CursorAdapter">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CustomTabs">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CustomView">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Design">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.DocumentFile">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.DrawerLayout">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Fragment">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Interpolator">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Loader">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.LocalBroadcastManager">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Media.Compat">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Print">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.SlidingPaneLayout">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.SwipeRefreshLayout">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Transition">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v13">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v4">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v7.CardView">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.VersionedParcelable">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.ViewPager">
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.Browser">
<Version>1.0.0-preview02</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.Legacy.Support.V13">
<Version>1.0.0-preview02</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.Migration">
<Version>1.0.0-preview05</Version>
</PackageReference>
<PackageReference Include="Xamarin.Build.Download">
<Version>0.4.2</Version>
</PackageReference>
<PackageReference Include="Xamarin.Google.Android.Material">
<Version>1.0.0-preview02</Version>
</PackageReference>
<PackageReference Include="Xamarin.GooglePlayServices.Drive">
<Version>27.0.0</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
<Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
</Target>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}".</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Xamarin.Build.Download.0.4.2\build\Xamarin.Build.Download.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Build.Download.0.4.2\build\Xamarin.Build.Download.props'))" />
<Error Condition="!Exists('..\packages\Xamarin.Build.Download.0.4.2\build\Xamarin.Build.Download.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Build.Download.0.4.2\build\Xamarin.Build.Download.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Annotations.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Annotations.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Annotations.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Annotations.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Arch.Core.Common.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Core.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Arch.Core.Common.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Core.Common.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Arch.Core.Runtime.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Core.Runtime.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Arch.Core.Runtime.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Core.Runtime.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Arch.Lifecycle.Common.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Arch.Lifecycle.Common.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.Common.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Arch.Lifecycle.LiveData.Core.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.LiveData.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Arch.Lifecycle.LiveData.Core.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.LiveData.Core.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Arch.Lifecycle.LiveData.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.LiveData.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Arch.Lifecycle.LiveData.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.LiveData.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Arch.Lifecycle.Runtime.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.Runtime.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Arch.Lifecycle.Runtime.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.Runtime.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Arch.Lifecycle.ViewModel.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.ViewModel.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Arch.Lifecycle.ViewModel.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.ViewModel.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Collections.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Collections.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Collections.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Collections.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.CursorAdapter.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.CursorAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.CursorAdapter.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.CursorAdapter.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.DocumentFile.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.DocumentFile.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.DocumentFile.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.DocumentFile.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Interpolator.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Interpolator.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Interpolator.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Interpolator.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.LocalBroadcastManager.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.LocalBroadcastManager.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.LocalBroadcastManager.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.LocalBroadcastManager.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Print.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Print.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Print.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Print.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.v7.CardView.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v7.CardView.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.v7.CardView.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v7.CardView.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.VersionedParcelable.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.VersionedParcelable.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.VersionedParcelable.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.VersionedParcelable.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Compat.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Compat.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Compat.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Compat.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.AsyncLayoutInflater.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.AsyncLayoutInflater.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.AsyncLayoutInflater.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.AsyncLayoutInflater.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.CustomView.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.CustomView.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.CustomView.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.CustomView.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.CoordinaterLayout.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.CoordinaterLayout.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.CoordinaterLayout.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.CoordinaterLayout.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.DrawerLayout.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.DrawerLayout.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.DrawerLayout.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.DrawerLayout.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Loader.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Loader.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Loader.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Loader.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Core.Utils.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Core.Utils.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Core.Utils.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Core.Utils.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Media.Compat.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Media.Compat.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Media.Compat.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Media.Compat.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.SlidingPaneLayout.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.SlidingPaneLayout.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.SlidingPaneLayout.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.SlidingPaneLayout.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.SwipeRefreshLayout.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.SwipeRefreshLayout.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.SwipeRefreshLayout.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.SwipeRefreshLayout.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Vector.Drawable.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Vector.Drawable.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Vector.Drawable.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Vector.Drawable.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.ViewPager.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.ViewPager.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.ViewPager.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.ViewPager.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Core.UI.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Core.UI.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Core.UI.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Core.UI.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Animated.Vector.Drawable.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Animated.Vector.Drawable.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.CustomTabs.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.CustomTabs.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.CustomTabs.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.CustomTabs.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Fragment.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Fragment.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Fragment.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Fragment.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Transition.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Transition.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Transition.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Transition.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.v4.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v4.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.v4.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v4.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.v13.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v13.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.v13.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v13.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.v7.AppCompat.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v7.AppCompat.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.v7.AppCompat.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v7.AppCompat.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.v7.RecyclerView.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v7.RecyclerView.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.v7.RecyclerView.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v7.RecyclerView.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Design.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Design.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Design.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Design.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Jetbrains.Annotations.13.0.0.1\build\monoandroid90\Xamarin.Jetbrains.Annotations.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Jetbrains.Annotations.13.0.0.1\build\monoandroid90\Xamarin.Jetbrains.Annotations.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Kotlin.StdLib.Common.1.3.50.1\build\monoandroid90\Xamarin.Kotlin.StdLib.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Kotlin.StdLib.Common.1.3.50.1\build\monoandroid90\Xamarin.Kotlin.StdLib.Common.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Kotlin.StdLib.1.3.50.1\build\monoandroid90\Xamarin.Kotlin.StdLib.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Kotlin.StdLib.1.3.50.1\build\monoandroid90\Xamarin.Kotlin.StdLib.targets'))" />
</Target>
<Import Project="..\packages\Xamarin.Build.Download.0.4.2\build\Xamarin.Build.Download.targets" Condition="Exists('..\packages\Xamarin.Build.Download.0.4.2\build\Xamarin.Build.Download.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Annotations.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Annotations.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Annotations.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Annotations.targets')" />
<Import Project="..\packages\Xamarin.Android.Arch.Core.Common.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Core.Common.targets" Condition="Exists('..\packages\Xamarin.Android.Arch.Core.Common.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Core.Common.targets')" />
<Import Project="..\packages\Xamarin.Android.Arch.Core.Runtime.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Core.Runtime.targets" Condition="Exists('..\packages\Xamarin.Android.Arch.Core.Runtime.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Core.Runtime.targets')" />
<Import Project="..\packages\Xamarin.Android.Arch.Lifecycle.Common.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.Common.targets" Condition="Exists('..\packages\Xamarin.Android.Arch.Lifecycle.Common.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.Common.targets')" />
<Import Project="..\packages\Xamarin.Android.Arch.Lifecycle.LiveData.Core.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.LiveData.Core.targets" Condition="Exists('..\packages\Xamarin.Android.Arch.Lifecycle.LiveData.Core.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.LiveData.Core.targets')" />
<Import Project="..\packages\Xamarin.Android.Arch.Lifecycle.LiveData.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.LiveData.targets" Condition="Exists('..\packages\Xamarin.Android.Arch.Lifecycle.LiveData.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.LiveData.targets')" />
<Import Project="..\packages\Xamarin.Android.Arch.Lifecycle.Runtime.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.Runtime.targets" Condition="Exists('..\packages\Xamarin.Android.Arch.Lifecycle.Runtime.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.Runtime.targets')" />
<Import Project="..\packages\Xamarin.Android.Arch.Lifecycle.ViewModel.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.ViewModel.targets" Condition="Exists('..\packages\Xamarin.Android.Arch.Lifecycle.ViewModel.1.1.1.1\build\monoandroid90\Xamarin.Android.Arch.Lifecycle.ViewModel.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Collections.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Collections.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Collections.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Collections.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.CursorAdapter.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.CursorAdapter.targets" Condition="Exists('..\packages\Xamarin.Android.Support.CursorAdapter.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.CursorAdapter.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.DocumentFile.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.DocumentFile.targets" Condition="Exists('..\packages\Xamarin.Android.Support.DocumentFile.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.DocumentFile.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Interpolator.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Interpolator.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Interpolator.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Interpolator.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.LocalBroadcastManager.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.LocalBroadcastManager.targets" Condition="Exists('..\packages\Xamarin.Android.Support.LocalBroadcastManager.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.LocalBroadcastManager.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Print.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Print.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Print.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Print.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.v7.CardView.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v7.CardView.targets" Condition="Exists('..\packages\Xamarin.Android.Support.v7.CardView.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v7.CardView.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.VersionedParcelable.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.VersionedParcelable.targets" Condition="Exists('..\packages\Xamarin.Android.Support.VersionedParcelable.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.VersionedParcelable.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Compat.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Compat.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Compat.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Compat.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.AsyncLayoutInflater.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.AsyncLayoutInflater.targets" Condition="Exists('..\packages\Xamarin.Android.Support.AsyncLayoutInflater.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.AsyncLayoutInflater.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.CustomView.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.CustomView.targets" Condition="Exists('..\packages\Xamarin.Android.Support.CustomView.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.CustomView.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.CoordinaterLayout.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.CoordinaterLayout.targets" Condition="Exists('..\packages\Xamarin.Android.Support.CoordinaterLayout.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.CoordinaterLayout.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.DrawerLayout.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.DrawerLayout.targets" Condition="Exists('..\packages\Xamarin.Android.Support.DrawerLayout.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.DrawerLayout.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Loader.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Loader.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Loader.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Loader.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Core.Utils.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Core.Utils.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Core.Utils.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Core.Utils.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Media.Compat.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Media.Compat.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Media.Compat.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Media.Compat.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.SlidingPaneLayout.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.SlidingPaneLayout.targets" Condition="Exists('..\packages\Xamarin.Android.Support.SlidingPaneLayout.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.SlidingPaneLayout.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.SwipeRefreshLayout.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.SwipeRefreshLayout.targets" Condition="Exists('..\packages\Xamarin.Android.Support.SwipeRefreshLayout.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.SwipeRefreshLayout.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Vector.Drawable.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Vector.Drawable.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Vector.Drawable.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Vector.Drawable.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.ViewPager.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.ViewPager.targets" Condition="Exists('..\packages\Xamarin.Android.Support.ViewPager.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.ViewPager.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Core.UI.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Core.UI.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Core.UI.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Core.UI.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Animated.Vector.Drawable.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Animated.Vector.Drawable.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.CustomTabs.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.CustomTabs.targets" Condition="Exists('..\packages\Xamarin.Android.Support.CustomTabs.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.CustomTabs.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Fragment.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Fragment.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Fragment.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Fragment.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Transition.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Transition.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Transition.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Transition.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.v4.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v4.targets" Condition="Exists('..\packages\Xamarin.Android.Support.v4.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v4.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.v13.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v13.targets" Condition="Exists('..\packages\Xamarin.Android.Support.v13.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v13.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.v7.AppCompat.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v7.AppCompat.targets" Condition="Exists('..\packages\Xamarin.Android.Support.v7.AppCompat.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v7.AppCompat.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.v7.RecyclerView.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v7.RecyclerView.targets" Condition="Exists('..\packages\Xamarin.Android.Support.v7.RecyclerView.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.v7.RecyclerView.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Design.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Design.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Design.28.0.0.1\build\monoandroid90\Xamarin.Android.Support.Design.targets')" />
<Import Project="..\packages\Xamarin.Jetbrains.Annotations.13.0.0.1\build\monoandroid90\Xamarin.Jetbrains.Annotations.targets" Condition="Exists('..\packages\Xamarin.Jetbrains.Annotations.13.0.0.1\build\monoandroid90\Xamarin.Jetbrains.Annotations.targets')" />
<Import Project="..\packages\Xamarin.Kotlin.StdLib.Common.1.3.50.1\build\monoandroid90\Xamarin.Kotlin.StdLib.Common.targets" Condition="Exists('..\packages\Xamarin.Kotlin.StdLib.Common.1.3.50.1\build\monoandroid90\Xamarin.Kotlin.StdLib.Common.targets')" />
<Import Project="..\packages\Xamarin.Kotlin.StdLib.1.3.50.1\build\monoandroid90\Xamarin.Kotlin.StdLib.targets" Condition="Exists('..\packages\Xamarin.Kotlin.StdLib.1.3.50.1\build\monoandroid90\Xamarin.Kotlin.StdLib.targets')" />
</Project>

View File

@@ -1,103 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="MonoAndroid60" />
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="MonoAndroid60" />
<package id="Microsoft.Graph" version="1.17.0" targetFramework="monoandroid90" />
<package id="Microsoft.Graph.Auth" version="1.0.0-preview.1" targetFramework="monoandroid90" />
<package id="Microsoft.Graph.Core" version="1.17.0" targetFramework="monoandroid90" />
<package id="Microsoft.Identity.Client" version="4.4.0" targetFramework="monoandroid90" />
<package id="Microsoft.NETCore.Platforms" version="1.1.1" targetFramework="monoandroid90" />
<package id="Microsoft.NETCore.Targets" version="1.1.3" targetFramework="monoandroid90" />
<package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="monoandroid90" />
<package id="NETStandard.Library" version="1.6.1" targetFramework="monoandroid90" />
<package id="Newtonsoft.Json" version="11.0.1" targetFramework="monoandroid90" />
<package id="System.AppContext" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Collections" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Collections.Concurrent" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Console" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Diagnostics.Tracing" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Globalization" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Globalization.Calendars" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.IO" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.IO.Compression" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.IO.Compression.ZipFile" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.IO.FileSystem" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Linq" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Linq.Expressions" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Net.Http" version="4.3.3" targetFramework="monoandroid90" />
<package id="System.Net.Primitives" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Net.Sockets" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.ObjectModel" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Private.Uri" version="4.3.2" targetFramework="monoandroid90" />
<package id="System.Reflection" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Reflection.Extensions" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Reflection.Primitives" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Runtime" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Runtime.Extensions" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Runtime.Handles" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Runtime.Numerics" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Security.Claims" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Security.Principal" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Security.SecureString" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Text.Encoding" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Text.RegularExpressions" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Threading" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Threading.Tasks" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Threading.Timer" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.ValueTuple" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="monoandroid90" />
<package id="System.Xml.XDocument" version="4.3.0" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Arch.Core.Common" version="1.1.1.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Arch.Core.Runtime" version="1.1.1.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Arch.Lifecycle.Common" version="1.1.1.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Arch.Lifecycle.LiveData" version="1.1.1.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Arch.Lifecycle.LiveData.Core" version="1.1.1.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Arch.Lifecycle.Runtime" version="1.1.1.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Arch.Lifecycle.ViewModel" version="1.1.1.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.Animated.Vector.Drawable" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.Annotations" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.AsyncLayoutInflater" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.Collections" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.Compat" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.CoordinaterLayout" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.Core.UI" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.Core.Utils" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.CursorAdapter" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.CustomTabs" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.CustomView" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.Design" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.DocumentFile" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.DrawerLayout" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.Fragment" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.Interpolator" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.Loader" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.LocalBroadcastManager" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.Media.Compat" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.Print" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.SlidingPaneLayout" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.SwipeRefreshLayout" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.Transition" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.v13" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.v4" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.v7.AppCompat" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.v7.CardView" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.v7.RecyclerView" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.Vector.Drawable" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.VersionedParcelable" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Android.Support.ViewPager" version="28.0.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Build.Download" version="0.4.2" targetFramework="monoandroid80" />
<package id="Xamarin.GooglePlayServices.Base" version="27.0.0.0" targetFramework="monoandroid80" />
<package id="Xamarin.GooglePlayServices.Basement" version="27.0.0.0" targetFramework="monoandroid80" />
<package id="Xamarin.GooglePlayServices.Drive" version="27.0.0.0" targetFramework="MonoAndroid50" />
</packages>

View File

@@ -84,11 +84,24 @@ namespace keepass2android.search
if (intent.Action == Intent.ActionView)
{
var entryIntent = new Intent(this, typeof(EntryActivity));
entryIntent.PutExtra(EntryActivity.KeyEntry, intent.Data.LastPathSegment);
entryIntent.AddFlags(ActivityFlags.ForwardResult);
Finish(); // Close this activity so that the entry activity is navigated to from the main activity, not this one.
StartActivity(entryIntent);
}
ElementAndDatabaseId id;
try
{
id = new ElementAndDatabaseId(intent.Data.LastPathSegment);
}
catch (Exception e)
{
Kp2aLog.Log("Failed to transform " + intent.Data.LastPathSegment + " to an ElementAndDatabaseId object. ");
Toast.MakeText(this, "Bad path passed. Please provide database and element ID.", ToastLength.Long).Show();
Finish();
return;
}
entryIntent.PutExtra(EntryActivity.KeyEntry, id.FullId);
entryIntent.AddFlags(ActivityFlags.ForwardResult);
Finish(); // Close this activity so that the entry activity is navigated to from the main activity, not this one.
StartActivity(entryIntent);
}
else
{
// Action may either by ActionSearch (from search widget) or null (if called from SearchActivity directly)

View File

@@ -16,7 +16,7 @@ using System.Linq;
namespace keepass2android.services.AutofillBase
{
public abstract class ChooseForAutofillActivityBase : AppCompatActivity
public abstract class ChooseForAutofillActivityBase : AndroidX.AppCompat.App.AppCompatActivity
{
protected Intent ReplyIntent;

View File

@@ -34,10 +34,10 @@ namespace keepass2android.services.AutofillBase
"org.mozilla.fenix","org.mozilla.fenix.nightly","org.mozilla.reference.browser",
"com.android.browser","com.android.chrome","com.chrome.beta","com.chrome.dev","com.chrome.canary",
"com.google.android.apps.chrome","com.google.android.apps.chrome_dev",
"com.opera.browser","com.opera.browser.beta","com.opera.mini.native",
"com.opera.browser","com.opera.browser.beta","com.opera.mini.native","com.opera.mini.native.beta","com.opera.touch",
"com.brave.browser","com.yandex.browser","com.microsoft.emmx","com.amazon.cloud9",
"com.sec.android.app.sbrowser","com.sec.android.app.sbrowser.beta","org.codeaurora.swe.browser",
"mark.via.gp","org.bromite.bromite", "org.mozilla.fennec_fdroid", "com.vivaldi.browser"
"mark.via.gp","org.bromite.bromite", "org.mozilla.fennec_fdroid", "com.vivaldi.browser","com.kiwibrowser.browser"
};
private bool IsTrustedBrowser(string packageName)

View File

@@ -36,6 +36,7 @@ using KeePassLib.Utility;
using Android.Views.InputMethods;
using KeePass.Util.Spr;
using KeePassLib.Serialization;
using PluginTOTP;
namespace keepass2android
{
@@ -61,6 +62,7 @@ namespace keepass2android
private bool _hasPassword;
private bool _hasUsername;
private bool _hasTotp;
private bool _hasKeyboard;
public void AddPasswordAccess()
@@ -72,6 +74,10 @@ namespace keepass2android
{
_hasUsername = true;
}
public void AddTotpAccess()
{
_hasTotp = true;
}
public void AddKeyboardAccess()
{
@@ -96,7 +102,7 @@ namespace keepass2android
private int CreateCombinedNotification(string entryName, Bitmap entryIcon)
{
if ((!_hasUsername) && (!_hasPassword) && (!_hasKeyboard))
if ((!_hasUsername) && (!_hasPassword) && (!_hasKeyboard) && (!_hasTotp))
return 0;
NotificationCompat.Builder notificationBuilder;
@@ -121,6 +127,10 @@ namespace keepass2android
notificationBuilder.AddAction(new NotificationCompat.Action(Resource.Drawable.ic_action_password,
_ctx.GetString(Resource.String.menu_copy_pass),
GetPendingIntent(Intents.CopyPassword, Resource.String.menu_copy_pass)));
if (_hasTotp)
notificationBuilder.AddAction(new NotificationCompat.Action(Resource.Drawable.ic_action_password,
_ctx.GetString(Resource.String.menu_copy_totp),
GetPendingIntent(Intents.CopyTotp, Resource.String.menu_copy_totp)));
notificationBuilder.SetPriority((int)Android.App.NotificationPriority.Max);
var notification = notificationBuilder.Build();
@@ -151,6 +161,15 @@ namespace keepass2android
_notificationManager.Notify(NotifyUsername, username);
numNotifications++;
}
if (_hasTotp)
{
// only show notification if totp is available
Notification totp = GetNotification(Intents.CopyTotp, Resource.String.copy_totp,
Resource.Drawable.ic_action_password, entryName, entryIcon);
totp.DeleteIntent = CreateDeleteIntent(NotifyTotp);
_notificationManager.Notify(NotifyTotp, totp);
numNotifications++;
}
if (_hasKeyboard)
{
// only show notification if username is available
@@ -222,6 +241,8 @@ namespace keepass2android
pending = PendingIntent.GetBroadcast(_ctx, descResId, intent, PendingIntentFlags.CancelCurrent);
return pending;
}
}
public const int NotifyUsername = 1;
@@ -229,6 +250,7 @@ namespace keepass2android
public const int NotifyKeyboard = 3;
public const int ClearClipboard = 4;
public const int NotifyCombined = 5;
public const int NotifyTotp = 6;
static public void CopyValueToClipboardWithTimeout(Context ctx, string text)
{
@@ -442,6 +464,10 @@ namespace keepass2android
{
notBuilder.AddUsernameAccess();
}
if (entry.OutputStrings.ReadSafe(UpdateTotpTimerTask.TotpKey).Length > 0)
{
notBuilder.AddTotpAccess();
}
}
bool hasKeyboardDataNow = false;
@@ -809,7 +835,9 @@ namespace keepass2android
}
if (mustUseHelperActivity)
{
StartActivity(typeof(SwitchImeActivity));
Intent switchImeIntent = new Intent(this, typeof(SwitchImeActivity));
switchImeIntent.SetFlags(ActivityFlags.NewTask);
StartActivity(switchImeIntent);
}
else
{
@@ -884,6 +912,15 @@ namespace keepass2android
}
context.SendBroadcast(new Intent(Intent.ActionCloseSystemDialogs)); //close notification drawer
}
else if (action.Equals(Intents.CopyTotp))
{
String totp = App.Kp2a.LastOpenedEntry.OutputStrings.ReadSafe(UpdateTotpTimerTask.TotpKey);
if (totp.Length > 0)
{
CopyToClipboardService.CopyValueToClipboardWithTimeout(context, totp);
}
context.SendBroadcast(new Intent(Intent.ActionCloseSystemDialogs)); //close notification drawer
}
else if (action.Equals(Intents.CheckKeyboard))
{
CopyToClipboardService.ActivateKeyboard(context);

View File

@@ -110,7 +110,7 @@ namespace keepass2android
SetContentView(Resource.Layout.preference);
SetSupportActionBar(FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.mytoolbar));
SetSupportActionBar(FindViewById<AndroidX.AppCompat.Widget.Toolbar>(Resource.Id.mytoolbar));
FragmentManager.FindFragmentById<SettingsFragment>(Resource.Id.settings_fragment).FindPreference(GetString(Resource.String.db_key)).Enabled = false;

View File

@@ -843,7 +843,7 @@ namespace keepass2android
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.preference);
SetSupportActionBar(FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.mytoolbar));
SetSupportActionBar(FindViewById<AndroidX.AppCompat.Widget.Toolbar>(Resource.Id.mytoolbar));
}