Compare commits

...

67 Commits

Author SHA1 Message Date
J-Jamet
b62106068b Solve compilation bug for fdroid 2017-12-13 18:55:32 +01:00
Jeremy
1218d89173 Solve preferences bugs 2017-12-12 02:57:53 +01:00
J-Jamet
37279af514 Change preferences as compat 2017-12-09 00:48:34 +01:00
J-Jamet
b45a8b5c94 Solve bug for fingerprint layout 2017-12-09 00:08:32 +01:00
J-Jamet
8a344170b3 Change description for rounds fix 2017-12-08 22:36:47 +01:00
J-Jamet
09f6498907 Solve settings style for API < 21 2017-12-08 21:04:02 +01:00
J-Jamet
57b8b9e53b Add features in Changelog 2017-12-08 21:03:33 +01:00
J-Jamet
8edb2c26d4 Merge branch 'upstream-update' 2.2.0.9 into develop #11 2017-12-08 20:30:26 +01:00
J-Jamet
7d7b34b2d0 Merge branch 'feature/EmptyPassword' into develop #2 2017-12-08 20:02:36 +01:00
J-Jamet
73765a7ecb Merge branch 'feature/FingerprintDialog' into develop #4 2017-12-08 19:18:26 +01:00
Jeremy
fb99c32708 Add fix for encryption rounds 2017-12-08 17:08:47 +01:00
Jeremy
6bb0b1a7e7 Add database lock for screen off 2017-12-08 15:53:25 +01:00
Jeremy
7a66c964a7 Add fingerprint setting for API < 23 2017-12-07 19:19:31 +01:00
Jeremy
a5b1535fb8 Add fingerprint setting 2017-12-07 15:57:16 +01:00
J-Jamet
05a5da4c8d Add fingerprint dialog and update icons 2017-12-06 22:28:25 +01:00
J-Jamet
f5314e0a9a Update ReadMe and screens 2017-12-05 21:14:54 +01:00
J-Jamet
332d1e0e06 Solve dialogs bugs (checkboxes) 2017-12-05 21:00:02 +01:00
Jeremy
9173c99928 Solve layout for selections 2017-12-04 21:28:44 +01:00
Jeremy
421bdae0d7 Solve select path bugs 2017-12-04 17:55:54 +01:00
Jeremy
421de6ea49 Add folder picker and solve asynctask 2017-12-04 04:39:52 +01:00
J-Jamet
ec2dd3db64 Add dialog to create database file 2017-12-03 16:45:40 +01:00
J-Jamet
e6cc9b628e New keyfile management 2017-12-01 20:03:22 +01:00
J-Jamet
7cce527e43 New workflow to assign master password 2017-12-01 18:24:20 +01:00
Jeremy
dd35fd508f Merge 2.2.0.9 into upstream-update 2017-11-30 22:40:34 +01:00
Brian Pellin
a7b5fd512a Version bump 2017-11-30 14:37:07 -06:00
Brian Pellin
45b03231dd Update build tools version 2017-11-30 14:34:20 -06:00
bpellin
85357e2168 Merge pull request #248 from pepeEL/patch-1
Update translation PL
2017-11-30 14:30:35 -06:00
bpellin
d6709254e2 Merge pull request #247 from bboa/master
Updated Russian strings.xml
2017-11-30 14:29:41 -06:00
J-Jamet
ef42dcd47f Change views and add checkboxes 2017-11-30 19:16:34 +01:00
J-Jamet
8536586c13 Solve settings title and change box by switch 2017-11-30 01:39:59 +01:00
J-Jamet
4794ccb38a Option to disable notifications #7 2017-11-30 01:32:16 +01:00
J-Jamet
d14dc22918 Solve layout password issue 2017-11-30 00:52:12 +01:00
J-Jamet
79084cee62 Merge branch 'develop' of repo 2017-11-30 00:39:23 +01:00
J-Jamet
f0ec9229cd Add visual representation of characters 2017-11-30 00:37:52 +01:00
J-Jamet
f6b04dff24 Password characters in settings 2017-11-30 00:19:26 +01:00
J-Jamet
b6721b32e7 Password length in settings #3 2017-11-29 20:42:01 +01:00
Jérémy JAMET
b1804a94b6 Update ReadMe.md 2017-11-29 20:41:22 +01:00
J-Jamet
f6bcd51cd3 Update gradle, .gitignore, add art screen and update readme 2017-11-29 20:41:22 +01:00
J-Jamet
a833dfe64a Remove unused libs and upgrade version 2017-11-29 20:41:22 +01:00
J-Jamet
87efd1daa4 Merge keepassdroid 2.2.0.8 and update changelog 2017-11-29 18:47:26 +01:00
J-Jamet
ecdd744b8e Merge keepassdroid 2.2.0.8 and update changelog 2017-11-29 18:46:46 +01:00
J-Jamet
9012fd6da6 Merge branch 'master' into develop 2017-11-28 01:27:31 +01:00
J-Jamet
c6a711dec5 Solve open file bug 2017-11-28 01:27:22 +01:00
pepeEL
9b1a0285c4 Update translation PL 2017-11-27 07:15:08 +01:00
Igor Nedoboy
fd6dd01ee7 Update strings.xml 2017-11-27 03:32:54 +03:00
Jérémy JAMET
bd10fe8542 Update ReadMe.md 2017-11-27 00:08:37 +01:00
J-Jamet
8333a80d88 Update gradle, .gitignore, add art screen and update readme 2017-11-27 00:07:08 +01:00
Brian Pellin
192f116925 Version bump 2017-11-25 23:45:25 -06:00
Brian Pellin
409ffd4f95 Fix UTF8 encoding 2017-11-25 23:42:24 -06:00
Brian Pellin
0add3c76c8 Add rounds corruption fix mode. 2017-11-25 23:42:21 -06:00
Brian Pellin
b4f9e06bd6 Version bump 2017-11-24 21:33:28 -06:00
Brian Pellin
c686ff7156 Fix kdbx4 attachments 2017-11-24 21:28:23 -06:00
Brian Pellin
da1370e7f5 Use the correct number of key encryption rounds on KDBX <4 2017-11-24 20:26:23 -06:00
Brian Pellin
c564253206 Use ACTION_GET_CONTENT when not using the storage access framework 2017-11-24 19:19:33 -06:00
Brian Pellin
3f22bf9e5c Updated Hungarian translations. 2017-11-24 19:18:06 -06:00
Brian Pellin
eae321d034 Add additional ndk abis 2017-11-21 20:59:07 -06:00
Brian Pellin
e2022183ea Version bump 2017-11-21 20:43:18 -06:00
Brian Pellin
924db245ec Make DateFormatter threadsafe 2017-11-21 20:40:55 -06:00
Brian Pellin
2dae805ac0 Only show fingerprint prompt on devices with fingerprint hardware 2017-11-21 20:39:40 -06:00
Brian Pellin
9ce0a413ad Update build file versions 2017-11-21 20:38:30 -06:00
Brian Pellin
1ece7b1df7 Version bump 2017-11-19 21:12:38 -06:00
Brian Pellin
b7aec355a2 Fingerprint fixes 2017-11-19 21:09:55 -06:00
Brian Pellin
780a0cd42d Version bump 2017-11-19 19:30:20 -06:00
Brian Pellin
de45421b50 Handle devices with unconfigured fingerprint sensors better 2017-11-19 19:27:47 -06:00
Brian Pellin
c11e17af05 Remove new APIs from fingerprint helper 2017-11-19 19:11:16 -06:00
Brian Pellin
260de4099b Fix crash on empty search results 2017-11-19 16:46:47 -06:00
J-Jamet
b8b106eb65 Remove unused libs and upgrade version 2017-11-18 16:28:29 +01:00
115 changed files with 4990 additions and 1245 deletions

15
.gitignore vendored
View File

@@ -6,6 +6,7 @@
# Built application files
*.apk
*.ap_
app/free_google/*
# Files for the ART/Dalvik VM
*.dex
@@ -39,7 +40,6 @@ captures/
# Intellij
*.iml
<<<<<<< HEAD
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
@@ -49,19 +49,16 @@ captures/
# Keystore files
# Uncomment the following line if you do not want to check your keystore files in.
#*.jks
=======
.idea/*
# Keystore files
*.jks
>>>>>>> master
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
# Google Services (e.g. APIs or Firebase)
google-services.json
<<<<<<< HEAD
# Freeline
freeline.py
@@ -70,5 +67,11 @@ freeline_project_description.json
# Iml Files
app/app.iml
=======
>>>>>>> master
# Art
art/screen*.png
art/logo_512.png
# Dir linux
.directory
*/.directory

View File

@@ -1,3 +1,17 @@
KeepassDX (2.5.0.0beta3)
* New database workflow with new screens and folder selection
* Settings for default password generation
* Fingerprint dialog for explanations
* Setting to disable fingerprint
* Directly opening kdbx file
* Setting to disable notifications
* Setting to lock database when screen is shut off
* Merge KeePassDroid 2.2.0.9
* Add corruption fix mode
KeepassDX (2.5.0.0beta2)
* Remove libs for F-Droid
KeepassDX (2.5.0.0beta1)
* Fork KeepassDroid
* Add Material Design
@@ -7,6 +21,33 @@ KeepassDX (2.5.0.0beta1)
* Update French translation
* Change donation (see KeepassDroid to contribute on both projects)
KeePassDroid (2.2.0.9)
* Update build tools version to workaround CM/Lineage bug (closes: #249)
* Update Russian translations
* Update Polish translations
KeePassDroid (2.2.0.8)
* Add corruption fix mode
* Update Hungarian translations
KeePassDroid (2.2.0.7)
* Fix KDBX3 encryption rounds corruption
* Fix KDBX4 attachement crashes
KeePassDroid (2.2.0.6)
* Add additional ndk ABIs
KeePassDroid (2.2.0.5)
* Don't show fingerprint prompt on devices without fingerprint hardware
* Fix dateformat crashes
KeePassDroid (2.2.0.4)
* Fingerprint fixes
KeePassDroid (2.2.0.3)
* Search crash fix
* Improve fingerprint handling
KeePassDroid (2.2.0.2)
* Fix non fingerprint password layout

View File

@@ -14,7 +14,7 @@ Tadashi Saito
vhschlenker
bumper314 - Samsung multiwindow support
Hans Cappelle - fingerprint sensor integration
Jeremy Jamet - Material Design - Patches
Jeremy Jamet - Keepass DX Material Design - Patches
Translations:
Diego Pierotto - Italian
@@ -30,7 +30,7 @@ Matsuu Takuto - Japanese
Carlos Schlyter - Portugese (Brazil)
YSmhXQDd6Z - Portugese (Portugal)
andriykopanytsia - Ukranian
intel - Hungarian
intel, Zoltán Antal - Hungarian
H Vanek - Czech
jipanos - Spanish
Erik Fdevriendt, Erik Jan Meijer - Dutch

View File

@@ -4,13 +4,14 @@
### Features
- Create database file / entries and groups
- Simplified creation of the database file
- Create entries and groups
- Open database, copy username / password, open URI / URL
- Fingerprint for fast unlocking
- Material design with themes
- Device integration and AutoFill (In progress)
<img src="https://raw.githubusercontent.com/Kunzisoft/KeePassDX/master/art/screen0.jpg" width="220">
<img src="https://raw.githubusercontent.com/Kunzisoft/KeePassDX/master/art/screen1.jpg" width="220">
<img src="https://raw.githubusercontent.com/Kunzisoft/KeePassDX/master/art/screen2.jpg" width="220">
## What is KeePass?
@@ -27,13 +28,23 @@ Yes, KeePass is really free, and more than that: it is open source (OSI certifie
Even if the application is free, to maintain the application, you can make donations.
[![Donation Paypal](https://4.bp.blogspot.com/-ncaIbUGaHOk/WfhaThYUPGI/AAAAAAAAAVQ/_HidNgdB1q4DaC24ujaKNzH64KUUJiQewCLcBGAs/s1600/pay-with-paypal.png "")](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KM6QMDAXZM3UU "Kunzisoft Paypal Donation")
[![Donation Paypal](https://4.bp.blogspot.com/-ncaIbUGaHOk/WfhaThYUPGI/AAAAAAAAAVQ/_HidNgdB1q4DaC24ujaKNzH64KUUJiQewCLcBGAs/s1600/pay-with-paypal.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KM6QMDAXZM3UU "Kunzisoft Paypal Donation")
[![Donation Liberapay](https://liberapay.com/assets/widgets/donate.svg "")](https://liberapay.com/Kunzisoft/donate "Kunzisoft Liberapay Donation")
[![Donation Liberapay](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/Kunzisoft/donate "Kunzisoft Liberapay Donation")
<img src="https://raw.githubusercontent.com/Kunzisoft/KeePassDX/master/art/screen4.jpg" width="220">
<img src="https://raw.githubusercontent.com/Kunzisoft/KeePassDX/master/art/screen5.jpg" width="220">
## Download
[<img src="https://f-droid.org/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/en/packages/com.kunzisoft.keepass.libre/)
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
alt="Get it on Google Play"
height="80">](https://play.google.com/store/apps/details?id=com.kunzisoft.keepass.free)
### JNI
Native library build instructions:

View File

@@ -2,17 +2,22 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion = 25
buildToolsVersion = "26.0.2"
buildToolsVersion = "27.0.1"
defaultConfig {
applicationId "com.kunzisoft.keepass"
minSdkVersion 14
targetSdkVersion 25
versionCode = 1
versionName = "2.5.0.0beta1"
versionCode = 3
versionName = "2.5.0.0beta3"
testApplicationId = "com.keepassdroid.tests"
testInstrumentationRunner = "android.test.InstrumentationTestRunner"
ndk {
abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a',
'arm64-v8a', 'mips', 'mips64'
}
}
externalNativeBuild {
@@ -21,6 +26,7 @@ android {
}
}
buildTypes {
release {
minifyEnabled = false
@@ -58,12 +64,15 @@ def supportVersion = "25.4.0"
def spongycastleVersion = "1.58.0.0"
dependencies {
androidTestCompile files('libs/junit4.jar')
androidTestCompile "junit:junit:4.12"
compile "com.android.support:appcompat-v7:$supportVersion"
compile "com.android.support:design:$supportVersion"
compile "com.android.support:preference-v7:$supportVersion"
compile "com.android.support:preference-v14:$supportVersion"
compile "com.android.support:cardview-v7:$supportVersion"
compile "com.madgag.spongycastle:core:$spongycastleVersion"
compile "com.madgag.spongycastle:prov:$spongycastleVersion"
compile "joda-time:joda-time:2.9.9"
compile "org.sufficientlysecure:html-textview:3.5"
compile "com.nononsenseapps:filepicker:4.1.0"
}

Binary file not shown.

Binary file not shown.

View File

@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kunzisoft.keepass"
android:installLocation="auto">
xmlns:tools="http://schemas.android.com/tools"
package="com.kunzisoft.keepass"
android:installLocation="auto">
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
@@ -19,10 +20,31 @@
android:allowBackup="true"
android:fullBackupContent="@xml/backup"
android:backupAgent="com.keepassdroid.backup.SettingsBackupAgent"
android:theme="@style/KeepassDXStyle.Light">
android:theme="@style/KeepassDXStyle.Light"
tools:replace="android:theme">
<!-- TODO backup API Key -->
<meta-data android:name="com.google.android.backup.api_key"
android:value="" />
<!-- Folder picker -->
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/nnf_provider_paths" />
</provider>
<activity
android:name="com.keepassdroid.FilePickerStylishActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".KeePass"
android:label="@string/app_name">
<intent-filter>
@@ -41,7 +63,8 @@
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:mimeType="*/*" />
<data android:scheme="content" />
<data android:mimeType="application/octet-stream" />
<data android:host="*" />
<data android:pathPattern=".*\\.kdb" />
<data android:pathPattern=".*\\..*\\.kdb" />
@@ -66,14 +89,10 @@
</intent-filter>
</activity>
<activity android:name="com.keepassdroid.GroupActivityV3" android:configChanges="orientation|keyboardHidden">
<!-- This metadata entry causes .app.SearchQueryResults to be the default context -->
<!-- whenever the user invokes search while in this Activity. -->
<meta-data android:name="android.app.default_searchable"
android:value="com.keepassdroid.search.SearchResults" />
</activity>
<activity android:name="com.keepassdroid.GroupActivityV4" android:configChanges="orientation|keyboardHidden">
<!-- This metadata entry causes .app.SearchQueryResults to be the default context -->
<!-- whenever the user invokes search while in this Activity. -->
<meta-data android:name="android.app.default_searchable"
android:value="com.keepassdroid.search.SearchResults"
android:exported="false" />

View File

@@ -0,0 +1,274 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.TextView;
import android.widget.Toast;
import com.keepassdroid.utils.EmptyUtils;
import com.keepassdroid.utils.UriUtil;
import com.keepassdroid.view.KeyFileHelper;
import com.kunzisoft.keepass.R;
public class AssignMasterKeyDialog extends DialogFragment {
private String masterPassword;
private Uri mKeyfile;
private View rootView;
private CompoundButton passwordCheckBox;
private TextView passView;
private TextView passConfView;
private CompoundButton keyfileCheckBox;
private TextView keyfileView;
private AssignPasswordDialogListener mListener;
private KeyFileHelper keyFileHelper;
public interface AssignPasswordDialogListener {
void onAssignKeyDialogPositiveClick(boolean masterPasswordChecked, String masterPassword,
boolean keyFileChecked, Uri keyFile);
void onAssignKeyDialogNegativeClick(boolean masterPasswordChecked, String masterPassword,
boolean keyFileChecked, Uri keyFile);
}
@Override
public void onAttach(Context activity) {
super.onAttach(activity);
try {
mListener = (AssignPasswordDialogListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement " + AssignPasswordDialogListener.class.getName());
}
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
rootView = inflater.inflate(R.layout.set_password, null);
builder.setView(rootView)
.setTitle(R.string.assign_master_key)
// Add action buttons
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
}
});
passwordCheckBox = (CompoundButton) rootView.findViewById(R.id.password_checkbox);
passView = (TextView) rootView.findViewById(R.id.pass_password);
passView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void afterTextChanged(Editable editable) {
passwordCheckBox.setChecked(true);
}
});
passConfView = (TextView) rootView.findViewById(R.id.pass_conf_password);
keyfileCheckBox = (CompoundButton) rootView.findViewById(R.id.keyfile_checkox);
keyfileView = (TextView) rootView.findViewById(R.id.pass_keyfile);
keyfileView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void afterTextChanged(Editable editable) {
keyfileCheckBox.setChecked(true);
}
});
keyFileHelper = new KeyFileHelper(this);
rootView.findViewById(R.id.browse_button)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
keyFileHelper.getOpenFileOnClickViewListener().onClick(view);
}
});
AlertDialog dialog = builder.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(final DialogInterface dialog) {
Button positiveButton = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE);
positiveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
masterPassword = "";
mKeyfile = null;
boolean error = verifyPassword() || verifyFile();
if (!passwordCheckBox.isChecked() && !keyfileCheckBox.isChecked()) {
error = true;
showNoKeyConfirmationDialog();
}
if (!error) {
mListener.onAssignKeyDialogPositiveClick(
passwordCheckBox.isChecked(), masterPassword,
keyfileCheckBox.isChecked(), mKeyfile);
dismiss();
}
}
});
Button negativeButton = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_NEGATIVE);
negativeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
mListener.onAssignKeyDialogNegativeClick(
passwordCheckBox.isChecked(), masterPassword,
keyfileCheckBox.isChecked(), mKeyfile);
dismiss();
}
});
}
});
return dialog;
}
private boolean verifyPassword() {
boolean error = false;
if (passwordCheckBox.isChecked()) {
masterPassword = passView.getText().toString();
String confpass = passConfView.getText().toString();
// Verify that passwords match
if (!masterPassword.equals(confpass)) {
error = true;
// Passwords do not match
Toast.makeText(getContext(), R.string.error_pass_match, Toast.LENGTH_LONG).show();
}
if (masterPassword == null || masterPassword.isEmpty()) {
error = true;
showEmptyPasswordConfirmationDialog();
}
}
return error;
}
private boolean verifyFile() {
boolean error = false;
if (keyfileCheckBox.isChecked()) {
Uri keyfile = UriUtil.parseDefaultFile(keyfileView.getText().toString());
mKeyfile = keyfile;
// Verify that a keyfile is set
if (EmptyUtils.isNullOrEmpty(keyfile)) {
error = true;
Toast.makeText(getContext(), R.string.error_nokeyfile, Toast.LENGTH_LONG).show();
}
}
return error;
}
private void showEmptyPasswordConfirmationDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(R.string.warning_empty_password)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
if (!verifyFile()) {
mListener.onAssignKeyDialogPositiveClick(
passwordCheckBox.isChecked(), masterPassword,
keyfileCheckBox.isChecked(), mKeyfile);
AssignMasterKeyDialog.this.dismiss();
}
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {}
});
builder.create().show();
}
private void showNoKeyConfirmationDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(R.string.warning_no_encryption_key)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
mListener.onAssignKeyDialogPositiveClick(
passwordCheckBox.isChecked(), masterPassword,
keyfileCheckBox.isChecked(), mKeyfile);
AssignMasterKeyDialog.this.dismiss();
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {}
});
builder.create().show();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
keyFileHelper.onActivityResultCallback(requestCode, resultCode, data,
new KeyFileHelper.KeyFileCallback() {
@Override
public void onKeyFileResultCallback(Uri uri) {
if(uri != null) {
Uri pathString = UriUtil.parseDefaultFile(uri.toString());
if (pathString != null) {
keyfileCheckBox.setChecked(true);
keyfileView.setText(pathString.toString());
}
}
}
});
}
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid;
import android.app.Dialog;
import android.content.Context;
public class CancelDialog extends Dialog {
private boolean mCanceled = false;
public CancelDialog(Context context) {
super(context);
}
public boolean canceled() {
return mCanceled;
}
@Override
public void cancel() {
super.cancel();
mCanceled = true;
}
}

View File

@@ -0,0 +1,182 @@
/*
* Copyright 2017 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import com.keepassdroid.utils.UriUtil;
import com.kunzisoft.keepass.R;
import com.nononsenseapps.filepicker.FilePickerActivity;
import com.nononsenseapps.filepicker.Utils;
import java.io.File;
public class CreateFileDialog extends DialogFragment implements AdapterView.OnItemSelectedListener{
private final int FILE_CODE = 3853;
private EditText folderPathView;
private EditText fileNameView;
private DefinePathDialogListener mListener;
private String extension;
private Uri uriPath;
public interface DefinePathDialogListener {
boolean onDefinePathDialogPositiveClick(Uri pathFile);
boolean onDefinePathDialogNegativeClick(Uri pathFile);
}
@Override
public void onAttach(Context activity) {
super.onAttach(activity);
try {
mListener = (DefinePathDialogListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement " + DefinePathDialogListener.class.getName());
}
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View rootView = inflater.inflate(R.layout.file_creation, null);
builder.setView(rootView)
.setTitle(R.string.create_keepass_file)
// Add action buttons
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {}
});
// Folder selection
View browseView = rootView.findViewById(R.id.browse_button);
folderPathView = (EditText) rootView.findViewById(R.id.folder_path);
fileNameView = (EditText) rootView.findViewById(R.id.filename);
String defaultPath = Environment.getExternalStorageDirectory().getPath()
+ getString(R.string.database_file_path_default);
folderPathView.setText(defaultPath);
browseView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(getContext(), FilePickerStylishActivity.class);
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false);
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true);
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR);
i.putExtra(FilePickerActivity.EXTRA_START_PATH,
Environment.getExternalStorageDirectory().getPath());
startActivityForResult(i, FILE_CODE);
}
});
// Init path
uriPath = null;
// Extension
extension = getString(R.string.database_file_extension_default);
Spinner spinner = (Spinner) rootView.findViewById(R.id.file_types);
spinner.setOnItemSelectedListener(this);
// Spinner Drop down elements
String[] fileTypes = getResources().getStringArray(R.array.file_types);
ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_item, fileTypes);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(dataAdapter);
AlertDialog dialog = builder.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(final DialogInterface dialog) {
Button positiveButton = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE);
positiveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
if(mListener.onDefinePathDialogPositiveClick(buildPath()))
CreateFileDialog.this.dismiss();
}
});
Button negativeButton = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_NEGATIVE);
negativeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
if(mListener.onDefinePathDialogNegativeClick(buildPath()))
CreateFileDialog.this.dismiss();
}
});
}
});
return dialog;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == FILE_CODE && resultCode == Activity.RESULT_OK) {
uriPath = data.getData();
if (uriPath != null) {
File file = Utils.getFileForUri(uriPath);
folderPathView.setText(file.getPath());
}
}
}
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
extension = adapterView.getItemAtPosition(position).toString();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
// Do nothing
}
private Uri buildPath() {
Uri path = new Uri.Builder().path(folderPathView.getText().toString())
.appendPath(fileNameView.getText().toString() + extension)
.build();
path = UriUtil.translate(getContext(), path);
return path;
}
}

View File

@@ -19,9 +19,29 @@
*/
package com.keepassdroid;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.util.Log;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.PwDatabaseV3;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.exception.ContentFileNotFoundException;
import com.keepassdroid.database.exception.InvalidDBException;
import com.keepassdroid.database.exception.InvalidPasswordException;
import com.keepassdroid.database.exception.PwDbOutputException;
import com.keepassdroid.database.load.Importer;
import com.keepassdroid.database.load.ImporterFactory;
import com.keepassdroid.database.save.PwDbOutput;
import com.keepassdroid.icons.DrawableFactory;
import com.keepassdroid.search.SearchDbHelper;
import com.keepassdroid.utils.UriUtil;
import com.kunzisoft.keepass.R;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -31,24 +51,6 @@ import java.io.SyncFailedException;
import java.util.HashSet;
import java.util.Set;
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
import android.util.Log;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.PwDatabaseV3;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.exception.ContentFileNotFoundException;
import com.keepassdroid.database.exception.InvalidDBException;
import com.keepassdroid.database.exception.PwDbOutputException;
import com.keepassdroid.database.load.Importer;
import com.keepassdroid.database.load.ImporterFactory;
import com.keepassdroid.database.save.PwDbOutput;
import com.keepassdroid.icons.DrawableFactory;
import com.keepassdroid.search.SearchDbHelper;
import com.keepassdroid.utils.UriUtil;
/**
* @author bpellin
*/
@@ -92,6 +94,26 @@ public class Database {
readOnly = !file.canWrite();
}
try {
passUrisAsInputStreams(ctx, uri, password, keyfile, status, debug, 0);
} catch (InvalidPasswordException e) {
// Retry with rounds fix
try {
passUrisAsInputStreams(ctx, uri, password, keyfile, status, debug, getFixRounds(ctx));
} catch (Exception e2) {
// Rethrow original exception
throw e;
}
}
}
private long getFixRounds(Context ctx) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
return prefs.getLong(ctx.getString(R.string.roundsFix_key), ctx.getResources().getInteger(R.integer.roundsFix_default));
}
private void passUrisAsInputStreams(Context ctx, Uri uri, String password, Uri keyfile, UpdateStatus status, boolean debug, long roundsFix) throws IOException, FileNotFoundException, InvalidDBException {
InputStream is, kfIs;
try {
is = UriUtil.getUriInputStream(ctx, uri);
@@ -106,7 +128,7 @@ public class Database {
Log.e("KPD", "Database::LoadData", e);
throw ContentFileNotFoundException.getInstance(keyfile);
}
LoadData(ctx, is, password, kfIs, status, debug);
LoadData(ctx, is, password, kfIs, status, debug, roundsFix);
}
public void LoadData(Context ctx, InputStream is, String password, InputStream kfIs, boolean debug) throws IOException, InvalidDBException {
@@ -114,6 +136,10 @@ public class Database {
}
public void LoadData(Context ctx, InputStream is, String password, InputStream kfIs, UpdateStatus status, boolean debug) throws IOException, InvalidDBException {
LoadData(ctx, is, password, kfIs, status, debug, 0);
}
public void LoadData(Context ctx, InputStream is, String password, InputStream kfIs, UpdateStatus status, boolean debug, long roundsFix) throws IOException, InvalidDBException {
BufferedInputStream bis = new BufferedInputStream(is);
if ( ! bis.markSupported() ) {
@@ -127,7 +153,7 @@ public class Database {
bis.reset(); // Return to the start
pm = imp.openDatabase(bis, password, kfIs, status);
pm = imp.openDatabase(bis, password, kfIs, status, roundsFix);
if ( pm != null ) {
PwGroup root = pm.rootGroup;
pm.populateGlobals(root);

View File

@@ -69,6 +69,8 @@ import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
import static com.keepassdroid.settings.PrefsUtil.isClipboardNotificationsEnable;
public class EntryActivity extends LockCloseHideActivity {
public static final String KEY_ENTRY = "entry";
public static final String KEY_REFRESH_POS = "refresh_pos";
@@ -153,7 +155,6 @@ public class EntryActivity extends LockCloseHideActivity {
Intent i = getIntent();
UUID uuid = Types.bytestoUUID(i.getByteArrayExtra(KEY_ENTRY));
mPos = i.getIntExtra(KEY_REFRESH_POS, -1);
assert(uuid != null);
mEntry = db.pm.entries.get(uuid);
if (mEntry == null) {
@@ -171,37 +172,41 @@ public class EntryActivity extends LockCloseHideActivity {
fillData(false);
setupEditButtons();
// Notification Manager
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if ( mEntry.getPassword().length() > 0 ) {
// only show notification if password is available
Notification password = getNotification(Intents.COPY_PASSWORD, R.string.copy_password);
mNM.notify(NOTIFY_PASSWORD, password);
}
if ( mEntry.getUsername().length() > 0 ) {
// only show notification if username is available
Notification username = getNotification(Intents.COPY_USERNAME, R.string.copy_username);
mNM.notify(NOTIFY_USERNAME, username);
}
// If notifications enabled in settings
if (isClipboardNotificationsEnable(getApplicationContext())) {
// Notification Manager
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (mEntry.getPassword().length() > 0) {
// only show notification if password is available
Notification password = getNotification(Intents.COPY_PASSWORD, R.string.copy_password);
mNM.notify(NOTIFY_PASSWORD, password);
}
if (mEntry.getUsername().length() > 0) {
// only show notification if username is available
Notification username = getNotification(Intents.COPY_USERNAME, R.string.copy_username);
mNM.notify(NOTIFY_USERNAME, username);
}
}
mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if ( action.equals(Intents.COPY_USERNAME) ) {
String username = mEntry.getUsername();
if ( username.length() > 0 ) {
timeoutCopyToClipboard(username);
}
} else if ( action.equals(Intents.COPY_PASSWORD) ) {
String password = new String(mEntry.getPassword());
if ( password.length() > 0 ) {
timeoutCopyToClipboard(new String(mEntry.getPassword()));
if ( action != null) {
if (action.equals(Intents.COPY_USERNAME)) {
String username = mEntry.getUsername();
if (username.length() > 0) {
timeoutCopyToClipboard(username);
}
} else if (action.equals(Intents.COPY_PASSWORD)) {
String password = mEntry.getPassword();
if (password.length() > 0) {
timeoutCopyToClipboard(password);
}
}
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2017 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.StyleRes;
import android.util.Log;
import com.keepassdroid.stylish.Stylish;
import com.kunzisoft.keepass.R;
import com.nononsenseapps.filepicker.FilePickerActivity;
public class FilePickerStylishActivity extends FilePickerActivity {
private @StyleRes
int themeId;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
this.themeId = FilePickerStylish.getThemeId(this);
setTheme(themeId);
super.onCreate(savedInstanceState);
}
@Override
protected void onResume() {
super.onResume();
if(FilePickerStylish.getThemeId(this) != this.themeId) {
Log.d(this.getClass().getName(), "Theme change detected, restarting activity");
this.recreate();
}
}
public static class FilePickerStylish extends Stylish {
public static @StyleRes int getThemeId(Context context) {
if (themeString.equals(context.getString(R.string.list_style_name_night)))
return R.style.KeepassDXStyle_FilePickerStyle_Night;
return R.style.KeepassDXStyle_FilePickerStyle_Light;
}
}
}

View File

@@ -30,13 +30,16 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.Toast;
import com.kunzisoft.keepass.R;
import com.keepassdroid.password.PasswordGenerator;
import com.keepassdroid.settings.PrefsUtil;
import com.kunzisoft.keepass.R;
import java.util.Set;
public class GeneratePasswordFragment extends DialogFragment {
@@ -46,6 +49,15 @@ public class GeneratePasswordFragment extends DialogFragment {
private View root;
private EditText lengthTextView;
private CompoundButton uppercaseBox;
private CompoundButton lowercaseBox;
private CompoundButton digitsBox;
private CompoundButton minusBox;
private CompoundButton underlineBox;
private CompoundButton spaceBox;
private CompoundButton specialsBox;
private CompoundButton bracketsBox;
@Override
public void onAttach(Context context) {
super.onAttach(context);
@@ -66,6 +78,17 @@ public class GeneratePasswordFragment extends DialogFragment {
lengthTextView = (EditText) root.findViewById(R.id.length);
uppercaseBox = (CompoundButton) root.findViewById(R.id.cb_uppercase);
lowercaseBox = (CompoundButton) root.findViewById(R.id.cb_lowercase);
digitsBox = (CompoundButton) root.findViewById(R.id.cb_digits);
minusBox = (CompoundButton) root.findViewById(R.id.cb_minus);
underlineBox = (CompoundButton) root.findViewById(R.id.cb_underline);
spaceBox = (CompoundButton) root.findViewById(R.id.cb_space);
specialsBox = (CompoundButton) root.findViewById(R.id.cb_specials);
bracketsBox = (CompoundButton) root.findViewById(R.id.cb_brackets);
assignDefaultCharacters();
SeekBar seekBar = (SeekBar) root.findViewById(R.id.seekbar_length);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
@@ -79,6 +102,7 @@ public class GeneratePasswordFragment extends DialogFragment {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
seekBar.setProgress(PrefsUtil.getDefaultPasswordLength(getContext().getApplicationContext()));
Button genPassButton = (Button) root.findViewById(R.id.generate_password_button);
genPassButton.setOnClickListener(new OnClickListener() {
@@ -113,6 +137,46 @@ public class GeneratePasswordFragment extends DialogFragment {
return builder.create();
}
private void assignDefaultCharacters() {
uppercaseBox.setChecked(false);
lowercaseBox.setChecked(false);
digitsBox.setChecked(false);
minusBox.setChecked(false);
underlineBox.setChecked(false);
spaceBox.setChecked(false);
specialsBox.setChecked(false);
bracketsBox.setChecked(false);
Set<String> defaultPasswordChars =
PrefsUtil.getDefaultPasswordCharacters(getContext().getApplicationContext());
for(String passwordChar : defaultPasswordChars) {
if (passwordChar.equals(getString(R.string.value_password_uppercase))) {
uppercaseBox.setChecked(true);
}
else if (passwordChar.equals(getString(R.string.value_password_lowercase))) {
lowercaseBox.setChecked(true);
}
else if (passwordChar.equals(getString(R.string.value_password_digits))) {
digitsBox.setChecked(true);
}
else if (passwordChar.equals(getString(R.string.value_password_minus))) {
minusBox.setChecked(true);
}
else if (passwordChar.equals(getString(R.string.value_password_underline))) {
underlineBox.setChecked(true);
}
else if (passwordChar.equals(getString(R.string.value_password_space))) {
spaceBox.setChecked(true);
}
else if (passwordChar.equals(getString(R.string.value_password_special))) {
specialsBox.setChecked(true);
}
else if (passwordChar.equals(getString(R.string.value_password_brackets))) {
bracketsBox.setChecked(true);
}
}
}
private void fillPassword() {
EditText txtPassword = (EditText) root.findViewById(R.id.password);
@@ -121,23 +185,19 @@ public class GeneratePasswordFragment extends DialogFragment {
public String generatePassword() {
String password = "";
try {
int length = Integer.valueOf(((EditText) root.findViewById(R.id.length)).getText().toString());
((CheckBox) root.findViewById(R.id.cb_uppercase)).isChecked();
PasswordGenerator generator = new PasswordGenerator(getActivity());
password = generator.generatePassword(length,
((CheckBox) root.findViewById(R.id.cb_uppercase)).isChecked(),
((CheckBox) root.findViewById(R.id.cb_lowercase)).isChecked(),
((CheckBox) root.findViewById(R.id.cb_digits)).isChecked(),
((CheckBox) root.findViewById(R.id.cb_minus)).isChecked(),
((CheckBox) root.findViewById(R.id.cb_underline)).isChecked(),
((CheckBox) root.findViewById(R.id.cb_space)).isChecked(),
((CheckBox) root.findViewById(R.id.cb_specials)).isChecked(),
((CheckBox) root.findViewById(R.id.cb_brackets)).isChecked());
uppercaseBox.isChecked(),
lowercaseBox.isChecked(),
digitsBox.isChecked(),
minusBox.isChecked(),
underlineBox.isChecked(),
spaceBox.isChecked(),
specialsBox.isChecked(),
bracketsBox.isChecked());
} catch (NumberFormatException e) {
Toast.makeText(getContext(), R.string.error_wrong_length, Toast.LENGTH_LONG).show();
} catch (IllegalArgumentException e) {

View File

@@ -25,6 +25,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
@@ -40,8 +41,6 @@ import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import com.kunzisoft.keepass.KeePass;
import com.kunzisoft.keepass.R;
import com.keepassdroid.app.App;
import com.keepassdroid.compat.ActivityCompat;
import com.keepassdroid.compat.EditorCompat;
@@ -49,10 +48,14 @@ import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.edit.OnFinish;
import com.keepassdroid.search.SearchResultsActivity;
import com.keepassdroid.utils.MenuUtil;
import com.keepassdroid.view.AssignPasswordHelper;
import com.keepassdroid.view.ClickView;
import com.keepassdroid.view.GroupViewOnlyView;
import com.kunzisoft.keepass.KeePass;
import com.kunzisoft.keepass.R;
public abstract class GroupBaseActivity extends LockCloseListActivity {
public abstract class GroupBaseActivity extends LockCloseListActivity
implements AssignMasterKeyDialog.AssignPasswordDialogListener {
protected ListView mList;
protected ListAdapter mAdapter;
@@ -148,14 +151,15 @@ public abstract class GroupBaseActivity extends LockCloseListActivity {
private void ensureCorrectListView(){
mList = (ListView)findViewById(R.id.group_list);
mList.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id)
{
onListItemClick((ListView)parent, v, position, id);
if (mList != null) {
mList.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
onListItemClick((ListView) parent, v, position, id);
}
}
}
);
);
}
}
@Override
@@ -265,8 +269,26 @@ public abstract class GroupBaseActivity extends LockCloseListActivity {
}
@Override
public void onAssignKeyDialogPositiveClick(
boolean masterPasswordChecked, String masterPassword,
boolean keyFileChecked, Uri keyFile) {
AssignPasswordHelper assignPasswordHelper =
new AssignPasswordHelper(this,
masterPassword, keyFile);
assignPasswordHelper.assignPasswordInDatabase(null);
}
@Override
public void onAssignKeyDialogNegativeClick(
boolean masterPasswordChecked, String masterPassword,
boolean keyFileChecked, Uri keyFile) {
}
private void setPassword() {
SetPasswordDialog dialog = new SetPasswordDialog();
AssignMasterKeyDialog dialog = new AssignMasterKeyDialog();
dialog.show(getSupportFragmentManager(), "passwordDialog");
}

View File

@@ -22,26 +22,8 @@ package com.keepassdroid;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import com.kunzisoft.keepass.KeePass;
import com.keepassdroid.app.App;
public abstract class LockCloseActivity extends LockingActivity {
@Override
protected void onResume() {
super.onResume();
checkShutdown();
}
private void checkShutdown() {
if ( App.isShutdown() && App.getDB().Loaded() ) {
setResult(KeePass.EXIT_LOCK);
finish();
}
}
/* (non-Javadoc) Workaround for HTC Linkify issues
* @see android.app.Activity#startActivity(android.content.Intent)
*/

View File

@@ -20,23 +20,76 @@
package com.keepassdroid;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.annotation.Nullable;
import com.keepassdroid.app.App;
import com.keepassdroid.settings.PrefsUtil;
import com.keepassdroid.stylish.StylishActivity;
import com.keepassdroid.timeout.TimeoutHelper;
import com.kunzisoft.keepass.KeePass;
public abstract class LockingActivity extends StylishActivity {
@Override
protected void onPause() {
super.onPause();
TimeoutHelper.pause(this);
}
private ScreenReceiver screenReceiver;
@Override
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (PrefsUtil.isLockDatabaseWhenScreenShutOffEnable(this)) {
screenReceiver = new ScreenReceiver();
registerReceiver(screenReceiver, new IntentFilter((Intent.ACTION_SCREEN_OFF)));
} else
screenReceiver = null;
}
@Override
protected void onResume() {
super.onResume();
checkShutdown();
TimeoutHelper.resume(this);
}
private void checkShutdown() {
if ( App.isShutdown() && App.getDB().Loaded() ) {
setResult(KeePass.EXIT_LOCK);
finish();
}
}
@Override
protected void onPause() {
super.onPause();
TimeoutHelper.pause(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
if(screenReceiver != null)
unregisterReceiver(screenReceiver);
}
public class ScreenReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction() != null) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
if (PrefsUtil.isLockDatabaseWhenScreenShutOffEnable(LockingActivity.this)) {
App.setShutdown();
checkShutdown();
}
}
}
}
}
}

View File

@@ -20,7 +20,6 @@
package com.keepassdroid;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
@@ -44,27 +43,28 @@ import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.kunzisoft.keepass.KeePass;
import com.kunzisoft.keepass.R;
import com.keepassdroid.app.App;
import com.keepassdroid.compat.BackupManagerCompat;
import com.keepassdroid.compat.ClipDataCompat;
import com.keepassdroid.compat.EditorCompat;
import com.keepassdroid.compat.StorageAF;
import com.keepassdroid.database.edit.LoadDB;
import com.keepassdroid.database.edit.OnFinish;
import com.keepassdroid.dialog.PasswordEncodingDialogHelper;
import com.keepassdroid.fileselect.BrowserDialog;
import com.keepassdroid.fingerprint.FingerPrintAnimatedVector;
import com.keepassdroid.fingerprint.FingerPrintHelper;
import com.keepassdroid.intents.Intents;
import com.keepassdroid.settings.PrefsUtil;
import com.keepassdroid.utils.EmptyUtils;
import com.keepassdroid.utils.Interaction;
import com.keepassdroid.utils.MenuUtil;
import com.keepassdroid.utils.UriUtil;
import com.keepassdroid.utils.Util;
import com.keepassdroid.view.FingerPrintDialog;
import com.keepassdroid.view.KeyFileHelper;
import com.kunzisoft.keepass.KeePass;
import com.kunzisoft.keepass.R;
import java.io.File;
import java.io.FileNotFoundException;
@@ -80,10 +80,6 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
private static final String KEY_LAUNCH_IMMEDIATELY = "launchImmediately";
private static final String VIEW_INTENT = "android.intent.action.VIEW";
private static final int FILE_BROWSE = 256;
public static final int GET_CONTENT = 257;
private static final int OPEN_DOC = 258;
private Uri mDbUri = null;
private Uri mKeyUri = null;
private boolean mRememberKeyfile;
@@ -96,10 +92,19 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
private int mode;
private static final String PREF_KEY_VALUE_PREFIX = "valueFor_"; // key is a combination of db file name and this prefix
private static final String PREF_KEY_IV_PREFIX = "ivFor_"; // key is a combination of db file name and this prefix
private View fingerprintView;
private TextView confirmationView;
private View fingerprintContainerView;
private View fingerprintImageView;
private FingerPrintAnimatedVector fingerPrintAnimatedVector;
private TextView fingerprintTextView;
private TextView filenameView;
private EditText passwordView;
private Button confirmButton;
private EditText keyFileView;
private Button confirmButtonView;
private CheckBox checkboxPasswordView;
private CheckBox checkboxKeyfileView;
private KeyFileHelper keyFileHelper;
public static void Launch(
Activity act,
@@ -116,6 +121,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
}
Uri uri = UriUtil.parseDefaultFile(fileName);
assert uri != null;
String scheme = uri.getScheme();
if (!EmptyUtils.isNullOrEmpty(scheme) && scheme.equalsIgnoreCase("file")) {
@@ -140,49 +146,30 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
Intent data) {
super.onActivityResult(requestCode, resultCode, data);
keyFileHelper.onActivityResultCallback(requestCode, resultCode, data,
new KeyFileHelper.KeyFileCallback() {
@Override
public void onKeyFileResultCallback(Uri uri) {
if(uri != null) {
keyFileView.setText(uri.toString());
}
}
});
switch (requestCode) {
case KeePass.EXIT_NORMAL:
setEditText(R.id.password, "");
setEmptyViews();
App.getDB().clear();
break;
case KeePass.EXIT_LOCK:
setResult(KeePass.EXIT_LOCK);
setEditText(R.id.password, "");
setEmptyViews();
finish();
App.getDB().clear();
break;
case FILE_BROWSE:
if (resultCode == RESULT_OK) {
String filename = data.getDataString();
if (filename != null) {
EditText fn = (EditText) findViewById(R.id.pass_keyfile);
fn.setText(filename);
mKeyUri = UriUtil.parseDefaultFile(filename);
}
}
break;
case GET_CONTENT:
case OPEN_DOC:
if (resultCode == RESULT_OK) {
if (data != null) {
Uri uri = data.getData();
if (uri != null) {
if (requestCode == GET_CONTENT) {
uri = UriUtil.translate(this, uri);
}
String path = uri.toString();
if (path != null) {
EditText fn = (EditText) findViewById(R.id.pass_keyfile);
fn.setText(path);
}
mKeyUri = uri;
}
}
}
break;
}
}
@Override
@@ -204,10 +191,45 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
confirmButton = (Button) findViewById(R.id.pass_ok);
fingerprintView = findViewById(R.id.fingerprint);
confirmationView = (TextView) findViewById(R.id.fingerprint_label);
confirmButtonView = (Button) findViewById(R.id.pass_ok);
fingerprintContainerView = findViewById(R.id.fingerprint_container);
fingerprintImageView = findViewById(R.id.fingerprint_image);
fingerprintTextView = (TextView) findViewById(R.id.fingerprint_label);
filenameView = (TextView) findViewById(R.id.filename);
passwordView = (EditText) findViewById(R.id.password);
keyFileView = (EditText) findViewById(R.id.pass_keyfile);
checkboxPasswordView = (CheckBox) findViewById(R.id.password_checkbox);
checkboxKeyfileView = (CheckBox) findViewById(R.id.keyfile_checkox);
passwordView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void afterTextChanged(Editable editable) {
checkboxPasswordView.setChecked(true);
}
});
keyFileView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void afterTextChanged(Editable editable) {
checkboxKeyfileView.setChecked(true);
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
fingerPrintAnimatedVector = new FingerPrintAnimatedVector(this,
(ImageView) fingerprintImageView);
}
new InitTask().execute(i);
}
@@ -219,8 +241,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
// If the application was shutdown make sure to clear the password field, if it
// was saved in the instance state
if (App.isShutdown()) {
TextView password = (TextView) findViewById(R.id.password);
password.setText("");
setEmptyViews();
}
// Clear the shutdown flag
@@ -230,13 +251,23 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
initForFingerprint();
checkAvailability();
if (fingerPrintAnimatedVector != null) {
fingerPrintAnimatedVector.startScan();
}
}
}
private void setEmptyViews() {
passwordView.setText("");
keyFileView.setText("");
checkboxPasswordView.setChecked(false);
checkboxKeyfileView.setChecked(false);
}
private void retrieveSettings() {
String defaultFilename = prefs.getString(KEY_DEFAULT_FILENAME, "");
if (!EmptyUtils.isNullOrEmpty(mDbUri.getPath()) && UriUtil.equalsDefaultfile(mDbUri, defaultFilename)) {
CheckBox checkbox = (CheckBox) findViewById(R.id.default_database);
CompoundButton checkbox = (CompoundButton) findViewById(R.id.default_database);
checkbox.setChecked(true);
}
}
@@ -251,14 +282,12 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
private void populateView() {
String db = (mDbUri == null) ? "" : mDbUri.toString();
setEditText(R.id.filename, db);
if (!db.isEmpty())
filenameView.setText(db);
String key = (mKeyUri == null) ? "" : mKeyUri.toString();
setEditText(R.id.pass_keyfile, key);
}
private void errorMessage(int resId) {
Toast.makeText(this, resId, Toast.LENGTH_LONG).show();
if (!key.isEmpty())
keyFileView.setText(key);
}
// fingerprint related code here
@@ -287,7 +316,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
if ( !fingerprintMustBeConfigured ) {
final boolean validInput = s.length() > 0;
// encrypt or decrypt mode based on how much input or not
confirmationView.setText(validInput ? R.string.store_with_fingerprint : R.string.scanning_fingerprint);
fingerprintTextView.setText(validInput ? R.string.store_with_fingerprint : R.string.scanning_fingerprint);
mode = validInput ? toggleMode(Cipher.ENCRYPT_MODE) : toggleMode(Cipher.DECRYPT_MODE);
}
}
@@ -304,7 +333,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
// errorCode = 5
// errString = "Fingerprint operation canceled."
//onFingerprintException();
//confirmationView.setText(errString);
//fingerprintTextView.setText(errString);
// true false fingerprint readings are handled otherwise with the toast messages, see below in code
}
@@ -314,7 +343,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
final CharSequence helpString) {
onFingerprintException(new Exception("onAuthenticationHelp"));
confirmationView.setText(helpString);
fingerprintTextView.setText(helpString);
}
@Override
@@ -370,6 +399,12 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
@Override
protected void onPause() {
super.onPause();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& fingerPrintAnimatedVector != null) {
fingerPrintAnimatedVector.stopScan();
}
// stop listening when we go in background
if (fingerPrintHelper != null) {
fingerPrintHelper.stopListening();
@@ -377,42 +412,50 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
}
private void setFingerPrintVisibility(int vis) {
fingerprintView.setVisibility(vis);
confirmationView.setVisibility(vis);
fingerprintContainerView.setVisibility(vis);
}
@RequiresApi(api = Build.VERSION_CODES.M)
private void checkAvailability() {
// fingerprint not supported (by API level or hardware) so keep option hidden
if (!fingerPrintHelper.isFingerprintSupported(FingerprintManagerCompat.from(this))) {
// or manually disable
if (!PrefsUtil.isFingerprintEnable(getApplicationContext())
|| !fingerPrintHelper.isFingerprintSupported(FingerprintManagerCompat.from(this))) {
setFingerPrintVisibility(View.GONE);
}
// fingerprint is available but not configured show icon but in disabled state with some information
else if (!fingerPrintHelper.hasEnrolledFingerprints()) {
setFingerPrintVisibility(View.VISIBLE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
fingerprintView.setAlpha(0.3f);
}
// This happens when no fingerprints are registered. Listening won't start
confirmationView.setText(R.string.configure_fingerprint);
}
// finally fingerprint available and configured so we can use it
else {
fingerprintMustBeConfigured = false;
// show explanations
fingerprintContainerView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
FingerPrintDialog fingerPrintDialog = new FingerPrintDialog();
fingerPrintDialog.show(getSupportFragmentManager(), "fingerprintDialog");
}
});
setFingerPrintVisibility(View.VISIBLE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
fingerprintView.setAlpha(1f);
if (!fingerPrintHelper.hasEnrolledFingerprints()) {
fingerprintImageView.setAlpha(0.3f);
// This happens when no fingerprints are registered. Listening won't start
fingerprintTextView.setText(R.string.configure_fingerprint);
}
// fingerprint available but no stored password found yet for this DB so show info don't listen
if (prefsNoBackup.getString(getPreferenceKeyValue(), null) == null) {
confirmationView.setText(R.string.no_password_stored);
}
// all is set here so we can confirm to user and start listening for fingerprints
// finally fingerprint available and configured so we can use it
else {
confirmationView.setText(R.string.scanning_fingerprint);
// listen for decryption by default
toggleMode(Cipher.DECRYPT_MODE);
fingerprintMustBeConfigured = false;
fingerprintImageView.setAlpha(1f);
// fingerprint available but no stored password found yet for this DB so show info don't listen
if (prefsNoBackup.getString(getPreferenceKeyValue(), null) == null) {
fingerprintTextView.setText(R.string.no_password_stored);
}
// all is set here so we can confirm to user and start listening for fingerprints
else {
fingerprintTextView.setText(R.string.scanning_fingerprint);
// listen for decryption by default
toggleMode(Cipher.DECRYPT_MODE);
}
}
}
}
@@ -427,15 +470,15 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
.putString(getPreferenceKeyIvSpec(), ivSpec)
.apply();
// and remove visual input to reset UI
confirmButton.performClick();
confirmationView.setText(R.string.encrypted_value_stored);
confirmButtonView.performClick();
fingerprintTextView.setText(R.string.encrypted_value_stored);
}
@Override
public void handleDecryptedResult(final String value) {
// on decrypt enter it for the purchase/login action
passwordView.setText(value);
confirmButton.performClick();
confirmButtonView.performClick();
}
@RequiresApi(api = Build.VERSION_CODES.M)
@@ -482,8 +525,8 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
private class OkClickHandler implements View.OnClickListener {
public void onClick(View view) {
String pass = getEditText(R.id.password);
String key = getEditText(R.id.pass_keyfile);
String pass = passwordView.getText().toString();
String key = keyFileView.getText().toString();
loadDatabase(pass, key);
}
}
@@ -497,10 +540,6 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
private void loadDatabase(
String pass,
Uri keyfile) {
if (pass.length() == 0 && (keyfile == null || keyfile.toString().length() == 0)) {
errorMessage(R.string.error_nopass);
return;
}
// Clear before we load
Database db = App.getDB();
@@ -509,6 +548,13 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
// Clear the shutdown flag
App.clearShutdown();
if (!checkboxPasswordView.isChecked()) {
pass = "";
}
if (!checkboxKeyfileView.isChecked()) {
keyfile = null;
}
Handler handler = new Handler();
LoadDB task = new LoadDB(db, PasswordActivity.this, mDbUri, pass, keyfile, new AfterLoad(handler, db));
ProgressTask pt = new ProgressTask(PasswordActivity.this, task, R.string.loading_database);
@@ -519,15 +565,6 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
return Util.getEditText(this, resId);
}
private void setEditText(
int resId,
String str) {
TextView te = (TextView) findViewById(resId);
if (te != null) {
te.setText(str);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
@@ -554,7 +591,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
private Database db;
public AfterLoad(
AfterLoad(
Handler handler,
Database db) {
super(handler);
@@ -654,69 +691,15 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
confirmButton.setOnClickListener(new OkClickHandler());
if (password != null) {
TextView tv_password = (TextView) findViewById(R.id.password);
tv_password.setText(password);
passwordView.setText(password);
}
CheckBox defaultCheck = (CheckBox) findViewById(R.id.default_database);
CompoundButton defaultCheck = (CompoundButton) findViewById(R.id.default_database);
defaultCheck.setOnCheckedChangeListener(new DefaultCheckChange());
View browse = findViewById(R.id.browse_button);
browse.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (StorageAF.useStorageFramework(PasswordActivity.this)) {
Intent i = new Intent(StorageAF.ACTION_OPEN_DOCUMENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
startActivityForResult(i, OPEN_DOC);
} else {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
try {
startActivityForResult(i, GET_CONTENT);
} catch (ActivityNotFoundException e) {
lookForOpenIntentsFilePicker();
}
}
}
private void lookForOpenIntentsFilePicker() {
if (Interaction.isIntentAvailable(PasswordActivity.this, Intents.OPEN_INTENTS_FILE_BROWSE)) {
Intent i = new Intent(Intents.OPEN_INTENTS_FILE_BROWSE);
// Get file path parent if possible
try {
if (mDbUri != null && mDbUri.toString().length() > 0) {
if (mDbUri.getScheme().equals("file")) {
File keyfile = new File(mDbUri.getPath());
File parent = keyfile.getParentFile();
if (parent != null) {
i.setData(Uri.parse("file://" + parent.getAbsolutePath()));
}
}
}
} catch (Exception e) {
// Ignore
}
try {
startActivityForResult(i, FILE_BROWSE);
} catch (ActivityNotFoundException e) {
showBrowserDialog();
}
} else {
showBrowserDialog();
}
}
private void showBrowserDialog() {
BrowserDialog browserDialog = new BrowserDialog(PasswordActivity.this);
browserDialog.show();
}
});
View browseView = findViewById(R.id.browse_button);
keyFileHelper = new KeyFileHelper(PasswordActivity.this);
browseView.setOnClickListener(keyFileHelper.getOpenFileOnClickViewListener());
retrieveSettings();

View File

@@ -1,156 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid;
import android.app.Dialog;
import android.content.DialogInterface;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.kunzisoft.keepass.R;
import com.keepassdroid.app.App;
import com.keepassdroid.database.edit.FileOnFinish;
import com.keepassdroid.database.edit.OnFinish;
import com.keepassdroid.database.edit.SetPassword;
import com.keepassdroid.utils.EmptyUtils;
import com.keepassdroid.utils.UriUtil;
public class SetPasswordDialog extends DialogFragment {
private final static String FINISH_TAG = "FINISH_TAG";
private byte[] masterKey;
private Uri mKeyfile;
private FileOnFinish mFinish;
private View rootView;
public byte[] getKey() {
return masterKey;
}
public Uri keyfile() {
return mKeyfile;
}
public static SetPasswordDialog newInstance(FileOnFinish finish) {
SetPasswordDialog setPasswordDialog = new SetPasswordDialog();
Bundle args = new Bundle();
args.putSerializable(FINISH_TAG, finish);
setPasswordDialog.setArguments(args);
return setPasswordDialog;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
if(getArguments() != null && getArguments().containsKey(FINISH_TAG)) {
mFinish = (FileOnFinish) getArguments().getSerializable(FINISH_TAG);
}
rootView = inflater.inflate(R.layout.set_password, null);
builder.setView(rootView)
// Add action buttons
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
TextView passView = (TextView) rootView.findViewById(R.id.pass_password);
String pass = passView.getText().toString();
TextView passConfView = (TextView) rootView.findViewById(R.id.pass_conf_password);
String confpass = passConfView.getText().toString();
// Verify that passwords match
if ( ! pass.equals(confpass) ) {
// Passwords do not match
Toast.makeText(getContext(), R.string.error_pass_match, Toast.LENGTH_LONG).show();
return;
}
TextView keyfileView = (TextView) rootView.findViewById(R.id.pass_keyfile);
Uri keyfile = UriUtil.parseDefaultFile(keyfileView.getText().toString());
mKeyfile = keyfile;
// Verify that a password or keyfile is set
if ( pass.length() == 0 && EmptyUtils.isNullOrEmpty(keyfile)) {
Toast.makeText(getContext(), R.string.error_nopass, Toast.LENGTH_LONG).show();
return;
}
SetPassword sp = new SetPassword(getContext(), App.getDB(), pass, keyfile, new AfterSave(mFinish, new Handler()));
final ProgressTask pt = new ProgressTask(getContext(), sp, R.string.saving_database);
boolean valid = sp.validatePassword(getContext(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
pt.run();
}
});
if (valid) {
pt.run();
}
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
SetPasswordDialog.this.getDialog().cancel();
if ( mFinish != null ) {
mFinish.run();
}
}
});
return builder.create();
}
private class AfterSave extends OnFinish {
private FileOnFinish mFinish;
public AfterSave(FileOnFinish finish, Handler handler) {
super(finish, handler);
mFinish = finish;
}
@Override
public void run() {
if ( mSuccess ) {
if ( mFinish != null ) {
mFinish.setFilename(mKeyfile);
}
dismiss();
} else {
displayMessage(getContext());
}
super.run();
}
}
}

View File

@@ -0,0 +1,39 @@
package com.keepassdroid;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import com.kunzisoft.keepass.R;
public class UnavailableFeatureDialog extends DialogFragment {
private static final String MIN_REQUIRED_VERSION_ARG = "MIN_REQUIRED_VERSION_ARG";
private int minVersionRequired = Build.VERSION_CODES.M;
public static UnavailableFeatureDialog getInstance(int minVersionRequired) {
UnavailableFeatureDialog fragment = new UnavailableFeatureDialog();
Bundle args = new Bundle();
args.putInt(MIN_REQUIRED_VERSION_ARG, minVersionRequired);
fragment.setArguments(args);
return fragment;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
if (getArguments() != null && getArguments().containsKey(MIN_REQUIRED_VERSION_ARG))
minVersionRequired = getArguments().getInt(MIN_REQUIRED_VERSION_ARG);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(getString(R.string.unavailable_feature_text, Build.VERSION.SDK_INT, minVersionRequired))
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) { }
});
return builder.create();
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2017 Brian Pellin.
*
* This file is part of KeePassDroid.
*
* KeePassDroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* KeePassDroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.compat;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.security.spec.AlgorithmParameterSpec;
public class KeyGenParameterSpecCompat {
private static Class builder;
private static Constructor buildConst;
private static Method builderBuild;
private static Method setBlockModes;
private static Method setUserAuthReq;
private static Method setEncPad;
private static boolean available;
static {
try {
builder = Class.forName("android.security.keystore.KeyGenParameterSpec$Builder");
buildConst = builder.getConstructor(String.class, int.class);
builderBuild = builder.getMethod("build", (Class [])null);
setBlockModes = builder.getMethod("setBlockModes", String[].class);
setUserAuthReq = builder.getMethod("setUserAuthenticationRequired", new Class []{boolean.class});
setEncPad = builder.getMethod("setEncryptionPaddings", String[].class);
available = true;
} catch (Exception e) {
available = false;
}
}
public static AlgorithmParameterSpec build(String keystoreAlias, int purpose, String blockMode,
boolean userAuthReq, String encPadding) {
if (!available) {
return null;
}
try {
Object inst = buildConst.newInstance(keystoreAlias, purpose);
inst = setBlockModes.invoke(inst, new Object[] {new String[] {blockMode}});
inst = setUserAuthReq.invoke(inst, userAuthReq);
inst = setEncPad.invoke(inst, new Object[] {new String[] {encPadding}});
return (AlgorithmParameterSpec) builderBuild.invoke(inst, null);
} catch (Exception e) {
return null;
}
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2017 Brian Pellin.
*
* This file is part of KeePassDroid.
*
* KeePassDroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* KeePassDroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.compat;
import android.app.KeyguardManager;
import java.lang.reflect.Method;
public class KeyguardManagerCompat {
private static Method isKeyguardSecure;
private static boolean available;
static {
try {
isKeyguardSecure = KeyguardManager.class.getMethod("isKeyguardSecure", (Class[]) null);
available = true;
} catch (Exception e) {
available = false;
}
}
public static boolean isKeyguardSecure(KeyguardManager inst) {
if (!available) {
return false;
}
try {
return (boolean) isKeyguardSecure.invoke(inst, null);
} catch (Exception e) {
return false;
}
}
}

View File

@@ -19,6 +19,7 @@
*/
package com.keepassdroid.database;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
@@ -49,6 +50,14 @@ public class BinaryPool {
public Set<Entry<Integer, ProtectedBinary>> entrySet() {
return pool.entrySet();
}
public void clear() {
pool.clear();
}
public Collection<ProtectedBinary> binaries() {
return pool.values();
}
private class AddBinaries extends EntryHandler<PwEntryV4> {
@@ -72,7 +81,7 @@ public class BinaryPool {
}
private void poolAdd(ProtectedBinary pb) {
public void poolAdd(ProtectedBinary pb) {
assert(pb != null);
if (poolFind(pb) != -1) return;

View File

@@ -19,12 +19,29 @@
*/
package com.keepassdroid.database;
import java.io.FileInputStream;
import android.webkit.URLUtil;
import com.keepassdroid.collections.VariantDictionary;
import com.keepassdroid.crypto.CryptoUtil;
import com.keepassdroid.crypto.engine.AesEngine;
import com.keepassdroid.crypto.engine.CipherEngine;
import com.keepassdroid.crypto.keyDerivation.AesKdf;
import com.keepassdroid.crypto.keyDerivation.KdfEngine;
import com.keepassdroid.crypto.keyDerivation.KdfFactory;
import com.keepassdroid.crypto.keyDerivation.KdfParameters;
import com.keepassdroid.database.exception.InvalidKeyFileException;
import com.keepassdroid.utils.EmptyUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.acl.Group;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
@@ -36,29 +53,8 @@ import java.util.UUID;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.spongycastle.crypto.engines.AESEngine;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import android.webkit.URLUtil;
import biz.source_code.base64Coder.Base64Coder;
import com.keepassdroid.collections.VariantDictionary;
import com.keepassdroid.crypto.CipherFactory;
import com.keepassdroid.crypto.CryptoUtil;
import com.keepassdroid.crypto.PwStreamCipherFactory;
import com.keepassdroid.crypto.engine.AesEngine;
import com.keepassdroid.crypto.engine.CipherEngine;
import com.keepassdroid.crypto.keyDerivation.AesKdf;
import com.keepassdroid.crypto.keyDerivation.KdfEngine;
import com.keepassdroid.crypto.keyDerivation.KdfFactory;
import com.keepassdroid.crypto.keyDerivation.KdfParameters;
import com.keepassdroid.database.exception.InvalidKeyFileException;
import com.keepassdroid.utils.EmptyUtils;
public class PwDatabaseV4 extends PwDatabase {
@@ -73,6 +69,7 @@ public class PwDatabaseV4 extends PwDatabase {
public UUID dataCipher = AesEngine.CIPHER_UUID;
public CipherEngine dataEngine = new AesEngine();
public PwCompressionAlgorithm compressionAlgorithm = PwCompressionAlgorithm.Gzip;
// TODO: Refactor me away to get directly from kdfParameters
public long numKeyEncRounds = 6000;
public Date nameChanged = DEFAULT_NOW;
public Date settingsChanged = DEFAULT_NOW;
@@ -103,7 +100,8 @@ public class PwDatabaseV4 extends PwDatabase {
public Map<String, String> customData = new HashMap<String, String>();
public KdfParameters kdfParameters = KdfFactory.getDefaultParameters();
public VariantDictionary publicCustomData = new VariantDictionary();
public BinaryPool binPool = new BinaryPool();
public String localizedAppName = "KeePassDroid";
public class MemoryProtectionConfig {
@@ -131,7 +129,7 @@ public class PwDatabaseV4 extends PwDatabase {
throws InvalidKeyFileException, IOException {
assert(key != null);
byte[] fKey;
byte[] fKey = new byte[]{};
if ( key.length() > 0 && keyInputStream != null) {
return getCompositeKey(key, keyInputStream);
@@ -139,8 +137,6 @@ public class PwDatabaseV4 extends PwDatabase {
fKey = getPasswordKey(key);
} else if ( keyInputStream != null) {
fKey = getFileKey(keyInputStream);
} else {
throw new IllegalArgumentException( "Key cannot be empty." );
}
MessageDigest md;
@@ -175,13 +171,24 @@ public class PwDatabaseV4 extends PwDatabase {
Arrays.fill(cmpKey, (byte)0);
}
}
public void makeFinalKey(byte[] masterSeed, KdfParameters kdfP) throws IOException {
makeFinalKey(masterSeed, kdfP, 0);
}
public void makeFinalKey(byte[] masterSeed, KdfParameters kdfP, long roundsFix)
throws IOException {
KdfEngine kdfEngine = KdfFactory.get(kdfP.kdfUUID);
if (kdfEngine == null) {
throw new IOException("Unknown key derivation function");
}
// Set to 6000 rounds to open corrupted database
if (roundsFix > 0 && kdfP.kdfUUID.equals(AesKdf.CIPHER_UUID)) {
kdfP.setUInt32(AesKdf.ParamRounds, roundsFix);
numKeyEncRounds = roundsFix;
}
byte[] transformedMasterKey = kdfEngine.transform(masterKey, kdfP);
if (transformedMasterKey.length != 32) {
transformedMasterKey = CryptoUtil.hashSha256(transformedMasterKey);

View File

@@ -23,16 +23,8 @@ import android.annotation.SuppressLint;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
@SuppressLint("SimpleDateFormat")
public class PwDatabaseV4XML {
public static final SimpleDateFormat dateFormat;
static {
dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
}
public static final String ElemDocNode = "KeePassFile";
public static final String ElemMeta = "Meta";
public static final String ElemRoot = "Root";
@@ -134,4 +126,15 @@ public class PwDatabaseV4XML {
public static final String ElemCustomData = "CustomData";
public static final String ElemStringDictExItem = "Item";
public static final ThreadLocal<SimpleDateFormat> dateFormatter =
new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
SimpleDateFormat dateFormat;
dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
return dateFormat;
}
};
}

View File

@@ -95,7 +95,6 @@ public class PwDbHeaderV4 extends PwDbHeader {
public byte[] streamStartBytes = new byte[32];
public CrsAlgorithm innerRandomStream;
public long version;
public List<ProtectedBinary> binaries = new ArrayList<ProtectedBinary>();
public PwDbHeaderV4(PwDatabaseV4 d) {
db = d;
@@ -194,7 +193,9 @@ public class PwDbHeaderV4 extends PwDbHeader {
if (!db.kdfParameters.kdfUUID.equals(kdfR.uuid)) {
db.kdfParameters = kdfR.getDefaultParameters();
}
db.kdfParameters.setUInt64(AesKdf.ParamRounds, LEDataInputStream.readLong(fieldData, 0));
long rounds = LEDataInputStream.readLong(fieldData, 0);
db.kdfParameters.setUInt64(AesKdf.ParamRounds, rounds);
db.numKeyEncRounds = rounds;
break;
case PwDbHeaderV4Fields.EncryptionIV:

View File

@@ -19,20 +19,14 @@
*/
package com.keepassdroid.database.edit;
import android.content.Context;
import android.net.Uri;
import com.keepassdroid.Database;
import com.keepassdroid.app.App;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.PwDatabaseV3;
import com.keepassdroid.database.PwEncryptionAlgorithm;
import com.keepassdroid.utils.UriUtil;
public class CreateDB extends RunnableOnFinish {
private final int DEFAULT_ENCRYPTION_ROUNDS = 300;
private String mFilename;
private boolean mDontSave;
@@ -57,7 +51,6 @@ public class CreateDB extends RunnableOnFinish {
// Set Database state
db.pm = pm;
Uri.Builder b = new Uri.Builder();
db.mUri = UriUtil.parseDefaultFile(mFilename);
db.setLoaded();
App.clearShutdown();

View File

@@ -19,9 +19,6 @@
*/
package com.keepassdroid.database.edit;
import java.io.IOException;
import java.io.InputStream;
import android.content.Context;
import android.content.DialogInterface;
import android.net.Uri;
@@ -32,6 +29,9 @@ import com.keepassdroid.database.exception.InvalidKeyFileException;
import com.keepassdroid.dialog.PasswordEncodingDialogHelper;
import com.keepassdroid.utils.UriUtil;
import java.io.IOException;
import java.io.InputStream;
public class SetPassword extends RunnableOnFinish {
private String mPassword;

View File

@@ -33,7 +33,7 @@ public abstract class Importer {
public abstract PwDatabase openDatabase( InputStream inStream, String password, InputStream keyInputStream)
throws IOException, InvalidDBException;
public abstract PwDatabase openDatabase( InputStream inStream, String password, InputStream keyInputStream, UpdateStatus status )
public abstract PwDatabase openDatabase( InputStream inStream, String password, InputStream keyInputStream, UpdateStatus status, long roundsFix)
throws IOException, InvalidDBException;

View File

@@ -125,10 +125,10 @@ public class ImporterV3 extends Importer {
public PwDatabaseV3 openDatabase( InputStream inStream, String password, InputStream kfIs)
throws IOException, InvalidDBException
{
return openDatabase(inStream, password, kfIs, new UpdateStatus());
return openDatabase(inStream, password, kfIs, new UpdateStatus(), 0);
}
public PwDatabaseV3 openDatabase( InputStream inStream, String password, InputStream kfIs, UpdateStatus status )
public PwDatabaseV3 openDatabase( InputStream inStream, String password, InputStream kfIs, UpdateStatus status, long roundsFix)
throws IOException, InvalidDBException
{
PwDatabaseV3 newManager;

View File

@@ -35,9 +35,10 @@ public class ImporterV3Debug extends ImporterV3 {
@Override
public PwDatabaseV3Debug openDatabase(InputStream inStream, String password,
InputStream keyInputStream, UpdateStatus status) throws IOException,
InputStream keyInputStream, UpdateStatus status, long roundsFix) throws IOException,
InvalidDBException {
return (PwDatabaseV3Debug) super.openDatabase(inStream, password, keyInputStream, status);
return (PwDatabaseV3Debug) super.openDatabase(inStream, password, keyInputStream, status,
roundsFix);
}

View File

@@ -78,11 +78,11 @@ public class ImporterV4 extends Importer {
private StreamCipher randomStream;
private PwDatabaseV4 db;
private BinaryPool binPool = new BinaryPool();
private byte[] hashOfHeader = null;
private byte[] pbHeader = null;
private long version;
private int binNum = 0;
Calendar utcCal;
public ImporterV4() {
@@ -98,18 +98,17 @@ public class ImporterV4 extends Importer {
public PwDatabaseV4 openDatabase(InputStream inStream, String password,
InputStream keyInputStream) throws IOException, InvalidDBException {
return openDatabase(inStream, password, keyInputStream, new UpdateStatus());
return openDatabase(inStream, password, keyInputStream, new UpdateStatus(), 0);
}
@Override
public PwDatabaseV4 openDatabase(InputStream inStream, String password,
InputStream keyInputStream, UpdateStatus status) throws IOException,
InvalidDBException {
public PwDatabaseV4 openDatabase(InputStream inStream, String password,
InputStream keyInputStream, UpdateStatus status, long roundsFix) throws IOException,
InvalidDBException {
db = createDB();
PwDbHeaderV4 header = new PwDbHeaderV4(db);
header.binaries.clear();
db.binPool.clear();
PwDbHeaderV4.HeaderAndHash hh = header.loadFromFile(inStream);
version = header.version;
@@ -118,7 +117,7 @@ public class ImporterV4 extends Importer {
pbHeader = hh.header;
db.setMasterKey(password, keyInputStream);
db.makeFinalKey(header.masterSeed, db.kdfParameters);
db.makeFinalKey(header.masterSeed, db.kdfParameters, roundsFix);
CipherEngine engine;
Cipher cipher;
@@ -253,6 +252,7 @@ public class ImporterV4 extends Importer {
byte[] bin = new byte[data.length - 1];
System.arraycopy(data, 1, bin, 0, data.length-1);
ProtectedBinary pb = new ProtectedBinary(prot, bin);
db.binPool.poolAdd(pb);
if (prot) {
Arrays.fill(data, (byte)0);
@@ -511,7 +511,7 @@ public class ImporterV4 extends Importer {
if ( key != null ) {
ProtectedBinary pbData = ReadProtectedBinary(xpp);
int id = Integer.parseInt(key);
binPool.put(id, pbData);
db.binPool.put(id, pbData);
} else {
ReadUnknown(xpp);
}
@@ -932,7 +932,7 @@ public class ImporterV4 extends Importer {
} else {
try {
utcDate = PwDatabaseV4XML.dateFormat.parse(sDate);
utcDate = PwDatabaseV4XML.dateFormatter.get().parse(sDate);
} catch (ParseException e) {
// Catch with null test below
}
@@ -1061,7 +1061,7 @@ public class ImporterV4 extends Importer {
xpp.next(); // Consume end tag
int id = Integer.parseInt(ref);
return binPool.get(id);
return db.binPool.get(id);
}
boolean compressed = false;

View File

@@ -35,9 +35,10 @@ public class ImporterV4Debug extends ImporterV4 {
@Override
public PwDatabaseV4Debug openDatabase(InputStream inStream, String password,
InputStream keyInputFile, UpdateStatus status) throws IOException,
InputStream keyInputFile, UpdateStatus status, long roundsFix) throws IOException,
InvalidDBException {
return (PwDatabaseV4Debug) super.openDatabase(inStream, password, keyInputFile, status);
return (PwDatabaseV4Debug) super.openDatabase(inStream, password, keyInputFile, status,
roundsFix);
}
}

View File

@@ -52,7 +52,7 @@ public class PwDbInnerHeaderOutputV4 {
los.writeInt(streamKeySize);
los.write(header.innerRandomStreamKey);
for (ProtectedBinary bin : header.binaries) {
for (ProtectedBinary bin : db.binPool.binaries()) {
byte flag = KdbxBinaryFlags.None;
if (bin.isProtected()) {
flag |= KdbxBinaryFlags.Protected;

View File

@@ -19,36 +19,13 @@
*/
package com.keepassdroid.database.save;
import static com.keepassdroid.database.PwDatabaseV4XML.*;
import java.io.IOException;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;
import java.util.UUID;
import java.util.zip.GZIPOutputStream;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import org.joda.time.DateTime;
import org.spongycastle.crypto.StreamCipher;
import org.xmlpull.v1.XmlSerializer;
import android.util.Xml;
import biz.source_code.base64Coder.Base64Coder;
import com.keepassdroid.crypto.CipherFactory;
import com.keepassdroid.crypto.PwStreamCipherFactory;
import com.keepassdroid.crypto.engine.CipherEngine;
import com.keepassdroid.crypto.keyDerivation.KdfEngine;
import com.keepassdroid.crypto.keyDerivation.KdfFactory;
import com.keepassdroid.database.BinaryPool;
import com.keepassdroid.database.CrsAlgorithm;
import com.keepassdroid.database.EntryHandler;
import com.keepassdroid.database.GroupHandler;
@@ -78,11 +55,115 @@ import com.keepassdroid.utils.EmptyUtils;
import com.keepassdroid.utils.MemUtil;
import com.keepassdroid.utils.Types;
import org.joda.time.DateTime;
import org.spongycastle.crypto.StreamCipher;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;
import java.util.UUID;
import java.util.zip.GZIPOutputStream;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import biz.source_code.base64Coder.Base64Coder;
import static com.keepassdroid.database.PwDatabaseV4XML.AttrCompressed;
import static com.keepassdroid.database.PwDatabaseV4XML.AttrId;
import static com.keepassdroid.database.PwDatabaseV4XML.AttrProtected;
import static com.keepassdroid.database.PwDatabaseV4XML.AttrRef;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemAutoType;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemAutoTypeDefaultSeq;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemAutoTypeEnabled;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemAutoTypeItem;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemAutoTypeObfuscation;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemBgColor;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemBinaries;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemBinary;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemCreationTime;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemCustomData;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemCustomIconID;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemCustomIconItem;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemCustomIconItemData;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemCustomIconItemID;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemCustomIcons;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbColor;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbDefaultUser;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbDefaultUserChanged;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbDesc;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbDescChanged;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbKeyChangeForce;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbKeyChangeRec;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbKeyChanged;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbMntncHistoryDays;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbName;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbNameChanged;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDeletedObject;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDeletedObjects;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDeletionTime;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDocNode;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemEnableAutoType;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemEnableSearching;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemEntry;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemEntryTemplatesGroup;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemEntryTemplatesGroupChanged;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemExpires;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemExpiryTime;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemFgColor;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemGenerator;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemGroup;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemGroupDefaultAutoTypeSeq;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemHeaderHash;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemHistory;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemHistoryMaxItems;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemHistoryMaxSize;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemIcon;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemIsExpanded;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemKey;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemKeystrokeSequence;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemLastAccessTime;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemLastModTime;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemLastSelectedGroup;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemLastTopVisibleEntry;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemLastTopVisibleGroup;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemLocationChanged;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemMemoryProt;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemMeta;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemName;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemNotes;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemOverrideUrl;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemProtNotes;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemProtPassword;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemProtTitle;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemProtURL;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemProtUserName;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemRecycleBinChanged;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemRecycleBinEnabled;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemRecycleBinUuid;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemRoot;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemString;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemStringDictExItem;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemTags;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemTimes;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemUsageCount;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemUuid;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemValue;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemWindow;
import static com.keepassdroid.database.PwDatabaseV4XML.ValFalse;
import static com.keepassdroid.database.PwDatabaseV4XML.ValTrue;
public class PwDbV4Output extends PwDbOutput {
PwDatabaseV4 mPM;
private StreamCipher randomStream;
private BinaryPool binPool;
private XmlSerializer xml;
private PwDbHeaderV4 header;
private byte[] hashOfHeader;
@@ -201,8 +282,7 @@ public class PwDbV4Output extends PwDbOutput {
}
private void outputDatabase(OutputStream os) throws IllegalArgumentException, IllegalStateException, IOException {
binPool = new BinaryPool((PwGroupV4)mPM.rootGroup);
xml = Xml.newSerializer();
xml.setOutput(os, "UTF-8");
@@ -420,7 +500,7 @@ public class PwDbV4Output extends PwDbOutput {
xml.startTag(null, ElemValue);
String strRef = null;
if (allowRef) {
int ref = binPool.poolFind(value);
int ref = mPM.binPool.poolFind(value);
strRef = Integer.toString(ref);
}
@@ -480,7 +560,7 @@ public class PwDbV4Output extends PwDbOutput {
private void writeObject(String name, Date value) throws IllegalArgumentException, IllegalStateException, IOException {
if (header.version < PwDbHeaderV4.FILE_VERSION_32_4) {
writeObject(name, PwDatabaseV4XML.dateFormat.format(value));
writeObject(name, PwDatabaseV4XML.dateFormatter.get().format(value));
} else {
DateTime dt = new DateTime(value);
long seconds = DateUtil.convertDateToKDBX4Time(dt);
@@ -720,7 +800,7 @@ public class PwDbV4Output extends PwDbOutput {
private void writeBinPool() throws IllegalArgumentException, IllegalStateException, IOException {
xml.startTag(null, ElemBinaries);
for (Entry<Integer, ProtectedBinary> pair : binPool.entrySet()) {
for (Entry<Integer, ProtectedBinary> pair : mPM.binPool.entrySet()) {
xml.startTag(null, ElemBinary);
xml.attribute(null, AttrId, Integer.toString(pair.getKey()));

View File

@@ -19,8 +19,8 @@
*/
package com.keepassdroid.fileselect;
import android.Manifest;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Intent;
@@ -28,13 +28,13 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
@@ -44,18 +44,16 @@ import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.kunzisoft.keepass.R;
import com.keepassdroid.AssignMasterKeyDialog;
import com.keepassdroid.CreateFileDialog;
import com.keepassdroid.GroupActivity;
import com.keepassdroid.PasswordActivity;
import com.keepassdroid.ProgressTask;
import com.keepassdroid.SetPasswordDialog;
import com.keepassdroid.app.App;
import com.keepassdroid.compat.ContentResolverCompat;
import com.keepassdroid.compat.StorageAF;
@@ -69,18 +67,25 @@ import com.keepassdroid.utils.Interaction;
import com.keepassdroid.utils.MenuUtil;
import com.keepassdroid.utils.UriUtil;
import com.keepassdroid.utils.Util;
import com.keepassdroid.view.AssignPasswordHelper;
import com.keepassdroid.view.FileNameView;
import com.kunzisoft.keepass.R;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.URLDecoder;
public class FileSelectActivity extends StylishActivity {
public class FileSelectActivity extends StylishActivity implements
CreateFileDialog.DefinePathDialogListener ,
AssignMasterKeyDialog.AssignPasswordDialogListener {
private static final String TAG = "FileSelectActivity";
private static final int MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE = 111;
private ListView mList;
private ListAdapter mAdapter;
private BaseAdapter mAdapter;
private static final int CMENU_CLEAR = Menu.FIRST;
@@ -92,18 +97,23 @@ public class FileSelectActivity extends StylishActivity {
private boolean recentMode = false;
private EditText openFileNameView;
private AssignPasswordHelper assignPasswordHelper;
private Uri databaseUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fileHistory = App.getFileHistory();
setContentView(R.layout.file_selection);
if (fileHistory.hasRecentFiles()) {
recentMode = true;
setContentView(R.layout.file_selection);
} else {
setContentView(R.layout.file_selection_no_recent);
}
findViewById(R.id.file_listtop).setVisibility(View.INVISIBLE);
}
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle(getString(R.string.app_name));
@@ -112,22 +122,20 @@ public class FileSelectActivity extends StylishActivity {
mList = (ListView)findViewById(R.id.file_list);
mList.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id)
{
onListItemClick((ListView)parent, v, position, id);
}
}
new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
onListItemClick((ListView)parent, v, position, id);
}
}
);
// Open button
Button openButton = (Button) findViewById(R.id.open);
View openButton = findViewById(R.id.open_database);
openButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
String fileName = Util.getEditText(FileSelectActivity.this,
R.id.file_filename);
try {
PasswordActivity.Launch(FileSelectActivity.this, fileName);
}
@@ -139,80 +147,16 @@ public class FileSelectActivity extends StylishActivity {
Toast.makeText(FileSelectActivity.this,
R.string.FileNotFound, Toast.LENGTH_LONG).show();
}
}
});
// Create button
Button createButton = (Button) findViewById(R.id.create);
View createButton = findViewById(R.id.create_database);
createButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
String filename = Util.getEditText(FileSelectActivity.this,
R.id.file_filename);
// Make sure file name exists
if (filename.length() == 0) {
Toast
.makeText(FileSelectActivity.this,
R.string.error_filename_required,
Toast.LENGTH_LONG).show();
return;
}
// Try to create the file
File file = new File(filename);
try {
if (file.exists()) {
Toast.makeText(FileSelectActivity.this,
R.string.error_database_exists,
Toast.LENGTH_LONG).show();
return;
}
File parent = file.getParentFile();
if ( parent == null || (parent.exists() && ! parent.isDirectory()) ) {
Toast.makeText(FileSelectActivity.this,
R.string.error_invalid_path,
Toast.LENGTH_LONG).show();
return;
}
if ( ! parent.exists() ) {
// Create parent dircetory
if ( ! parent.mkdirs() ) {
Toast.makeText(FileSelectActivity.this,
R.string.error_could_not_create_parent,
Toast.LENGTH_LONG).show();
return;
}
}
file.createNewFile();
} catch (IOException e) {
Toast.makeText(
FileSelectActivity.this,
getText(R.string.error_file_not_create) + " "
+ e.getLocalizedMessage(),
Toast.LENGTH_LONG).show();
return;
}
// Prep an object to collect a password once the database has
// been created
CollectPassword password = new CollectPassword(
new LaunchGroupActivity(filename));
// Create the new database
CreateDB create = new CreateDB(FileSelectActivity.this, filename, password, true);
ProgressTask createTask = new ProgressTask(
FileSelectActivity.this, create,
R.string.progress_create);
createTask.run();
CreateFileDialog createFileDialog = new CreateFileDialog();
createFileDialog.show(getSupportFragmentManager(), "createFileDialog");
}
});
View browseButton = findViewById(R.id.browse_button);
@@ -223,16 +167,14 @@ public class FileSelectActivity extends StylishActivity {
Intent i = new Intent(StorageAF.ACTION_OPEN_DOCUMENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION|Intent.FLAG_GRANT_WRITE_URI_PERMISSION|Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION|
Intent.FLAG_GRANT_WRITE_URI_PERMISSION|
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
startActivityForResult(i, OPEN_DOC);
}
else {
Intent i;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
i = new Intent(Intent.ACTION_OPEN_DOCUMENT);
} else {
i = new Intent(Intent.ACTION_GET_CONTENT);
}
i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
@@ -247,7 +189,6 @@ public class FileSelectActivity extends StylishActivity {
}
private void lookForOpenIntentsFilePicker() {
if (Interaction.isIntentAvailable(FileSelectActivity.this, Intents.OPEN_INTENTS_FILE_BROWSE)) {
Intent i = new Intent(Intents.OPEN_INTENTS_FILE_BROWSE);
i.setData(Uri.parse("file://" + Util.getEditText(FileSelectActivity.this, R.id.file_filename)));
@@ -256,7 +197,6 @@ public class FileSelectActivity extends StylishActivity {
} catch (ActivityNotFoundException e) {
showBrowserDialog();
}
} else {
showBrowserDialog();
}
@@ -268,6 +208,14 @@ public class FileSelectActivity extends StylishActivity {
}
});
// Set the initial value of the filename
openFileNameView = (EditText) findViewById(R.id.file_filename);
String defaultPath = Environment.getExternalStorageDirectory().getAbsolutePath()
+ getString(R.string.database_file_path_default)
+ getString(R.string.database_file_name_default)
+ getString(R.string.database_file_extension_default);
openFileNameView.setText(defaultPath);
fillData();
registerForContextMenu(mList);
@@ -278,7 +226,9 @@ public class FileSelectActivity extends StylishActivity {
if (fileName.length() > 0) {
Uri dbUri = UriUtil.parseDefaultFile(fileName);
String scheme = dbUri.getScheme();
String scheme = null;
if (dbUri!=null)
scheme = dbUri.getScheme();
if (!EmptyUtils.isNullOrEmpty(scheme) && scheme.equalsIgnoreCase("file")) {
String path = dbUri.getPath();
@@ -302,12 +252,135 @@ public class FileSelectActivity extends StylishActivity {
}
}
/**
* Create file for database
* @return If not created, return false
*/
private boolean createDatabaseFile(Uri path) {
String pathString = URLDecoder.decode(path.getPath());
// Make sure file name exists
if (pathString.length() == 0) {
Log.e(TAG, getString(R.string.error_filename_required));
Toast.makeText(FileSelectActivity.this,
R.string.error_filename_required,
Toast.LENGTH_LONG).show();
return false;
}
// Try to create the file
File file = new File(pathString);
try {
if (file.exists()) {
Log.e(TAG, getString(R.string.error_database_exists) + " " + file);
Toast.makeText(FileSelectActivity.this,
R.string.error_database_exists,
Toast.LENGTH_LONG).show();
return false;
}
File parent = file.getParentFile();
if ( parent == null || (parent.exists() && ! parent.isDirectory()) ) {
Log.e(TAG, getString(R.string.error_invalid_path) + " " + file);
Toast.makeText(FileSelectActivity.this,
R.string.error_invalid_path,
Toast.LENGTH_LONG).show();
return false;
}
if ( ! parent.exists() ) {
// Create parent directory
if ( ! parent.mkdirs() ) {
Log.e(TAG, getString(R.string.error_could_not_create_parent) + " " + parent);
Toast.makeText(FileSelectActivity.this,
R.string.error_could_not_create_parent,
Toast.LENGTH_LONG).show();
return false;
}
}
return file.createNewFile();
} catch (IOException e) {
Log.e(TAG, getString(R.string.error_could_not_create_parent) + " " + e.getLocalizedMessage());
e.printStackTrace();
Toast.makeText(
FileSelectActivity.this,
getText(R.string.error_file_not_create) + " "
+ e.getLocalizedMessage(),
Toast.LENGTH_LONG).show();
return false;
}
}
@Override
public boolean onDefinePathDialogPositiveClick(Uri pathFile) {
databaseUri = pathFile;
if(createDatabaseFile(pathFile)) {
AssignMasterKeyDialog assignMasterKeyDialog = new AssignMasterKeyDialog();
assignMasterKeyDialog.show(getSupportFragmentManager(), "passwordDialog");
return true;
} else
return false;
}
@Override
public boolean onDefinePathDialogNegativeClick(Uri pathFile) {
return true;
}
@Override
public void onAssignKeyDialogPositiveClick(
boolean masterPasswordChecked, String masterPassword,
boolean keyFileChecked, Uri keyFile) {
String databaseFilename = databaseUri.getPath();
// Prep an object to collect a password once the database has
// been created
FileOnFinish launchActivityOnFinish = new FileOnFinish(
new LaunchGroupActivity(databaseFilename));
AssignPasswordOnFinish assignPasswordOnFinish =
new AssignPasswordOnFinish(launchActivityOnFinish);
// Create the new database
CreateDB create = new CreateDB(FileSelectActivity.this,
databaseFilename, assignPasswordOnFinish, true);
ProgressTask createTask = new ProgressTask(
FileSelectActivity.this, create,
R.string.progress_create);
createTask.run();
assignPasswordHelper =
new AssignPasswordHelper(this,
masterPassword, keyFile);
}
@Override
public void onAssignKeyDialogNegativeClick(
boolean masterPasswordChecked, String masterPassword,
boolean keyFileChecked, Uri keyFile) {
}
private class AssignPasswordOnFinish extends FileOnFinish {
AssignPasswordOnFinish(FileOnFinish fileOnFinish) {
super(fileOnFinish);
}
@Override
public void run() {
if (mSuccess) {
assignPasswordHelper.assignPasswordInDatabase(mOnFinish);
}
}
}
private class LaunchGroupActivity extends FileOnFinish {
private Uri mUri;
public LaunchGroupActivity(String filename) {
LaunchGroupActivity(String filename) {
super(null);
mUri = UriUtil.parseDefaultFile(filename);
}
@@ -316,61 +389,19 @@ public class FileSelectActivity extends StylishActivity {
if (mSuccess) {
// Add to recent files
fileHistory.createFile(mUri, getFilename());
mAdapter.notifyDataSetChanged();
GroupActivity.Launch(FileSelectActivity.this);
}
}
}
private class CollectPassword extends FileOnFinish {
public CollectPassword(FileOnFinish finish) {
super(finish);
}
@Override
public void run() {
SetPasswordDialog dialog = SetPasswordDialog.newInstance(mOnFinish);
dialog.show(getSupportFragmentManager(), "passwordDialog");
}
}
private void fillData() {
// Set the initial value of the filename
EditText filename = (EditText) findViewById(R.id.file_filename);
filename.setText(Environment.getExternalStorageDirectory().getAbsolutePath() + getString(R.string.default_file_path));
mAdapter = new ArrayAdapter<String>(this, R.layout.file_row, R.id.file_filename, fileHistory.getDbList());
mList.setAdapter(mAdapter);
mAdapter = new ArrayAdapter<>(FileSelectActivity.this, R.layout.file_row, R.id.file_filename, fileHistory.getDbList());
mList.setAdapter(mAdapter);
}
protected void onListItemClick(ListView l, View v, int position, long id) {
new AsyncTask<Integer, Void, Void>() {
String fileName;
String keyFile;
protected Void doInBackground(Integer... args) {
int position = args[0];
fileName = fileHistory.getDatabaseAt(position);
keyFile = fileHistory.getKeyfileAt(position);
return null;
}
protected void onPostExecute(Void v) {
try {
PasswordActivity.Launch(FileSelectActivity.this, fileName, keyFile);
}
catch (ContentFileNotFoundException e) {
Toast.makeText(FileSelectActivity.this, R.string.file_not_found_content, Toast.LENGTH_LONG)
.show();
}
catch (FileNotFoundException e) {
Toast.makeText(FileSelectActivity.this, R.string.FileNotFound, Toast.LENGTH_LONG)
.show();
}
}
}.execute(position);
new OpenFileHistoryAsyncTask(this, fileHistory).execute(position);
}
@Override
@@ -414,8 +445,7 @@ public class FileSelectActivity extends StylishActivity {
}
if (filename != null) {
EditText fn = (EditText) findViewById(R.id.file_filename);
fn.setText(filename);
openFileNameView.setText(filename);
}
}
@@ -522,25 +552,65 @@ public class FileSelectActivity extends StylishActivity {
TextView tv = (TextView) acmi.targetView;
String filename = tv.getText().toString();
new AsyncTask<String, Void, Void>() {
protected java.lang.Void doInBackground(String... args) {
String filename = args[0];
fileHistory.deleteFile(Uri.parse(args[0]));
return null;
}
protected void onPostExecute(Void v) {
refreshList();
}
}.execute(filename);
new DeleteFileHistoryAsyncTask(fileHistory, mAdapter).execute(filename);
return true;
}
return false;
}
private void refreshList() {
((BaseAdapter) mAdapter).notifyDataSetChanged();
}
private static class OpenFileHistoryAsyncTask extends AsyncTask<Integer, Void, Void> {
private WeakReference<Activity> weakActivity;
private RecentFileHistory fileHistory;
private String fileName;
private String keyFile;
OpenFileHistoryAsyncTask(Activity activity, RecentFileHistory fileHistory) {
this.weakActivity = new WeakReference<>(activity);
this.fileHistory = fileHistory;
}
protected Void doInBackground(Integer... args) {
int position = args[0];
fileName = fileHistory.getDatabaseAt(position);
keyFile = fileHistory.getKeyfileAt(position);
return null;
}
protected void onPostExecute(Void v) {
try {
PasswordActivity.Launch(weakActivity.get(), fileName, keyFile);
}
catch (ContentFileNotFoundException e) {
Toast.makeText(weakActivity.get(), R.string.file_not_found_content, Toast.LENGTH_LONG)
.show();
}
catch (FileNotFoundException e) {
Toast.makeText(weakActivity.get(), R.string.FileNotFound, Toast.LENGTH_LONG)
.show();
}
}
}
private static class DeleteFileHistoryAsyncTask extends AsyncTask<String, Void, Void> {
private RecentFileHistory fileHistory;
private BaseAdapter adapter;
DeleteFileHistoryAsyncTask(RecentFileHistory fileHistory, BaseAdapter adapter) {
this.fileHistory = fileHistory;
this.adapter = adapter;
}
protected java.lang.Void doInBackground(String... args) {
fileHistory.deleteFile(Uri.parse(args[0]));
return null;
}
protected void onPostExecute(Void v) {
adapter.notifyDataSetChanged();
}
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2017 Brian Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.fingerprint;
import android.content.Context;
import android.graphics.drawable.Animatable2;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.widget.ImageView;
import com.kunzisoft.keepass.R;
@RequiresApi(api = Build.VERSION_CODES.M)
public class FingerPrintAnimatedVector {
private AnimatedVectorDrawable scanFingerprint;
public FingerPrintAnimatedVector(Context context, ImageView imageView) {
scanFingerprint = (AnimatedVectorDrawable) context.getDrawable(R.drawable.scan_fingerprint);
imageView.setImageDrawable(scanFingerprint);
}
public void startScan() {
scanFingerprint.registerAnimationCallback(new Animatable2.AnimationCallback() {
public void onAnimationEnd(Drawable drawable) {
scanFingerprint.start();
}
});
scanFingerprint.start();
}
public void stopScan() {
scanFingerprint.stop();
}
}

View File

@@ -2,12 +2,14 @@ package com.keepassdroid.settings;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceFragmentCompat;
import android.widget.Toast;
import com.kunzisoft.keepass.R;
import com.keepassdroid.Database;
import com.keepassdroid.app.App;
import com.kunzisoft.keepass.R;
public class MainPreferenceFragment extends PreferenceFragmentCompat implements Preference.OnPreferenceClickListener {
@@ -33,12 +35,25 @@ public class MainPreferenceFragment extends PreferenceFragmentCompat implements
preference.setOnPreferenceClickListener(this);
preference = findPreference(getString(R.string.db_key));
preference.setOnPreferenceClickListener(this);
Database db = App.getDB();
if (!(db.Loaded() && db.pm.appSettingsEnabled())) {
Preference dbSettings = findPreference(getString(R.string.db_key));
dbSettings.setEnabled(false);
} else {
preference.setOnPreferenceClickListener(this);
if (!(db.Loaded())) {
preference.setEnabled(false);
}
}
@Override
public void onDisplayPreferenceDialog(Preference preference) {
// Try if the preference is one of our custom Preferences
if (preference instanceof RoundsPreference) {
DialogFragment dialogFragment = RoundsFixPreferenceDialogFragmentCompat.newInstance(preference.getKey());
dialogFragment.setTargetFragment(this, 0);
dialogFragment.show(getFragmentManager(), null);
}
// Could not be handled here. Try with the super method.
else {
super.onDisplayPreferenceDialog(preference);
}
}

View File

@@ -20,11 +20,16 @@
package com.keepassdroid.settings;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.support.v14.preference.SwitchPreference;
import android.support.v4.app.DialogFragment;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceFragmentCompat;
import android.util.Log;
import android.widget.Toast;
import com.keepassdroid.UnavailableFeatureDialog;
import com.kunzisoft.keepass.R;
import com.keepassdroid.Database;
import com.keepassdroid.app.App;
@@ -98,28 +103,44 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat {
}
});
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
// False if under Marshmallow
SwitchPreference preference = (SwitchPreference) findPreference(getString(R.string.fingerprint_enable_key));
preference.setDefaultValue(false);
preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
((SwitchPreference) preference).setChecked(false);
UnavailableFeatureDialog.getInstance(Build.VERSION_CODES.M)
.show(getFragmentManager(), "unavailableFeatureDialog");
return false;
}
});
}
break;
case NESTED_SCREEN_DB_KEY:
setPreferencesFromResource(R.xml.db_preferences, rootKey);
Database db = App.getDB();
Preference algorithmPref = findPreference(getString(R.string.algorithm_key));
Preference roundPref = findPreference(getString(R.string.rounds_key));
if (!(db.Loaded() && db.pm.appSettingsEnabled())) {
algorithmPref.setEnabled(false);
roundPref.setEnabled(false);
}
if (db.Loaded() && db.pm.appSettingsEnabled()) {
Preference rounds = findPreference(getString(R.string.rounds_key));
rounds.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
roundPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
setRounds(App.getDB(), preference);
return true;
}
});
setRounds(db, rounds);
Preference algorithm = findPreference(getString(R.string.algorithm_key));
setAlgorithm(db, algorithm);
setRounds(db, roundPref);
setAlgorithm(db, algorithmPref);
} else {
Log.e(getClass().getName(), "Database isn't ready");
}
@@ -131,6 +152,20 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat {
}
}
@Override
public void onDisplayPreferenceDialog(Preference preference) {
// Try if the preference is one of our custom Preferences
if (preference instanceof RoundsPreference) {
DialogFragment dialogFragment = RoundsPreferenceDialogFragmentCompat.newInstance(preference.getKey());
dialogFragment.setTargetFragment(this, 0);
dialogFragment.show(getFragmentManager(), null);
}
// Could not be handled here. Try with the super method.
else {
super.onDisplayPreferenceDialog(preference);
}
}
private void setRounds(Database db, Preference rounds) {
rounds.setSummary(Long.toString(db.pm.getNumRounds()));
}

View File

@@ -25,10 +25,46 @@ import android.preference.PreferenceManager;
import com.kunzisoft.keepass.R;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class PrefsUtil {
public static float getListTextSize(Context ctx) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
return Float.parseFloat(prefs.getString(ctx.getString(R.string.list_size_key), ctx.getString(R.string.list_size_default)));
}
public static int getDefaultPasswordLength(Context ctx) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
return prefs.getInt(ctx.getString(R.string.password_length_key),
Integer.parseInt(ctx.getString(R.string.default_password_length)));
}
public static Set<String> getDefaultPasswordCharacters(Context ctx) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
return prefs.getStringSet(ctx.getString(R.string.list_password_generator_options_key),
new HashSet<>(Arrays.asList(
ctx.getResources()
.getStringArray(R.array.list_password_generator_options_default_values))));
}
public static boolean isClipboardNotificationsEnable(Context ctx) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
return prefs.getBoolean(ctx.getString(R.string.clipboard_notifications_key),
ctx.getResources().getBoolean(R.bool.clipboard_notifications_default));
}
public static boolean isLockDatabaseWhenScreenShutOffEnable(Context ctx) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
return prefs.getBoolean(ctx.getString(R.string.lock_database_screen_off_key),
ctx.getResources().getBoolean(R.bool.lock_database_screen_off_default));
}
public static boolean isFingerprintEnable(Context ctx) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
return prefs.getBoolean(ctx.getString(R.string.fingerprint_enable_key),
ctx.getResources().getBoolean(R.bool.fingerprint_enable_default));
}
}

View File

@@ -0,0 +1,65 @@
package com.keepassdroid.settings;
import android.os.Bundle;
import android.support.v7.preference.DialogPreference;
import android.support.v7.preference.PreferenceDialogFragmentCompat;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.kunzisoft.keepass.R;
public class RoundsFixPreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat {
private TextView mRoundsView;
public static RoundsFixPreferenceDialogFragmentCompat newInstance(
String key) {
final RoundsFixPreferenceDialogFragmentCompat
fragment = new RoundsFixPreferenceDialogFragmentCompat();
final Bundle b = new Bundle(1);
b.putString(ARG_KEY, key);
fragment.setArguments(b);
return fragment;
}
@Override
public void onDialogClosed(boolean positiveResult) {
if ( positiveResult ) {
long rounds;
try {
String strRounds = mRoundsView.getText().toString();
rounds = Long.valueOf(strRounds);
} catch (NumberFormatException e) {
Toast.makeText(getContext(), R.string.error_rounds_not_number, Toast.LENGTH_LONG).show();
return;
}
DialogPreference preference = getPreference();
if (preference instanceof RoundsPreference) {
RoundsPreference roundsPreference = (RoundsPreference) preference;
// This allows the client to ignore the user value.
if (roundsPreference.callChangeListener(rounds)) {
// Save the value
roundsPreference.setRounds(rounds);
}
}
}
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
TextView textDescriptionView = (TextView) view.findViewById(R.id.rounds_explanation);
mRoundsView = (TextView) view.findViewById(R.id.rounds);
DialogPreference preference = getPreference();
if (preference instanceof RoundsPreference) {
textDescriptionView.setText(((RoundsPreference) preference).getExplanations());
long numRounds = ((RoundsPreference) preference).getRounds();
mRoundsView.setText(String.valueOf(numRounds));
}
}
}

View File

@@ -19,112 +19,91 @@
*/
package com.keepassdroid.settings;
import android.content.Context;
import android.os.Handler;
import android.preference.DialogPreference;
import android.content.res.TypedArray;
import android.support.v7.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.kunzisoft.keepass.R;
import com.keepassdroid.Database;
import com.keepassdroid.ProgressTask;
import com.keepassdroid.app.App;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.edit.OnFinish;
import com.keepassdroid.database.edit.SaveDB;
public class RoundsPreference extends DialogPreference {
private PwDatabase mPM;
private TextView mRoundsView;
@Override
protected View onCreateDialogView() {
View view = super.onCreateDialogView();
mRoundsView = (TextView) view.findViewById(R.id.rounds);
Database db = App.getDB();
mPM = db.pm;
long numRounds = mPM.getNumRounds();
mRoundsView.setText(Long.toString(numRounds));
return view;
}
private long mRounds;
private String explanations;
public RoundsPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RoundsPreference(Context context) {
this(context, null);
}
public RoundsPreference(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.dialogPreferenceStyle);
}
public RoundsPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, defStyleAttr);
}
public RoundsPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.RoundsDialog,
0, 0);
try {
explanations = a.getString(R.styleable.RoundsDialog_description);
} finally {
a.recycle();
}
}
public RoundsPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public int getDialogLayoutResource() {
return R.layout.pref_dialog_rounds;
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
public String getExplanations() {
return explanations;
}
if ( positiveResult ) {
int rounds;
try {
String strRounds = mRoundsView.getText().toString();
rounds = Integer.parseInt(strRounds);
} catch (NumberFormatException e) {
Toast.makeText(getContext(), R.string.error_rounds_not_number, Toast.LENGTH_LONG).show();
return;
}
if ( rounds < 1 ) {
rounds = 1;
}
long oldRounds = mPM.getNumRounds();
try {
mPM.setNumRounds(rounds);
} catch (NumberFormatException e) {
Toast.makeText(getContext(), R.string.error_rounds_too_large, Toast.LENGTH_LONG).show();
mPM.setNumRounds(Integer.MAX_VALUE);
}
Handler handler = new Handler();
SaveDB save = new SaveDB(getContext(), App.getDB(), new AfterSave(getContext(), handler, oldRounds));
ProgressTask pt = new ProgressTask(getContext(), save, R.string.saving_database);
pt.run();
}
public void setExplanations(String explanations) {
this.explanations = explanations;
}
}
private class AfterSave extends OnFinish {
private long mOldRounds;
private Context mCtx;
public AfterSave(Context ctx, Handler handler, long oldRounds) {
super(handler);
mCtx = ctx;
mOldRounds = oldRounds;
}
public long getRounds() {
return mRounds;
}
@Override
public void run() {
if ( mSuccess ) {
OnPreferenceChangeListener listner = getOnPreferenceChangeListener();
if ( listner != null ) {
listner.onPreferenceChange(RoundsPreference.this, null);
}
} else {
displayMessage(mCtx);
mPM.setNumRounds(mOldRounds);
}
super.run();
}
}
public void setRounds(long rounds) {
this.mRounds = rounds;
// Save to Shared Preferences
persistLong(rounds);
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
// Default value from attribute. Fallback value is set to 0.
return a.getInt(index, 0);
}
@Override
protected void onSetInitialValue(boolean restorePersistedValue,
Object defaultValue) {
// Read the value. Use the default value if it is not possible.
long rounds;
if (!restorePersistedValue) {
rounds = 100000;
if (defaultValue instanceof String) {
rounds = Long.parseLong((String) defaultValue);
}
if (defaultValue instanceof Integer) {
rounds = (Integer) defaultValue;
}
try {
rounds = (long) defaultValue;
} catch (Exception e) {
e.printStackTrace();
}
} else {
rounds = getPersistedLong(mRounds);
}
setRounds(rounds);
}
}

View File

@@ -0,0 +1,111 @@
package com.keepassdroid.settings;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.preference.DialogPreference;
import android.support.v7.preference.PreferenceDialogFragmentCompat;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.keepassdroid.Database;
import com.keepassdroid.ProgressTask;
import com.keepassdroid.app.App;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.edit.OnFinish;
import com.keepassdroid.database.edit.SaveDB;
import com.kunzisoft.keepass.R;
public class RoundsPreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat {
private PwDatabase mPM;
private TextView mRoundsView;
public static RoundsPreferenceDialogFragmentCompat newInstance(
String key) {
final RoundsPreferenceDialogFragmentCompat
fragment = new RoundsPreferenceDialogFragmentCompat();
final Bundle b = new Bundle(1);
b.putString(ARG_KEY, key);
fragment.setArguments(b);
return fragment;
}
@Override
public void onDialogClosed(boolean positiveResult) {
if ( positiveResult ) {
long rounds;
try {
String strRounds = mRoundsView.getText().toString();
rounds = Long.parseLong(strRounds);
} catch (NumberFormatException e) {
Toast.makeText(getContext(), R.string.error_rounds_not_number, Toast.LENGTH_LONG).show();
return;
}
if ( rounds < 1 ) {
rounds = 1;
}
long oldRounds = mPM.getNumRounds();
try {
mPM.setNumRounds(rounds);
} catch (NumberFormatException e) {
Toast.makeText(getContext(), R.string.error_rounds_too_large, Toast.LENGTH_LONG).show();
mPM.setNumRounds(Integer.MAX_VALUE);
}
Handler handler = new Handler();
SaveDB save = new SaveDB(getContext(), App.getDB(), new AfterSave(getContext(), handler, oldRounds));
ProgressTask pt = new ProgressTask(getContext(), save, R.string.saving_database);
pt.run();
}
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
mRoundsView = (TextView) view.findViewById(R.id.rounds);
// Get the time from the related Preference
Database db = App.getDB();
mPM = db.pm;
long numRounds = mPM.getNumRounds();
DialogPreference preference = getPreference();
if (preference instanceof RoundsPreference) {
numRounds = ((RoundsPreference) preference).getRounds();
}
mRoundsView.setText(String.valueOf(numRounds));
}
private class AfterSave extends OnFinish {
private long mOldRounds;
private Context mCtx;
public AfterSave(Context ctx, Handler handler, long oldRounds) {
super(handler);
mCtx = ctx;
mOldRounds = oldRounds;
}
@Override
public void run() {
if ( mSuccess ) {
} else {
displayMessage(mCtx);
mPM.setNumRounds(mOldRounds);
}
super.run();
}
}
}

View File

@@ -97,8 +97,8 @@ public class SettingsActivity extends StylishActivity implements MainPreferenceF
super.onBackPressed();
} else {
getFragmentManager().popBackStack();
toolbar.setTitle(R.string.settings);
}
toolbar.setTitle(R.string.settings);
}
@Override

View File

@@ -9,9 +9,9 @@ import com.kunzisoft.keepass.R;
public class Stylish {
private static String stylishPrefKey;
protected static String stylishPrefKey;
private static String themeString;
protected static String themeString;
public static void init(Context context) {
stylishPrefKey = context.getString(R.string.setting_style_key);
@@ -23,7 +23,7 @@ public class Stylish {
themeString = styleString;
}
static @StyleRes int getThemeId(Context context) {
public static @StyleRes int getThemeId(Context context) {
if (themeString.equals(context.getString(R.string.list_style_name_night)))
return R.style.KeepassDXStyle_Night;

View File

@@ -19,12 +19,6 @@
*/
package com.keepassdroid.utils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import com.keepassdroid.database.exception.SamsungClipboardException;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -33,6 +27,12 @@ import android.net.Uri;
import android.text.ClipboardManager;
import android.widget.TextView;
import com.keepassdroid.database.exception.SamsungClipboardException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class Util {
public static String getClipboard(Context context) {
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
@@ -75,14 +75,6 @@ public class Util {
}
}
public static void setEditText(Activity act, int resId, String str) {
TextView te = (TextView) act.findViewById(resId);
if (te != null) {
te.setText(str);
}
}
public static void copyStream(InputStream in, OutputStream out) throws IOException {
byte[] buf = new byte[1024];
int read;

View File

@@ -0,0 +1,67 @@
package com.keepassdroid.view;
import android.content.Context;
import android.content.DialogInterface;
import android.net.Uri;
import android.os.Handler;
import com.keepassdroid.ProgressTask;
import com.keepassdroid.app.App;
import com.keepassdroid.database.edit.FileOnFinish;
import com.keepassdroid.database.edit.OnFinish;
import com.keepassdroid.database.edit.SetPassword;
import com.kunzisoft.keepass.R;
public class AssignPasswordHelper {
private Context context;
private String masterPassword;
private Uri keyfile;
public AssignPasswordHelper(Context context,
String masterPassword,
Uri keyfile) {
this.context = context;
this.masterPassword = masterPassword;
this.keyfile = keyfile;
}
public void assignPasswordInDatabase(FileOnFinish fileOnFinish) {
SetPassword sp = new SetPassword(context, App.getDB(), masterPassword, keyfile, new AfterSave(fileOnFinish, new Handler()));
final ProgressTask pt = new ProgressTask(context, sp, R.string.saving_database);
boolean valid = sp.validatePassword(context, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
pt.run();
}
});
if (valid) {
pt.run();
}
}
private class AfterSave extends OnFinish {
private FileOnFinish mFinish;
public AfterSave(FileOnFinish finish, Handler handler) {
super(finish, handler);
mFinish = finish;
}
@Override
public void run() {
if ( mSuccess ) {
if ( mFinish != null ) {
mFinish.setFilename(keyfile);
}
} else {
displayMessage(context);
}
super.run();
}
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.view;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import com.keepassdroid.fingerprint.FingerPrintAnimatedVector;
import com.kunzisoft.keepass.R;
@RequiresApi(api = Build.VERSION_CODES.M)
public class FingerPrintDialog extends DialogFragment {
private FingerPrintAnimatedVector fingerPrintAnimatedVector;
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View rootView = inflater.inflate(R.layout.fingerprint_dialog, null);
View fingerprintSettingWayTextView = rootView.findViewById(R.id.fingerprint_setting_way_text);
fingerprintSettingWayTextView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(android.provider.Settings.ACTION_SECURITY_SETTINGS));
}
});
fingerPrintAnimatedVector =
new FingerPrintAnimatedVector(getContext(),
(ImageView) rootView.findViewById(R.id.fingerprint_image));
builder.setView(rootView)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
}
});
return builder.create();
}
@Override
public void onResume() {
super.onResume();
fingerPrintAnimatedVector.startScan();
}
@Override
public void onPause() {
super.onPause();
fingerPrintAnimatedVector.stopScan();
}
}

View File

@@ -0,0 +1,178 @@
/*
* Copyright 2017 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.view;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.support.v4.app.Fragment;
import android.view.View;
import com.keepassdroid.compat.StorageAF;
import com.keepassdroid.fileselect.BrowserDialog;
import com.keepassdroid.intents.Intents;
import com.keepassdroid.utils.Interaction;
import com.keepassdroid.utils.UriUtil;
import java.io.File;
import static android.app.Activity.RESULT_OK;
public class KeyFileHelper {
public static final int GET_CONTENT = 25745;
private static final int OPEN_DOC = 25845;
private static final int FILE_BROWSE = 25645;
private Activity activity;
private Fragment fragment;
private Uri mDbUri;
public KeyFileHelper(Activity context) {
this(context, null);
}
public KeyFileHelper(Activity context, Uri mDbUri) {
this.activity = context;
this.fragment = null;
this.mDbUri = mDbUri;
}
public KeyFileHelper(Fragment context) {
this(context, null);
}
public KeyFileHelper(Fragment context, Uri mDbUri) {
this.activity = context.getActivity();
this.fragment = context;
this.mDbUri = mDbUri;
}
public View.OnClickListener getOpenFileOnClickViewListener() {
return new View.OnClickListener() {
public void onClick(View v) {
if (StorageAF.useStorageFramework(activity)) {
Intent i = new Intent(StorageAF.ACTION_OPEN_DOCUMENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
if(fragment != null)
fragment.startActivityForResult(i, OPEN_DOC);
else
activity.startActivityForResult(i, OPEN_DOC);
} else {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
try {
if(fragment != null)
fragment.startActivityForResult(i, GET_CONTENT);
else
activity.startActivityForResult(i, GET_CONTENT);
} catch (ActivityNotFoundException e) {
lookForOpenIntentsFilePicker();
}
}
}
};
}
private void lookForOpenIntentsFilePicker() {
if (Interaction.isIntentAvailable(activity, Intents.OPEN_INTENTS_FILE_BROWSE)) {
Intent i = new Intent(Intents.OPEN_INTENTS_FILE_BROWSE);
// Get file path parent if possible
try {
if (mDbUri != null && mDbUri.toString().length() > 0) {
if (mDbUri.getScheme().equals("file")) {
File keyfile = new File(mDbUri.getPath());
File parent = keyfile.getParentFile();
if (parent != null) {
i.setData(Uri.parse("file://" + parent.getAbsolutePath()));
}
}
}
} catch (Exception e) {
// Ignore
}
try {
if(fragment != null)
fragment.startActivityForResult(i, FILE_BROWSE);
else
activity.startActivityForResult(i, FILE_BROWSE);
} catch (ActivityNotFoundException e) {
showBrowserDialog();
}
} else {
showBrowserDialog();
}
}
private void showBrowserDialog() {
BrowserDialog browserDialog = new BrowserDialog(activity);
browserDialog.show();
}
public void onActivityResultCallback(
int requestCode,
int resultCode,
Intent data,
KeyFileCallback keyFileCallback) {
switch (requestCode) {
case FILE_BROWSE:
if (resultCode == RESULT_OK) {
String filename = data.getDataString();
Uri keyUri = null;
if (filename != null) {
keyUri = UriUtil.parseDefaultFile(filename);
}
if (keyFileCallback != null)
keyFileCallback.onKeyFileResultCallback(keyUri);
}
break;
case GET_CONTENT:
case OPEN_DOC:
if (resultCode == RESULT_OK) {
if (data != null) {
Uri uri = data.getData();
if (uri != null) {
if (requestCode == GET_CONTENT) {
uri = UriUtil.translate(activity, uri);
}
if (keyFileCallback != null)
keyFileCallback.onKeyFileResultCallback(uri);
}
}
}
break;
}
}
public interface KeyFileCallback {
void onKeyFileResultCallback(Uri uri);
}
}

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="sequentially">
<objectAnimator
android:propertyName="pathData"
android:valueFrom="@string/clip_path_scan_top"
android:valueTo="@string/clip_path_scan_bottom"
android:valueType="pathType"
android:duration="800"
android:interpolator="@android:interpolator/fast_out_slow_in" />
<objectAnimator
android:propertyName="pathData"
android:valueFrom="@string/clip_path_scan_bottom"
android:valueTo="@string/clip_path_scan_top"
android:valueType="pathType"
android:startOffset="50"
android:duration="500"
android:interpolator="@android:interpolator/fast_out_slow_in" />
</set>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/fingerprint_width"
android:height="@dimen/fingerprint_height"
android:viewportWidth="@integer/fingerprint_viewport_width"
android:viewportHeight="@integer/fingerprint_viewport_height">
<group
android:name="fingerprint"
android:pivotX="@integer/fingerprint_viewport_center"
android:pivotY="@integer/fingerprint_viewport_center">
<path
android:name="ridge_1"
android:pathData="@string/path_ridge_1"
android:strokeColor="@color/fingerprint_ridge"
android:strokeLineCap="round"
android:strokeWidth="@integer/fingerprint_stroke_width" />
<path
android:name="ridge_2"
android:pathData="@string/path_ridge_2"
android:strokeColor="@color/fingerprint_ridge"
android:strokeLineCap="round"
android:strokeWidth="@integer/fingerprint_stroke_width" />
<path
android:name="ridge_3"
android:pathData="@string/path_ridge_3"
android:strokeColor="@color/fingerprint_ridge"
android:strokeLineCap="round"
android:strokeWidth="@integer/fingerprint_stroke_width" />
<path
android:name="ridge_4"
android:pathData="@string/path_ridge_4"
android:strokeColor="@color/fingerprint_ridge"
android:strokeLineCap="round"
android:strokeWidth="@integer/fingerprint_stroke_width" />
<path
android:name="ridge_5"
android:pathData="@string/path_ridge_5"
android:strokeColor="@color/fingerprint_ridge"
android:strokeLineCap="round"
android:strokeWidth="@integer/fingerprint_stroke_width" />
</group>
</vector>

View File

@@ -0,0 +1,109 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/fingerprint_width"
android:height="@dimen/fingerprint_height"
android:viewportWidth="@integer/fingerprint_viewport_width"
android:viewportHeight="@integer/fingerprint_viewport_height">
<group
android:name="fingerprint">
<path
android:name="ridge_1"
android:pathData="@string/path_ridge_1"
android:strokeColor="@color/fingerprint_ridge"
android:strokeLineCap="round"
android:strokeWidth="@integer/fingerprint_stroke_width" />
<path
android:name="ridge_2"
android:pathData="@string/path_ridge_2"
android:strokeColor="@color/fingerprint_ridge"
android:strokeLineCap="round"
android:strokeWidth="@integer/fingerprint_stroke_width" />
<path
android:name="ridge_3"
android:pathData="@string/path_ridge_3"
android:strokeColor="@color/fingerprint_ridge"
android:strokeLineCap="round"
android:strokeWidth="@integer/fingerprint_stroke_width" />
<path
android:name="ridge_4"
android:pathData="@string/path_ridge_4"
android:strokeColor="@color/fingerprint_ridge"
android:strokeLineCap="round"
android:strokeWidth="@integer/fingerprint_stroke_width" />
<path
android:name="ridge_5"
android:pathData="@string/path_ridge_5"
android:strokeColor="@color/fingerprint_ridge"
android:strokeLineCap="round"
android:strokeWidth="@integer/fingerprint_stroke_width" />
</group>
<!-- we overlay the above with a duplicate of the fingerprint which is colored differently
and uses a clip to only reveal portions at a time. -->
<group
android:name="fingerprint_scan">
<clip-path
android:name="scan_clip"
android:pathData="@string/clip_path_scan_top" />
<path
android:name="ridge_1"
android:pathData="@string/path_ridge_1"
android:strokeColor="@color/fingerprint_ridge_scan"
android:strokeLineCap="round"
android:strokeWidth="@integer/fingerprint_stroke_width" />
<path
android:name="ridge_2"
android:pathData="@string/path_ridge_2"
android:strokeColor="@color/fingerprint_ridge_scan"
android:strokeLineCap="round"
android:strokeWidth="@integer/fingerprint_stroke_width" />
<path
android:name="ridge_3"
android:pathData="@string/path_ridge_3"
android:strokeColor="@color/fingerprint_ridge_scan"
android:strokeLineCap="round"
android:strokeWidth="@integer/fingerprint_stroke_width" />
<path
android:name="ridge_4"
android:pathData="@string/path_ridge_4"
android:strokeColor="@color/fingerprint_ridge_scan"
android:strokeLineCap="round"
android:strokeWidth="@integer/fingerprint_stroke_width" />
<path
android:name="ridge_5"
android:pathData="@string/path_ridge_5"
android:strokeColor="@color/fingerprint_ridge_scan"
android:strokeLineCap="round"
android:strokeWidth="@integer/fingerprint_stroke_width" />
</group>
</vector>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/circle"
/>
<item
android:drawable="@drawable/ic_lock_open_white_24dp"
android:bottom="12dp"
android:left="12dp"
android:right="12dp"
android:top="12dp"/>
</layer-list>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/fingerprint_scan">
<target
android:name="scan_clip"
android:animation="@animator/scan" />
</animated-vector>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
android:color="@color/green"/>
</shape>

View File

@@ -0,0 +1,10 @@
<!-- drawable/database_plus.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M9,3C4.58,3 1,4.79 1,7C1,9.21 4.58,11 9,11C13.42,11 17,9.21 17,7C17,4.79 13.42,3 9,3M1,9V12C1,14.21 4.58,16 9,16C13.42,16 17,14.21 17,12V9C17,11.21 13.42,13 9,13C4.58,13 1,11.21 1,9M1,14V17C1,19.21 4.58,21 9,21C10.41,21 11.79,20.81 13,20.46V17.46C11.79,17.81 10.41,18 9,18C4.58,18 1,16.21 1,14M18,14V17H15V19H18V22H20V19H23V17H20V14" />
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="?attr/iconPreferenceColor"
android:pathData="M11,4.07L11,2.05c-2.01,0.2 -3.84,1 -5.32,2.21L7.1,5.69c1.11,-0.86 2.44,-1.44 3.9,-1.62zM18.32,4.26C16.84,3.05 15.01,2.25 13,2.05v2.02c1.46,0.18 2.79,0.76 3.9,1.62l1.42,-1.43zM19.93,11h2.02c-0.2,-2.01 -1,-3.84 -2.21,-5.32L18.31,7.1c0.86,1.11 1.44,2.44 1.62,3.9zM5.69,7.1L4.26,5.68C3.05,7.16 2.25,8.99 2.05,11h2.02c0.18,-1.46 0.76,-2.79 1.62,-3.9zM4.07,13L2.05,13c0.2,2.01 1,3.84 2.21,5.32l1.43,-1.43c-0.86,-1.1 -1.44,-2.43 -1.62,-3.89zM15,12c0,-1.66 -1.34,-3 -3,-3s-3,1.34 -3,3 1.34,3 3,3 3,-1.34 3,-3zM18.31,16.9l1.43,1.43c1.21,-1.48 2.01,-3.32 2.21,-5.32h-2.02c-0.18,1.45 -0.76,2.78 -1.62,3.89zM13,19.93v2.02c2.01,-0.2 3.84,-1 5.32,-2.21l-1.43,-1.43c-1.1,0.86 -2.43,1.44 -3.89,1.62zM5.68,19.74C7.16,20.95 9,21.75 11,21.95v-2.02c-1.46,-0.18 -2.79,-0.76 -3.9,-1.62l-1.42,1.43z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6h1.9c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM18,20L6,20L6,10h12v10z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<!-- drawable/folder_open.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M19,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10L12,6H19A2,2 0 0,1 21,8H21L4,8V18L6.14,10H23.21L20.93,18.5C20.7,19.37 19.92,20 19,20Z" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,136 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/default_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.Title"
android:text="@string/fingerprint_quick_unlock_title"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="20dp"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.WarningTextStyle"
android:text="@string/chapter_1"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/fingerprint_setting_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
style="@style/KeepassDXStyle.TextAppearance.TinyText"
android:text="@string/fingerprint_setting_text"/>
<TextView
android:id="@+id/fingerprint_setting_way_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.TinyText"
android:textColor="?attr/colorAccent"
android:text="@string/fingerprint_setting_way_text"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="12dp">
<TextView
android:layout_width="20dp"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.WarningTextStyle"
android:text="@string/chapter_2"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.TinyText"
android:padding="5dp"
android:text="@string/fingerprint_type_password_text"/>
<android.support.v7.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="38dp"
android:src="@drawable/type_assword"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="12dp">
<TextView
android:layout_width="20dp"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.WarningTextStyle"
android:text="@string/chapter_3" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.TinyText"
android:padding="5dp"
android:text="@string/fingerprint_scan_to_store"/>
</LinearLayout>
<android.support.v7.widget.AppCompatImageView
android:id="@+id/fingerprint_image"
android:layout_gravity="center"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginBottom="8dp"
android:elevation="4dp"
android:src="@drawable/fingerprint"
android:background="@drawable/circle"
android:backgroundTint="?attr/colorAccent"
tools:targetApi="lollipop" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.Title"
android:text="@string/usage" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.TinyText"
android:padding="5dp"
android:gravity="center"
android:text="@string/fingerprint_scan_to_open"/>
<android.support.v7.widget.AppCompatImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:elevation="4dp"
android:layout_marginBottom="8dp"
android:layout_gravity="center"
android:src="@drawable/lock_open"
android:background="@drawable/circle"
android:backgroundTint="?attr/colorPrimary"
tools:targetApi="lollipop" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fingerprint_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:visibility="gone">
<!-- added these 2 fingerprint related views -->
<android.support.v7.widget.AppCompatImageView
android:id="@+id/fingerprint_image"
android:layout_width="38dp"
android:layout_height="38dp"
android:layout_margin="4dp"
android:layout_alignParentEnd="true"
android:elevation="4dp"
android:src="@drawable/fingerprint"
android:background="@drawable/circle"
android:backgroundTint="?attr/colorAccent" />
<TextView
android:id="@+id/fingerprint_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/fingerprint_image"
android:gravity="center_vertical|end"
android:text="@string/entry_and_or"
android:textColor="?attr/colorAccent" />
</RelativeLayout>

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/default_margin">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatImageView
android:id="@+id/browse_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="6dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignBottom="@+id/folder_path_input_layout"
android:src="@drawable/ic_folder_white_24dp"
android:tint="?attr/colorAccentCompat" />
<android.support.design.widget.TextInputLayout
android:id="@+id/folder_path_input_layout"
android:layout_toLeftOf="@id/browse_button"
android:layout_toStartOf="@id/browse_button"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:id="@+id/folder_path"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/path"
android:inputType="textUri"
android:maxLines="1"
android:singleLine="true"/>
</android.support.design.widget.TextInputLayout>
</RelativeLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputLayout
android:id="@+id/filename_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/file_types"
android:layout_toStartOf="@+id/file_types">
<android.support.design.widget.TextInputEditText
android:id="@+id/filename"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/file_name"
android:text="@string/database_file_name_default"
android:inputType="textUri"
android:maxLines="1"
android:singleLine="true"/>
</android.support.design.widget.TextInputLayout>
<android.support.v7.widget.AppCompatSpinner
android:id="@+id/file_types"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/filename_input_layout"
android:layout_marginBottom="8dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@@ -17,32 +17,47 @@
You should have received a copy of the GNU General Public License
along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar_default" />
<com.keepassdroid.view.FileNameView android:id="@+id/file_select"
android:layout_marginBottom="@dimen/default_margin"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:layout_height="match_parent"
android:orientation="vertical">
<TextView android:id="@+id/file_listtop"
android:layout_marginTop="@dimen/default_margin"
android:layout_marginLeft="@dimen/default_margin"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginRight="@dimen/default_margin"
android:layout_marginEnd="@dimen/default_margin"
android:layout_width="match_parent"
<include
android:id="@+id/toolbar"
layout="@layout/toolbar_default" />
<com.keepassdroid.view.FileNameView android:id="@+id/file_select"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView android:id="@+id/file_listtop"
android:layout_marginLeft="@dimen/default_margin"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginRight="@dimen/default_margin"
android:layout_marginEnd="@dimen/default_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.Title"
android:text="@string/open_recent" />
<ListView android:id="@+id/file_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/create_database"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.Title"
android:text="@string/open_recent" />
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:src="@drawable/ic_database_plus_white_24dp"
style="@style/KeepassDXStyle.Fab"/>
<ListView android:id="@+id/file_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</RelativeLayout>

View File

@@ -17,62 +17,76 @@
You should have received a copy of the GNU General Public License
along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_margin="@dimen/default_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView android:id="@+id/label_warning"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:visibility="invisible" />
<TextView android:id="@+id/label_open_by_filename"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.Title"
android:text="@string/enter_filename"/>
<android.support.v7.widget.AppCompatImageView
android:id="@+id/browse_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/file_filename"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_below="@id/label_open_by_filename"
android:padding="6dp"
android:src="@drawable/ic_folder_white_24dp"
android:tint="?attr/colorAccentCompat" />
<android.support.v7.widget.AppCompatEditText
android:id="@+id/file_filename"
<android.support.v7.widget.CardView
android:id="@+id/filename_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/label_open_by_filename"
android:inputType="textUri"
android:layout_toLeftOf="@+id/browse_button"
android:layout_toStartOf="@+id/browse_button"
android:maxLines="1" />
android:layout_marginBottom="32dp">
<android.support.v7.widget.AppCompatButton android:id="@+id/open"
android:layout_margin="@dimen/button_margin"
android:text="@string/menu_open"
android:layout_below="@id/file_filename"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_toLeftOf="@+id/create"
android:layout_toStartOf="@+id/create"
android:width="100sp"/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/default_margin"
android:layout_marginLeft="@dimen/default_margin"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginRight="@dimen/default_margin"
android:layout_marginEnd="@dimen/default_margin"
android:layout_marginBottom="12dp">
<android.support.v7.widget.AppCompatButton android:id="@+id/create"
android:layout_margin="@dimen/button_margin"
android:text="@string/menu_create"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_below="@id/file_filename"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:width="100sp"/>
</RelativeLayout>
<TextView android:id="@+id/label_warning"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:visibility="invisible" />
<TextView android:id="@+id/label_open_by_filename"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.Title"
android:text="@string/enter_filename"/>
<android.support.v7.widget.AppCompatImageView
android:id="@+id/browse_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/file_filename"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_below="@id/label_open_by_filename"
android:padding="6dp"
android:src="@drawable/ic_folder_white_24dp"
android:tint="?attr/colorAccentCompat" />
<android.support.v7.widget.AppCompatEditText
android:id="@+id/file_filename"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/label_open_by_filename"
android:inputType="textUri"
android:layout_toLeftOf="@+id/browse_button"
android:layout_toStartOf="@+id/browse_button"
android:maxLines="1" />
</RelativeLayout>
</android.support.v7.widget.CardView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/open_database"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/filename_container"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginEnd="24dp"
android:layout_marginRight="24dp"
app:fabSize="mini"
app:layout_anchor="@id/filename_container"
app:layout_anchorGravity="bottom|start"
android:src="@drawable/ic_open_folder_white_24dp" />
</android.support.design.widget.CoordinatorLayout>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fingerprint_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:visibility="gone" />

View File

@@ -20,6 +20,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -35,7 +36,8 @@
android:layout_height="wrap_content"
android:ems="10"
android:maxLines="3"
android:hint="@string/hint_generated_password" />
android:hint="@string/hint_generated_password"
tools:ignore="TextFields" />
<Button android:id="@+id/generate_password_button"
android:layout_margin="@dimen/button_margin"
@@ -71,7 +73,7 @@
android:maxLines="1"
android:maxLength="3"
android:inputType="number"
android:text="@integer/default_password_length"
android:text="@string/default_password_length"
android:hint="@string/hint_length"/>
<android.support.v7.widget.AppCompatSeekBar android:id="@+id/seekbar_length"
@@ -83,59 +85,176 @@
android:layout_alignTop="@+id/length"
android:layout_toEndOf="@+id/length"
android:layout_toRightOf="@+id/length"
app:min="1"
android:progress="@integer/default_password_length"
android:max="64"/>
app:min="@string/min_password_length"
android:progress="@string/default_password_length"
android:max="@string/max_password_length"/>
</RelativeLayout>
<LinearLayout android:id="@+id/RelativeLayout"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical">
android:orientation="vertical"
android:layout_marginRight="20dp"
android:layout_marginEnd="20dp">
<CheckBox android:id="@+id/cb_uppercase"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/uppercase"
android:checked="true" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_uppercase"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/uppercase"
android:checked="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="end"
android:layout_toEndOf="@+id/cb_uppercase"
android:layout_toRightOf="@+id/cb_uppercase"
android:text="@string/visual_uppercase" />
</RelativeLayout>
<CheckBox android:id="@+id/cb_lowercase"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/lowercase"
android:checked="true" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_lowercase"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/lowercase"
android:checked="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="end"
android:layout_toEndOf="@+id/cb_lowercase"
android:layout_toRightOf="@+id/cb_lowercase"
android:text="@string/visual_lowercase" />
</RelativeLayout>
<CheckBox android:id="@+id/cb_digits"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/digits"
android:checked="true" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_digits"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/digits"
android:checked="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="end"
android:layout_toEndOf="@+id/cb_digits"
android:layout_toRightOf="@+id/cb_digits"
android:text="@string/visual_digits" />
</RelativeLayout>
<CheckBox android:id="@+id/cb_minus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/minus" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_minus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/minus" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="end"
android:layout_toEndOf="@+id/cb_minus"
android:layout_toRightOf="@+id/cb_minus"
android:text="@string/visual_minus" />
</RelativeLayout>
<CheckBox android:id="@+id/cb_underline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/underline" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_underline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/underline" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="end"
android:layout_toEndOf="@+id/cb_underline"
android:layout_toRightOf="@+id/cb_underline"
android:text="@string/visual_underline" />
</RelativeLayout>
<CheckBox android:id="@+id/cb_space"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/space" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_space"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/space" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="end"
android:layout_toEndOf="@+id/cb_space"
android:layout_toRightOf="@+id/cb_space"
android:text="@string/visual_space" />
</RelativeLayout>
<CheckBox android:id="@+id/cb_specials"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/special" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_specials"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/special" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="end"
android:layout_toEndOf="@+id/cb_specials"
android:layout_toRightOf="@+id/cb_specials"
android:text="@string/visual_special" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_brackets"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/brackets"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="end"
android:layout_toEndOf="@+id/cb_brackets"
android:layout_toRightOf="@+id/cb_brackets"
android:text="@string/visual_brackets" />
</RelativeLayout>
<CheckBox android:id="@+id/cb_brackets"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/brackets" />
</LinearLayout>
</LinearLayout>
</ScrollView>

View File

@@ -24,13 +24,13 @@
android:id="@+id/group_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ListView android:id="@android:id/list"
<ListView android:id="@+id/group_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/group_header"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@android:id/list"
android:layout_below="@id/group_list"
android:text="@string/no_results"/>
</RelativeLayout>

View File

@@ -59,60 +59,44 @@
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/toolbar"
android:layout_above="@+id/pass_ok">
android:layout_below="@+id/toolbar">
<RelativeLayout
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/default_margin">
<TextView
android:id="@+id/password_label"
style="@style/KeepassDXStyle.TextAppearance.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/entry_and_or" />
<include
layout="@layout/fingerprint_show" />
<!-- Password Input -->
<RelativeLayout
android:id="@+id/password_container"
android:layout_width="match_parent"
android:id="@+id/password_input_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/password_label"
style="@style/KeepassDXStyle.TextAppearance.Title"
<android.support.v7.widget.AppCompatCheckBox
android:id="@+id/password_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/entry_and_or" />
android:layout_alignParentBottom="true"
android:paddingBottom="20dp"
android:gravity="center_vertical" />
<!-- added these 2 fingerprint related views -->
<android.support.v7.widget.AppCompatImageView
android:id="@+id/fingerprint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_small"
android:layout_marginRight="@dimen/margin_small"
android:layout_below="@id/password_label"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:src="@drawable/ic_fp_40px"
android:visibility="gone"
tools:visibility="visible"
/>
<TextView
android:id="@+id/fingerprint_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/fingerprint"
android:layout_below="@+id/password_label"
android:layout_toLeftOf="@id/fingerprint"
android:layout_toStartOf="@id/fingerprint"
android:gravity="center_vertical|end"
android:text="@string/entry_and_or"
android:visibility="gone"
tools:visibility="visible" />
<!-- Password Input -->
<android.support.design.widget.TextInputLayout
android:id="@+id/password_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/fingerprint_label"
android:layout_toRightOf="@+id/password_checkbox"
android:layout_toEndOf="@+id/password_checkbox"
app:passwordToggleEnabled="true"
app:passwordToggleTint="?attr/colorAccent">
@@ -120,12 +104,25 @@
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/hint_login_pass"
android:hint="@string/password"
android:inputType="textPassword"
android:maxLines="1"/>
</android.support.design.widget.TextInputLayout>
</RelativeLayout>
<!-- File Input -->
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatCheckBox
android:id="@+id/keyfile_checkox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:paddingBottom="20dp"
android:gravity="center_vertical" />
<!-- File Input -->
<android.support.v7.widget.AppCompatImageView
android:id="@+id/browse_button"
android:layout_width="wrap_content"
@@ -133,36 +130,37 @@
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_below="@+id/password_input_layout"
android:padding="12dp"
android:src="@drawable/ic_folder_white_24dp"
android:tint="?attr/colorAccentCompat" />
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:id="@+id/input_entry_keyfile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/password_input_layout"
android:layout_toLeftOf="@id/browse_button"
android:layout_toStartOf="@id/browse_button" >
android:layout_toEndOf="@+id/keyfile_checkox"
android:layout_toRightOf="@+id/keyfile_checkox"
android:layout_toLeftOf="@+id/browse_button"
android:layout_toStartOf="@+id/browse_button">
<android.support.v7.widget.AppCompatEditText
android:id="@+id/pass_keyfile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:hint="@string/entry_keyfile"
android:inputType="text"
android:hint="@string/entry_keyfile" />
android:maxLines="1" />
</android.support.design.widget.TextInputLayout>
</RelativeLayout>
<android.support.v7.widget.AppCompatCheckBox
<android.support.v7.widget.SwitchCompat
android:id="@+id/default_database"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/password_container"
android:layout_marginTop="8dp"
android:layout_margin="16dp"
android:text="@string/default_checkbox" />
</RelativeLayout>
</LinearLayout>
</ScrollView>

View File

@@ -17,21 +17,25 @@
You should have received a copy of the GNU General Public License
along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/edit"
android:padding="20dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar_default" />
<com.keepassdroid.view.FileNameView android:id="@+id/file_select"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/toolbar" />
<!-- Small hack because I need to include a list since this is a list activity -->
<ListView android:id="@+id/file_list"
android:layout_width="0sp"
android:layout_height="0sp" />
</RelativeLayout>
<android.support.v7.widget.AppCompatTextView
android:layout_marginBottom="8dp"
android:id="@+id/rounds_explanation"
android:gravity="center"
android:text="@string/rounds_explaination"
style="@style/KeepassDXStyle.TextAppearance.SmallTitle"
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
<android.support.v7.widget.AppCompatEditText
android:id="@+id/rounds"
android:hint="@string/rounds_hint"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:digits="0123456789"
android:inputType="number"/>
</LinearLayout>

View File

@@ -17,27 +17,109 @@
You should have received a copy of the GNU General Public License
along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="@dimen/default_margin"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText android:id="@+id/pass_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:maxLines="1"
android:hint="@string/hint_pass"/>
<EditText android:id="@+id/pass_conf_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/pass_password"
android:inputType="textPassword"
android:maxLines="1"
android:hint="@string/hint_conf_pass"/>
<EditText android:id="@+id/pass_keyfile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/pass_conf_password"
android:maxLines="1"
android:hint="@string/hint_keyfile"/>
</RelativeLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:padding="@dimen/default_margin"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
android:id="@+id/card_view_master_password"
android:layout_margin="4dp"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/default_margin"
android:orientation="vertical">
<android.support.v7.widget.AppCompatCheckBox
android:id="@+id/password_checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/password"/>
<!-- Password Input -->
<android.support.design.widget.TextInputLayout
android:id="@+id/password_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:passwordToggleEnabled="true"
app:passwordToggleTint="?attr/colorAccent">
<android.support.design.widget.TextInputEditText
android:id="@+id/pass_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:maxLines="1"
android:hint="@string/hint_pass"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/password_repeat_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:passwordToggleEnabled="true"
app:passwordToggleTint="?attr/colorAccent">
<EditText android:id="@+id/pass_conf_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:maxLines="1"
android:hint="@string/hint_conf_pass"/>
</android.support.design.widget.TextInputLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/card_view_key_file"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
app:cardCornerRadius="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/default_margin"
android:orientation="vertical">
<android.support.v7.widget.AppCompatCheckBox
android:id="@+id/keyfile_checkox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/entry_keyfile"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatImageView
android:id="@+id/browse_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:padding="12dp"
android:src="@drawable/ic_folder_white_24dp"
android:tint="?attr/colorAccentCompat" />
<android.support.v7.widget.AppCompatEditText
android:id="@+id/pass_keyfile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/browse_button"
android:layout_toStartOf="@+id/browse_button"
android:hint="@string/hint_keyfile"
android:maxLines="1"
android:singleLine="true"/>
</RelativeLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>

View File

@@ -61,7 +61,7 @@
<string name="entry_confpassword">Confirma contrasenya:</string>
<string name="entry_created">Creada: </string>
<string name="entry_expires">Expira: </string>
<string name="entry_keyfile">Arxiu clau (opcional)</string>
<string name="entry_keyfile">Arxiu clau</string>
<string name="entry_modified">Modificada: </string>
<string name="entry_password">Contrasenya:</string>
<string name="entry_save">Guarda</string>
@@ -80,7 +80,7 @@
<string name="error_invalid_db">Base de dades invàlida.</string>
<string name="error_invalid_path">Camí invàlid.</string>
<string name="error_no_name">És necessari un nom.</string>
<string name="error_nopass">És necessaria una contrasenya o un arxiu clau.</string>
<string name="error_nokeyfile">És necessaria una contrasenya o un arxiu clau.</string>
<string name="error_out_of_memory">El telèfon sha quedat sense memòria processant la teva base de dades. Potser és massa gran pel teu telèfon.</string>
<string name="error_pass_gen_type">Has de seleccionar almenys un tipus de generador de contrasenyes</string>
<string name="error_pass_match">Les contrasenyes no coincideixen.</string>
@@ -99,7 +99,7 @@
<string name="hint_keyfile">arxiu clau</string>
<string name="hint_length">longitud</string>
<string name="hint_pass">contrasenya</string>
<string name="hint_login_pass">Contrasenya</string>
<string name="password">Contrasenya</string>
<string name="hint_title">nom</string>
<string name="hint_url">url</string>
<string name="hint_username">usuari</string>

View File

@@ -66,7 +66,7 @@
<string name="entry_confpassword">Potvrďte heslo:</string>
<string name="entry_created">Vytvořeno: </string>
<string name="entry_expires">Vyprší: </string>
<string name="entry_keyfile">Klíčový soubor (nepovinné)</string>
<string name="entry_keyfile">Klíčový soubor</string>
<string name="entry_modified">Změněno: </string>
<string name="entry_not_found">Vstupní data nenalezena.</string>
<string name="entry_password">Heslo:</string>
@@ -86,7 +86,7 @@
<string name="error_invalid_db">Chybná databáze.</string>
<string name="error_invalid_path">Chybná cesta.</string>
<string name="error_no_name">Jméno je povinné.</string>
<string name="error_nopass">Heslo nebo klíčový soubor jsou povinné.</string>
<string name="error_nokeyfile">Heslo nebo klíčový soubor jsou povinné.</string>
<string name="error_out_of_memory">Přístroj má málo paměti pro zpracování databáze. Možná je příliš velká pro Váš přístroj.</string>
<string name="error_pass_gen_type">Minimálně jeden typ generování hesla musí být zvolen</string>
<string name="error_pass_match">Hesla se neshodují.</string>
@@ -108,7 +108,7 @@
<string name="hint_keyfile">klíčový soubor</string>
<string name="hint_length">délka</string>
<string name="hint_pass">heslo</string>
<string name="hint_login_pass">Heslo</string>
<string name="password">Heslo</string>
<string name="hint_title">název</string>
<string name="hint_url">url</string>
<string name="hint_username">uživatelské jméno</string>

View File

@@ -65,7 +65,7 @@
<string name="entry_confpassword">Bekræft adgangskode:</string>
<string name="entry_created">Oprettet: </string>
<string name="entry_expires">Udløber: </string>
<string name="entry_keyfile">Nøglefil (valgfri)</string>
<string name="entry_keyfile">Nøglefil</string>
<string name="entry_modified">Ændret: </string>
<string name="entry_not_found">Data for posten blev ikke fundet.</string>
<string name="entry_password">Adgangskode:</string>
@@ -85,7 +85,7 @@
<string name="error_invalid_db">Ugyldig database.</string>
<string name="error_invalid_path">Ugyldig sti.</string>
<string name="error_no_name">Et navn er påkrævet.</string>
<string name="error_nopass">En adgangskode eller nøglefil er påkrævet.</string>
<string name="error_nokeyfile">En adgangskode eller nøglefil er påkrævet.</string>
<string name="error_out_of_memory">Telefonen løb tør for hukommelse under analysen af din database. Den kan være for stor til, at din telefon kan håndtere den.</string>
<string name="error_pass_gen_type">Mindst én adgangskode-genererings-type skal vælges</string>
<string name="error_pass_match">Adgangskoder matcher ikke.</string>
@@ -107,7 +107,7 @@
<string name="hint_keyfile">nøglefil</string>
<string name="hint_length">længde</string>
<string name="hint_pass">adgangskode</string>
<string name="hint_login_pass">Adgangskode</string>
<string name="password">Adgangskode</string>
<string name="hint_title">navn</string>
<string name="hint_url">url</string>
<string name="hint_username">brugernavn</string>

View File

@@ -69,7 +69,7 @@
<string name="entry_confpassword">Passwort wiederholen:</string>
<string name="entry_created">Erstelldatum:</string>
<string name="entry_expires">Ablaufdatum:</string>
<string name="entry_keyfile">Schlüsseldatei (optional)</string>
<string name="entry_keyfile">Schlüsseldatei</string>
<string name="entry_modified">Änderungsdatum:</string>
<string name="entry_not_found">Eintrag wurde nicht gefunden.</string>
<string name="entry_password">Passwort:</string>
@@ -89,7 +89,7 @@
<string name="error_invalid_db">Ungültige Datenbank.</string>
<string name="error_invalid_path">Ungültiger Pfad.</string>
<string name="error_no_name">Ein Name wird benötigt.</string>
<string name="error_nopass">Ein Passwort oder eine Schlüsseldatei wird benötigt.</string>
<string name="error_nokeyfile">Ein Passwort oder eine Schlüsseldatei wird benötigt.</string>
<string name="error_out_of_memory">Der Speicher Ihres Smartphones reicht nicht aus, um die Datenbank zu analysieren. Sie ist wahrscheinlich zu groß.</string>
<string name="error_pass_gen_type">Mindestens ein Passwort-Generierungstyp muss ausgewählt werden.</string>
<string name="error_pass_match">Die Passwörter stimmen nicht überein.</string>
@@ -112,7 +112,7 @@
<string name="hint_keyfile">Schlüsseldatei</string>
<string name="hint_length">Länge</string>
<string name="hint_pass">Passwort</string>
<string name="hint_login_pass">Passwort</string>
<string name="password">Passwort</string>
<string name="hint_title">Name</string>
<string name="hint_url">URL-Adresse</string>
<string name="hint_username">Benutzername</string>

View File

@@ -63,7 +63,7 @@
<string name="entry_confpassword">Επιβεβαίωση κωδικού πρόσβασης:</string>
<string name="entry_created">Δημιουργήθηκε: </string>
<string name="entry_expires">Λήγει: </string>
<string name="entry_keyfile">Αρχείο Κλειδιού (προαιρετικό)</string>
<string name="entry_keyfile">Αρχείο Κλειδιού</string>
<string name="entry_modified">Τροποποιήθηκε: </string>
<string name="entry_not_found">Δεν βρέθηκαν δεδομένα εγγραφών.</string>
<string name="entry_password">Κωδικός Πρόσβασης:</string>
@@ -83,7 +83,7 @@
<string name="error_invalid_db">Μη έγκυρη βάση δεδομένων.</string>
<string name="error_invalid_path">Μη έγκυρη διαδρομή.</string>
<string name="error_no_name">Απαιτείται ένα όνομα.</string>
<string name="error_nopass">Απαιτείται ο κωδικός πρόσβασης ή ένα αρχείο κλειδιού.</string>
<string name="error_nokeyfile">Απαιτείται ο κωδικός πρόσβασης ή ένα αρχείο κλειδιού.</string>
<string name="error_out_of_memory">Το τηλέφωνο ξέμεινε από μνήμη κατά τη διάρκεια προσπέλασης της βάσης δεδομένων σας. Μπορεί να είναι πολύ μεγάλη για το τηλέφωνο σας.</string>
<string name="error_pass_gen_type">Πρέπει να επιλεγεί τουλάχιστον ένας τύπος δημιουργίας κωδικού πρόσβασης</string>
<string name="error_pass_match">Οι κωδικοί δεν ταιριάζουν.</string>
@@ -105,7 +105,7 @@
<string name="hint_keyfile">αρχείο κλειδιού</string>
<string name="hint_length">μήκος</string>
<string name="hint_pass">κωδικός</string>
<string name="hint_login_pass">Κωδικός Πρόσβασης</string>
<string name="password">Κωδικός Πρόσβασης</string>
<string name="hint_title">όνομα</string>
<string name="hint_url">διεύθυνση url</string>
<string name="hint_username">όνομα χρήστη</string>

View File

@@ -60,7 +60,7 @@ Spanish translation by José I. Paños. Updated by David García-Abad (23-09-201
<string name="entry_confpassword">Confirmar contraseña:</string>
<string name="entry_created">Creación: </string>
<string name="entry_expires">Caducidad: </string>
<string name="entry_keyfile">Archivo de clave (opcional)</string>
<string name="entry_keyfile">Archivo de clave</string>
<string name="entry_modified">Modificación: </string>
<string name="entry_password">Contraseña:</string>
<string name="entry_save">Guardar</string>
@@ -79,7 +79,7 @@ Spanish translation by José I. Paños. Updated by David García-Abad (23-09-201
<string name="error_invalid_db">Base de datos no válida.</string>
<string name="error_invalid_path">Ruta no válida.</string>
<string name="error_no_name">Se necesita un nombre.</string>
<string name="error_nopass">Se necesita una contraseña o un archivo de clave.</string>
<string name="error_nokeyfile">Se necesita una contraseña o un archivo de clave.</string>
<string name="error_out_of_memory">El dispositivo se quedó sin memory mientras analizada la base de datos. Puede ser demasiado grande para este dispositivo.</string>
<string name="error_pass_gen_type">Debe seleccionar al menos un tipo de generación de contraseñas</string>
<string name="error_pass_match">Las contraseñas no coinciden.</string>
@@ -97,7 +97,7 @@ Spanish translation by José I. Paños. Updated by David García-Abad (23-09-201
<string name="hint_group_name">Nombre de grupo</string>
<string name="hint_keyfile">archivo clave</string>
<string name="hint_length">longitud</string>
<string name="hint_login_pass">Contraseña</string>
<string name="password">Contraseña</string>
<string name="hint_pass">contraseña</string>
<string name="hint_title">nombre</string>
<string name="hint_url">url</string>

View File

@@ -65,7 +65,7 @@
<string name="entry_confpassword">Pasahitza berretsi:</string>
<string name="entry_created">Sortua: </string>
<string name="entry_expires">Iraungitzen da: </string>
<string name="entry_keyfile">Gako fitxategia (aukerazkoa)</string>
<string name="entry_keyfile">Gako fitxategia</string>
<string name="entry_modified">Aldatua: </string>
<string name="entry_not_found">Sarreraren datuak ez aurkituak.</string>
<string name="entry_password">Pasahitza:</string>
@@ -85,7 +85,7 @@
<string name="error_invalid_db">Datubase baliogabea.</string>
<string name="error_invalid_path">Fitxategirako bide baliogabea.</string>
<string name="error_no_name">Izen bat behar da.</string>
<string name="error_nopass">Pasahitz edo gako fitxategi bat beharrezkoak dira.</string>
<string name="error_nokeyfile">Pasahitz edo gako fitxategi bat beharrezkoak dira.</string>
<string name="error_out_of_memory">Telefonoa memoriarik gabe gelditu da zure datubasea arakatzean. Handiegia izan daiteke zure telefonorako.</string>
<string name="error_pass_gen_type">Pasahitza sortzeko mota bat gutxienez aukeratu behar da</string>
<string name="error_pass_match">Pasahitzak ez datoz bat.</string>
@@ -107,7 +107,7 @@
<string name="hint_keyfile">gako fitxategia</string>
<string name="hint_length">luzera</string>
<string name="hint_pass">pasahitza</string>
<string name="hint_login_pass">Pasahitza</string>
<string name="password">Pasahitza</string>
<string name="hint_title">izena</string>
<string name="hint_url">url</string>
<string name="hint_username">erabiltzaile izena</string>

View File

@@ -63,7 +63,7 @@
<string name="entry_confpassword">Vahvista salasana:</string>
<string name="entry_created">Luotu: </string>
<string name="entry_expires">Vanhenee: </string>
<string name="entry_keyfile">Avaintiedosto (valinnainen)</string>
<string name="entry_keyfile">Avaintiedosto</string>
<string name="entry_modified">Muokattu: </string>
<string name="entry_not_found">Tietueen tietoja ei löytynyt.</string>
<string name="entry_password">Salasana:</string>
@@ -83,7 +83,7 @@
<string name="error_invalid_db">Viallinen salasanatietokanta.</string>
<string name="error_invalid_path">Viallinen hakemistopolku.</string>
<string name="error_no_name">Nimi puuttuu.</string>
<string name="error_nopass">Salasana tai avaintiedosto puuttuu.</string>
<string name="error_nokeyfile">Salasana tai avaintiedosto puuttuu.</string>
<string name="error_out_of_memory">Puhelimesta loppui muisti salasanatietokantaa avatessa. Tietokanta voi olla liian suuri tälle puhelinmallille.</string>
<string name="error_pass_gen_type">Vähintään yksi salasanagenerointitapa täytyy olla valittuna.</string>
<string name="error_pass_match">Salasanat eivät täsmää.</string>
@@ -105,7 +105,7 @@
<string name="hint_keyfile">avaintiedosto</string>
<string name="hint_length">pituus</string>
<string name="hint_pass">salasana</string>
<string name="hint_login_pass">Salasana</string>
<string name="password">Salasana</string>
<string name="hint_title">nimi</string>
<string name="hint_url">url-osoite</string>
<string name="hint_username">käyttäjänimi</string>

View File

@@ -66,7 +66,7 @@
<string name="entry_confpassword">Confirmer mot de passe</string>
<string name="entry_created">Créé</string>
<string name="entry_expires">Expire</string>
<string name="entry_keyfile">Clé (facultative)</string>
<string name="entry_keyfile">Fichier clé</string>
<string name="entry_modified">Modifié</string>
<string name="entry_not_found">Entry data not found.</string>
<string name="entry_password">Mot de passe</string>
@@ -86,12 +86,12 @@
<string name="error_invalid_db">Base de données invalide.</string>
<string name="error_invalid_path">Chemin invalide.</string>
<string name="error_no_name">Le nom est obligatoire.</string>
<string name="error_nopass">Un mot de passe ou clé de fichier est requis.</string>
<string name="error_nokeyfile">Un fichier clé est requis.</string>
<string name="error_out_of_memory">Votre appareil ne dispose pas de suffisamment de mémoire pour ouvrir votre base de données. Elle est probablement trop grosse pour votre appareil.</string>
<string name="error_pass_gen_type">Au moins un type de génération de mot de passe doit être sélectionné</string>
<string name="error_pass_match">Les mots de passe ne correspondent pas.</string>
<string name="error_rounds_not_number">La série doit être un nombre.</string>
<string name="error_rounds_too_large">Rounds too big. Setting to 2147483648.</string>
<string name="error_rounds_too_large">Niveau trop gros. Paramètres à 2147483648.</string>
<string name="error_string_key">A field name is required for each string.</string>
<string name="error_title_required">Le titre est obligatoire.</string>
<string name="error_wrong_length">Entrez un entier positif pour la longueur du champ</string>
@@ -109,7 +109,7 @@
<string name="hint_keyfile">clé de fichier</string>
<string name="hint_length">longueur</string>
<string name="hint_pass">mot de passe</string>
<string name="hint_login_pass">Mot de passe</string>
<string name="password">Mot de passe</string>
<string name="hint_title">nom</string>
<string name="hint_url">URL</string>
<string name="hint_username">nom d\'utilisateur</string>
@@ -172,6 +172,9 @@
<string name="rounds">Niveau du chiffrement</string>
<string name="rounds_explaination">Un niveau de chiffrement supérieur assure une protection supplémentaire contre les attaques de force brute, mais peut considérablement ralentir l\'ouverture et l\'enregistrement.</string>
<string name="rounds_hint">niveaux</string>
<string name="rounds_fix_title">Résolution de la base de données</string>
<string name="rounds_fix">Clé de niveau de chiffrement avant corruption</string>
<string name="rounds_fix_explanation">Si votre base de données a été corrompue par KeePassDroid version 2.2.0.0 à 2.2.0.6, entrez le niveau de chiffrement utilisé précédemment et cela vous permettra d\'ouvrir votre base.</string>
<string name="saving_database">Enregistrement de la base de données…</string>
<string name="space">Espace</string>
<string name="search_label">Rechercher</string>
@@ -191,6 +194,8 @@
<string name="warning_password_encoding">Le format .kdb ne supporte que le jeu de caractère Latin1. Votre mot de passe doit contenir des caractères en dehors de ce jeu. Tous les caractères non-Latin1 sont convertis en un même caractère, ce qui diminue la sécurité de votre mot de passe. Le changement de votre mot de passe est recommandé.</string>
<string name="warning_read_only">Votre carte SD est actuellement en lecture seule. Vous ne pourrez pas enregistrer les changements dans la base de données.</string>
<string name="warning_unmounted">Votre carte SD n\'est actuellement pas montée sur votre appareil. Vous ne pourrez pas charger ou créer votre base de données.</string>
<string name="warning_empty_password">Voulez-vous vraiment utiliser une chaine de caractères vide comme mot de passe ?</string>
<string name="warning_no_encryption_key">Etes-vous sûr de ne vouloir utiliser aucune clé de chiffrement.</string>
<string name="version_label">Version\u00A0:</string>
<string name="configure_fingerprint">Reconnaissance d\'empreinte digitale non configuré pour cet appareil</string>
<string name="scanning_fingerprint">Attente d\'une reconnaissance d\'empreinte digitale</string>
@@ -199,6 +204,32 @@
<string name="fingerprint_error">Problème d\'empreinte digitale</string>
<string name="store_with_fingerprint">Utiliser l\'empreinte digitale pour stocker le mot de passe</string>
<string name="no_password_stored">Pas de mot de passe encore stocké pour cette base de données</string>
<string name="history">Historique</string>
<string name="appearance">Apparence</string>
<string name="general">Générale</string>
<string name="password_size_title">Taille de mot de passe</string>
<string name="password_size_summary">Définir la taille par défaut du mot de passe généré</string>
<string name="list_password_generator_options_title">Caractères de mot de passe</string>
<string name="list_password_generator_options_summary">Définir les caractères par défaut du générateur de mot de passe</string>
<string name="clipboard_notifications_title">Notifications du presse-papiers</string>
<string name="clipboard_notifications_summary">Activer les notifications du presse-papiers pour copier le nom d\'utilisateur et le mot de passe</string>
<string name="lock_database_screen_off_title">Verrouillage d\'écran</string>
<string name="lock_database_screen_off_summary">Verrouiller la base de données quand l\'écran est éteint</string>
<string name="fingerprint_quick_unlock_title">Comment configurer l\'empreinte digitale pour un déverrouillage rapide?</string>
<string name="fingerprint_setting_text">Définissez votre empreinte digitale personnelle pour votre appareil dans </string>
<string name="fingerprint_setting_way_text">Paramètres -> Sécurité -> Empreinte digitale</string>
<string name="fingerprint_type_password_text">Tapez votre mot de passe dans Keepass DX</string>
<string name="fingerprint_scan_to_store">Scannez votre empreinte digitale pour stocker votre mot de passe maître en toute sécurité</string>
<string name="fingerprint_scan_to_open">Il suffit de scanner votre empreinte digitale dans Keepass DX lorsque le champ mot de passe est vide pour ouvrir la base de données</string>
<string name="usage">Usage</string>
<string name="fingerprint">Empreinte digitale</string>
<string name="fingerprint_enable_title">Écoute d\'empreintes digitales</string>
<string name="fingerprint_enable_summary">Activer l\'ouverture de la base de données par empreinte digitale</string>
<string name="unavailable_feature_text">Impossible de démarrer cette fonctionnalité\nVotre version Android %1$d n\'est pas la version minimale %2$d requise</string>
<string name="file_name">Nom de fichier</string>
<string name="path">Chemin</string>
<string name="assign_master_key">Assigner une clé maître</string>
<string name="create_keepass_file">Créer un fichier keepass</string>
<string-array name="clipboard_timeout_options">
<item>30 secondes</item>
@@ -218,7 +249,5 @@
<item>Light Theme</item>
<item>Night Theme</item>
</string-array>
<string name="history">Historique</string>
<string name="appearance">Apparence</string>
<string name="general">Générale</string>
</resources>

View File

@@ -1,4 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2009-2016 Brian Pellin.
This file is part of KeePassDroid.
KeePassDroid is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
KeePassDroid is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
-->
<resources>
<string name="about_feedback">Visszajelzés:</string>
<string name="about_homepage">Weboldal:</string>
@@ -35,7 +50,7 @@
<string name="decrypting_entry">Bejegyzés dekódolása</string>
<string name="default_checkbox">Adatbázis beállítása alapértelmezettként</string>
<string name="digits">Számok</string>
<string name="disclaimer_formal">KeePass DX Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft. Ehhez a programhoz SEMMILYEN GARANCIA NEM JÁR; Ez egy szabad szoftver, GNU General Public License v2 vagy későbbi verziójának feltételei mellett terjeszthető, illetve módosítható. Fordította: intel</string>
<string name="disclaimer_formal">KeePass DX Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft. Ehhez a programhoz SEMMILYEN GARANCIA NEM JÁR; Ez egy szabad szoftver, GNU General Public License v2 vagy későbbi verziójának feltételei mellett terjeszthető, illetve módosítható. Fordította: Eversmann</string>
<string name="ellipsis"></string>
<string name="enter_filename">Adja meg az adatbázis fájlnevét:</string>
<string name="entry_accessed">Utolsó hozzáférés:</string>
@@ -45,7 +60,7 @@
<string name="entry_confpassword">Jelszó megerősítése:</string>
<string name="entry_created">Létrehozva:</string>
<string name="entry_expires">Lejárat:</string>
<string name="entry_keyfile">Kulcsfájl (opcionális)</string>
<string name="entry_keyfile">Kulcsfájl</string>
<string name="entry_modified">Módosítva:</string>
<string name="entry_password">Jelszó:</string>
<string name="entry_save">Mentés</string>
@@ -63,19 +78,20 @@
<string name="error_file_not_create">Nem sikerült létrehozni a fájlt:</string>
<string name="error_invalid_db">Érvénytelen adatbázis.</string>
<string name="error_invalid_path">Érvénytelen útvonal.</string>
<string name="error_no_name">Egy névre van szükség.</string>
<string name="error_nopass">Jelszóra vagy kulcsfájlra van szükség.</string>
<string name="error_no_name">Név szükséges.</string>
<string name="error_nokeyfile">Jelszóra vagy kulcsfájlra van szükség.</string>
<string name="error_out_of_memory">A telefon memóriája megtelt az adatbázis feldolgozása közben. Lehet túl sok ez a telefonnak.</string>
<string name="error_pass_gen_type">Legalább egy jelszógenerálási típust kell választania</string>
<string name="error_pass_match">A jelszavak nem egyeznek meg.</string>
<string name="error_rounds_not_number">A mező csak számokat tartalmazhat.</string>
<string name="error_rounds_too_large">A menetek száma túl nagy. A maximális 2147483648.</string>
<string name="error_string_key">A megnevezés mező kitöltése kötelező.</string>
<string name="error_title_required">Cím szükséges.</string>
<string name="error_string_key">Az érték mező kitöltése kötelező.</string>
<string name="error_title_required">Név szükséges.</string>
<string name="error_wrong_length">Írjon be egy pozitív egész számot a hossz mezőbe</string>
<string name="field_name">Megnevezés</string>
<string name="field_value">Érték</string>
<string name="FileNotFound">A fájl nem található.</string>
<string name="FileNotFound">A fájl nem található</string>
<string name="file_not_found_content">A fájl nem található. Próbálja meg újra megnyitni.</string>
<string name="file_browser">Fájlkezelő</string>
<string name="generate_password">Jelszó generálás</string>
<string name="group">Csoport</string>
@@ -86,7 +102,7 @@
<string name="hint_keyfile">kulcsfájl</string>
<string name="hint_length">hosszúság</string>
<string name="hint_pass">jelszó</string>
<string name="hint_login_pass">Jelszó</string>
<string name="password">Jelszó</string>
<string name="hint_title">név</string>
<string name="hint_url">url</string>
<string name="hint_username">felhasználónév</string>
@@ -114,7 +130,7 @@
<string name="menu_db_settings">Adatbázis beállítások</string>
<string name="menu_delete">Törlés</string>
<string name="menu_donate">Támogatás</string>
<string name="menu_edit">Szerkeszt</string>
<string name="menu_edit">Szerkesztés</string>
<string name="menu_hide_password">Jelszó elrejtése</string>
<string name="menu_homepage">Weboldal megtekintése</string>
<string name="menu_lock">Adatbázis lezárása</string>
@@ -132,10 +148,15 @@
<string name="omitbackup_title">Keresési kivételek</string>
<string name="omitbackup_summary">A Backup és Lomtár csoportok kihagyása a keresésből</string>
<string name="pass_filename">KeePass adatbázis fájlnév:</string>
<string name="password_title">Adatbázis jelszó megadása</string>
<string name="password_title">Adatbázis jelszó</string>
<string name="progress_create">Új adatbázis létrehozása…</string>
<string name="progress_title">Feldolgozás…</string>
<string name="protection">Memórián belüli védelem</string>
<string name="read_only">Csak olvasható</string>
<string name="read_only_warning">A programnak nincs engedélye az adatbázis írásához a jelenlegi helyén, ezért a megnyitása után csak olvasható lesz.</string>
<string name="read_only_kitkat_warning">A KitKat-es android verziótól kezdődően a futó alkalmazásoknak nincs jogosultságuk írni a külső SD kártyára.</string>
<string name="recentfile_title">Adatbázis mentése</string>
<string name="recentfile_summary">Jegyezze meg az adatbázisok helyét</string>
<string name="remember_keyfile_summary">Jegyezze meg a kulcsfájlok helyét</string>
<string name="remember_keyfile_title">Kulcsfájl mentése</string>
<string name="remove_from_filelist">Eltávolítás</string>
@@ -151,15 +172,26 @@
<string name="sort_name">Rendezés név alapján</string>
<string name="sort_db">Rendezés dátum alapján</string>
<string name="special">Speciális</string>
<string name="search_hint">Bejegyzés cím/leírás</string>
<string name="search_hint">Bejegyzés név/leírás</string>
<string name="search_results">Keresés eredménye</string>
<string name="twofish">Twofish</string>
<string name="underline">Aláhúzás</string>
<string name="unsupported_db_version">Nem támogatott adatbázis.</string>
<string name="uppercase">Nagybetűk</string>
<string name="use_saf_summary">Használja az Android Storage Access Framework-öt a fájlok böngészéséhez (KitKat vagy későbbi)</string>
<string name="use_saf_title">Storage Access Framework</string>
<string name="warning">Figyelmeztetés</string>
<string name="warning_password_encoding">A .kdb formátum csak a Latin1 karakterkészletet támogatja. A jelenlegi jelszó olyan karaktereket is tartalmazhat, amik ezen kívül esnek. Az összes ilyen karakter át lesz lesz konvertálva, viszont ez nagyban csökkenteni fogja a jelszó erősségét. Mielőbbi megváltoztatása ajánlott.</string>
<string name="warning_read_only">A memóriakártya jelenleg csak olvasható. Lehet, hogy nem tudja menteni a módosításokat az adatbázisban.</string>
<string name="warning_unmounted">A memóriakártya jelenleg el van távolítva. Nem fogja tudni az adatbázist betölteni vagy módosítani.</string>
<string name="version_label">Verzió:</string>
<string name="configure_fingerprint">Az ujjlenyomat használat nincs még beállítva az eszközön</string>
<string name="scanning_fingerprint">Várakozás az ujjelnyomat megadására</string>
<string name="encrypted_value_stored">Titkosított jelszó elmentve</string>
<string name="fingerprint_invalid_key">Érvénytelen kulcs</string>
<string name="fingerprint_error">Érvénytelen ujjlenyomat</string>
<string name="store_with_fingerprint">Használjon ujjlenyomatot a jelszó elmentéséhez</string>
<string name="no_password_stored">Nincs még jelszó beállítva ehhez az adatbázishoz</string>
<string-array name="clipboard_timeout_options">
<item>30 másodperc</item>
@@ -172,4 +204,4 @@
<item>Közepes</item>
<item>Nagy</item>
</string-array>
</resources>
</resources>

View File

@@ -61,7 +61,7 @@
<string name="entry_confpassword">Conferma password:</string>
<string name="entry_created">Creato: </string>
<string name="entry_expires">Scade: </string>
<string name="entry_keyfile">File chiave (opzionale)</string>
<string name="entry_keyfile">File chiave</string>
<string name="entry_modified">Modificato: </string>
<string name="entry_password">Password</string>
<string name="entry_save">Salva</string>
@@ -80,7 +80,7 @@
<string name="error_invalid_db">Database non valido.</string>
<string name="error_invalid_path">Percorso non valido.</string>
<string name="error_no_name">E\' necessario un nome.</string>
<string name="error_nopass">E\' necessaria una password o un file chiave.</string>
<string name="error_nokeyfile">E\' necessaria una password o un file chiave.</string>
<string name="error_out_of_memory">Il telefono ha esaurito la memoria durante l\'elaborazione del database. Potrebbe essere troppo grande per il tuo telefono.</string>
<string name="error_pass_gen_type">Almeno un tipo di generazione password deve essere selezionato</string>
<string name="error_pass_match">Le password non corrispondono.</string>
@@ -98,7 +98,7 @@
<string name="hint_group_name">Nome gruppo</string>
<string name="hint_keyfile">file chiave</string>
<string name="hint_length">lunghezza</string>
<string name="hint_login_pass">Password</string>
<string name="password">Password</string>
<string name="hint_pass">password</string>
<string name="hint_title">nome</string>
<string name="hint_url">url</string>

View File

@@ -62,7 +62,7 @@
<string name="entry_confpassword">אשר סיסמה:</string>
<string name="entry_created">תאריך יצירה: </string>
<string name="entry_expires">פג תוקף: </string>
<string name="entry_keyfile">קובץ מפתח (רשות)</string>
<string name="entry_keyfile">קובץ מפתח</string>
<string name="entry_modified">נערך לאחרונה: </string>
<string name="entry_not_found">נתוני ערך לא נמצאו.</string>
<string name="entry_password">סיסמה:</string>
@@ -81,7 +81,7 @@
<string name="error_invalid_db">מסד נתונים לא חוקי.</string>
<string name="error_invalid_path">נתיב לא חוקי.</string>
<string name="error_no_name">שם נדרש.</string>
<string name="error_nopass">סיסמה או קובץ מפתח נדרשים.</string>
<string name="error_nokeyfile">סיסמה או קובץ מפתח נדרשים.</string>
<string name="error_out_of_memory">זיכרון המכשיר אזל בזמן ניתוח מסד הנתונים. יתכן והוא גדול מדי למכשירך.</string>
<string name="error_pass_gen_type">לפחות סוג אחד ליצירת סיסמה צריך להיבחר</string>
<string name="error_pass_match">הסיסמאות לא תואמות.</string>
@@ -103,7 +103,7 @@
<string name="hint_keyfile">קובץ המפתח</string>
<string name="hint_length">אורך</string>
<string name="hint_pass">סיסמה</string>
<string name="hint_login_pass">סיסמה</string>
<string name="password">סיסמה</string>
<string name="hint_title">שם</string>
<string name="hint_username">שם משתמש</string>
<string name="install_from_market">התקן מחנות Play</string>

View File

@@ -58,7 +58,7 @@
<string name="entry_confpassword">パスワードの確認:</string>
<string name="entry_created">作成日: </string>
<string name="entry_expires">有効期限: </string>
<string name="entry_keyfile">キーファイル(オプション)</string>
<string name="entry_keyfile">キーファイル</string>
<string name="entry_modified">更新日: </string>
<string name="entry_password">パスワード:</string>
<string name="entry_save">保存</string>
@@ -77,7 +77,7 @@
<string name="error_invalid_db">無効なデータベースです。</string>
<string name="error_invalid_path">パスが無効です。</string>
<string name="error_no_name">タイトルは必須入力です。</string>
<string name="error_nopass">パスワードかキーファイルが必要です。</string>
<string name="error_nokeyfile">パスワードかキーファイルが必要です。</string>
<string name="error_out_of_memory">データベース解析中にメモリ不足になりました。</string>
<string name="error_pass_gen_type">少なくとも1つ以上のパスワード生成タイプを選択する必要があります。</string>
<string name="error_pass_match">パスワードが一致しません</string>
@@ -95,7 +95,7 @@
<string name="hint_group_name">グループ名</string>
<string name="hint_keyfile">キーファイル</string>
<string name="hint_length">長さ</string>
<string name="hint_login_pass">パスワード</string>
<string name="password">パスワード</string>
<string name="hint_pass">パスワード</string>
<string name="hint_title">タイトル</string>
<string name="hint_url">url</string>

View File

@@ -44,7 +44,7 @@
<string name="hint_group_name">Grupės pavadinimas</string>
<string name="hint_keyfile">rakto failas</string>
<string name="hint_length">ilgis</string>
<string name="hint_login_pass">Slaptažodis</string>
<string name="password">Slaptažodis</string>
<string name="hint_pass">slaptažodis</string>
<string name="hint_title">pavadinimas</string>
<string name="hint_url">url</string>
@@ -102,7 +102,7 @@
<string name="entry_not_found">Įrašo duomenys nerasti.</string>
<string name="keyfile_is_empty">Rakto failas yra tuščias.</string>
<string name="keyfile_does_not_exist">Rakto failas neegzistuoja.</string>
<string name="entry_keyfile">Rakto failas (pasirinktinis)</string>
<string name="entry_keyfile">Rakto failas</string>
<string name="search_hint">Įrašo pavadinimas/aprašymas</string>
<string name="menu_change_key">Pakeisti master raktą</string>
<string name="entry_accessed">Naudota:</string>

View File

@@ -45,7 +45,7 @@
<string name="entry_confpassword">Apstipriniet paroli:</string>
<string name="entry_created">Izveidots:</string>
<string name="entry_expires">Derīguma termiņš beidzas:</string>
<string name="entry_keyfile">Atslēgas fails (pēc izvēles)</string>
<string name="entry_keyfile">Atslēgas fails</string>
<string name="entry_modified">Modificēts:</string>
<string name="entry_password">Parole:</string>
<string name="entry_save">Saglabāt</string>
@@ -64,7 +64,7 @@
<string name="error_invalid_db">Nederīga datu bāze.</string>
<string name="error_invalid_path">Nederīgs ceļš.</string>
<string name="error_no_name">Vajag ievadīt faila nosaukumu</string>
<string name="error_nopass">Vajadzīga parole vai atslēgas fails.</string>
<string name="error_nokeyfile">Vajadzīga parole vai atslēgas fails.</string>
<string name="error_out_of_memory">Darbam ar datu bāzi, tālrunī nepietiek atmiņas.</string>
<string name="error_pass_gen_type">Ir jāatlasa vismaz viens paroles ģenerēšanas tips</string>
<string name="error_pass_match">Paroles nesakrīt.</string>
@@ -86,7 +86,7 @@
<string name="hint_keyfile">atslēgas fails</string>
<string name="hint_length">garums</string>
<string name="hint_pass">parole</string>
<string name="hint_login_pass">Parole</string>
<string name="password">Parole</string>
<string name="hint_title">vārds</string>
<string name="hint_url">url</string>
<string name="hint_username">lietotājvārds</string>

View File

@@ -60,7 +60,7 @@
<string name="entry_confpassword">Bevestig wachtwoord:</string>
<string name="entry_created">Aangemaakt op: </string>
<string name="entry_expires">Verloopt op: </string>
<string name="entry_keyfile">Sleutelbestand (optioneel)</string>
<string name="entry_keyfile">Sleutelbestand</string>
<string name="entry_modified">Gewijzigd op: </string>
<string name="entry_password">Wachtwoord:</string>
<string name="entry_save">Opslaan</string>
@@ -79,7 +79,7 @@
<string name="error_invalid_db">Ongeldige database.</string>
<string name="error_invalid_path">Ongeldige padnaam.</string>
<string name="error_no_name">Een naam ontbreekt.</string>
<string name="error_nopass">Een wachtwoord of sleutenbestand ontbreekt.</string>
<string name="error_nokeyfile">Een wachtwoord of sleutenbestand ontbreekt.</string>
<string name="error_out_of_memory">Onvoldoende vrij geheugen om de database te lezen. Misschien is de database te groot voor deze telefoon.</string>
<string name="error_pass_gen_type">U moet minstens één type van wachtwoordgeneratie kiezen.</string>
<string name="error_pass_match">Wachtwoorden zijn niet gelijk.</string>
@@ -97,7 +97,7 @@
<string name="hint_group_name">Groepnaam</string>
<string name="hint_keyfile">sleutelbestand</string>
<string name="hint_length">lengte</string>
<string name="hint_login_pass">Wachtwoord</string>
<string name="password">Wachtwoord</string>
<string name="hint_pass">wachtwoord</string>
<string name="hint_title">naam</string>
<string name="hint_url">url</string>

View File

@@ -58,7 +58,7 @@
<string name="entry_confpassword">Stadfest passordet:</string>
<string name="entry_created">Laga: </string>
<string name="entry_expires">Går ut: </string>
<string name="entry_keyfile">Nøkkelfil (valfri)</string>
<string name="entry_keyfile">Nøkkelfil</string>
<string name="entry_modified">Endra: </string>
<string name="entry_password">Passord:</string>
<string name="entry_save">Lagra</string>
@@ -77,7 +77,7 @@
<string name="error_invalid_db">Ugyldig database.</string>
<string name="error_invalid_path">Ugyldig stig.</string>
<string name="error_no_name">Treng eit namn.</string>
<string name="error_nopass">Treng eit passord eller ei nøkkelfil.</string>
<string name="error_nokeyfile">Treng eit passord eller ei nøkkelfil.</string>
<string name="error_out_of_memory">Telefonen gjekk tom for minne ved lesinga av databasen din. Databasen er kanskje for stor.</string>
<string name="error_pass_gen_type">Du må velja minst éin passordlagingstype</string>
<string name="error_pass_match">Passorda samsvarer ikkje.</string>
@@ -95,7 +95,7 @@
<string name="hint_group_name">Gruppenamn</string>
<string name="hint_keyfile">nøkkelfil</string>
<string name="hint_length">lengd</string>
<string name="hint_login_pass">Passord</string>
<string name="password">Passord</string>
<string name="hint_pass">passord</string>
<string name="hint_title">namn</string>
<string name="hint_url">adresse</string>

View File

@@ -56,7 +56,7 @@ along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
<string name="entry_confpassword">Potwierdź hasło:</string>
<string name="entry_created">Utworzono: </string>
<string name="entry_expires">Wygasa: </string>
<string name="entry_keyfile">Plik klucza (opcjonalnie)</string>
<string name="entry_keyfile">Plik klucza</string>
<string name="entry_modified">Zmodyfikowano: </string>
<string name="entry_password">Hasło</string>
<string name="entry_save">Zapisz</string>
@@ -75,7 +75,7 @@ along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
<string name="error_invalid_db">Nieprawidłowa baza danych.</string>
<string name="error_invalid_path">Nieprawidłowa ścieżka dostępu.</string>
<string name="error_no_name">Wymagana nazwa.</string>
<string name="error_nopass">Wymagane hasło lub plik klucza.</string>
<string name="error_nokeyfile">Wymagane hasło lub plik klucza.</string>
<string name="error_out_of_memory">Podczas parsowania bazy danych zabrakło pamięci. Być może ta baza danych jest za duża dla Twojego urządzenia.</string>
<string name="error_pass_gen_type">Przynajmniej jeden sposób generowania hasła musi być wybrany</string>
<string name="error_pass_match">Hasła nie pasują do siebie.</string>
@@ -93,7 +93,7 @@ along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
<string name="hint_group_name">Nazwa grupy</string>
<string name="hint_keyfile">plik klucza</string>
<string name="hint_length">długość</string>
<string name="hint_login_pass">Hasło</string>
<string name="password">Hasło</string>
<string name="hint_pass">hasło</string>
<string name="hint_title">nazwa</string>
<string name="hint_url">url</string>
@@ -134,10 +134,14 @@ along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
<string name="no_results">Brak wyników wyszukiwania</string>
<string name="no_url_handler">Brak obsługi dla tego urla.</string>
<string name="open_recent">Otwórz ostatnio używaną bazę danych (kliknij by otworzyć):</string>
<string name="omitbackup_title">Nie wyszukuj zapasowych wpisów</string>
<string name="omitbackup_summary">Pomiń kopię zapasową grupy z wyników wyszukiwania (dotyczy tylko .kdb)</string>
<string name="pass_filename">Nazwa pliku bazy danych KeePass:</string>
<string name="password_title">Wprowadź hasło bazy danych</string>
<string name="progress_create">Tworzenie nowej bazy danych&#8230;</string>
<string name="progress_title">Pracuję&#8230;</string>
<string name="recentfile_title">Najnowsza historia plików</string>
<string name="recentfile_summary">Zapamiętaj ostatnio uzywane nazwy plików</string>
<string name="remember_keyfile_summary">Zapamiętaj lokację plików kluczy</string>
<string name="remember_keyfile_title">Zapisz plik klucza</string>
<string name="remove_from_filelist">Usuń</string>
@@ -145,6 +149,8 @@ along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
<string name="root">Root</string>
<string name="rounds">Złożoność szyfrowania</string>
<string name="rounds_explaination">Większa złożoność szyfrowania zapewnia dodatkowe zabezpieczenie przed atakiem brute force, ale może spowolnić wczytywanie i zapisywanie bazy danych.</string>
<string name="rounds_fix">Kluczowe rundy szyfrowania przed zniszczeniem</string>
<string name="rounds_fix_explanation">Jeśli twoja baza danych została uszkodzona przez KeePassDroid w wersji 2.2.0.0 do 2.2.0.6, wprowadź liczbę rund użytych poprzednio, a to pozwoli ci otworzyć twoją bazę danych.</string>
<string name="rounds_hint">złożoność</string>
<string name="saving_database">Zapisywanie bazy danych&#8230;</string>
<string name="space">Spacja</string>
@@ -158,6 +164,8 @@ along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
<string name="underline">Podkreślenie</string>
<string name="unsupported_db_version">Nieobsługiwana wersja bazy danych.</string>
<string name="uppercase">Wielkie litery</string>
<string name="use_saf_summary">Użyj przeglądarki Android Storage Access Framework do przeglądania plików (KitKat i nowsze)</string>
<string name="use_saf_title">Storage Access Framework</string>
<string name="warning_read_only">Karta SD jest obecnie w trybie tylko do odczytu. Możesz nie być w stanie zapisać zmian w bazie danych.</string>
<string name="warning_unmounted">Karta SD nie jest obecnie zamontowana w urządzeniu. Możesz nie być w stanie wczytać lub utworzyć bazy danych.</string>

View File

@@ -61,7 +61,7 @@
<string name="entry_confpassword">Confirmar senha:</string>
<string name="entry_created">Criado: </string>
<string name="entry_expires">Expira: </string>
<string name="entry_keyfile">Arquivo de chave (opcional)</string>
<string name="entry_keyfile">Arquivo de chave</string>
<string name="entry_modified">Modificado: </string>
<string name="entry_password">Senha:</string>
<string name="entry_save">Salvar</string>
@@ -80,7 +80,7 @@
<string name="error_invalid_db">Banco de dados inválido.</string>
<string name="error_invalid_path">Caminho inválido.</string>
<string name="error_no_name">É necessário um nome.</string>
<string name="error_nopass">São necessários uma senha ou um arquivo de chaves.</string>
<string name="error_nokeyfile">São necessários uma senha ou um arquivo de chaves.</string>
<string name="error_out_of_memory">Foi atingida a capacidade máxima de memória do seu dispositivo ao carregar o banco de dados. O banco de dados pode ser muito grande para este dispositivo.</string>
<string name="error_pass_gen_type">Pelo menos um tipo de geração de senhas deve ser selecionado</string>
<string name="error_pass_match">As senhas não combinam.</string>
@@ -98,7 +98,7 @@
<string name="hint_group_name">Nome do Grupo</string>
<string name="hint_keyfile">arquivo de chave</string>
<string name="hint_length">tamanho</string>
<string name="hint_login_pass">Senha</string>
<string name="password">Senha</string>
<string name="hint_pass">senha</string>
<string name="hint_title">nome</string>
<string name="hint_url">url</string>

View File

@@ -66,7 +66,7 @@
<string name="entry_confpassword">Confirmar palavra-passe:</string>
<string name="entry_created">Criado: </string>
<string name="entry_expires">Expira: </string>
<string name="entry_keyfile">Ficheiro chave (opcional)</string>
<string name="entry_keyfile">Ficheiro chave</string>
<string name="entry_modified">Modificado: </string>
<string name="entry_not_found">Dados da entrada não encontrados.</string>
<string name="entry_password">Palavra-passe:</string>
@@ -86,7 +86,7 @@
<string name="error_invalid_db">Base de dados inválida.</string>
<string name="error_invalid_path">Caminho inválido.</string>
<string name="error_no_name">É obrigatório introduzir um nome.</string>
<string name="error_nopass">É obrigatório introduzir uma palavra-passe ou um ficheiro chave.</string>
<string name="error_nokeyfile">É obrigatório introduzir uma palavra-passe ou um ficheiro chave.</string>
<string name="error_out_of_memory">O dispositivo ficou sem memória ao analisar a base de dados. Poderá ser muito grande para o seu dispositivo.</string>
<string name="error_pass_gen_type">Pelo menos um tipo de geração de palavra-passe deve ser selecionado</string>
<string name="error_pass_match">As palavra-passe não coincidem.</string>
@@ -109,7 +109,7 @@
<string name="hint_keyfile">ficheiro chave</string>
<string name="hint_length">comprimento</string>
<string name="hint_pass">palavra-passe</string>
<string name="hint_login_pass">Palavra-passe</string>
<string name="password">Palavra-passe</string>
<string name="hint_title">nome</string>
<string name="hint_url">url</string>
<string name="hint_username">nome de utilizador</string>

View File

@@ -53,10 +53,7 @@
<string name="decrypting_entry">Расшифровка записи…</string>
<string name="default_checkbox">По умолчанию</string>
<string name="digits">Цифры 0…9</string>
<string name="disclaimer_formal">"KeePass DX © 20092013
Разработчик Brian Pellin
Программа предоставляется БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ. Распространяется свободно по лицензии GPL v2 или новее"</string>
<string name="disclaimer_formal">"KeePass DX © 20092017 Разработчик Brian Pellin, Jeremy JAMET / Kunzisoft Программа предоставляется БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ. Распространяется свободно по лицензии GPL v2 или новее"</string>
<string name="ellipsis"></string>
<string name="enter_filename">Путь к базе KeePass:</string>
<string name="entry_accessed">Доступ:</string>
@@ -86,7 +83,7 @@
<string name="error_invalid_db">Неверный формат базы</string>
<string name="error_invalid_path">Путь указан неверно</string>
<string name="error_no_name">Необходимо ввести имя файла</string>
<string name="error_nopass">Необходим пароль или файл-ключ</string>
<string name="error_nokeyfile">Необходим пароль или файл-ключ</string>
<string name="error_out_of_memory">Недостаточно памяти для работы с базой</string>
<string name="error_pass_gen_type">Выберите один или несколько типов символов</string>
<string name="error_pass_match">Пароли не совпадают</string>
@@ -108,7 +105,7 @@
<string name="hint_keyfile">файл-ключ</string>
<string name="hint_length">длина</string>
<string name="hint_pass">пароль</string>
<string name="hint_login_pass">пароль</string>
<string name="password">пароль</string>
<string name="hint_title">название</string>
<string name="hint_url">ссылка</string>
<string name="hint_username">логин</string>
@@ -169,6 +166,8 @@
<string name="root">База</string>
<string name="rounds">Проходы шифрования</string>
<string name="rounds_explaination">Больше проходов – выше стойкость базы к подбору пароля, но медленнее открытие и сохранение</string>
<string name="rounds_fix">Проходы до поломки базы</string>
<string name="rounds_fix_explanation">Если база была повреждена в KeePassDroid 2.2.0.02.2.0.6, введите ранее используемое количество проходов шифрования, чтобы открыть её</string>
<string name="rounds_hint">проходы</string>
<string name="saving_database">Сохранение базы…</string>
<string name="space">П р о б е л</string>

View File

@@ -58,7 +58,7 @@
<string name="entry_confpassword">Potvrdiť heslo:</string>
<string name="entry_created">Vytvorené: </string>
<string name="entry_expires">Expirácia: </string>
<string name="entry_keyfile">Súbor Keyfile (voliteľné)</string>
<string name="entry_keyfile">Súbor Keyfile</string>
<string name="entry_modified">Upravené: </string>
<string name="entry_password">Heslo:</string>
<string name="entry_save">Uložiť</string>
@@ -77,7 +77,7 @@
<string name="error_invalid_db">Chybná databáza.</string>
<string name="error_invalid_path">Chybná cesta.</string>
<string name="error_no_name">Vyžaduje sa meno.</string>
<string name="error_nopass">Vyžaduje sa heslo, alebo súbor keyfile.</string>
<string name="error_nokeyfile">Vyžaduje sa heslo, alebo súbor keyfile.</string>
<string name="error_out_of_memory">Telefón vyčerpal pamäť pri analýze databázy. Možno je to príliš na Váš telefón.</string>
<string name="error_pass_gen_type">Musí byť vybraý najmenej jeden typ generovania hesla</string>
<string name="error_pass_match">Heslá sa nezhodujú.</string>
@@ -95,7 +95,7 @@
<string name="hint_group_name">Názov Skupiny</string>
<string name="hint_keyfile">súbor keyfile</string>
<string name="hint_length">dĺžka</string>
<string name="hint_login_pass">Heslo</string>
<string name="password">Heslo</string>
<string name="hint_pass">heslo</string>
<string name="hint_title">meno</string>
<string name="hint_url">url</string>

View File

@@ -65,7 +65,7 @@
<string name="entry_confpassword">Bekräfta lösenord:</string>
<string name="entry_created">Skapad: </string>
<string name="entry_expires">Upphör att gälla: </string>
<string name="entry_keyfile">Nyckelfil (valfri)</string>
<string name="entry_keyfile">Nyckelfil</string>
<string name="entry_modified">Senast ändrad: </string>
<string name="entry_password">Lösenord:</string>
<string name="entry_save">Spara</string>
@@ -84,7 +84,7 @@
<string name="error_invalid_db">Ogiltig databas.</string>
<string name="error_invalid_path">Ogiltig sökväg.</string>
<string name="error_no_name">Ett namn krävs.</string>
<string name="error_nopass">Ett lösenord eller en nyckelfil är ett krav.</string>
<string name="error_nokeyfile">Ett lösenord eller en nyckelfil är ett krav.</string>
<string name="error_out_of_memory">The phone ran out of memory while parsing your database. It may be too large for your phone.</string>
<string name="error_pass_gen_type">At least one password generation type must be selected</string>
<string name="error_pass_match">Lösenorden matchar inte.</string>
@@ -106,7 +106,7 @@
<string name="hint_keyfile">nyckelfil</string>
<string name="hint_length">längd</string>
<string name="hint_pass">lösenord</string>
<string name="hint_login_pass">Lösenord</string>
<string name="password">Lösenord</string>
<string name="hint_title">namn</string>
<string name="hint_url">url</string>
<string name="hint_username">användarnamn</string>

View File

@@ -58,7 +58,7 @@
<string name="entry_confpassword">Підтвердження паролю:</string>
<string name="entry_created">Створено: </string>
<string name="entry_expires">Закінчується: </string>
<string name="entry_keyfile">Файл ключа (необов’язково)</string>
<string name="entry_keyfile">Файл ключа</string>
<string name="entry_modified">Змінено: </string>
<string name="entry_password">Пароль:</string>
<string name="entry_save">Зберегти</string>
@@ -77,7 +77,7 @@
<string name="error_invalid_db">Невірна база даних.</string>
<string name="error_invalid_path">Невірний шлях.</string>
<string name="error_no_name">Потрібне ім’я.</string>
<string name="error_nopass">Необхідно пароль або файл ключа.</string>
<string name="error_nokeyfile">Необхідно пароль або файл ключа.</string>
<string name="error_out_of_memory">Телефону не вистачило пам’яті при аналізі вашої бази даних. Можливо база надто велика для вашог телефона.</string>
<string name="error_pass_gen_type">Принаймні один тип генерації пароля необхідно вибрати.</string>
<string name="error_pass_match">Паролі не співпадають.</string>
@@ -95,7 +95,7 @@
<string name="hint_group_name">Ім’я групи</string>
<string name="hint_keyfile">файл-ключ</string>
<string name="hint_length">довжина</string>
<string name="hint_login_pass">Пароль</string>
<string name="password">Пароль</string>
<string name="hint_pass">пароль</string>
<string name="hint_title">ім’я</string>
<string name="hint_url">url</string>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- For setting encapsulation -->
<style name="KeepassDXStyle.Light" parent="KeepassDXStyle.Light.v21" >
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14</item>
</style>
<style name="KeepassDXStyle.Night" parent="KeepassDXStyle.Night.v21" >
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14</item>
</style>
</resources>

View File

@@ -2,9 +2,11 @@
<resources>
<!-- For elevation encapsulation -->
<style name="KeepassDXStyle.Light" parent="KeepassDXStyle.Light.v21" >
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
<item name="android:statusBarColor">?attr/colorPrimaryDark</item>
</style>
<style name="KeepassDXStyle.Night" parent="KeepassDXStyle.Night.v21" >
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
<item name="android:statusBarColor">?attr/colorPrimaryDark</item>
</style>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
Copyright 2017 Jeremy Jamet / Kunzisoft.
This file is part of KeePass DX.
@@ -17,18 +17,6 @@
You should have received a copy of the GNU General Public License
along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_margin="@dimen/default_margin"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText android:id="@+id/rounds"
android:hint="@string/rounds_hint"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:inputType="number"/>
<TextView android:id="@+id/rounds_explaination"
android:text="@string/rounds_explaination"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_below="@id/rounds"/>
</RelativeLayout>
<resources>
<bool name="fingerprint_enable_default" translatable="true">true</bool>
</resources>

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<integer name="fingerprint_viewport_width">160</integer>
<integer name="fingerprint_viewport_height">160</integer>
<integer name="fingerprint_viewport_center">80</integer>
<integer name="fingerprint_stroke_width">5</integer>
<integer name="tick_cross_stroke_width">7</integer>
<dimen name="fingerprint_width">80dp</dimen>
<dimen name="fingerprint_height">80dp</dimen>
<!-- a pretty rough & ready re-draw of the fingerprint glyph from
https://github.com/googlesamples/android-FingerprintDialog -->
<string translatable="false" name="path_ridge_1">M56.2199243,45.3815903 C56.2199243,45.3815903 65.1913567,38.8543184 80.3604294,38.8543184 C95.5295022,38.8543184 103.720044,45.2851323 103.720044,45.2851323</string>
<string translatable="false" name="path_ridge_2">M45.5181172,67.9181841 C49.9761548,62.7019025 59.122049,49.7790452 80.2279027,49.7790452 C101.333756,49.7790452 110.740506,62.0384399 114.937688,67.9181841</string>
<string translatable="false" name="path_ridge_3">M51.7375623,107.718438 C51.7375623,107.718438 48.7129745,99.6302234 48.7129745,91.6334356 C48.7129745,81.3266864 55.9028711,60.2476586 80.4057228,60.2478671 C100.798248,60.2480407 112.457463,79.7942647 112.457463,88.386575 C112.457462,99.2963939 105.619846,103.039218 100.781849,102.18762 C95.9438519,101.336021 90.4490979,97.2187731 91.0639139,92.3178681 C91.67873,87.4169631 85.2177374,81.3265129 80.7504553,81.3266871 C73.0900115,81.3269859 69.8146331,85.3921834 69.8146329,92.2700585 C69.8146324,107.718437 83.7557525,121.02713 91.6787289,121.027128</string>
<string translatable="false" name="path_ridge_4">M70.7357889,121.024995 C70.7357889,121.024995 57.4650216,106.018711 58.8888756,91.5596242 C60.5513085,74.6777941 73.9858126,70.313752 80.3788823,70.3807995 C86.771952,70.4478469 101.550994,76.8218704 101.550997,92.2895418</string>
<string translatable="false" name="path_ridge_5">M80.1599645,91.1813411 C80.1599645,91.1813411 81.1144795,102.68333 86.7971146,107.529716 C93.2390527,113.023667 105.911091,112.342743 105.911091,112.342743</string>
<string translatable="false" name="path_tick">M52.2735573,79.0771904 C52.2735573,79.0771904 69.2403688,96.0440006 69.2403683,96.0440014 C69.2403679,96.0440021 109.820188,55.4641819 109.820188,55.4641819</string>
<string translatable="false" name="path_cross_1">M62,62 C62,62 80.5647617,80.5647617 80.564762,80.564762 C80.5647622,80.5647622 94.2921789,94.223714 98.5644262,98.5644262</string>
<string translatable="false" name="path_cross_2">M98.5644262,62 C98.5644251,62 81.1979242,79.366503 81.1979229,79.3665033 C81.1979216,79.3665035 62,98.5644262 62,98.5644262</string>
<!-- a 'window' which is ¼ of the height of the viewport that we use as a clip during the 'scan'
operation by animating it from the top to the bottom and back. -->
<string translatable="false" name="clip_path_scan_top">M0 0 L160 0 L160 40 L0 40 Z</string>
<string translatable="false" name="clip_path_scan_bottom">M0 120 L160 120 L160 160 L0 160 Z</string>
<color name="fingerprint_ridge">#deffffff</color>
<color name="fingerprint_ridge_scan">#ffffffff</color>
<color name="circle_default">#ff607d8b</color>
</resources>

Some files were not shown because too many files have changed in this diff Show More