mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Compare commits
118 Commits
2.5.0.0bet
...
2.5.0.0bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c24c18d89e | ||
|
|
61043b3acb | ||
|
|
52f8862e71 | ||
|
|
8bd32e6605 | ||
|
|
d430305eb1 | ||
|
|
2cb3972865 | ||
|
|
724bb1fc86 | ||
|
|
38def26865 | ||
|
|
a08e65733d | ||
|
|
e5bc9bfd1d | ||
|
|
767f7b06d6 | ||
|
|
a06977cd25 | ||
|
|
60be6f1223 | ||
|
|
e9929ed848 | ||
|
|
21c657c107 | ||
|
|
a93271401d | ||
|
|
a66cd68ae2 | ||
|
|
9ac060ea05 | ||
|
|
c20f453b90 | ||
|
|
27d633a1e9 | ||
|
|
221a851f44 | ||
|
|
c091ffb5e1 | ||
|
|
d8f81b669d | ||
|
|
fb72f37ebb | ||
|
|
6c5936d15d | ||
|
|
e68c682cac | ||
|
|
04da145513 | ||
|
|
a15a039f2a | ||
|
|
818c0a769b | ||
|
|
cc7b8a3fd8 | ||
|
|
43b4d00902 | ||
|
|
06b126469a | ||
|
|
2ca4e817e9 | ||
|
|
42a52b26bf | ||
|
|
5d8a73080b | ||
|
|
0b736ce0b3 | ||
|
|
dea6515e90 | ||
|
|
1bd1b2a224 | ||
|
|
b7a76ed2e7 | ||
|
|
a1237215cc | ||
|
|
4bb869e288 | ||
|
|
1d528488d3 | ||
|
|
90282d9722 | ||
|
|
2c7b19d67d | ||
|
|
981fef8fb1 | ||
|
|
77c8207c73 | ||
|
|
825a5c7e73 | ||
|
|
d921a0ae1a | ||
|
|
1946844858 | ||
|
|
b62106068b | ||
|
|
1218d89173 | ||
|
|
052641c556 | ||
|
|
7950933d1f | ||
|
|
37279af514 | ||
|
|
b45a8b5c94 | ||
|
|
8a344170b3 | ||
|
|
09f6498907 | ||
|
|
57b8b9e53b | ||
|
|
8edb2c26d4 | ||
|
|
7d7b34b2d0 | ||
|
|
73765a7ecb | ||
|
|
fb99c32708 | ||
|
|
6bb0b1a7e7 | ||
|
|
7a66c964a7 | ||
|
|
a5b1535fb8 | ||
|
|
05a5da4c8d | ||
|
|
f5314e0a9a | ||
|
|
332d1e0e06 | ||
|
|
9173c99928 | ||
|
|
421bdae0d7 | ||
|
|
421de6ea49 | ||
|
|
ec2dd3db64 | ||
|
|
e6cc9b628e | ||
|
|
7cce527e43 | ||
|
|
dd35fd508f | ||
|
|
a7b5fd512a | ||
|
|
45b03231dd | ||
|
|
85357e2168 | ||
|
|
d6709254e2 | ||
|
|
ef42dcd47f | ||
|
|
8536586c13 | ||
|
|
4794ccb38a | ||
|
|
d14dc22918 | ||
|
|
79084cee62 | ||
|
|
f0ec9229cd | ||
|
|
f6b04dff24 | ||
|
|
b6721b32e7 | ||
|
|
b1804a94b6 | ||
|
|
f6bcd51cd3 | ||
|
|
a833dfe64a | ||
|
|
87efd1daa4 | ||
|
|
ecdd744b8e | ||
|
|
9012fd6da6 | ||
|
|
c6a711dec5 | ||
|
|
9b1a0285c4 | ||
|
|
fd6dd01ee7 | ||
|
|
bd10fe8542 | ||
|
|
8333a80d88 | ||
|
|
192f116925 | ||
|
|
409ffd4f95 | ||
|
|
0add3c76c8 | ||
|
|
b4f9e06bd6 | ||
|
|
c686ff7156 | ||
|
|
da1370e7f5 | ||
|
|
c564253206 | ||
|
|
3f22bf9e5c | ||
|
|
eae321d034 | ||
|
|
e2022183ea | ||
|
|
924db245ec | ||
|
|
2dae805ac0 | ||
|
|
9ce0a413ad | ||
|
|
1ece7b1df7 | ||
|
|
b7aec355a2 | ||
|
|
780a0cd42d | ||
|
|
de45421b50 | ||
|
|
c11e17af05 | ||
|
|
260de4099b | ||
|
|
b8b106eb65 |
15
.gitignore
vendored
15
.gitignore
vendored
@@ -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
|
||||
|
||||
54
CHANGELOG
54
CHANGELOG
@@ -1,3 +1,26 @@
|
||||
KeepassDX (2.5.0.0beta4)
|
||||
* Show only file name
|
||||
* Setting for full path
|
||||
* Add information for each database file
|
||||
* Setting to delete fingerprints
|
||||
* Solve bugs when change fingerprint
|
||||
* Delete view assignment for fingerprint opening
|
||||
* Merge KeePassDroid 2.2.1
|
||||
|
||||
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 +30,37 @@ KeepassDX (2.5.0.0beta1)
|
||||
* Update French translation
|
||||
* Change donation (see KeepassDroid to contribute on both projects)
|
||||
|
||||
KeePassDroid (2.2.1)
|
||||
* Fix kdbx4 date corruption
|
||||
* Updated German translations
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -14,14 +14,14 @@ 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
|
||||
Laurent, Norman Obry, Nam, Bruno Parmentier, Credomo - French
|
||||
Maciej Bieniek, cod3r - Polish
|
||||
Максим Сёмочкин, i.nedoboy, filimonic, bboa - Russian
|
||||
MaWi, rvs2008, meviox, MaDill - German
|
||||
MaWi, rvs2008, meviox, MaDill, EdlerProgrammierer, Jan Thomas - German
|
||||
yslandro - Norwegian Nynorsk
|
||||
王科峰 - Chinese
|
||||
Typhoon - Slovak
|
||||
@@ -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
|
||||
|
||||
19
ReadMe.md
19
ReadMe.md
@@ -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.
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KM6QMDAXZM3UU "Kunzisoft Paypal Donation")
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KM6QMDAXZM3UU "Kunzisoft Paypal Donation")
|
||||
|
||||
[](https://liberapay.com/Kunzisoft/donate "Kunzisoft Liberapay Donation")
|
||||
[](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:
|
||||
|
||||
@@ -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 = 4
|
||||
versionName = "2.5.0.0beta4"
|
||||
|
||||
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.
@@ -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>
|
||||
@@ -31,17 +53,21 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="com.keepassdroid.fileselect.FileSelectActivity"
|
||||
android:launchMode="singleInstance"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
<activity android:name="com.keepassdroid.AboutActivity"
|
||||
android:launchMode="singleInstance"
|
||||
android:label="@string/menu_about" />
|
||||
<activity android:name="com.keepassdroid.PasswordActivity" android:configChanges="orientation|keyboardHidden">
|
||||
<activity android:name="com.keepassdroid.PasswordActivity"
|
||||
android:configChanges="orientation|keyboardHidden">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<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 +92,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" />
|
||||
|
||||
@@ -27,8 +27,10 @@ import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.keepassdroid.stylish.StylishActivity;
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
public class AboutActivity extends StylishActivity {
|
||||
|
||||
@@ -56,6 +58,9 @@ public class AboutActivity extends StylishActivity {
|
||||
version = getString(R.string.version_label) + " " + version;
|
||||
TextView versionText = (TextView) findViewById(R.id.activity_about_version);
|
||||
versionText.setText(version);
|
||||
|
||||
TextView disclaimerText = (TextView) findViewById(R.id.disclaimer);
|
||||
disclaimerText.setText(getString(R.string.disclaimer_formal, new DateTime().getYear()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
274
app/src/main/java/com/keepassdroid/AssignMasterKeyDialog.java
Normal file
274
app/src/main/java/com/keepassdroid/AssignMasterKeyDialog.java
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
182
app/src/main/java/com/keepassdroid/CreateFileDialog.java
Normal file
182
app/src/main/java/com/keepassdroid/CreateFileDialog.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -19,12 +19,14 @@
|
||||
*/
|
||||
package com.keepassdroid;
|
||||
|
||||
|
||||
import android.app.SearchManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.os.Build;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
@@ -40,8 +42,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 +49,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 +152,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 +270,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");
|
||||
}
|
||||
|
||||
@@ -284,6 +307,24 @@ public abstract class GroupBaseActivity extends LockCloseListActivity {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
|
||||
/*
|
||||
* ACTION_SEARCH automatically forces a new task. This occurs when you open a kdb file in
|
||||
* another app such as Files or GoogleDrive and then Search for an entry. Here we remove the
|
||||
* FLAG_ACTIVITY_NEW_TASK flag bit allowing search to open it's activity in the current task.
|
||||
*/
|
||||
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
||||
int flags = intent.getFlags();
|
||||
flags &= ~Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
intent.setFlags(flags);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
super.startActivityForResult(intent, requestCode, options);
|
||||
}
|
||||
}
|
||||
|
||||
public class AfterDeleteGroup extends OnFinish {
|
||||
public AfterDeleteGroup(Handler handler) {
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +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;
|
||||
import android.content.Intent;
|
||||
@@ -41,65 +39,68 @@ import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
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;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
public class PasswordActivity extends LockingActivity implements FingerPrintHelper.FingerPrintCallback {
|
||||
public class PasswordActivity extends LockingActivity
|
||||
implements FingerPrintHelper.FingerPrintCallback, UriIntentInitTaskCallback {
|
||||
|
||||
public static final String KEY_DEFAULT_FILENAME = "defaultFileName";
|
||||
private static final String KEY_FILENAME = "fileName";
|
||||
private static final String KEY_KEYFILE = "keyFile";
|
||||
private static final String KEY_PASSWORD = "password";
|
||||
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;
|
||||
SharedPreferences prefs;
|
||||
SharedPreferences prefsNoBackup;
|
||||
|
||||
private FingerPrintHelper fingerPrintHelper;
|
||||
private boolean fingerprintMustBeConfigured = true;
|
||||
private boolean mRememberKeyfile;
|
||||
|
||||
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 CompoundButton checkboxPasswordView;
|
||||
private CompoundButton checkboxKeyfileView;
|
||||
private CompoundButton checkboxDefaultDatabaseView;
|
||||
|
||||
private KeyFileHelper keyFileHelper;
|
||||
|
||||
public static void Launch(
|
||||
Activity act,
|
||||
@@ -116,6 +117,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")) {
|
||||
@@ -126,8 +128,8 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
}
|
||||
|
||||
Intent i = new Intent(act, PasswordActivity.class);
|
||||
i.putExtra(KEY_FILENAME, fileName);
|
||||
i.putExtra(KEY_KEYFILE, keyFile);
|
||||
i.putExtra(UriIntentInitTask.KEY_FILENAME, fileName);
|
||||
i.putExtra(UriIntentInitTask.KEY_KEYFILE, keyFile);
|
||||
|
||||
act.startActivityForResult(i, 0);
|
||||
|
||||
@@ -140,48 +142,30 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (keyFileHelper != null) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,12 +173,12 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Intent i = getIntent();
|
||||
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
prefsNoBackup = getSharedPreferences("nobackup", Context.MODE_PRIVATE);
|
||||
prefsNoBackup = PrefsUtil.getNoBackupSharedPreferences(getApplicationContext());
|
||||
|
||||
mRememberKeyfile = prefs.getBoolean(getString(R.string.keyfile_key),
|
||||
getResources().getBoolean(R.bool.keyfile_default));
|
||||
|
||||
mRememberKeyfile = prefs.getBoolean(getString(R.string.keyfile_key), getResources().getBoolean(R.bool.keyfile_default));
|
||||
setContentView(R.layout.password);
|
||||
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
@@ -204,12 +188,114 @@ 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 = (CompoundButton) findViewById(R.id.password_checkbox);
|
||||
checkboxKeyfileView = (CompoundButton) findViewById(R.id.keyfile_checkox);
|
||||
checkboxDefaultDatabaseView = (CompoundButton) findViewById(R.id.default_database);
|
||||
|
||||
new InitTask().execute(i);
|
||||
View browseView = findViewById(R.id.browse_button);
|
||||
keyFileHelper = new KeyFileHelper(PasswordActivity.this);
|
||||
browseView.setOnClickListener(keyFileHelper.getOpenFileOnClickViewListener());
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
new UriIntentInitTask(this, mRememberKeyfile)
|
||||
.execute(getIntent());
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
fingerPrintAnimatedVector = new FingerPrintAnimatedVector(this,
|
||||
(ImageView) fingerprintImageView);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostInitTask(Uri dbUri, Uri keyFileUri, Integer errorStringId) {
|
||||
|
||||
mDbUri = dbUri;
|
||||
mKeyUri = keyFileUri;
|
||||
|
||||
Intent intent = getIntent();
|
||||
String password = intent.getStringExtra(KEY_PASSWORD);
|
||||
boolean launch_immediately = intent.getBooleanExtra(KEY_LAUNCH_IMMEDIATELY, false);
|
||||
|
||||
if (errorStringId != null) {
|
||||
Toast.makeText(PasswordActivity.this, errorStringId, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
populateView();
|
||||
|
||||
confirmButtonView.setOnClickListener(new OkClickHandler());
|
||||
|
||||
if (password != null) {
|
||||
passwordView.setText(password);
|
||||
}
|
||||
|
||||
checkboxDefaultDatabaseView.setOnCheckedChangeListener(new DefaultCheckChange());
|
||||
|
||||
retrieveSettings();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
checkFingerprintAvailability();
|
||||
}
|
||||
|
||||
if (launch_immediately) {
|
||||
verifyCheckboxesAndLoadDatabase(password, mKeyUri);
|
||||
}
|
||||
}
|
||||
|
||||
private void retrieveSettings() {
|
||||
String defaultFilename = prefs.getString(KEY_DEFAULT_FILENAME, "");
|
||||
if (mDbUri!=null
|
||||
&& !EmptyUtils.isNullOrEmpty(mDbUri.getPath())
|
||||
&& UriUtil.equalsDefaultfile(mDbUri, defaultFilename)) {
|
||||
checkboxDefaultDatabaseView.setChecked(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void populateView() {
|
||||
String db = (mDbUri == null) ? "" : mDbUri.toString();
|
||||
if (!db.isEmpty()) {
|
||||
if (PrefsUtil.isFullFilePathEnable(this))
|
||||
filenameView.setText(db);
|
||||
else
|
||||
filenameView.setText(new File(mDbUri.getPath()).getName()); // TODO Encapsulate
|
||||
}
|
||||
|
||||
String key = (mKeyUri == null) ? "" : mKeyUri.toString();
|
||||
if (!key.isEmpty() && mRememberKeyfile) { // Bug KeepassDX #18
|
||||
keyFileView.setText(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -219,8 +305,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
|
||||
@@ -229,15 +314,20 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
// checks if fingerprint is available, will also start listening for fingerprints when available
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
initForFingerprint();
|
||||
checkAvailability();
|
||||
checkFingerprintAvailability();
|
||||
if (fingerPrintAnimatedVector != null) {
|
||||
fingerPrintAnimatedVector.startScan();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
checkbox.setChecked(true);
|
||||
private void setEmptyViews() {
|
||||
passwordView.setText("");
|
||||
checkboxPasswordView.setChecked(false);
|
||||
// Bug KeepassDX #18
|
||||
if (!mRememberKeyfile) {
|
||||
keyFileView.setText("");
|
||||
checkboxKeyfileView.setChecked(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,21 +339,11 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
}
|
||||
}
|
||||
|
||||
private void populateView() {
|
||||
String db = (mDbUri == null) ? "" : mDbUri.toString();
|
||||
setEditText(R.id.filename, 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();
|
||||
}
|
||||
|
||||
// fingerprint related code here
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private void initForFingerprint() {
|
||||
mode = -1;
|
||||
|
||||
fingerPrintHelper = new FingerPrintHelper(this, this);
|
||||
|
||||
// when text entered we can enable the logon/purchase button and if required update encryption/decryption mode
|
||||
@@ -287,7 +367,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);
|
||||
setFingerPrintTextView(validInput ? R.string.store_with_fingerprint : R.string.scanning_fingerprint);
|
||||
mode = validInput ? toggleMode(Cipher.ENCRYPT_MODE) : toggleMode(Cipher.DECRYPT_MODE);
|
||||
}
|
||||
}
|
||||
@@ -304,7 +384,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
|
||||
}
|
||||
|
||||
@@ -313,8 +393,9 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
final int helpCode,
|
||||
final CharSequence helpString) {
|
||||
|
||||
onFingerprintException(new Exception("onAuthenticationHelp"));
|
||||
confirmationView.setText(helpString);
|
||||
showError(helpString);
|
||||
checkFingerprintAvailability();
|
||||
fingerprintTextView.setText(helpString);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -338,7 +419,8 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed() {
|
||||
onFingerprintException(new Exception("onAuthenticationFailed"));
|
||||
showError(R.string.fingerprint_not_recognized);
|
||||
checkFingerprintAvailability();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -353,16 +435,19 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private int toggleMode(final int newMode) {
|
||||
mode = newMode;
|
||||
switch (mode) {
|
||||
case Cipher.ENCRYPT_MODE:
|
||||
fingerPrintHelper.initEncryptData();
|
||||
break;
|
||||
case Cipher.DECRYPT_MODE:
|
||||
final String ivSpecValue = prefsNoBackup.getString(getPreferenceKeyIvSpec(), null);
|
||||
fingerPrintHelper.initDecryptData(ivSpecValue);
|
||||
break;
|
||||
private synchronized int toggleMode(final int newMode) {
|
||||
if(newMode != mode) {
|
||||
mode = newMode;
|
||||
switch (mode) {
|
||||
case Cipher.ENCRYPT_MODE:
|
||||
fingerPrintHelper.initEncryptData();
|
||||
break;
|
||||
case Cipher.DECRYPT_MODE:
|
||||
final String ivSpecValue = prefsNoBackup.getString(getPreferenceKeyIvSpec(), null);
|
||||
if (ivSpecValue != null)
|
||||
fingerPrintHelper.initDecryptData(ivSpecValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return newMode;
|
||||
}
|
||||
@@ -370,49 +455,88 @@ 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();
|
||||
}
|
||||
}
|
||||
|
||||
private void setFingerPrintVisibility(int vis) {
|
||||
fingerprintView.setVisibility(vis);
|
||||
confirmationView.setVisibility(vis);
|
||||
private void setFingerPrintVisibility(final int vis) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fingerprintContainerView.setVisibility(vis);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setFingerPrintTextView(final int textId) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fingerprintTextView.setText(textId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setFingerPrintAlphaImageView(final float alpha) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fingerprintImageView.setAlpha(alpha);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private void checkAvailability() {
|
||||
private synchronized void checkFingerprintAvailability() {
|
||||
|
||||
// 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()) {
|
||||
setFingerPrintAlphaImageView(0.3f);
|
||||
// This happens when no fingerprints are registered. Listening won't start
|
||||
setFingerPrintTextView(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;
|
||||
setFingerPrintAlphaImageView(1f);
|
||||
|
||||
// fingerprint available but no stored password found yet for this DB so show info don't listen
|
||||
if (!prefsNoBackup.contains(getPreferenceKeyValue())) {
|
||||
setFingerPrintTextView(R.string.no_password_stored);
|
||||
// listen for encryption
|
||||
toggleMode(Cipher.ENCRYPT_MODE);
|
||||
}
|
||||
// all is set here so we can confirm to user and start listening for fingerprints
|
||||
else {
|
||||
setFingerPrintTextView(R.string.scanning_fingerprint);
|
||||
// listen for decryption
|
||||
toggleMode(Cipher.DECRYPT_MODE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -421,36 +545,58 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
public void handleEncryptedResult(
|
||||
final String value,
|
||||
final String ivSpec) {
|
||||
|
||||
prefsNoBackup.edit()
|
||||
.putString(getPreferenceKeyValue(), value)
|
||||
.putString(getPreferenceKeyIvSpec(), ivSpec)
|
||||
.apply();
|
||||
// and remove visual input to reset UI
|
||||
confirmButton.performClick();
|
||||
confirmationView.setText(R.string.encrypted_value_stored);
|
||||
confirmButtonView.performClick();
|
||||
setFingerPrintTextView(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();
|
||||
public void handleDecryptedResult(final String passwordValue) {
|
||||
// Load database directly
|
||||
String key = keyFileView.getText().toString();
|
||||
loadDatabase(passwordValue, key);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
@Override
|
||||
public void onInvalidKeyException() {
|
||||
Toast.makeText(this, R.string.fingerprint_invalid_key, Toast.LENGTH_SHORT).show();
|
||||
checkAvailability(); // restarts listening
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
@Override
|
||||
public void onFingerprintException(Exception e) {
|
||||
//Toast.makeText(this, R.string.fingerprint_error, Toast.LENGTH_SHORT).show();
|
||||
checkAvailability();
|
||||
public void onInvalidKeyException(Exception e) {
|
||||
showError(R.string.fingerprint_invalid_key);
|
||||
prefsNoBackup.edit()
|
||||
.remove(getPreferenceKeyValue())
|
||||
.remove(getPreferenceKeyIvSpec())
|
||||
.apply();
|
||||
e.printStackTrace();
|
||||
checkFingerprintAvailability(); // restarts listening
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
@Override
|
||||
public void onFingerPrintException(Exception e) {
|
||||
showError(R.string.fingerprint_error);
|
||||
e.printStackTrace();
|
||||
checkFingerprintAvailability();
|
||||
}
|
||||
|
||||
private void showError(final int messageId) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(getApplicationContext(), messageId, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showError(final CharSequence message) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class DefaultCheckChange implements CompoundButton.OnCheckedChangeListener {
|
||||
@@ -482,12 +628,30 @@ 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);
|
||||
loadDatabase(pass, key);
|
||||
String pass = passwordView.getText().toString();
|
||||
String key = keyFileView.getText().toString();
|
||||
verifyCheckboxesAndLoadDatabase(pass, key);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyCheckboxesAndLoadDatabase(
|
||||
String pass,
|
||||
String keyfile) {
|
||||
verifyCheckboxesAndLoadDatabase(pass, UriUtil.parseDefaultFile(keyfile));
|
||||
}
|
||||
|
||||
private void verifyCheckboxesAndLoadDatabase(
|
||||
String pass,
|
||||
Uri keyfile) {
|
||||
if (!checkboxPasswordView.isChecked()) {
|
||||
pass = "";
|
||||
}
|
||||
if (!checkboxKeyfileView.isChecked()) {
|
||||
keyfile = null;
|
||||
}
|
||||
loadDatabase(pass, keyfile);
|
||||
}
|
||||
|
||||
private void loadDatabase(
|
||||
String pass,
|
||||
String keyfile) {
|
||||
@@ -497,10 +661,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();
|
||||
@@ -515,19 +675,6 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
pt.run();
|
||||
}
|
||||
|
||||
private String getEditText(int resId) {
|
||||
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 +701,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
|
||||
private Database db;
|
||||
|
||||
public AfterLoad(
|
||||
AfterLoad(
|
||||
Handler handler,
|
||||
Database db) {
|
||||
super(handler);
|
||||
@@ -584,20 +731,30 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
}
|
||||
}
|
||||
|
||||
private class InitTask extends AsyncTask<Intent, Void, Integer> {
|
||||
private static class UriIntentInitTask extends AsyncTask<Intent, Void, Integer> {
|
||||
|
||||
String password = "";
|
||||
boolean launch_immediately = false;
|
||||
static final String KEY_FILENAME = "fileName";
|
||||
static final String KEY_KEYFILE = "keyFile";
|
||||
private static final String VIEW_INTENT = "android.intent.action.VIEW";
|
||||
|
||||
private UriIntentInitTaskCallback uriIntentInitTaskCallback;
|
||||
private boolean isKeyFileNeeded;
|
||||
private Uri databaseUri;
|
||||
private Uri keyFileUri;
|
||||
|
||||
UriIntentInitTask(UriIntentInitTaskCallback uriIntentInitTaskCallback, boolean isKeyFileNeeded) {
|
||||
this.uriIntentInitTaskCallback = uriIntentInitTaskCallback;
|
||||
this.isKeyFileNeeded = isKeyFileNeeded;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(Intent... args) {
|
||||
Intent i = args[0];
|
||||
String action = i.getAction();
|
||||
Intent intent = args[0];
|
||||
String action = intent.getAction();
|
||||
if (action != null && action.equals(VIEW_INTENT)) {
|
||||
Uri incoming = i.getData();
|
||||
mDbUri = incoming;
|
||||
|
||||
mKeyUri = ClipDataCompat.getUriFromIntent(i, KEY_KEYFILE);
|
||||
Uri incoming = intent.getData();
|
||||
databaseUri = incoming;
|
||||
keyFileUri = ClipDataCompat.getUriFromIntent(intent, KEY_KEYFILE);
|
||||
|
||||
if (incoming == null) {
|
||||
return R.string.error_can_not_handle_uri;
|
||||
@@ -606,122 +763,47 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
|
||||
if (fileName.length() == 0) {
|
||||
// No file name
|
||||
return R.string.FileNotFound;
|
||||
return R.string.file_not_found;
|
||||
}
|
||||
|
||||
File dbFile = new File(fileName);
|
||||
if (!dbFile.exists()) {
|
||||
// File does not exist
|
||||
return R.string.FileNotFound;
|
||||
return R.string.file_not_found;
|
||||
}
|
||||
|
||||
if (mKeyUri == null) {
|
||||
mKeyUri = getKeyFile(mDbUri);
|
||||
if (keyFileUri == null) {
|
||||
keyFileUri = getKeyFile(databaseUri);
|
||||
}
|
||||
} else if (incoming.getScheme().equals("content")) {
|
||||
if (mKeyUri == null) {
|
||||
mKeyUri = getKeyFile(mDbUri);
|
||||
if (keyFileUri == null) {
|
||||
keyFileUri = getKeyFile(databaseUri);
|
||||
}
|
||||
} else {
|
||||
return R.string.error_can_not_handle_uri;
|
||||
}
|
||||
password = i.getStringExtra(KEY_PASSWORD);
|
||||
launch_immediately = i.getBooleanExtra(KEY_LAUNCH_IMMEDIATELY, false);
|
||||
|
||||
|
||||
} else {
|
||||
mDbUri = UriUtil.parseDefaultFile(i.getStringExtra(KEY_FILENAME));
|
||||
mKeyUri = UriUtil.parseDefaultFile(i.getStringExtra(KEY_KEYFILE));
|
||||
password = i.getStringExtra(KEY_PASSWORD);
|
||||
launch_immediately = i.getBooleanExtra(KEY_LAUNCH_IMMEDIATELY, false);
|
||||
databaseUri = UriUtil.parseDefaultFile(intent.getStringExtra(KEY_FILENAME));
|
||||
keyFileUri = UriUtil.parseDefaultFile(intent.getStringExtra(KEY_KEYFILE));
|
||||
|
||||
if (mKeyUri == null || mKeyUri.toString().length() == 0) {
|
||||
mKeyUri = getKeyFile(mDbUri);
|
||||
if (keyFileUri == null || keyFileUri.toString().length() == 0) {
|
||||
keyFileUri = getKeyFile(databaseUri);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void onPostExecute(Integer result) {
|
||||
if (result != null) {
|
||||
Toast.makeText(PasswordActivity.this, result, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
uriIntentInitTaskCallback.onPostInitTask(databaseUri, keyFileUri, result);
|
||||
}
|
||||
|
||||
populateView();
|
||||
|
||||
Button confirmButton = (Button) findViewById(R.id.pass_ok);
|
||||
confirmButton.setOnClickListener(new OkClickHandler());
|
||||
|
||||
if (password != null) {
|
||||
TextView tv_password = (TextView) findViewById(R.id.password);
|
||||
tv_password.setText(password);
|
||||
}
|
||||
|
||||
CheckBox defaultCheck = (CheckBox) 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();
|
||||
}
|
||||
});
|
||||
|
||||
retrieveSettings();
|
||||
|
||||
if (launch_immediately) {
|
||||
loadDatabase(password, mKeyUri);
|
||||
private Uri getKeyFile(Uri dbUri) {
|
||||
if (isKeyFileNeeded) {
|
||||
return App.getFileHistory().getFileByName(dbUri);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
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());
|
||||
|
||||
String message = getString(R.string.unavailable_feature_text).concat("\n");
|
||||
if(Build.VERSION.SDK_INT <= minVersionRequired)
|
||||
message = message.concat(getString(R.string.unavailable_feature_version,
|
||||
Build.VERSION.SDK_INT,
|
||||
minVersionRequired));
|
||||
else
|
||||
message = message.concat(getString(R.string.unavailable_feature_hardware));
|
||||
|
||||
builder.setMessage(message)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) { }
|
||||
});
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.keepassdroid;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
interface UriIntentInitTaskCallback {
|
||||
void onPostInitTask(Uri dbUri, Uri keyFileUri, Integer errorStringId);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -78,7 +78,7 @@ public class LoadDB extends RunnableOnFinish {
|
||||
finish(false, mCtx.getString(R.string.file_not_found_content));
|
||||
return;
|
||||
} catch (FileNotFoundException e) {
|
||||
finish(false, mCtx.getString(R.string.FileNotFound));
|
||||
finish(false, mCtx.getString(R.string.file_not_found));
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
finish(false, e.getMessage());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -922,7 +922,7 @@ public class ImporterV4 extends Importer {
|
||||
byte[] buf = Base64Coder.decode(sDate);
|
||||
if (buf.length != 8) {
|
||||
byte[] buf8 = new byte[8];
|
||||
System.arraycopy(buf, 0, buf8, 0, buf.length);
|
||||
System.arraycopy(buf, 0, buf8, 0, Math.min(buf.length, 8));
|
||||
buf = buf8;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()));
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2018 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.fileselect;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
class DeleteFileHistoryAsyncTask extends AsyncTask<FileSelectBean, Void, Void> {
|
||||
|
||||
private AfterDeleteFileHistoryListener afterDeleteFileHistoryListener;
|
||||
private RecentFileHistory fileHistory;
|
||||
private FileSelectAdapter adapter;
|
||||
|
||||
DeleteFileHistoryAsyncTask(AfterDeleteFileHistoryListener afterDeleteFileHistoryListener, RecentFileHistory fileHistory, FileSelectAdapter adapter) {
|
||||
this.afterDeleteFileHistoryListener = afterDeleteFileHistoryListener;
|
||||
this.fileHistory = fileHistory;
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
protected Void doInBackground(FileSelectBean... args) {
|
||||
fileHistory.deleteFile(args[0].getFileUri());
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void onPostExecute(Void v) {
|
||||
adapter.notifyDataSetChanged();
|
||||
if (adapter.getItemCount() == 0) {
|
||||
if(afterDeleteFileHistoryListener != null)
|
||||
afterDeleteFileHistoryListener.afterDeleteFile();
|
||||
}
|
||||
}
|
||||
|
||||
public interface AfterDeleteFileHistoryListener {
|
||||
void afterDeleteFile();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2018 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.fileselect;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
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.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
import java.text.DateFormat;
|
||||
|
||||
public class FileInformationDialogFragment extends DialogFragment {
|
||||
|
||||
private static final String FILE_SELECT_BEEN_ARG = "FILE_SELECT_BEEN_ARG";
|
||||
|
||||
public static FileInformationDialogFragment newInstance(FileSelectBean fileSelectBean) {
|
||||
FileInformationDialogFragment fileInformationDialogFragment =
|
||||
new FileInformationDialogFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putSerializable(FILE_SELECT_BEEN_ARG, fileSelectBean);
|
||||
fileInformationDialogFragment.setArguments(args);
|
||||
return fileInformationDialogFragment;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
View root = inflater.inflate(R.layout.file_selection_information, null);
|
||||
|
||||
if (getArguments() != null && getArguments().containsKey(FILE_SELECT_BEEN_ARG)) {
|
||||
FileSelectBean fileSelectBean = (FileSelectBean) getArguments().getSerializable(FILE_SELECT_BEEN_ARG);
|
||||
TextView fileWarningView = (TextView) root.findViewById(R.id.file_warning);
|
||||
if(fileSelectBean != null) {
|
||||
TextView fileNameView = (TextView) root.findViewById(R.id.file_filename);
|
||||
TextView filePathView = (TextView) root.findViewById(R.id.file_path);
|
||||
TextView fileSizeView = (TextView) root.findViewById(R.id.file_size);
|
||||
TextView fileModificationView = (TextView) root.findViewById(R.id.file_modification);
|
||||
fileWarningView.setVisibility(View.GONE);
|
||||
fileNameView.setText(fileSelectBean.getFileName());
|
||||
filePathView.setText(Uri.decode(fileSelectBean.getFileUri().toString()));
|
||||
fileSizeView.setText(String.valueOf(fileSelectBean.getSize()));
|
||||
fileModificationView.setText(DateFormat.getDateTimeInstance()
|
||||
.format(fileSelectBean.getLastModification()));
|
||||
if(fileSelectBean.notFound())
|
||||
showFileNotFound(fileWarningView);
|
||||
} else
|
||||
showFileNotFound(fileWarningView);
|
||||
}
|
||||
|
||||
builder.setView(root);
|
||||
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
|
||||
}
|
||||
});
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
private void showFileNotFound(TextView fileWarningView) {
|
||||
fileWarningView.setVisibility(View.VISIBLE);
|
||||
fileWarningView.setText(R.string.file_not_found);
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@
|
||||
*/
|
||||
package com.keepassdroid.fileselect;
|
||||
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ContentResolver;
|
||||
@@ -27,35 +26,26 @@ import android.content.Intent;
|
||||
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.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
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,20 +59,27 @@ 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.net.URLDecoder;
|
||||
|
||||
public class FileSelectActivity extends StylishActivity {
|
||||
public class FileSelectActivity extends StylishActivity implements
|
||||
CreateFileDialog.DefinePathDialogListener ,
|
||||
AssignMasterKeyDialog.AssignPasswordDialogListener,
|
||||
FileSelectAdapter.FileSelectClearListener,
|
||||
FileSelectAdapter.FileInformationShowListener {
|
||||
|
||||
private static final String TAG = "FileSelectActivity";
|
||||
|
||||
private static final int MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE = 111;
|
||||
private ListView mList;
|
||||
private ListAdapter mAdapter;
|
||||
|
||||
private static final int CMENU_CLEAR = Menu.FIRST;
|
||||
private RecyclerView mListFiles;
|
||||
private FileSelectAdapter mAdapter;
|
||||
private View fileListTitle;
|
||||
|
||||
public static final int FILE_BROWSE = 1;
|
||||
public static final int GET_CONTENT = 2;
|
||||
@@ -92,42 +89,37 @@ 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);
|
||||
fileListTitle = findViewById(R.id.file_list_title);
|
||||
if (fileHistory.hasRecentFiles()) {
|
||||
recentMode = true;
|
||||
setContentView(R.layout.file_selection);
|
||||
} else {
|
||||
setContentView(R.layout.file_selection_no_recent);
|
||||
}
|
||||
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
toolbar.setTitle(getString(R.string.app_name));
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
);
|
||||
mListFiles = (RecyclerView) findViewById(R.id.file_list);
|
||||
mListFiles.setLayoutManager(new LinearLayoutManager(this));
|
||||
|
||||
// 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);
|
||||
}
|
||||
@@ -137,82 +129,18 @@ public class FileSelectActivity extends StylishActivity {
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
Toast.makeText(FileSelectActivity.this,
|
||||
R.string.FileNotFound, Toast.LENGTH_LONG).show();
|
||||
R.string.file_not_found, 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 +151,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 +173,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 +181,6 @@ public class FileSelectActivity extends StylishActivity {
|
||||
} catch (ActivityNotFoundException e) {
|
||||
showBrowserDialog();
|
||||
}
|
||||
|
||||
} else {
|
||||
showBrowserDialog();
|
||||
}
|
||||
@@ -268,17 +192,25 @@ 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);
|
||||
|
||||
|
||||
// Load default database
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
String fileName = prefs.getString(PasswordActivity.KEY_DEFAULT_FILENAME, "");
|
||||
|
||||
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 +234,142 @@ public class FileSelectActivity extends StylishActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTitleFileListView() {
|
||||
if(mAdapter.getItemCount() == 0)
|
||||
fileListTitle.setVisibility(View.INVISIBLE);
|
||||
else
|
||||
fileListTitle.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,62 +378,66 @@ public class FileSelectActivity extends StylishActivity {
|
||||
if (mSuccess) {
|
||||
// Add to recent files
|
||||
fileHistory.createFile(mUri, getFilename());
|
||||
|
||||
mAdapter.notifyDataSetChanged();
|
||||
updateTitleFileListView();
|
||||
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 FileSelectAdapter(FileSelectActivity.this, fileHistory.getDbList());
|
||||
mAdapter.setOnItemClickListener(
|
||||
new View.OnClickListener() {
|
||||
public void onClick(View view) {
|
||||
int itemPosition = mListFiles.getChildLayoutPosition(view);
|
||||
new OpenFileHistoryAsyncTask(new OpenFileHistoryAsyncTask.AfterOpenFileHistoryListener() {
|
||||
@Override
|
||||
public void afterOpenFile(String fileName, String keyFile) {
|
||||
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.file_not_found, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
}
|
||||
updateTitleFileListView();
|
||||
}
|
||||
}, fileHistory).execute(itemPosition);
|
||||
}
|
||||
}
|
||||
);
|
||||
mAdapter.setFileSelectClearListener(this);
|
||||
mAdapter.setFileInformationShowListener(this);
|
||||
mListFiles.setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
protected void onListItemClick(ListView l, View v, int position, long id) {
|
||||
@Override
|
||||
public void onClickFileInformation(FileSelectBean fileSelectBean) {
|
||||
if (fileSelectBean != null) {
|
||||
FileInformationDialogFragment fileInformationDialogFragment =
|
||||
FileInformationDialogFragment.newInstance(fileSelectBean);
|
||||
fileInformationDialogFragment.show(getSupportFragmentManager(), "fileInformation");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@Override
|
||||
public boolean onFileSelectClearListener(final FileSelectBean fileSelectBean) {
|
||||
new DeleteFileHistoryAsyncTask(new DeleteFileHistoryAsyncTask.AfterDeleteFileHistoryListener() {
|
||||
@Override
|
||||
public void afterDeleteFile() {
|
||||
fileHistory.deleteFile(fileSelectBean.getFileUri());
|
||||
mAdapter.notifyDataSetChanged();
|
||||
updateTitleFileListView();
|
||||
}
|
||||
}, fileHistory, mAdapter).execute(fileSelectBean);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
@@ -414,8 +480,7 @@ public class FileSelectActivity extends StylishActivity {
|
||||
}
|
||||
|
||||
if (filename != null) {
|
||||
EditText fn = (EditText) findViewById(R.id.file_filename);
|
||||
fn.setText(filename);
|
||||
openFileNameView.setText(filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,6 +501,8 @@ public class FileSelectActivity extends StylishActivity {
|
||||
|
||||
FileNameView fnv = (FileNameView) findViewById(R.id.file_select);
|
||||
fnv.updateExternalStorageWarning();
|
||||
|
||||
updateTitleFileListView();
|
||||
}
|
||||
|
||||
private void checkStoragePermission() {
|
||||
@@ -505,42 +572,4 @@ public class FileSelectActivity extends StylishActivity {
|
||||
&& super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||
ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
|
||||
menu.add(0, CMENU_CLEAR, 0, R.string.remove_from_filelist);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
super.onContextItemSelected(item);
|
||||
|
||||
if ( item.getItemId() == CMENU_CLEAR ) {
|
||||
AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) item.getMenuInfo();
|
||||
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void refreshList() {
|
||||
((BaseAdapter) mAdapter).notifyDataSetChanged();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright 2018 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.fileselect;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.keepassdroid.settings.PrefsUtil;
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FileSelectAdapter extends RecyclerView.Adapter<FileSelectViewHolder> {
|
||||
|
||||
private static final int MENU_CLEAR = 1;
|
||||
|
||||
private Context context;
|
||||
private LayoutInflater inflater;
|
||||
private List<String> listFiles;
|
||||
private View.OnClickListener mOnClickListener;
|
||||
private FileSelectClearListener fileSelectClearListener;
|
||||
private FileInformationShowListener fileInformationShowListener;
|
||||
|
||||
private @ColorInt
|
||||
int warningColor;
|
||||
|
||||
FileSelectAdapter(Context context, List<String> listFiles) {
|
||||
inflater = LayoutInflater.from(context);
|
||||
this.context = context;
|
||||
this.listFiles = listFiles;
|
||||
|
||||
TypedValue typedValue = new TypedValue();
|
||||
Resources.Theme theme = context.getTheme();
|
||||
theme.resolveAttribute(R.attr.colorAccentCompat, typedValue, true);
|
||||
warningColor = typedValue.data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSelectViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = inflater.inflate(R.layout.file_row, parent, false);
|
||||
view.setOnClickListener(mOnClickListener);
|
||||
return new FileSelectViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(FileSelectViewHolder holder, int position) {
|
||||
FileSelectBean fileSelectBean = new FileSelectBean(context, listFiles.get(position));
|
||||
holder.fileContainer.setOnCreateContextMenuListener(new ContextMenuBuilder(fileSelectBean));
|
||||
|
||||
if (PrefsUtil.isFullFilePathEnable(context))
|
||||
holder.fileName.setText(Uri.decode(fileSelectBean.getFileUri().toString()));
|
||||
else
|
||||
holder.fileName.setText(fileSelectBean.getFileName());
|
||||
holder.fileName.setTextSize(PrefsUtil.getListTextSize(context));
|
||||
|
||||
|
||||
if(fileSelectBean.notFound()) {
|
||||
holder.fileInformation.setColorFilter(
|
||||
warningColor,
|
||||
android.graphics.PorterDuff.Mode.MULTIPLY);
|
||||
}
|
||||
if (fileInformationShowListener != null)
|
||||
holder.fileInformation.setOnClickListener(new FileInformationClickListener(fileSelectBean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return listFiles.size();
|
||||
}
|
||||
|
||||
void setOnItemClickListener(View.OnClickListener onItemClickListener) {
|
||||
this.mOnClickListener = onItemClickListener;
|
||||
}
|
||||
|
||||
void setFileSelectClearListener(FileSelectClearListener fileSelectClearListener) {
|
||||
this.fileSelectClearListener = fileSelectClearListener;
|
||||
}
|
||||
|
||||
void setFileInformationShowListener(FileInformationShowListener fileInformationShowListener) {
|
||||
this.fileInformationShowListener = fileInformationShowListener;
|
||||
}
|
||||
|
||||
public interface FileInformationShowListener {
|
||||
void onClickFileInformation(FileSelectBean fileSelectBean);
|
||||
}
|
||||
|
||||
public interface FileSelectClearListener {
|
||||
boolean onFileSelectClearListener(FileSelectBean fileSelectBean);
|
||||
}
|
||||
|
||||
private class FileInformationClickListener implements View.OnClickListener {
|
||||
|
||||
private FileSelectBean fileSelectBean;
|
||||
|
||||
FileInformationClickListener(FileSelectBean fileSelectBean) {
|
||||
this.fileSelectBean = fileSelectBean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
fileInformationShowListener.onClickFileInformation(fileSelectBean);
|
||||
}
|
||||
}
|
||||
|
||||
private class ContextMenuBuilder implements View.OnCreateContextMenuListener {
|
||||
|
||||
private FileSelectBean fileSelectBean;
|
||||
|
||||
public ContextMenuBuilder(FileSelectBean fileSelectBean) {
|
||||
this.fileSelectBean = fileSelectBean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
|
||||
MenuItem clearMenu = contextMenu.add(Menu.NONE, MENU_CLEAR, Menu.NONE, R.string.remove_from_filelist);
|
||||
clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);
|
||||
}
|
||||
|
||||
private MenuItem.OnMenuItemClickListener mOnMyActionClickListener = new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
if (item.getItemId() == MENU_CLEAR) {
|
||||
return fileSelectClearListener.onFileSelectClearListener(fileSelectBean);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.fileselect;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.support.v4.provider.DocumentFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
public class FileSelectBean implements Serializable {
|
||||
|
||||
private static final String EXTERNAL_STORAGE_AUTHORITY = "com.android.externalstorage.documents";
|
||||
|
||||
private String fileName = "";
|
||||
private Uri fileUri;
|
||||
private Date lastModification = new Date();
|
||||
private long size = 0;
|
||||
|
||||
public FileSelectBean(Context context, String pathFile) {
|
||||
fileUri = Uri.parse(pathFile);
|
||||
if (EXTERNAL_STORAGE_AUTHORITY.equals(fileUri.getAuthority())) {
|
||||
DocumentFile file = DocumentFile.fromSingleUri(context, fileUri);
|
||||
size = file.length();
|
||||
fileName = file.getName();
|
||||
lastModification = new Date(file.lastModified());
|
||||
} else {
|
||||
File file = new File(fileUri.getPath());
|
||||
size = file.length();
|
||||
fileName = file.getName();
|
||||
lastModification = new Date(file.lastModified());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean notFound() {
|
||||
return getSize() == 0;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public Uri getFileUri() {
|
||||
return fileUri;
|
||||
}
|
||||
|
||||
public void setFileUri(Uri fileUri) {
|
||||
this.fileUri = fileUri;
|
||||
}
|
||||
|
||||
public Date getLastModification() {
|
||||
return lastModification;
|
||||
}
|
||||
|
||||
public void setLastModification(Date lastModification) {
|
||||
this.lastModification = lastModification;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(long size) {
|
||||
this.size = size;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* Copyright 2018 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
@@ -17,26 +17,25 @@
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.keepassdroid;
|
||||
package com.keepassdroid.fileselect;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class CancelDialog extends Dialog {
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
private boolean mCanceled = false;
|
||||
|
||||
public CancelDialog(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public boolean canceled() {
|
||||
return mCanceled;
|
||||
}
|
||||
class FileSelectViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
super.cancel();
|
||||
mCanceled = true;
|
||||
}
|
||||
View fileContainer;
|
||||
TextView fileName;
|
||||
ImageView fileInformation;
|
||||
|
||||
FileSelectViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
fileContainer = itemView.findViewById(R.id.file_container);
|
||||
fileName = (TextView) itemView.findViewById(R.id.file_filename);
|
||||
fileInformation = (ImageView) itemView.findViewById(R.id.file_information);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2018 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.fileselect;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
class OpenFileHistoryAsyncTask extends AsyncTask<Integer, Void, Void> {
|
||||
|
||||
private AfterOpenFileHistoryListener afterOpenFileHistoryListener;
|
||||
private RecentFileHistory fileHistory;
|
||||
private String fileName;
|
||||
private String keyFile;
|
||||
|
||||
OpenFileHistoryAsyncTask(AfterOpenFileHistoryListener afterOpenFileHistoryListener, RecentFileHistory fileHistory) {
|
||||
this.afterOpenFileHistoryListener = afterOpenFileHistoryListener;
|
||||
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) {
|
||||
afterOpenFileHistoryListener.afterOpenFile(fileName, keyFile);
|
||||
}
|
||||
|
||||
public interface AfterOpenFileHistoryListener {
|
||||
void afterOpenFile(String fileName, String keyFile);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -34,8 +34,14 @@ import android.util.Base64;
|
||||
|
||||
import com.keepassdroid.compat.BuildCompat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
@@ -43,7 +49,7 @@ import javax.crypto.spec.IvParameterSpec;
|
||||
|
||||
public class FingerPrintHelper {
|
||||
|
||||
private static final String ALIAS_KEY = "example-key";
|
||||
private static final String FINGERPRINT_KEYSTORE_KEY = "example-key";
|
||||
|
||||
private FingerprintManagerCompat fingerprintManager;
|
||||
private KeyStore keyStore = null;
|
||||
@@ -74,7 +80,7 @@ public class FingerPrintHelper {
|
||||
}
|
||||
|
||||
public void stopListening() {
|
||||
if (!isFingerprintInitialized()) {
|
||||
if (!isFingerprintInitialized(false)) {
|
||||
return;
|
||||
}
|
||||
if (cancellationSignal != null) {
|
||||
@@ -83,13 +89,6 @@ public class FingerPrintHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public interface FingerPrintCallback {
|
||||
void handleEncryptedResult(String value, String ivSpec);
|
||||
void handleDecryptedResult(String value);
|
||||
void onInvalidKeyException();
|
||||
void onFingerprintException(Exception e);
|
||||
}
|
||||
|
||||
@TargetApi(BuildCompat.VERSION_CODE_M)
|
||||
public FingerPrintHelper(
|
||||
final Context context,
|
||||
@@ -118,20 +117,26 @@ public class FingerPrintHelper {
|
||||
setInitOk(true);
|
||||
} catch (final Exception e) {
|
||||
setInitOk(false);
|
||||
fingerPrintCallback.onFingerprintException(e);
|
||||
fingerPrintCallback.onFingerPrintException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFingerprintSupported(FingerprintManagerCompat fingerprintManager) {
|
||||
public static boolean isFingerprintSupported(FingerprintManagerCompat fingerprintManager) {
|
||||
return Build.VERSION.SDK_INT >= BuildCompat.VERSION_CODE_M
|
||||
&& fingerprintManager != null
|
||||
&& fingerprintManager.isHardwareDetected();
|
||||
}
|
||||
|
||||
public boolean isFingerprintInitialized() {
|
||||
return isFingerprintInitialized(true);
|
||||
}
|
||||
|
||||
public boolean isFingerprintInitialized(boolean throwException) {
|
||||
boolean isFingerprintInit = hasEnrolledFingerprints() && initOk;
|
||||
if (!isFingerprintInit && fingerPrintCallback != null) {
|
||||
fingerPrintCallback.onFingerprintException(new Exception("FingerPrint not initialized"));
|
||||
if(throwException)
|
||||
fingerPrintCallback.onFingerPrintException(new Exception("FingerPrint not initialized"));
|
||||
}
|
||||
return isFingerprintInit;
|
||||
}
|
||||
@@ -144,16 +149,17 @@ public class FingerPrintHelper {
|
||||
try {
|
||||
createNewKeyIfNeeded(false); // no need to keep deleting existing keys
|
||||
keyStore.load(null);
|
||||
final SecretKey key = (SecretKey) keyStore.getKey(ALIAS_KEY, null);
|
||||
final SecretKey key = (SecretKey) keyStore.getKey(FINGERPRINT_KEYSTORE_KEY, null);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
|
||||
stopListening();
|
||||
startListening();
|
||||
|
||||
} catch (final UnrecoverableKeyException unrecoverableKeyException) {
|
||||
deleteEntryKey();
|
||||
} catch (final KeyPermanentlyInvalidatedException invalidKeyException) {
|
||||
fingerPrintCallback.onInvalidKeyException();
|
||||
fingerPrintCallback.onInvalidKeyException(invalidKeyException);
|
||||
} catch (final Exception e) {
|
||||
fingerPrintCallback.onFingerprintException(e);
|
||||
fingerPrintCallback.onFingerPrintException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +170,7 @@ public class FingerPrintHelper {
|
||||
try {
|
||||
// actual do encryption here
|
||||
byte[] encrypted = cipher.doFinal(value.getBytes());
|
||||
final String encryptedValue = Base64.encodeToString(encrypted, 0 /* flags */);
|
||||
final String encryptedValue = Base64.encodeToString(encrypted, Base64.DEFAULT);
|
||||
|
||||
// passes updated iv spec on to callback so this can be stored for decryption
|
||||
final IvParameterSpec spec = cipher.getParameters().getParameterSpec(IvParameterSpec.class);
|
||||
@@ -172,7 +178,7 @@ public class FingerPrintHelper {
|
||||
fingerPrintCallback.handleEncryptedResult(encryptedValue, ivSpecValue);
|
||||
|
||||
} catch (final Exception e) {
|
||||
fingerPrintCallback.onFingerprintException(e);
|
||||
fingerPrintCallback.onFingerPrintException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +190,7 @@ public class FingerPrintHelper {
|
||||
try {
|
||||
createNewKeyIfNeeded(false);
|
||||
keyStore.load(null);
|
||||
final SecretKey key = (SecretKey) keyStore.getKey(ALIAS_KEY, null);
|
||||
final SecretKey key = (SecretKey) keyStore.getKey(FINGERPRINT_KEYSTORE_KEY, null);
|
||||
|
||||
// important to restore spec here that was used for decryption
|
||||
final byte[] iv = Base64.decode(ivSpecValue, Base64.DEFAULT);
|
||||
@@ -195,9 +201,11 @@ public class FingerPrintHelper {
|
||||
startListening();
|
||||
|
||||
} catch (final KeyPermanentlyInvalidatedException invalidKeyException) {
|
||||
fingerPrintCallback.onInvalidKeyException();
|
||||
fingerPrintCallback.onInvalidKeyException(invalidKeyException);
|
||||
} catch (final UnrecoverableKeyException unrecoverableKeyException) {
|
||||
deleteEntryKey();
|
||||
} catch (final Exception e) {
|
||||
fingerPrintCallback.onFingerprintException(e);
|
||||
fingerPrintCallback.onFingerPrintException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,14 +215,16 @@ public class FingerPrintHelper {
|
||||
}
|
||||
try {
|
||||
// actual decryption here
|
||||
final byte[] encrypted = Base64.decode(encryptedValue, 0);
|
||||
final byte[] encrypted = Base64.decode(encryptedValue, Base64.DEFAULT);
|
||||
byte[] decrypted = cipher.doFinal(encrypted);
|
||||
final String decryptedString = new String(decrypted);
|
||||
|
||||
//final String encryptedString = Base64.encodeToString(encrypted, 0 /* flags */);
|
||||
fingerPrintCallback.handleDecryptedResult(decryptedString);
|
||||
} catch (final BadPaddingException badPaddingException) {
|
||||
fingerPrintCallback.onInvalidKeyException(badPaddingException);
|
||||
} catch (final Exception e) {
|
||||
fingerPrintCallback.onFingerprintException(e);
|
||||
fingerPrintCallback.onFingerPrintException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,18 +236,17 @@ public class FingerPrintHelper {
|
||||
try {
|
||||
keyStore.load(null);
|
||||
if (allowDeleteExisting
|
||||
&& keyStore.containsAlias(ALIAS_KEY)) {
|
||||
|
||||
keyStore.deleteEntry(ALIAS_KEY);
|
||||
&& keyStore.containsAlias(FINGERPRINT_KEYSTORE_KEY)) {
|
||||
keyStore.deleteEntry(FINGERPRINT_KEYSTORE_KEY);
|
||||
}
|
||||
|
||||
// Create new key if needed
|
||||
if (!keyStore.containsAlias(ALIAS_KEY)) {
|
||||
if (!keyStore.containsAlias(FINGERPRINT_KEYSTORE_KEY)) {
|
||||
// Set the alias of the entry in Android KeyStore where the key will appear
|
||||
// and the constrains (purposes) in the constructor of the Builder
|
||||
keyGenerator.init(
|
||||
new KeyGenParameterSpec.Builder(
|
||||
ALIAS_KEY,
|
||||
FINGERPRINT_KEYSTORE_KEY,
|
||||
KeyProperties.PURPOSE_ENCRYPT |
|
||||
KeyProperties.PURPOSE_DECRYPT)
|
||||
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
|
||||
@@ -249,7 +258,19 @@ public class FingerPrintHelper {
|
||||
keyGenerator.generateKey();
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
fingerPrintCallback.onFingerprintException(e);
|
||||
fingerPrintCallback.onFingerPrintException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteEntryKey() {
|
||||
try {
|
||||
keyStore.load(null);
|
||||
keyStore.deleteEntry(FINGERPRINT_KEYSTORE_KEY);
|
||||
} catch (KeyStoreException
|
||||
| CertificateException
|
||||
| NoSuchAlgorithmException
|
||||
| IOException e) {
|
||||
fingerPrintCallback.onFingerPrintException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,8 +278,6 @@ public class FingerPrintHelper {
|
||||
public boolean hasEnrolledFingerprints() {
|
||||
// fingerprint hardware supported and api level OK
|
||||
return isFingerprintSupported(fingerprintManager)
|
||||
&& fingerprintManager != null
|
||||
&& fingerprintManager.isHardwareDetected()
|
||||
// fingerprints enrolled
|
||||
&& fingerprintManager.hasEnrolledFingerprints()
|
||||
// and lockscreen configured
|
||||
@@ -269,4 +288,40 @@ public class FingerPrintHelper {
|
||||
this.initOk = initOk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove entry key in keystore
|
||||
*/
|
||||
public static void deleteEntryKeyInKeystoreForFingerprints(final Context context,
|
||||
final FingerPrintErrorCallback fingerPrintCallback) {
|
||||
FingerPrintHelper fingerPrintHelper = new FingerPrintHelper(
|
||||
context, new FingerPrintCallback() {
|
||||
@Override
|
||||
public void handleEncryptedResult(String value, String ivSpec) {}
|
||||
|
||||
@Override
|
||||
public void handleDecryptedResult(String value) {}
|
||||
|
||||
@Override
|
||||
public void onInvalidKeyException(Exception e) {
|
||||
fingerPrintCallback.onInvalidKeyException(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFingerPrintException(Exception e) {
|
||||
fingerPrintCallback.onFingerPrintException(e);
|
||||
}
|
||||
});
|
||||
fingerPrintHelper.deleteEntryKey();
|
||||
}
|
||||
|
||||
public interface FingerPrintErrorCallback {
|
||||
void onInvalidKeyException(Exception e);
|
||||
void onFingerPrintException(Exception e);
|
||||
}
|
||||
|
||||
public interface FingerPrintCallback extends FingerPrintErrorCallback {
|
||||
void handleEncryptedResult(String value, String ivSpec);
|
||||
void handleDecryptedResult(String value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,12 +2,13 @@ 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 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 +34,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,17 +19,26 @@
|
||||
*/
|
||||
package com.keepassdroid.settings;
|
||||
|
||||
import android.content.DialogInterface;
|
||||
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.v4.hardware.fingerprint.FingerprintManagerCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceFragmentCompat;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.keepassdroid.Database;
|
||||
import com.keepassdroid.UnavailableFeatureDialog;
|
||||
import com.keepassdroid.app.App;
|
||||
import com.keepassdroid.database.PwEncryptionAlgorithm;
|
||||
import com.keepassdroid.fingerprint.FingerPrintHelper;
|
||||
import com.keepassdroid.stylish.Stylish;
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
public class NestedSettingsFragment extends PreferenceFragmentCompat {
|
||||
|
||||
@@ -98,28 +107,84 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat {
|
||||
}
|
||||
});
|
||||
|
||||
SwitchPreference fingerprintEnablePreference = (SwitchPreference) findPreference(getString(R.string.fingerprint_enable_key));
|
||||
if (!FingerPrintHelper.isFingerprintSupported(FingerprintManagerCompat.from(getContext()))) {
|
||||
// False if under Marshmallow
|
||||
fingerprintEnablePreference.setDefaultValue(false);
|
||||
fingerprintEnablePreference.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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Preference deleteKeysFingerprints = findPreference(getString(R.string.fingerprint_delete_all_key));
|
||||
deleteKeysFingerprints.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setMessage(getResources().getString(R.string.fingerprint_delete_all_warning))
|
||||
.setIcon(getResources().getDrawable(
|
||||
android.R.drawable.ic_dialog_alert))
|
||||
.setPositiveButton(
|
||||
getResources().getString(android.R.string.yes),
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog,
|
||||
int which) {
|
||||
FingerPrintHelper.deleteEntryKeyInKeystoreForFingerprints(
|
||||
getContext(),
|
||||
new FingerPrintHelper.FingerPrintErrorCallback() {
|
||||
@Override
|
||||
public void onInvalidKeyException(Exception e) {}
|
||||
|
||||
@Override
|
||||
public void onFingerPrintException(Exception e) {
|
||||
Toast.makeText(getContext(), R.string.fingerprint_error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
PrefsUtil.deleteAllValuesFromNoBackupPreferences(getContext());
|
||||
}
|
||||
})
|
||||
.setNegativeButton(
|
||||
getResources().getString(android.R.string.no),
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog,
|
||||
int which) {
|
||||
}
|
||||
}).show();
|
||||
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 +196,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()));
|
||||
}
|
||||
|
||||
@@ -25,10 +25,67 @@ import android.preference.PreferenceManager;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class PrefsUtil {
|
||||
|
||||
private static final String NO_BACKUP_PREFERENCE_FILE_NAME = "nobackup";
|
||||
|
||||
public static SharedPreferences getNoBackupSharedPreferences(Context ctx) {
|
||||
return ctx.getSharedPreferences(
|
||||
PrefsUtil.NO_BACKUP_PREFERENCE_FILE_NAME,
|
||||
Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public static void deleteAllValuesFromNoBackupPreferences(Context ctx) {
|
||||
SharedPreferences prefsNoBackup = getNoBackupSharedPreferences(ctx);
|
||||
SharedPreferences.Editor sharedPreferencesEditor = prefsNoBackup.edit();
|
||||
sharedPreferencesEditor.clear();
|
||||
sharedPreferencesEditor.apply();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
public static boolean isFullFilePathEnable(Context ctx) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
return prefs.getBoolean(ctx.getString(R.string.full_file_path_enable_key),
|
||||
ctx.getResources().getBoolean(R.bool.full_file_path_enable_default));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -21,17 +21,37 @@ package com.keepassdroid.utils;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.Seconds;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class DateUtil {
|
||||
private static final DateTime dotNetEpoch = new DateTime(1, 1, 1, 0, 0, 0, DateTimeZone.UTC);
|
||||
private static final DateTime javaEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeZone.UTC);
|
||||
|
||||
private static final long epochOffset;
|
||||
|
||||
static {
|
||||
Date dotNet = dotNetEpoch.toDate();
|
||||
Date java = javaEpoch.toDate();
|
||||
|
||||
epochOffset = (javaEpoch.getMillis() - dotNetEpoch.getMillis()) / 1000L;
|
||||
}
|
||||
|
||||
public static Date convertKDBX4Time(long seconds) {
|
||||
return dotNetEpoch.plus(seconds).toDate();
|
||||
|
||||
DateTime dt = dotNetEpoch.plus(seconds * 1000L);
|
||||
|
||||
// Switch corrupted dates to a more recent date that won't cause issues on the client
|
||||
if (dt.isBefore(javaEpoch)) {
|
||||
return javaEpoch.toDate();
|
||||
}
|
||||
|
||||
return dt.toDate();
|
||||
}
|
||||
|
||||
public static long convertDateToKDBX4Time(DateTime dt) {
|
||||
return (dt.getMillis() / 1000) - (dotNetEpoch.getMillis() / 1000);
|
||||
Seconds secs = Seconds.secondsBetween(javaEpoch, dt);
|
||||
return secs.getSeconds() + epochOffset;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
178
app/src/main/java/com/keepassdroid/view/KeyFileHelper.java
Normal file
178
app/src/main/java/com/keepassdroid/view/KeyFileHelper.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
39
app/src/main/res/animator-v23/scan.xml
Normal file
39
app/src/main/res/animator-v23/scan.xml
Normal 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>
|
||||
65
app/src/main/res/drawable-v23/fingerprint.xml
Normal file
65
app/src/main/res/drawable-v23/fingerprint.xml
Normal 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>
|
||||
109
app/src/main/res/drawable-v23/fingerprint_scan.xml
Normal file
109
app/src/main/res/drawable-v23/fingerprint_scan.xml
Normal 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>
|
||||
12
app/src/main/res/drawable-v23/lock_open.xml
Normal file
12
app/src/main/res/drawable-v23/lock_open.xml
Normal 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>
|
||||
26
app/src/main/res/drawable-v23/scan_fingerprint.xml
Normal file
26
app/src/main/res/drawable-v23/scan_fingerprint.xml
Normal 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>
|
||||
6
app/src/main/res/drawable/circle.xml
Normal file
6
app/src/main/res/drawable/circle.xml
Normal 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>
|
||||
10
app/src/main/res/drawable/ic_database_plus_white_24dp.xml
Normal file
10
app/src/main/res/drawable/ic_database_plus_white_24dp.xml
Normal 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>
|
||||
@@ -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>
|
||||
9
app/src/main/res/drawable/ic_info_white_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_info_white_24dp.xml
Normal 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="#FFFFFF"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_lock_open_white_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_lock_open_white_24dp.xml
Normal 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>
|
||||
10
app/src/main/res/drawable/ic_open_folder_white_24dp.xml
Normal file
10
app/src/main/res/drawable/ic_open_folder_white_24dp.xml
Normal 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>
|
||||
BIN
app/src/main/res/drawable/type_assword.png
Normal file
BIN
app/src/main/res/drawable/type_assword.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
136
app/src/main/res/layout-v23/fingerprint_dialog.xml
Normal file
136
app/src/main/res/layout-v23/fingerprint_dialog.xml
Normal 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>
|
||||
29
app/src/main/res/layout-v23/fingerprint_show.xml
Normal file
29
app/src/main/res/layout-v23/fingerprint_show.xml
Normal 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>
|
||||
78
app/src/main/res/layout/file_creation.xml
Normal file
78
app/src/main/res/layout/file_creation.xml
Normal 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>
|
||||
@@ -17,11 +17,35 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/file_filename"
|
||||
android:layout_width="wrap_content"
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/file_container"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingLeft="18dp"
|
||||
android:paddingRight="18dp"
|
||||
android:paddingBottom="8dp" />
|
||||
android:background="?android:attr/selectableItemBackground">
|
||||
<android.support.v7.widget.AppCompatTextView
|
||||
android:id="@+id/file_filename"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toLeftOf="@+id/file_information"
|
||||
android:layout_toStartOf="@+id/file_information"
|
||||
android:paddingBottom="18dp"
|
||||
android:paddingEnd="18dp"
|
||||
android:paddingLeft="18dp"
|
||||
android:paddingRight="18dp"
|
||||
android:paddingStart="18dp"
|
||||
android:paddingTop="18dp" />
|
||||
<android.support.v7.widget.AppCompatImageView
|
||||
android:id="@+id/file_information"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:padding="18dp"
|
||||
android:src="@drawable/ic_info_white_24dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:tint="?attr/colorPrimary"/>
|
||||
</RelativeLayout>
|
||||
@@ -17,32 +17,100 @@
|
||||
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"
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
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_marginBottom="@dimen/default_margin"
|
||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<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"
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:id="@+id/app_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="4dp"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<android.support.design.widget.CollapsingToolbarLayout
|
||||
android:id="@+id/toolbar_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:titleEnabled="false"
|
||||
app:contentScrim="?attr/colorPrimary"
|
||||
app:layout_scrollFlags="scroll|enterAlways|snap">
|
||||
|
||||
<com.keepassdroid.view.FileNameView android:id="@+id/file_select"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="?attr/actionBarSize"/>
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
app:theme="?attr/toolbarAppearance"
|
||||
app:popupTheme="?attr/toolbarPopupAppearance"
|
||||
app:layout_collapseMode="pin"/>
|
||||
|
||||
</android.support.design.widget.CollapsingToolbarLayout>
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/open_database"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginLeft="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginRight="24dp"
|
||||
android:layout_marginBottom="48dp"
|
||||
android:paddingTop="-20dp"
|
||||
app:fabSize="mini"
|
||||
app:layout_anchor="@id/app_bar"
|
||||
app:layout_anchorGravity="bottom|end"
|
||||
android:src="@drawable/ic_open_folder_white_24dp" />
|
||||
|
||||
<android.support.v4.widget.NestedScrollView
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="fill_vertical"
|
||||
android:fillViewport="true">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView android:id="@+id/file_list_title"
|
||||
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"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Title"
|
||||
android:text="@string/open_recent" />
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/file_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
</android.support.v4.widget.NestedScrollView>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
<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" />
|
||||
|
||||
<ListView android:id="@+id/file_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:src="@drawable/ic_database_plus_white_24dp"
|
||||
style="@style/KeepassDXStyle.Fab"/>
|
||||
</RelativeLayout>
|
||||
@@ -17,62 +17,63 @@
|
||||
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"
|
||||
app:cardBackgroundColor="?attr/colorPrimary"
|
||||
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_height="wrap_content">
|
||||
|
||||
<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="22dp">
|
||||
|
||||
<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.Inverse"
|
||||
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:textColor="?attr/textColorInverse"
|
||||
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.CoordinatorLayout>
|
||||
|
||||
72
app/src/main/res/layout/file_selection_information.xml
Normal file
72
app/src/main/res/layout/file_selection_information.xml
Normal file
@@ -0,0 +1,72 @@
|
||||
<?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">
|
||||
|
||||
<android.support.v7.widget.AppCompatTextView
|
||||
android:id="@+id/file_filename"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/KeepassDXStyle.TextAppearance.LargeTitle"/>
|
||||
|
||||
<android.support.v7.widget.AppCompatTextView
|
||||
android:id="@+id/file_path"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:textStyle="italic"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end">
|
||||
<android.support.v7.widget.AppCompatTextView
|
||||
android:id="@+id/file_modification_label"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/entry_modified"/>
|
||||
<android.support.v7.widget.AppCompatTextView
|
||||
android:id="@+id/file_modification"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end" />
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp">
|
||||
<android.support.v7.widget.AppCompatTextView
|
||||
android:id="@+id/file_size"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toLeftOf="@+id/file_size_unit"
|
||||
android:layout_toStartOf="@+id/file_size_unit"
|
||||
android:gravity="end" />
|
||||
<android.support.v7.widget.AppCompatTextView
|
||||
android:id="@+id/file_size_unit"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/bytes"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true" />
|
||||
</RelativeLayout>
|
||||
|
||||
<android.support.v7.widget.AppCompatTextView
|
||||
android:id="@+id/file_warning"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
style="@style/KeepassDXStyle.TextAppearance.WarningTextStyle"/>
|
||||
</LinearLayout>
|
||||
7
app/src/main/res/layout/fingerprint_show.xml
Normal file
7
app/src/main/res/layout/fingerprint_show.xml
Normal 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" />
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<string name="decrypting_entry">Desencriptant entrada</string>
|
||||
<string name="default_checkbox">Utilitza aquesta com a base de dades per defecte</string>
|
||||
<string name="digits">Dígits</string>
|
||||
<string name="disclaimer_formal">KeePass DX Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft ve SENSE CAP MENA DE GARANTIA; Això és programari lliure, i pots redistribuïr-lo sota els termes de la llicència GPL versió 2 o posterior.</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Jeremy Jamet / Kunzisoft, Brian Pellin ve SENSE CAP MENA DE GARANTIA; Això és programari lliure, i pots redistribuïr-lo sota els termes de la llicència GPL versió 2 o posterior.</string>
|
||||
<string name="ellipsis">\u2026</string>
|
||||
<string name="enter_filename">Introdueix el nom de la base de dades:</string>
|
||||
<string name="entry_accessed">Accedida: </string>
|
||||
@@ -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>
|
||||
@@ -88,7 +88,7 @@
|
||||
<string name="error_rounds_too_large">Massa passades. Establint a 2147483648.</string>
|
||||
<string name="error_title_required">És necessari un títol.</string>
|
||||
<string name="error_wrong_length">Insereix un enter positiu al camp longitud</string>
|
||||
<string name="FileNotFound">Arxiu no trobat.</string>
|
||||
<string name="file_not_found">Arxiu no trobat.</string>
|
||||
<string name="file_browser">Explorador d\'arxius</string>
|
||||
<string name="generate_password">Generar contrasenya</string>
|
||||
<string name="group">Grup</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>
|
||||
@@ -138,7 +138,7 @@
|
||||
<string name="no_keys">Sense entrades a la base de dades o grup.</string>
|
||||
<string name="no_results">Cap resultat de cerca</string>
|
||||
<string name="no_url_handler">Sense gestor per aquesta url.</string>
|
||||
<string name="open_recent">Obre base de dades recent (clica per obrir):</string>
|
||||
<string name="open_recent">Obre base de dades recent :</string>
|
||||
<string name="omitbackup_title">No cerquis entrades a còpia de seguretat ni paperera</string>
|
||||
<string name="omitbackup_summary">Omet els grups \'Còpia de seguretat\' i paperera dels resultats de cerca</string>
|
||||
<string name="pass_filename">Nom de base de dades KeePass:</string>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
<string name="decrypting_entry">Dešifruji záznam</string>
|
||||
<string name="default_checkbox">Použít jako výchozí databázi</string>
|
||||
<string name="digits">Čísla</string>
|
||||
<string name="disclaimer_formal">KeePass DX Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft dodáván BEZ JAKÉKOLIV ZÁRUKY; Toto je free software zdarma, a je možná jeho redistribuce pod podmínkou licence GPL verze 2 nebo novější.</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Jeremy Jamet / Kunzisoft, Brian Pellin dodáván BEZ JAKÉKOLIV ZÁRUKY; Toto je free software zdarma, a je možná jeho redistribuce pod podmínkou licence GPL verze 2 nebo novější.</string>
|
||||
<string name="ellipsis">\u2026</string>
|
||||
<string name="enter_filename">Zadejte názvev souboru databáze:</string>
|
||||
<string name="entry_accessed">Poslední přístup: </string>
|
||||
@@ -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>
|
||||
@@ -97,7 +97,7 @@
|
||||
<string name="error_wrong_length">Zadejte celé kladné číslo do délky pole</string>
|
||||
<string name="field_name">Název pole</string>
|
||||
<string name="field_value">Hodnota pole</string>
|
||||
<string name="FileNotFound">Soubor nenalezen.</string>
|
||||
<string name="file_not_found">Soubor nenalezen.</string>
|
||||
<string name="file_browser">Správce souborů</string>
|
||||
<string name="generate_password">Generovat heslo</string>
|
||||
<string name="group">Skupina</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>
|
||||
@@ -150,7 +150,7 @@
|
||||
<string name="no_keys">Žádný záznam v databázi nebo ve skupině.</string>
|
||||
<string name="no_results">žádný výsledek hledání</string>
|
||||
<string name="no_url_handler">Žádný handler pro toto url.</string>
|
||||
<string name="open_recent">Otevřít poslední databázi (kliknout pro otevření):</string>
|
||||
<string name="open_recent">Otevřít poslední databázi :</string>
|
||||
<string name="omitbackup_title">Neprohledávat zálohy a koš</string>
|
||||
<string name="omitbackup_summary">Vynechat skupiny Záloha a Koš ve výsledcích hledání</string>
|
||||
<string name="pass_filename">Název souboru KeePass databáze:</string>
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<string name="decrypting_entry">Dekrypterer post</string>
|
||||
<string name="default_checkbox">Brug denne database som standard</string>
|
||||
<string name="digits">Cifre</string>
|
||||
<string name="disclaimer_formal">KeePass DX Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft comes with ABSOLUTELY NO WARRANTY; This is free software, and you are welcome to redistribute it under the conditions of the GPL version 2 or later.</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Jeremy Jamet / Kunzisoft, Brian Pellin comes with ABSOLUTELY NO WARRANTY; This is free software, and you are welcome to redistribute it under the conditions of the GPL version 2 or later.</string>
|
||||
<string name="ellipsis">\u2026</string>
|
||||
<string name="enter_filename">Angiv navn på databasefil:</string>
|
||||
<string name="entry_accessed">Senest åbnet: </string>
|
||||
@@ -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>
|
||||
@@ -96,7 +96,7 @@
|
||||
<string name="error_wrong_length">Angiv et positivt helt tal i feltet</string>
|
||||
<string name="field_name">Felt-navn</string>
|
||||
<string name="field_value">Felt-værdi</string>
|
||||
<string name="FileNotFound">Filen blev ikke fundet.</string>
|
||||
<string name="file_not_found">Filen blev ikke fundet.</string>
|
||||
<string name="file_browser">Fil-browser</string>
|
||||
<string name="generate_password">Generer adgangskode</string>
|
||||
<string name="group">Gruppe</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>
|
||||
@@ -149,7 +149,7 @@
|
||||
<string name="no_keys">Ingen poster i databasen eller gruppen.</string>
|
||||
<string name="no_results">Ingen søgeresultater</string>
|
||||
<string name="no_url_handler">Kan ikke håndtere denne url.</string>
|
||||
<string name="open_recent">Åbn seneste database (klik for at åbne):</string>
|
||||
<string name="open_recent">Åbn seneste database :</string>
|
||||
<string name="omitbackup_title">Søg ikke efter backup poster og poster i papirkurven</string>
|
||||
<string name="omitbackup_summary">Udelad \'Backup\' og papirkurvs-gruppen i søgeresultater</string>
|
||||
<string name="pass_filename">KeePass database filnavn:</string>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<string name="brackets">Klammern</string>
|
||||
<string name="browser_intall_text">Um diese Funktion nutzen zu können, benötigen Sie den OI File Manager, den Sie über Google Play bzw. direkt von der Entwicklerwebseite herunterladen können. Aufgrund einiger Eigenheiten des Dateimanagers, kann es bei der ersten Benutzung zu Einschränkungen kommen.</string>
|
||||
<string name="building_search_idx">Erstelle den Suchindex\u2026</string>
|
||||
<string name="cancel">Abbr.</string>
|
||||
<string name="cancel">Abbrechen</string>
|
||||
<string name="ClearClipboard">Zwischenablage geleert</string>
|
||||
<string name="clipboard_error_title">Zwischenablagefehler</string>
|
||||
<string name="clipboard_error">Die Implementierung der Zwischenablagefunktion in einigen Samsung Android-Smartphones ist offenbar fehlerhaft, wodurch das Kopieren von Daten aus der Anwendung heraus fehlschlägt. Weitere Informationen dazu finden Sie unter:</string>
|
||||
@@ -59,7 +59,7 @@
|
||||
<string name="decrypting_entry">Eintrag entschlüsselt</string>
|
||||
<string name="default_checkbox">Als Standard-Datenbank benutzen</string>
|
||||
<string name="digits">Zahlen</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 2009–2013 Brian Pellin. Alle Rechte vorbehalten. Die Nutzung der Software erfolgt auf eigene Verantwortung und ohne jegliche Garantie. Die Applikation ist kostenlos und wird unter den Bedingungen der GNU GPL Version 2 (oder später) verbreitet und lizenziert.</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Jeremy Jamet / Kunzisoft, Brian Pellin. Alle Rechte vorbehalten. Die Nutzung der Software erfolgt auf eigene Verantwortung und ohne jegliche Garantie. Die Applikation ist kostenlos und wird unter den Bedingungen der GNU GPL Version 2 (oder später) verbreitet und lizenziert.</string>
|
||||
<string name="ellipsis">\u2026</string>
|
||||
<string name="enter_filename">Dateinamen der Datenbank eingeben:</string>
|
||||
<string name="entry_accessed">Letzter Zugriff:</string>
|
||||
@@ -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>
|
||||
@@ -100,7 +100,7 @@
|
||||
<string name="error_wrong_length">Geben Sie die erforderliche Länge als positive Ganzzahl in das Feld ein.</string>
|
||||
<string name="field_name">Feldname</string>
|
||||
<string name="field_value">Feldwert</string>
|
||||
<string name="FileNotFound">Datei nicht gefunden.</string>
|
||||
<string name="file_not_found">Datei nicht gefunden.</string>
|
||||
<string name="file_not_found_content">Datei nicht gefunden. Versuche es von ihrem Dienstanbieter erneut zu öffnen.</string>
|
||||
<string name="file_browser">Dateimanager</string>
|
||||
<string name="generate_password">Passwort generieren</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>
|
||||
@@ -154,7 +154,7 @@
|
||||
<string name="no_keys">Keine Einträge in dieser Datenbank oder Gruppe.</string>
|
||||
<string name="no_results">Keine Suchergebnisse</string>
|
||||
<string name="no_url_handler">Kein Handler zum Öffnen der URL vorhanden.</string>
|
||||
<string name="open_recent">Zuletzt geöffnete Datenbank (Klicken zum Öffnen):</string>
|
||||
<string name="open_recent">Zuletzt geöffnete Datenbank :</string>
|
||||
<string name="omitbackup_title">Papierkorb/Sicherungen nicht durchsuchen</string>
|
||||
<string name="omitbackup_summary">Papierkorb und Sicherungseinträge werden bei der Suche nicht berücksichtigt (nur bei kdb Dateien).</string>
|
||||
<string name="pass_filename">KeePass Datenbankdatei:</string>
|
||||
@@ -175,6 +175,9 @@
|
||||
<string name="rounds">Schlüsseltransformationen</string>
|
||||
<string name="rounds_explaination">Je höher die Anzahl der Schlüsseltransformationen, desto besser ist der Schutz gegen Wörterbuch- oder Brute-Force-Angriffe. Allerdings dauert dann auch das Laden und Speichern der Datenbank entsprechend länger.</string>
|
||||
<string name="rounds_hint">Schlüsseltransformationen</string>
|
||||
<string name="rounds_fix_title">Datenbank reparieren</string>
|
||||
<string name="rounds_fix">Schlüsseltransformationen vor Datenbankkorruption</string>
|
||||
<string name="rounds_fix_explanation">Falls ihre Datenbank von KeepassDroid version 2.2.0.0 bis 2.2.0.6 beschädigt wurde, können Sie die Anzahl der Schlüsseltransformationen welche verwendet wurden eingeben um ihre Datenbank wieder zu öffnen.</string>
|
||||
<string name="saving_database">Speichere Datenbank\u2026</string>
|
||||
<string name="space">Leerzeichen</string>
|
||||
<string name="search_label">Suchen</string>
|
||||
@@ -207,4 +210,41 @@
|
||||
<item>Mittel</item>
|
||||
<item>Groß</item>
|
||||
</string-array>
|
||||
|
||||
<string name="warning_empty_password">Sind Sie sicher, dass sie ein leeres Passwort verwenden wollen ?</string>
|
||||
<string name="warning_no_encryption_key">Sind Sie sicher, dass sie keinen Verschlüsselungsschlüssel verwenden wollen ?</string>
|
||||
<string name="appearance">Aussehen</string>
|
||||
<string name="password_size_title">Passwortgröße</string>
|
||||
<string name="password_size_summary">Standartlänge des generierten Passworts ändern</string>
|
||||
<string name="clipboard_notifications_title">Zwischenablagenbenachrichtigungen</string>
|
||||
<string name="clipboard_notifications_summary">Zwischenablagenbenachrichtigungen zum kopieren von Benutzername und Passwort einschalten</string>
|
||||
<string name="lock_database_screen_off_title">Bildschirmsperre</string>
|
||||
<string name="lock_database_screen_off_summary">Datenbank sperren, wenn der Bildschirm ausgeschaltet wird</string>
|
||||
<string name="create_keepass_file">Keepass Datei erstellen</string>
|
||||
<string name="style_choose_title">Thema auswählen</string>
|
||||
<string name="assign_master_key">Hauptschlüssel zuweisen</string>
|
||||
<string name="path">Pfad</string>
|
||||
<string name="file_name">Dateiname</string>
|
||||
<string name="unavailable_feature_text">Dieses Feature wird nicht von ihrer Android version unterstützt</string>
|
||||
<string name="fingerprint_enable_summary">Datenbanköffnung mit Fingerabdruck einschalten</string>
|
||||
<string name="fingerprint">Fingerabdruck</string>
|
||||
<string name="fingerprint_enable_title">Fingerabruckscanner</string>
|
||||
<string name="fingerprint_scan_to_open">Fingerabruck scannen während Passwortfeld leer ist, um Datenbank zu öffnen</string>
|
||||
<string name="fingerprint_scan_to_store">Fingerabruck scannen, um Masterpasswort zu speichern</string>
|
||||
<string name="fingerprint_type_password_text">Geben Sie ihr Passwort in Keepass DX ein</string>
|
||||
<string name="lock">Sperre</string>
|
||||
<string name="list_password_generator_options_summary">Standartzeichen für Passwortgenerator setzen</string>
|
||||
<string name="list_password_generator_options_title">Passwortzeichen</string>
|
||||
<string name="configure_fingerprint">Fingerabruck unterstützt, jedoch nicht für dieses Gerät konfiguriert</string>
|
||||
<string name="scanning_fingerprint">Fingerabdruck wird gescannt</string>
|
||||
<string name="encrypted_value_stored">Verschlüsseltes Passwort wurde gespeichert</string>
|
||||
<string name="history">Verlauf</string>
|
||||
<string name="fingerprint_quick_unlock_title">Wie richte ich den Fingerabdruckscanner ein ?</string>
|
||||
<string name="fingerprint_setting_text">Speichern sie ihren persönlichen Fingerabruck in</string>
|
||||
<string name="fingerprint_setting_way_text">Einstellungen -> Fingerabdruck</string>
|
||||
<string name="usage">Verwendung</string>
|
||||
<string name="general">Allgemein</string>
|
||||
<string name="store_with_fingerprint">Fingerabruck verwenden um dieses Passwort zu speichern</string>
|
||||
<string name="no_password_stored">Noch kein Passwort für diese Datenbank gespeichert</string>
|
||||
<string name="style_choose_summary">Thema durch verändern der Farben ändern</string>
|
||||
</resources>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<string name="decrypting_entry">Αποκρυπτογράφηση εγγραφής</string>
|
||||
<string name="default_checkbox">Χρήση αυτής της βάσης ως προεπιλεγμένη</string>
|
||||
<string name="digits">Ψηφία</string>
|
||||
<string name="disclaimer_formal">KeePass DX Πνευματική Ιδιοκτησία 2009–2012 Brian Pellin χωρίς ΚΑΜΙΑ ΑΠΟΛΥΤΩΣ ΕΓΓΥΗΣΗ. Το παρόν είναι δωρεάν λογισμικό και είστε ευπρόσδεκτοι να το διαμοιράσετε υπό τις συνθήκες της ΙΕΛ έκδοσης 2 ή μεταγενέστερης.</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Jeremy Jamet / Kunzisoft, Brian Pellin χωρίς ΚΑΜΙΑ ΑΠΟΛΥΤΩΣ ΕΓΓΥΗΣΗ. Το παρόν είναι δωρεάν λογισμικό και είστε ευπρόσδεκτοι να το διαμοιράσετε υπό τις συνθήκες της ΙΕΛ έκδοσης 2 ή μεταγενέστερης.</string>
|
||||
<string name="ellipsis">\u2026</string>
|
||||
<string name="enter_filename">Εισαγωγή ονόματος βάσης δεδομένων:</string>
|
||||
<string name="entry_accessed">Προσπελάσθηκε: </string>
|
||||
@@ -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>
|
||||
@@ -94,7 +94,7 @@
|
||||
<string name="error_wrong_length">Εισάγετε έναν θετικό ακέραιο αριθμό στο πεδίο μήκους</string>
|
||||
<string name="field_name">Όνομα Πεδίου</string>
|
||||
<string name="field_value">Τιμή πεδίου</string>
|
||||
<string name="FileNotFound">Το αρχείο δεν βρέθηκε.</string>
|
||||
<string name="file_not_found">Το αρχείο δεν βρέθηκε.</string>
|
||||
<string name="file_browser">Διαχείριση Αρχείων</string>
|
||||
<string name="generate_password">Δημιουργία Κωδικού</string>
|
||||
<string name="group">Ομάδα</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>
|
||||
@@ -147,7 +147,7 @@
|
||||
<string name="no_keys">Δεν υπάρχουν εγγραφές στη βάση ή στην ομάδα.</string>
|
||||
<string name="no_results">Δε βρέθηκαν αποτελέσματα αναζήτησης</string>
|
||||
<string name="no_url_handler">Χωρίς χειριστή για τη διεύθυνση url.</string>
|
||||
<string name="open_recent">Άνοιγμα πρόσφατης βάσης (πατήστε για άνοιγμα):</string>
|
||||
<string name="open_recent">Άνοιγμα πρόσφατης βάσης :</string>
|
||||
<string name="omitbackup_title">Να μην γίνει αναζήτηση σε αντίγραφο ασφαλείας εγγραφών</string>
|
||||
<string name="omitbackup_summary">Παράληψη ομάδας \'Αντίγραφο Ασφαλείας\' από τα αποτελέσματα αναζήτησης (εφαρμόζεται μόνο σε αρχεία .kdb)</string>
|
||||
<string name="pass_filename">Όνομα βάσης δεδομένων KeePass:</string>
|
||||
|
||||
@@ -50,7 +50,7 @@ Spanish translation by José I. Paños. Updated by David García-Abad (23-09-201
|
||||
<string name="decrypting_entry">Descrifrando la entrada</string>
|
||||
<string name="default_checkbox">Utilice esto como base de datos por defecto</string>
|
||||
<string name="digits">Dígitos</string>
|
||||
<string name="disclaimer_formal">KeePass DX Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft NO TIENE TOTAL GARANTÍA; Este es software libre, y puedes redristribuirlo bajo las condiciones de la licencia GPL version 2 o posterior.</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Jeremy Jamet / Kunzisoft, Brian Pellin NO TIENE TOTAL GARANTÍA; Este es software libre, y puedes redristribuirlo bajo las condiciones de la licencia GPL version 2 o posterior.</string>
|
||||
<string name="ellipsis">\u2026</string>
|
||||
<string name="enter_filename">Introduzca el nombre del archivo de base de datos:</string>
|
||||
<string name="entry_accessed">Acceso: </string>
|
||||
@@ -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>
|
||||
@@ -87,7 +87,7 @@ Spanish translation by José I. Paños. Updated by David García-Abad (23-09-201
|
||||
<string name="error_rounds_too_large">Pasadas demasiado grande. Establecido a 2147483648.</string>
|
||||
<string name="error_title_required">Se necesita un título.</string>
|
||||
<string name="error_wrong_length">Introduzca un entero positivo en el campo longitud</string>
|
||||
<string name="FileNotFound">Archivo no encontrado.</string>
|
||||
<string name="file_not_found">Archivo no encontrado.</string>
|
||||
<string name="file_browser">Explorador de Archivos</string>
|
||||
<string name="generate_password">Generar Contraseña</string>
|
||||
<string name="group">Grupo</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>
|
||||
@@ -139,7 +139,7 @@ Spanish translation by José I. Paños. Updated by David García-Abad (23-09-201
|
||||
<string name="no_url_handler">Sin manejador para esta url.</string>
|
||||
<string name="recentfile_title">Historial de archivos recientes</string>
|
||||
<string name="recentfile_summary">Recordar nombres de archivos usados recientemente</string>
|
||||
<string name="open_recent">Abrir base de datos reciente (clic para abrir):</string>
|
||||
<string name="open_recent">Abrir base de datos reciente :</string>
|
||||
<string name="omitbackup_title">No buscar en las entradas de copia de seguridad o papelera de reciclaje</string>
|
||||
<string name="omitbackup_summary">Omitir \'Backup\' y grupo de Papelera de Reciclaje en los resultados de búsqueda</string>
|
||||
<string name="pass_filename">Nombre de archivo de base de datos de KeePass:</string>
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<string name="decrypting_entry">Sarrera desenkriptatzen</string>
|
||||
<string name="default_checkbox">Hau erabili modu lehenetsitako datubase gisa</string>
|
||||
<string name="digits">Zenbakiak</string>
|
||||
<string name="disclaimer_formal">KeePass DX Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft ez dakar inolako bermerik; Lan hau software librea da; banatu edo/eta aldatu egin dezakezu GNU General Public License bigarren bertsioaren baldintzapean.</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Jeremy Jamet / Kunzisoft, Brian Pellin ez dakar inolako bermerik; Lan hau software librea da; banatu edo/eta aldatu egin dezakezu GNU General Public License bigarren bertsioaren baldintzapean.</string>
|
||||
<string name="ellipsis">\u2026</string>
|
||||
<string name="enter_filename">Datubasearen fitxategiaren izena sartu:</string>
|
||||
<string name="entry_accessed">Akzesoa: </string>
|
||||
@@ -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>
|
||||
@@ -96,7 +96,7 @@
|
||||
<string name="error_wrong_length">Eremuaren luzeran entero positibo bat sartu</string>
|
||||
<string name="field_name">Eremuaren izena</string>
|
||||
<string name="field_value">Eremuaren balorea</string>
|
||||
<string name="FileNotFound">Fitxategi ez aurkitua.</string>
|
||||
<string name="file_not_found">Fitxategi ez aurkitua.</string>
|
||||
<string name="file_browser">Fitxategien nabigatzailea</string>
|
||||
<string name="generate_password">Pasahitza sortu</string>
|
||||
<string name="group">Taldea</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>
|
||||
@@ -149,7 +149,7 @@
|
||||
<string name="no_keys">Sarrerarik ez datubasean edo taldean.</string>
|
||||
<string name="no_results">Emaitzarik gabeko bilaketa</string>
|
||||
<string name="no_url_handler">URL kudatzeko euskarririk ez.</string>
|
||||
<string name="open_recent">Duela gutxiko datubasea ireki (klik irekitzeko):</string>
|
||||
<string name="open_recent">Duela gutxiko datubasea ireki :</string>
|
||||
<string name="omitbackup_title">Ez bilatu segurtasun kopiaren sarreretan</string>
|
||||
<string name="omitbackup_summary">Kendu segurtasun kopien taldea bilaketen emaitzetatik (.kdb fitxategie dagokie bakarrik)</string>
|
||||
<string name="pass_filename">Keepass datubasearen izena:</string>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<string name="decrypting_entry">Puretaan salasanatietuetta</string>
|
||||
<string name="default_checkbox">Käytä tätä oletustietokantana</string>
|
||||
<string name="digits">Numerot</string>
|
||||
<string name="disclaimer_formal">KeePass DX Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft comes with ABSOLUTELY NO WARRANTY; This is free software, and you are welcome to redistribute it under the conditions of the GPL version 2 or later.</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Jeremy Jamet / Kunzisoft, Brian Pellin comes with ABSOLUTELY NO WARRANTY; This is free software, and you are welcome to redistribute it under the conditions of the GPL version 2 or later.</string>
|
||||
<string name="ellipsis">\u2026</string>
|
||||
<string name="enter_filename">Anna tietokannan tiedostonimi:</string>
|
||||
<string name="entry_accessed">Käytetty: </string>
|
||||
@@ -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>
|
||||
@@ -94,7 +94,7 @@
|
||||
<string name="error_wrong_length">Syötä positiivinen kokonaisluku pituus-kenttään</string>
|
||||
<string name="field_name">Kentän nimi</string>
|
||||
<string name="field_value">Kentän arvo</string>
|
||||
<string name="FileNotFound">Tiedostoa ei löydetty.</string>
|
||||
<string name="file_not_found">Tiedostoa ei löydetty.</string>
|
||||
<string name="file_browser">Tiedostoselain</string>
|
||||
<string name="generate_password">Generoi salasana</string>
|
||||
<string name="group">Ryhmä</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>
|
||||
@@ -147,7 +147,7 @@
|
||||
<string name="no_keys">Ei tietueita tietokannassa tai ryhmässä.</string>
|
||||
<string name="no_results">Ei hakutuloksia</string>
|
||||
<string name="no_url_handler">Tälle URL:lle ei ole käsittelijää.</string>
|
||||
<string name="open_recent">Avaa viimeisin salasanatietokanta (avaa klikkaamalla):</string>
|
||||
<string name="open_recent">Avaa viimeisin salasanatietokanta :</string>
|
||||
<string name="omitbackup_title">Älä etsi varmuuskopioista eikä roskakorista</string>
|
||||
<string name="omitbackup_summary">Poista \'Varmuuskopiot\' ja roskakori hakutuloksista</string>
|
||||
<string name="pass_filename">KeePass salasanatietokannan tiedostonimi:</string>
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
<resources
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:ignore="MissingTranslation">
|
||||
<string name="about_feedback">Signaler une anomalie\u00A0:</string>
|
||||
<string name="about_homepage">Site web\u00A0:</string>
|
||||
<string name="about_feedback">Signaler une anomalie :</string>
|
||||
<string name="about_homepage">Site web :</string>
|
||||
<string name="AboutText">KeePass DX est une implémentation sur Android du gestionnaire de mots de passe KeePass.</string>
|
||||
<string name="accept">Accepter</string>
|
||||
<string name="add_entry">Ajouter une entrée</string>
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="add_group_title">Ajouter un groupe</string>
|
||||
<string name="add_string">Ajouter une chaîne</string>
|
||||
<string name="algorithm">Algorithme</string>
|
||||
<string name="algorithm_colon">Algorithme\u00A0:</string>
|
||||
<string name="algorithm_colon">Algorithme :</string>
|
||||
<string name="app_timeout">Application timeout</string>
|
||||
<string name="app_timeout_summary">Temps avant le verrouillage de la base de données lorsque l\'application est inactive.</string>
|
||||
<string name="application">Application</string>
|
||||
@@ -42,31 +42,31 @@
|
||||
<string name="cancel">Annuler</string>
|
||||
<string name="ClearClipboard">Presse-papier vidé</string>
|
||||
<string name="clipboard_error_title">Erreur de presse-papier</string>
|
||||
<string name="clipboard_error">Certains appareils Android Samsung ont un bug dans l\'implémentation du presse-papier qui empêche la copie depuis des applications. Pour plus de détails, visitez\u00A0:</string>
|
||||
<string name="clipboard_error">Certains appareils Android Samsung ont un bug dans l\'implémentation du presse-papier qui empêche la copie depuis des applications. Pour plus de détails, visitez :</string>
|
||||
<string name="clipboard_error_clear">Le vidage du presse-papier a échoué</string>
|
||||
<string name="clipboard_timeout">Clipboard timeout</string>
|
||||
<string name="clipboard_timeout_summary">Temps avant le vidage du presse-papier après copie du nom d\'utilisateur ou du mot de passe</string>
|
||||
<string name="copy_username">Copier le nom d\'utilisateur dans le presse-papier</string>
|
||||
<string name="copy_password">Copier le mot de passe dans le presse-papier</string>
|
||||
<string name="creating_db_key">Création de la clé de base de données…</string>
|
||||
<string name="current_group">Groupe actuel\u00A0:</string>
|
||||
<string name="current_group_root">Groupe actuel\u00A0: Racine</string>
|
||||
<string name="current_group">Groupe actuel :</string>
|
||||
<string name="current_group_root">Groupe actuel : Racine</string>
|
||||
<string name="database">Base de données</string>
|
||||
<string name="decrypting_db">Déchiffrement du contenu de la base de données…</string>
|
||||
<string name="decrypting_entry">Déchiffrement de l\'entrée</string>
|
||||
<string name="default_checkbox">Utiliser comme base de données par défaut</string>
|
||||
<string name="digits">Nombres</string>
|
||||
<string name="disclaimer_formal">KeePass DX Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft n\'offre ABSOLUMENT AUCUNE GARANTIE; il s\'agit d\'un logiciel libre, vous pouvez le redistribuer sous les conditions de la licence GPL v2 ou ultérieure.</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Jeremy Jamet / Kunzisoft, Brian Pellin n\'offre ABSOLUMENT AUCUNE GARANTIE; il s\'agit d\'un logiciel libre, vous pouvez le redistribuer sous les conditions de la licence GPL v2 ou ultérieure.</string>
|
||||
<string name="ellipsis">\u2026</string>
|
||||
<string name="enter_filename">Sélectionnez la base de données\u00A0:</string>
|
||||
<string name="enter_filename">Sélectionnez la base de données :</string>
|
||||
<string name="entry_accessed">Dernier accès</string>
|
||||
<string name="entry_and_or">Entrez un mot de passe et/ou un fichier de clé pour ouvrir la base de données\u00A0:</string>
|
||||
<string name="entry_and_or">Entrez un mot de passe et/ou un fichier de clé pour ouvrir la base de données :</string>
|
||||
<string name="entry_cancel">Annuler</string>
|
||||
<string name="entry_comment">Commentaires</string>
|
||||
<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>
|
||||
@@ -82,22 +82,22 @@
|
||||
<string name="error_database_settings">Impossible de déterminer les paramètres de la base de données.</string>
|
||||
<string name="error_failed_to_launch_link">Échec lors de l\'ouverture du lien.</string>
|
||||
<string name="error_filename_required">Le nom de fichier est obligatoire.</string>
|
||||
<string name="error_file_not_create">Impossible de créer le fichier\u00A0:</string>
|
||||
<string name="error_file_not_create">Impossible de créer le fichier :</string>
|
||||
<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>
|
||||
<string name="field_name">Nom du champ</string>
|
||||
<string name="field_value">Valeur</string>
|
||||
<string name="FileNotFound">Fichier non trouvé.</string>
|
||||
<string name="file_not_found">Fichier non trouvé.</string>
|
||||
<string name="file_not_found_content">Fichier non trouvé. Essayer de l\'ouvrir à nouveau à partir de votre fournisseur de contenu.</string>
|
||||
<string name="file_browser">Navigateur de fichiers</string>
|
||||
<string name="generate_password">Générer mot de passe</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>
|
||||
@@ -121,8 +121,8 @@
|
||||
<string name="keyfile_does_not_exist">Le fichier de clé n\'existe pas.</string>
|
||||
<string name="keyfile_is_empty">Le fichier de clé est vide.</string>
|
||||
<string name="length">Longueur</string>
|
||||
<string name="list_size_title">Taille de la liste des groupes</string>
|
||||
<string name="list_size_summary">Taille de la police de caractères utilisée pour la liste des groupes</string>
|
||||
<string name="list_size_title">Taille des éléments de liste</string>
|
||||
<string name="list_size_summary">Taille de la police de caractères utilisée pour les éléments de liste</string>
|
||||
<string name="loading_database">Ouverture de la base de données…</string>
|
||||
<string name="lowercase">Minuscule</string>
|
||||
<string name="MaskedPassword">*****</string>
|
||||
@@ -151,7 +151,7 @@
|
||||
<string name="no_keys">Aucun élément.</string>
|
||||
<string name="no_results">Aucun résultat pour cette recherche.</string>
|
||||
<string name="no_url_handler">Impossible d\'ouvrir cette URL.</string>
|
||||
<string name="open_recent">Bases de données utilisées récemment\u00A0:</string>
|
||||
<string name="open_recent">Bases de données utilisées récemment :</string>
|
||||
<string name="omitbackup_title">Ignorer les sauvegardes</string>
|
||||
<string name="omitbackup_summary">Ignorer le groupe Sauvegardes des résultats de recherche (uniquement pour .kdb)</string>
|
||||
<string name="pass_filename">Fichier de base de données KeePass</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,14 +194,51 @@
|
||||
<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="version_label">Version\u00A0:</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 :</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>
|
||||
<string name="encrypted_value_stored">Mot de passe encrypté stocké</string>
|
||||
<string name="fingerprint_invalid_key">Problème de clé invalide</string>
|
||||
<string name="fingerprint_not_recognized">Empreinte digitale non reconnue</string>
|
||||
<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="fingerprint_delete_all_title">Supprimer les clés de chiffrement</string>
|
||||
<string name="fingerprint_delete_all_summary">Supprimer toutes les clés de chiffrement liées à la reconnaissance des empreintes digitales</string>
|
||||
<string name="fingerprint_delete_all_warning">Êtes-vous sûr de vouloir supprimer toutes les clés liées aux empreintes digitales?</string>
|
||||
<string name="unavailable_feature_text">Impossible de démarrer cette fonctionnalité.</string>
|
||||
<string name="unavailable_feature_version">Votre version Android %1$d n\'est pas la version minimale %2$d requise.</string>
|
||||
<string name="unavailable_feature_hardware">Le matériel n\'est pas détecté.</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 name="bytes">Octets</string>
|
||||
<string name="full_file_path_enable_title">Chemin de fichier</string>
|
||||
<string name="full_file_path_enable_summary">Afficher le chemin complet des fichiers</string>
|
||||
|
||||
<string-array name="clipboard_timeout_options">
|
||||
<item>30 secondes</item>
|
||||
@@ -218,7 +258,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>
|
||||
|
||||
@@ -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 \u00A9 %1$d Jeremy Jamet / Kunzisoft, Brian Pellin. 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="file_not_found">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>
|
||||
@@ -128,14 +144,19 @@
|
||||
<string name="no_keys">Nincs bejegyzés az adatbázisban vagy csoportban.</string>
|
||||
<string name="no_results">Nincs találat</string>
|
||||
<string name="no_url_handler">Nem található kezelő ehhez az url-hez.</string>
|
||||
<string name="open_recent">Korábbi adatbázis megnyitása (kattintson rá a megnyitáshoz):</string>
|
||||
<string name="open_recent">Korábbi adatbázis megnyitása :</string>
|
||||
<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>
|
||||
@@ -51,7 +51,7 @@
|
||||
<string name="decrypting_entry">Decodifica valore</string>
|
||||
<string name="default_checkbox">Usa come database predefinito</string>
|
||||
<string name="digits">Cifre</string>
|
||||
<string name="disclaimer_formal">KeePass DX Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft viene distribuito ASSOLUTAMENTE con NESSUNA GARANZIA; Si tratta di software libero, e sei invitato a distribuirlo sotto le condizioni della licenza GPL versione 2 o superiore.</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Jeremy Jamet / Kunzisoft, Brian Pellin viene distribuito ASSOLUTAMENTE con NESSUNA GARANZIA; Si tratta di software libero, e sei invitato a distribuirlo sotto le condizioni della licenza GPL versione 2 o superiore.</string>
|
||||
<string name="ellipsis">\u2026</string>
|
||||
<string name="enter_filename">Inserisci il nome file del database:</string>
|
||||
<string name="entry_accessed">Ultimo accesso: </string>
|
||||
@@ -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>
|
||||
@@ -88,7 +88,7 @@
|
||||
<string name="error_rounds_too_large">Livello troppo grande. Impostato a 2147483648.</string>
|
||||
<string name="error_title_required">E\' necessario un titolo.</string>
|
||||
<string name="error_wrong_length">Inserisci un valore positivo nella lunghezza campo</string>
|
||||
<string name="FileNotFound">File non trovato.</string>
|
||||
<string name="file_not_found">File non trovato.</string>
|
||||
<string name="file_browser">Sfoglia file</string>
|
||||
<string name="generate_password">Genera password</string>
|
||||
<string name="group">Gruppo</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>
|
||||
@@ -138,7 +138,7 @@
|
||||
<string name="no_keys">Nessuna voce nel database o nel gruppo.</string>
|
||||
<string name="no_results">Nessun risultato di ricerca</string>
|
||||
<string name="no_url_handler">Nessun gestore per questo URL.</string>
|
||||
<string name="open_recent">Apri un database recente (clicca per aprire):</string>
|
||||
<string name="open_recent">Apri un database recente :</string>
|
||||
<string name="omitbackup_title">Non cercare voci di backup e nel Cestino</string>
|
||||
<string name="omitbackup_summary">Ometti i gruppi \'Backup\' e Cestino dai risultati di ricerca</string>
|
||||
<string name="pass_filename">Nome file del database di KeePass:</string>
|
||||
|
||||
@@ -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>
|
||||
@@ -92,7 +92,7 @@
|
||||
<string name="error_wrong_length">הזן מספר חיובי בשדה האורך</string>
|
||||
<string name="field_name">שם השדה</string>
|
||||
<string name="field_value">ערך השדה</string>
|
||||
<string name="FileNotFound">קובץ לא נמצא.</string>
|
||||
<string name="file_not_found">קובץ לא נמצא.</string>
|
||||
<string name="file_browser">סייר קבצים</string>
|
||||
<string name="generate_password">צור סיסמה</string>
|
||||
<string name="group">קבוצה</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>
|
||||
@@ -143,7 +143,7 @@
|
||||
<string name="no_keys">אין ערכים במסד נתונים או בקבוצה.</string>
|
||||
<string name="no_results">אין תוצאות חיפוש</string>
|
||||
<string name="no_url_handler">אין מטפל לכתובת url זו.</string>
|
||||
<string name="open_recent">פתח מסד נתונים אחרון (לחץ לפתיחה):</string>
|
||||
<string name="open_recent">פתח מסד נתונים אחרון :</string>
|
||||
<string name="omitbackup_title">אל תחפש ערכי גיבוי</string>
|
||||
<string name="omitbackup_summary">הורד את קבוצת \"גיבוי\" מתוצאות חיפוש (תואם רק לקבצי kdb)</string>
|
||||
<string name="pass_filename">שם קובץ למסד נתוני KeePass:</string>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<string name="decrypting_entry">暗号解除エントリー</string>
|
||||
<string name="default_checkbox">このデータベースを次回以降も利用する</string>
|
||||
<string name="digits">数字</string>
|
||||
<string name="disclaimer_formal">KeePass DX Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft によって作られたフリーソフトウェアであり、無保証です。GPLバージョン2以上の条件下でこれを再頒布することができます。</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Jeremy Jamet / Kunzisoft, Brian Pellin によって作られたフリーソフトウェアであり、無保証です。GPLバージョン2以上の条件下でこれを再頒布することができます。</string>
|
||||
<string name="ellipsis">\u2026</string>
|
||||
<string name="enter_filename">データベースファイル:</string>
|
||||
<string name="entry_accessed">最終アクセス日: </string>
|
||||
@@ -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>
|
||||
@@ -85,7 +85,7 @@
|
||||
<string name="error_rounds_too_large">値が大きすぎます。 2147483648にセットしました。</string>
|
||||
<string name="error_title_required">タイトルは必須入力です。</string>
|
||||
<string name="error_wrong_length">\"長さ\"欄には正の整数を入力してください。</string>
|
||||
<string name="FileNotFound">ファイルが見つかりません。</string>
|
||||
<string name="file_not_found">ファイルが見つかりません。</string>
|
||||
<string name="file_browser">ファイルブラウザ</string>
|
||||
<string name="generate_password">パスワードを生成する</string>
|
||||
<string name="group">グループ</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>
|
||||
@@ -135,7 +135,7 @@
|
||||
<string name="no_keys">データベース・グループがありません。</string>
|
||||
<string name="no_results">検索結果に該当するものはありません。</string>
|
||||
<string name="no_url_handler">このuriを処理できません。</string>
|
||||
<string name="open_recent">以前使用したデータベースを開く(クリック):</string>
|
||||
<string name="open_recent">以前使用したデータベースを開く:</string>
|
||||
<string name="omitbackup_title">検索対象から除外</string>
|
||||
<string name="omitbackup_summary">\"バックアップ\"と\"ごみ箱\"を検索対象から除外します</string>
|
||||
<string name="pass_filename">KeePassデータベースファイル:</string>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<resources>
|
||||
<string name="AboutText">KeePass DX yra KeePass slaptažodžių tvarkyklės realizacija Android platformai</string>
|
||||
<string name="ClearClipboard">Iškarpinė išvalyta.</string>
|
||||
<string name="FileNotFound">Failas nerastas.</string>
|
||||
<string name="file_not_found">Failas nerastas.</string>
|
||||
<string name="InvalidPassword">Neteisingas slaptažodis arba rakto failas.</string>
|
||||
<string name="MaskedPassword">*****</string>
|
||||
<string name="about_feedback">Atsiliepimai:</string>
|
||||
@@ -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>
|
||||
@@ -113,7 +113,7 @@
|
||||
<string name="lowercase">Mažosios raidės</string>
|
||||
<string name="minus">Minusas</string>
|
||||
<string name="underline">Pabraukimas</string>
|
||||
<string name="open_recent">Atidaryti naujausią duomenų bazę (spausti)</string>
|
||||
<string name="open_recent">Atidaryti naujausią duomenų bazę </string>
|
||||
<string name="default_checkbox">Naudoti šią duomenų bazę kaip numatytąją</string>
|
||||
<string name="maskpass_summary">Slėpti slaptažodžius pagal nutylėjimą</string>
|
||||
<string name="menu_homepage">Eiti į pagrindinį puslapį</string>
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
<string name="decrypting_entry">Ieraksta atšifrēšana</string>
|
||||
<string name="default_checkbox">Izmantot šo kā manu noklusējuma datu bāzi</string>
|
||||
<string name="digits">Cipari</string>
|
||||
<string name="disclaimer_formal">Paroles Aurortiesības 2009–2012 Brian Pellin.</string>
|
||||
<string name="ellipsis">…</string>
|
||||
<string name="enter_filename">Ievadiet datu bāzes nosaukumu:</string>
|
||||
<string name="entry_accessed">Piekļuve:</string>
|
||||
@@ -45,7 +44,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 +63,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>
|
||||
@@ -75,7 +74,7 @@
|
||||
<string name="error_wrong_length">Norādiet garumu lielāku par nulli</string>
|
||||
<string name="field_name">Lauka nosaukums</string>
|
||||
<string name="field_value">Lauka vērtība</string>
|
||||
<string name="FileNotFound">Fails nav atrasts.</string>
|
||||
<string name="file_not_found">Fails nav atrasts.</string>
|
||||
<string name="file_browser">Failu pārlūks</string>
|
||||
<string name="generate_password">Ģenerēt Paroli</string>
|
||||
<string name="group">Grupa</string>
|
||||
@@ -86,7 +85,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>
|
||||
@@ -128,7 +127,7 @@
|
||||
<string name="no_keys">Nav ierakstu datu bāzē vai grupā.</string>
|
||||
<string name="no_results">Nav meklēšanas rezultātu</string>
|
||||
<string name="no_url_handler">Neizdevās atvērt saiti.</string>
|
||||
<string name="open_recent">Atvērt pēdējo datu bāzi (noklikšķiniet, lai atvērtu):</string>
|
||||
<string name="open_recent">Atvērt pēdējo datu bāzi :</string>
|
||||
<string name="omitbackup_title">Nemeklēt kopijās un atkritnē</string>
|
||||
<string name="omitbackup_summary">Izlaist kopijas un atkritni no meklēšanas rezultātiem</string>
|
||||
<string name="pass_filename">KeePass datu bāzes faila nosaukums:</string>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user