mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Merge branch 'develop' 2.5.0.0beta3 into feature/Autofill
This commit is contained in:
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
|
||||
|
||||
41
CHANGELOG
41
CHANGELOG
@@ -1,3 +1,17 @@
|
||||
KeepassDX (2.5.0.0beta3)
|
||||
* New database workflow with new screens and folder selection
|
||||
* Settings for default password generation
|
||||
* Fingerprint dialog for explanations
|
||||
* Setting to disable fingerprint
|
||||
* Directly opening kdbx file
|
||||
* Setting to disable notifications
|
||||
* Setting to lock database when screen is shut off
|
||||
* Merge KeePassDroid 2.2.0.9
|
||||
* Add corruption fix mode
|
||||
|
||||
KeepassDX (2.5.0.0beta2)
|
||||
* Remove libs for F-Droid
|
||||
|
||||
KeepassDX (2.5.0.0beta1)
|
||||
* Fork KeepassDroid
|
||||
* Add Material Design
|
||||
@@ -7,6 +21,33 @@ KeepassDX (2.5.0.0beta1)
|
||||
* Update French translation
|
||||
* Change donation (see KeepassDroid to contribute on both projects)
|
||||
|
||||
KeePassDroid (2.2.0.9)
|
||||
* Update build tools version to workaround CM/Lineage bug (closes: #249)
|
||||
* Update Russian translations
|
||||
* Update Polish translations
|
||||
|
||||
KeePassDroid (2.2.0.8)
|
||||
* Add corruption fix mode
|
||||
* Update Hungarian translations
|
||||
|
||||
KeePassDroid (2.2.0.7)
|
||||
* Fix KDBX3 encryption rounds corruption
|
||||
* Fix KDBX4 attachement crashes
|
||||
|
||||
KeePassDroid (2.2.0.6)
|
||||
* Add additional ndk ABIs
|
||||
|
||||
KeePassDroid (2.2.0.5)
|
||||
* Don't show fingerprint prompt on devices without fingerprint hardware
|
||||
* Fix dateformat crashes
|
||||
|
||||
KeePassDroid (2.2.0.4)
|
||||
* Fingerprint fixes
|
||||
|
||||
KeePassDroid (2.2.0.3)
|
||||
* Search crash fix
|
||||
* Improve fingerprint handling
|
||||
|
||||
KeePassDroid (2.2.0.2)
|
||||
* Fix non fingerprint password layout
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ Tadashi Saito
|
||||
vhschlenker
|
||||
bumper314 - Samsung multiwindow support
|
||||
Hans Cappelle - fingerprint sensor integration
|
||||
Jeremy Jamet - Material Design - Patches
|
||||
Jeremy Jamet - Keepass DX Material Design - Patches
|
||||
|
||||
Translations:
|
||||
Diego Pierotto - Italian
|
||||
@@ -30,7 +30,7 @@ Matsuu Takuto - Japanese
|
||||
Carlos Schlyter - Portugese (Brazil)
|
||||
YSmhXQDd6Z - Portugese (Portugal)
|
||||
andriykopanytsia - Ukranian
|
||||
intel - Hungarian
|
||||
intel, Zoltán Antal - Hungarian
|
||||
H Vanek - Czech
|
||||
jipanos - Spanish
|
||||
Erik Fdevriendt, Erik Jan Meijer - Dutch
|
||||
|
||||
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 = 26
|
||||
buildToolsVersion = "26.0.2"
|
||||
buildToolsVersion = "27.0.1"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.kunzisoft.keepass"
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 26
|
||||
versionCode = 1
|
||||
versionName = "2.5.0.0beta1"
|
||||
versionCode = 3
|
||||
versionName = "2.5.0.0beta3"
|
||||
|
||||
testApplicationId = "com.keepassdroid.tests"
|
||||
testInstrumentationRunner = "android.test.InstrumentationTestRunner"
|
||||
|
||||
ndk {
|
||||
abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a',
|
||||
'arm64-v8a', 'mips', 'mips64'
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
@@ -21,6 +26,7 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled = false
|
||||
@@ -67,9 +73,12 @@ dependencies {
|
||||
implementation "com.android.support:design:$supportVersion"
|
||||
implementation "com.android.support:preference-v7:$supportVersion"
|
||||
implementation "com.android.support:preference-v14:$supportVersion"
|
||||
implementation "com.android.support:cardview-v7:$supportVersion"
|
||||
implementation "com.madgag.spongycastle:core:$spongycastleVersion"
|
||||
implementation "com.madgag.spongycastle:prov:$spongycastleVersion"
|
||||
implementation "joda-time:joda-time:2.9.9"
|
||||
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.1'
|
||||
implementation group: 'com.google.guava', name: 'guava', version: '22.0-android'
|
||||
implementation "org.sufficientlysecure:html-textview:3.5"
|
||||
implementation "com.nononsenseapps:filepicker:4.1.0"
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.kunzisoft.keepass"
|
||||
android:installLocation="auto">
|
||||
<supports-screens
|
||||
@@ -19,10 +20,31 @@
|
||||
android:allowBackup="true"
|
||||
android:fullBackupContent="@xml/backup"
|
||||
android:backupAgent="com.keepassdroid.backup.SettingsBackupAgent"
|
||||
android:theme="@style/KeepassDXStyle.Light">
|
||||
android:theme="@style/KeepassDXStyle.Light"
|
||||
tools:replace="android:theme">
|
||||
<!-- TODO backup API Key -->
|
||||
<meta-data android:name="com.google.android.backup.api_key"
|
||||
android:value="" />
|
||||
|
||||
<!-- Folder picker -->
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:authorities="${applicationId}.provider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/nnf_provider_paths" />
|
||||
</provider>
|
||||
<activity
|
||||
android:name="com.keepassdroid.FilePickerStylishActivity"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.GET_CONTENT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".KeePass"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
@@ -41,7 +63,8 @@
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="file" />
|
||||
<data android:mimeType="*/*" />
|
||||
<data android:scheme="content" />
|
||||
<data android:mimeType="application/octet-stream" />
|
||||
<data android:host="*" />
|
||||
<data android:pathPattern=".*\\.kdb" />
|
||||
<data android:pathPattern=".*\\..*\\.kdb" />
|
||||
@@ -66,14 +89,10 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="com.keepassdroid.GroupActivityV3" android:configChanges="orientation|keyboardHidden">
|
||||
<!-- This metadata entry causes .app.SearchQueryResults to be the default context -->
|
||||
<!-- whenever the user invokes search while in this Activity. -->
|
||||
<meta-data android:name="android.app.default_searchable"
|
||||
android:value="com.keepassdroid.search.SearchResults" />
|
||||
</activity>
|
||||
<activity android:name="com.keepassdroid.GroupActivityV4" android:configChanges="orientation|keyboardHidden">
|
||||
<!-- This metadata entry causes .app.SearchQueryResults to be the default context -->
|
||||
<!-- whenever the user invokes search while in this Activity. -->
|
||||
<meta-data android:name="android.app.default_searchable"
|
||||
android:value="com.keepassdroid.search.SearchResults"
|
||||
android:exported="false" />
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.keepassdroid;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
|
||||
public class CancelDialog extends Dialog {
|
||||
|
||||
private boolean mCanceled = false;
|
||||
|
||||
public CancelDialog(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public boolean canceled() {
|
||||
return mCanceled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
super.cancel();
|
||||
mCanceled = true;
|
||||
}
|
||||
}
|
||||
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.PreferencesUtil.isClipboardNotificationsEnable;
|
||||
|
||||
public class EntryActivity extends LockCloseHideActivity {
|
||||
public static final String KEY_ENTRY = "entry";
|
||||
public static final String KEY_REFRESH_POS = "refresh_pos";
|
||||
@@ -124,7 +126,7 @@ public class EntryActivity extends LockCloseHideActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
mShowPassword = ! prefs.getBoolean(getString(R.string.settings_maskpass_key), getResources().getBoolean(R.bool.settings_maskpass_default));
|
||||
mShowPassword = ! prefs.getBoolean(getString(R.string.maskpass_key), getResources().getBoolean(R.bool.maskpass_default));
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
setEntryView();
|
||||
@@ -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) {
|
||||
@@ -172,6 +173,8 @@ public class EntryActivity extends LockCloseHideActivity {
|
||||
|
||||
setupEditButtons();
|
||||
|
||||
// If notifications enabled in settings
|
||||
if (isClipboardNotificationsEnable(getApplicationContext())) {
|
||||
// Notification Manager
|
||||
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
|
||||
@@ -185,6 +188,7 @@ public class EntryActivity extends LockCloseHideActivity {
|
||||
// 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() {
|
||||
@@ -192,16 +196,17 @@ public class EntryActivity extends LockCloseHideActivity {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
|
||||
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 = new String(mEntry.getPassword());
|
||||
String password = mEntry.getPassword();
|
||||
if (password.length() > 0) {
|
||||
timeoutCopyToClipboard(new String(mEntry.getPassword()));
|
||||
timeoutCopyToClipboard(password);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -428,7 +433,7 @@ public class EntryActivity extends LockCloseHideActivity {
|
||||
}
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
String sClipClear = prefs.getString(getString(R.string.settings_clipboard_timeout_key), getString(R.string.clipboard_timeout_default));
|
||||
String sClipClear = prefs.getString(getString(R.string.clipboard_timeout_key), getString(R.string.clipboard_timeout_default));
|
||||
|
||||
long clipClearTime = Long.parseLong(sClipClear);
|
||||
|
||||
|
||||
@@ -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.PreferencesUtil;
|
||||
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(PreferencesUtil.getDefaultPasswordLength(getContext().getApplicationContext()));
|
||||
|
||||
Button genPassButton = (Button) root.findViewById(R.id.generate_password_button);
|
||||
genPassButton.setOnClickListener(new OnClickListener() {
|
||||
@@ -114,6 +138,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 =
|
||||
PreferencesUtil.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);
|
||||
txtPassword.setText(generatePassword());
|
||||
@@ -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) {
|
||||
|
||||
@@ -247,7 +247,7 @@ public abstract class GroupActivity extends GroupBaseActivity
|
||||
if (App.getDB().readOnly) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
if (prefs.getBoolean(getString(R.string.settings_show_read_only_warning), true)) {
|
||||
if (prefs.getBoolean(getString(R.string.show_read_only_warning), true)) {
|
||||
Dialog dialog = new ReadOnlyDialog(this);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
@@ -40,8 +41,6 @@ import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.kunzisoft.keepass.KeePass;
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.keepassdroid.app.App;
|
||||
import com.keepassdroid.compat.ActivityCompat;
|
||||
import com.keepassdroid.compat.EditorCompat;
|
||||
@@ -49,10 +48,14 @@ import com.keepassdroid.database.PwGroup;
|
||||
import com.keepassdroid.database.edit.OnFinish;
|
||||
import com.keepassdroid.search.SearchResultsActivity;
|
||||
import com.keepassdroid.utils.MenuUtil;
|
||||
import com.keepassdroid.view.AssignPasswordHelper;
|
||||
import com.keepassdroid.view.ClickView;
|
||||
import com.keepassdroid.view.GroupViewOnlyView;
|
||||
import com.kunzisoft.keepass.KeePass;
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
public abstract class GroupBaseActivity extends LockCloseListActivity {
|
||||
public abstract class GroupBaseActivity extends LockCloseListActivity
|
||||
implements AssignMasterKeyDialog.AssignPasswordDialogListener {
|
||||
protected ListView mList;
|
||||
protected ListAdapter mAdapter;
|
||||
|
||||
@@ -148,15 +151,16 @@ public abstract class GroupBaseActivity extends LockCloseListActivity {
|
||||
|
||||
private void ensureCorrectListView(){
|
||||
mList = (ListView)findViewById(R.id.group_list);
|
||||
if (mList != null) {
|
||||
mList.setOnItemClickListener(
|
||||
new AdapterView.OnItemClickListener() {
|
||||
public void onItemClick(AdapterView<?> parent, View v, int position, long id)
|
||||
{
|
||||
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
|
||||
onListItemClick((ListView) parent, v, position, id);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
@@ -191,7 +195,7 @@ public abstract class GroupBaseActivity extends LockCloseListActivity {
|
||||
|
||||
// Will be null if onPrepareOptionsMenu is called before onCreate
|
||||
if (prefs != null) {
|
||||
sortByName = prefs.getBoolean(getString(R.string.settings_sort_key), getResources().getBoolean(R.bool.settings_sort_default));
|
||||
sortByName = prefs.getBoolean(getString(R.string.sort_key), getResources().getBoolean(R.bool.sort_default));
|
||||
}
|
||||
|
||||
int resId;
|
||||
@@ -245,8 +249,8 @@ public abstract class GroupBaseActivity extends LockCloseListActivity {
|
||||
|
||||
private void toggleSort() {
|
||||
// Toggle setting
|
||||
String sortKey = getString(R.string.settings_sort_key);
|
||||
boolean sortByName = prefs.getBoolean(sortKey, getResources().getBoolean(R.bool.settings_sort_default));
|
||||
String sortKey = getString(R.string.sort_key);
|
||||
boolean sortByName = prefs.getBoolean(sortKey, getResources().getBoolean(R.bool.sort_default));
|
||||
Editor editor = prefs.edit();
|
||||
editor.putBoolean(sortKey, ! sortByName);
|
||||
EditorCompat.apply(editor);
|
||||
@@ -265,8 +269,26 @@ public abstract class GroupBaseActivity extends LockCloseListActivity {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAssignKeyDialogPositiveClick(
|
||||
boolean masterPasswordChecked, String masterPassword,
|
||||
boolean keyFileChecked, Uri keyFile) {
|
||||
|
||||
AssignPasswordHelper assignPasswordHelper =
|
||||
new AssignPasswordHelper(this,
|
||||
masterPassword, keyFile);
|
||||
assignPasswordHelper.assignPasswordInDatabase(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAssignKeyDialogNegativeClick(
|
||||
boolean masterPasswordChecked, String masterPassword,
|
||||
boolean keyFileChecked, Uri keyFile) {
|
||||
|
||||
}
|
||||
|
||||
private void setPassword() {
|
||||
SetPasswordDialog dialog = new SetPasswordDialog();
|
||||
AssignMasterKeyDialog dialog = new AssignMasterKeyDialog();
|
||||
dialog.show(getSupportFragmentManager(), "passwordDialog");
|
||||
}
|
||||
|
||||
|
||||
@@ -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,12 +20,49 @@
|
||||
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.PreferencesUtil;
|
||||
import com.keepassdroid.stylish.StylishActivity;
|
||||
import com.keepassdroid.timeout.TimeoutHelper;
|
||||
import com.kunzisoft.keepass.KeePass;
|
||||
|
||||
|
||||
public abstract class LockingActivity extends StylishActivity {
|
||||
|
||||
private ScreenReceiver screenReceiver;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (PreferencesUtil.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();
|
||||
@@ -34,9 +71,25 @@ public abstract class LockingActivity extends StylishActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if(screenReceiver != null)
|
||||
unregisterReceiver(screenReceiver);
|
||||
}
|
||||
|
||||
TimeoutHelper.resume(this);
|
||||
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 (PreferencesUtil.isLockDatabaseWhenScreenShutOffEnable(LockingActivity.this)) {
|
||||
App.setShutdown();
|
||||
checkShutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ package com.keepassdroid;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
@@ -47,6 +46,7 @@ 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;
|
||||
|
||||
@@ -54,18 +54,18 @@ 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.PreferencesUtil;
|
||||
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;
|
||||
|
||||
@@ -84,10 +84,6 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
private static final String KEY_LAUNCH_IMMEDIATELY = "launchImmediately";
|
||||
private static final String VIEW_INTENT = "android.intent.action.VIEW";
|
||||
|
||||
private static final int FILE_BROWSE = 256;
|
||||
public static final int GET_CONTENT = 257;
|
||||
private static final int OPEN_DOC = 258;
|
||||
|
||||
private Uri mDbUri = null;
|
||||
private Uri mKeyUri = null;
|
||||
private boolean mRememberKeyfile;
|
||||
@@ -100,10 +96,19 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
private int mode;
|
||||
private static final String PREF_KEY_VALUE_PREFIX = "valueFor_"; // key is a combination of db file name and this prefix
|
||||
private static final String PREF_KEY_IV_PREFIX = "ivFor_"; // key is a combination of db file name and this prefix
|
||||
private View fingerprintView;
|
||||
private TextView confirmationView;
|
||||
|
||||
private View fingerprintContainerView;
|
||||
private View fingerprintImageView;
|
||||
private FingerPrintAnimatedVector fingerPrintAnimatedVector;
|
||||
private TextView fingerprintTextView;
|
||||
private TextView filenameView;
|
||||
private EditText passwordView;
|
||||
private Button confirmButton;
|
||||
private EditText keyFileView;
|
||||
private Button confirmButtonView;
|
||||
private CheckBox checkboxPasswordView;
|
||||
private CheckBox checkboxKeyfileView;
|
||||
|
||||
private KeyFileHelper keyFileHelper;
|
||||
|
||||
private Intent mReplyIntent;
|
||||
|
||||
@@ -124,6 +129,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")) {
|
||||
@@ -152,50 +158,31 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
keyFileHelper.onActivityResultCallback(requestCode, resultCode, data,
|
||||
new KeyFileHelper.KeyFileCallback() {
|
||||
@Override
|
||||
public void onKeyFileResultCallback(Uri uri) {
|
||||
if(uri != null) {
|
||||
keyFileView.setText(uri.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
switch (requestCode) {
|
||||
case KeePass.EXIT_NORMAL:
|
||||
setEditText(R.id.password, "");
|
||||
setEmptyViews();
|
||||
App.getDB().clear();
|
||||
break;
|
||||
|
||||
case KeePass.EXIT_LOCK:
|
||||
setResult(KeePass.EXIT_LOCK);
|
||||
setEditText(R.id.password, "");
|
||||
setEmptyViews();
|
||||
finish();
|
||||
App.getDB().clear();
|
||||
break;
|
||||
case FILE_BROWSE:
|
||||
if (resultCode == RESULT_OK) {
|
||||
String filename = data.getDataString();
|
||||
if (filename != null) {
|
||||
EditText fn = (EditText) findViewById(R.id.pass_keyfile);
|
||||
fn.setText(filename);
|
||||
mKeyUri = UriUtil.parseDefaultFile(filename);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GET_CONTENT:
|
||||
case OPEN_DOC:
|
||||
if (resultCode == RESULT_OK) {
|
||||
if (data != null) {
|
||||
Uri uri = data.getData();
|
||||
if (uri != null) {
|
||||
if (requestCode == GET_CONTENT) {
|
||||
uri = UriUtil.translate(this, uri);
|
||||
}
|
||||
String path = uri.toString();
|
||||
if (path != null) {
|
||||
EditText fn = (EditText) findViewById(R.id.pass_keyfile);
|
||||
fn.setText(path);
|
||||
|
||||
}
|
||||
mKeyUri = uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -206,7 +193,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
prefsNoBackup = getSharedPreferences("nobackup", Context.MODE_PRIVATE);
|
||||
|
||||
mRememberKeyfile = prefs.getBoolean(getString(R.string.settings_keyfile_key), getResources().getBoolean(R.bool.settings_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);
|
||||
@@ -216,10 +203,45 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
||||
|
||||
confirmButton = (Button) findViewById(R.id.pass_ok);
|
||||
fingerprintView = findViewById(R.id.fingerprint);
|
||||
confirmationView = (TextView) findViewById(R.id.fingerprint_label);
|
||||
confirmButtonView = (Button) findViewById(R.id.pass_ok);
|
||||
fingerprintContainerView = findViewById(R.id.fingerprint_container);
|
||||
fingerprintImageView = findViewById(R.id.fingerprint_image);
|
||||
fingerprintTextView = (TextView) findViewById(R.id.fingerprint_label);
|
||||
filenameView = (TextView) findViewById(R.id.filename);
|
||||
passwordView = (EditText) findViewById(R.id.password);
|
||||
keyFileView = (EditText) findViewById(R.id.pass_keyfile);
|
||||
checkboxPasswordView = (CheckBox) findViewById(R.id.password_checkbox);
|
||||
checkboxKeyfileView = (CheckBox) findViewById(R.id.keyfile_checkox);
|
||||
|
||||
passwordView.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
checkboxPasswordView.setChecked(true);
|
||||
}
|
||||
});
|
||||
keyFileView.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
checkboxKeyfileView.setChecked(true);
|
||||
}
|
||||
});
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
fingerPrintAnimatedVector = new FingerPrintAnimatedVector(this,
|
||||
(ImageView) fingerprintImageView);
|
||||
}
|
||||
|
||||
new InitTask().execute(i);
|
||||
}
|
||||
@@ -231,8 +253,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
|
||||
@@ -242,13 +263,23 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
initForFingerprint();
|
||||
checkAvailability();
|
||||
if (fingerPrintAnimatedVector != null) {
|
||||
fingerPrintAnimatedVector.startScan();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setEmptyViews() {
|
||||
passwordView.setText("");
|
||||
keyFileView.setText("");
|
||||
checkboxPasswordView.setChecked(false);
|
||||
checkboxKeyfileView.setChecked(false);
|
||||
}
|
||||
|
||||
private void retrieveSettings() {
|
||||
String defaultFilename = prefs.getString(KEY_DEFAULT_FILENAME, "");
|
||||
if (!EmptyUtils.isNullOrEmpty(mDbUri.getPath()) && UriUtil.equalsDefaultfile(mDbUri, defaultFilename)) {
|
||||
CheckBox checkbox = (CheckBox) findViewById(R.id.default_database);
|
||||
CompoundButton checkbox = (CompoundButton) findViewById(R.id.default_database);
|
||||
checkbox.setChecked(true);
|
||||
}
|
||||
}
|
||||
@@ -263,14 +294,12 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
|
||||
private void populateView() {
|
||||
String db = (mDbUri == null) ? "" : mDbUri.toString();
|
||||
setEditText(R.id.filename, db);
|
||||
if (!db.isEmpty())
|
||||
filenameView.setText(db);
|
||||
|
||||
String key = (mKeyUri == null) ? "" : mKeyUri.toString();
|
||||
setEditText(R.id.pass_keyfile, key);
|
||||
}
|
||||
|
||||
private void errorMessage(int resId) {
|
||||
Toast.makeText(this, resId, Toast.LENGTH_LONG).show();
|
||||
if (!key.isEmpty())
|
||||
keyFileView.setText(key);
|
||||
}
|
||||
|
||||
// fingerprint related code here
|
||||
@@ -299,7 +328,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
if ( !fingerprintMustBeConfigured ) {
|
||||
final boolean validInput = s.length() > 0;
|
||||
// encrypt or decrypt mode based on how much input or not
|
||||
confirmationView.setText(validInput ? R.string.store_with_fingerprint : R.string.scanning_fingerprint);
|
||||
fingerprintTextView.setText(validInput ? R.string.store_with_fingerprint : R.string.scanning_fingerprint);
|
||||
mode = validInput ? toggleMode(Cipher.ENCRYPT_MODE) : toggleMode(Cipher.DECRYPT_MODE);
|
||||
}
|
||||
}
|
||||
@@ -316,7 +345,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
|
||||
}
|
||||
|
||||
@@ -326,7 +355,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
final CharSequence helpString) {
|
||||
|
||||
onFingerprintException(new Exception("onAuthenticationHelp"));
|
||||
confirmationView.setText(helpString);
|
||||
fingerprintTextView.setText(helpString);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -382,6 +411,12 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||
&& fingerPrintAnimatedVector != null) {
|
||||
fingerPrintAnimatedVector.stopScan();
|
||||
}
|
||||
|
||||
// stop listening when we go in background
|
||||
if (fingerPrintHelper != null) {
|
||||
fingerPrintHelper.stopListening();
|
||||
@@ -389,41 +424,53 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
}
|
||||
|
||||
private void setFingerPrintVisibility(int vis) {
|
||||
fingerprintView.setVisibility(vis);
|
||||
confirmationView.setVisibility(vis);
|
||||
fingerprintContainerView.setVisibility(vis);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private void checkAvailability() {
|
||||
|
||||
// fingerprint not supported (by API level or hardware) so keep option hidden
|
||||
if (!fingerPrintHelper.isFingerprintSupported(FingerprintManagerCompat.from(this))) {
|
||||
// or manually disable
|
||||
if (!PreferencesUtil .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()) {
|
||||
|
||||
else {
|
||||
// show explanations
|
||||
fingerprintContainerView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
FingerPrintDialog fingerPrintDialog = new FingerPrintDialog();
|
||||
fingerPrintDialog.show(getSupportFragmentManager(), "fingerprintDialog");
|
||||
}
|
||||
});
|
||||
setFingerPrintVisibility(View.VISIBLE);
|
||||
fingerprintView.setAlpha(0.3f);
|
||||
|
||||
if (!fingerPrintHelper.hasEnrolledFingerprints()) {
|
||||
fingerprintImageView.setAlpha(0.3f);
|
||||
// This happens when no fingerprints are registered. Listening won't start
|
||||
confirmationView.setText(R.string.configure_fingerprint);
|
||||
fingerprintTextView.setText(R.string.configure_fingerprint);
|
||||
}
|
||||
// finally fingerprint available and configured so we can use it
|
||||
else {
|
||||
fingerprintMustBeConfigured = false;
|
||||
setFingerPrintVisibility(View.VISIBLE);
|
||||
fingerprintView.setAlpha(1f);
|
||||
fingerprintImageView.setAlpha(1f);
|
||||
|
||||
// fingerprint available but no stored password found yet for this DB so show info don't listen
|
||||
if (prefsNoBackup.getString(getPreferenceKeyValue(), null) == null) {
|
||||
confirmationView.setText(R.string.no_password_stored);
|
||||
fingerprintTextView.setText(R.string.no_password_stored);
|
||||
}
|
||||
// all is set here so we can confirm to user and start listening for fingerprints
|
||||
else {
|
||||
confirmationView.setText(R.string.scanning_fingerprint);
|
||||
fingerprintTextView.setText(R.string.scanning_fingerprint);
|
||||
// listen for decryption by default
|
||||
toggleMode(Cipher.DECRYPT_MODE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEncryptedResult(
|
||||
@@ -435,15 +482,15 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
.putString(getPreferenceKeyIvSpec(), ivSpec)
|
||||
.apply();
|
||||
// and remove visual input to reset UI
|
||||
confirmButton.performClick();
|
||||
confirmationView.setText(R.string.encrypted_value_stored);
|
||||
confirmButtonView.performClick();
|
||||
fingerprintTextView.setText(R.string.encrypted_value_stored);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleDecryptedResult(final String value) {
|
||||
// on decrypt enter it for the purchase/login action
|
||||
passwordView.setText(value);
|
||||
confirmButton.performClick();
|
||||
confirmButtonView.performClick();
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
@@ -490,8 +537,8 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
private class OkClickHandler implements View.OnClickListener {
|
||||
|
||||
public void onClick(View view) {
|
||||
String pass = getEditText(R.id.password);
|
||||
String key = getEditText(R.id.pass_keyfile);
|
||||
String pass = passwordView.getText().toString();
|
||||
String key = keyFileView.getText().toString();
|
||||
loadDatabase(pass, key);
|
||||
}
|
||||
}
|
||||
@@ -505,10 +552,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();
|
||||
@@ -517,6 +560,13 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
// Clear the shutdown flag
|
||||
App.clearShutdown();
|
||||
|
||||
if (!checkboxPasswordView.isChecked()) {
|
||||
pass = "";
|
||||
}
|
||||
if (!checkboxKeyfileView.isChecked()) {
|
||||
keyfile = null;
|
||||
}
|
||||
|
||||
Handler handler = new Handler();
|
||||
AfterLoad afterLoad;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||
@@ -537,15 +587,6 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
return Util.getEditText(this, resId);
|
||||
}
|
||||
|
||||
private void setEditText(
|
||||
int resId,
|
||||
String str) {
|
||||
TextView te = (TextView) findViewById(resId);
|
||||
if (te != null) {
|
||||
te.setText(str);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
@@ -572,7 +613,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
|
||||
protected Database db;
|
||||
|
||||
public AfterLoad(
|
||||
AfterLoad(
|
||||
Handler handler,
|
||||
Database db) {
|
||||
super(handler);
|
||||
@@ -690,69 +731,15 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
confirmButton.setOnClickListener(new OkClickHandler());
|
||||
|
||||
if (password != null) {
|
||||
TextView tv_password = (TextView) findViewById(R.id.password);
|
||||
tv_password.setText(password);
|
||||
passwordView.setText(password);
|
||||
}
|
||||
|
||||
CheckBox defaultCheck = (CheckBox) findViewById(R.id.default_database);
|
||||
CompoundButton defaultCheck = (CompoundButton) findViewById(R.id.default_database);
|
||||
defaultCheck.setOnCheckedChangeListener(new DefaultCheckChange());
|
||||
|
||||
View browse = findViewById(R.id.browse_button);
|
||||
browse.setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
public void onClick(View v) {
|
||||
if (StorageAF.useStorageFramework(PasswordActivity.this)) {
|
||||
Intent i = new Intent(StorageAF.ACTION_OPEN_DOCUMENT);
|
||||
i.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
i.setType("*/*");
|
||||
startActivityForResult(i, OPEN_DOC);
|
||||
} else {
|
||||
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
i.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
i.setType("*/*");
|
||||
|
||||
try {
|
||||
startActivityForResult(i, GET_CONTENT);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
lookForOpenIntentsFilePicker();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void lookForOpenIntentsFilePicker() {
|
||||
if (Interaction.isIntentAvailable(PasswordActivity.this, Intents.OPEN_INTENTS_FILE_BROWSE)) {
|
||||
Intent i = new Intent(Intents.OPEN_INTENTS_FILE_BROWSE);
|
||||
|
||||
// Get file path parent if possible
|
||||
try {
|
||||
if (mDbUri != null && mDbUri.toString().length() > 0) {
|
||||
if (mDbUri.getScheme().equals("file")) {
|
||||
File keyfile = new File(mDbUri.getPath());
|
||||
File parent = keyfile.getParentFile();
|
||||
if (parent != null) {
|
||||
i.setData(Uri.parse("file://" + parent.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
try {
|
||||
startActivityForResult(i, FILE_BROWSE);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
showBrowserDialog();
|
||||
}
|
||||
} else {
|
||||
showBrowserDialog();
|
||||
}
|
||||
}
|
||||
|
||||
private void showBrowserDialog() {
|
||||
BrowserDialog browserDialog = new BrowserDialog(PasswordActivity.this);
|
||||
browserDialog.show();
|
||||
}
|
||||
});
|
||||
View browseView = findViewById(R.id.browse_button);
|
||||
keyFileHelper = new KeyFileHelper(PasswordActivity.this);
|
||||
browseView.setOnClickListener(keyFileHelper.getOpenFileOnClickViewListener());
|
||||
|
||||
retrieveSettings();
|
||||
|
||||
|
||||
@@ -19,22 +19,22 @@
|
||||
*/
|
||||
package com.keepassdroid;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.keepassdroid.database.PwEntry;
|
||||
import com.keepassdroid.database.PwGroup;
|
||||
import com.keepassdroid.view.PwEntryView;
|
||||
import com.keepassdroid.view.PwGroupView;
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class PwGroupListAdapter extends BaseAdapter {
|
||||
|
||||
@@ -79,7 +79,7 @@ public class PwGroupListAdapter extends BaseAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
boolean sortLists = prefs.getBoolean(mAct.getString(R.string.settings_sort_key), mAct.getResources().getBoolean(R.bool.settings_sort_default));
|
||||
boolean sortLists = prefs.getBoolean(mAct.getString(R.string.sort_key), mAct.getResources().getBoolean(R.bool.sort_default));
|
||||
if ( sortLists ) {
|
||||
groupsForViewing = new ArrayList<PwGroup>(mGroup.childGroups);
|
||||
|
||||
|
||||
@@ -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,39 @@
|
||||
package com.keepassdroid;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
public class UnavailableFeatureDialog extends DialogFragment {
|
||||
|
||||
private static final String MIN_REQUIRED_VERSION_ARG = "MIN_REQUIRED_VERSION_ARG";
|
||||
private int minVersionRequired = Build.VERSION_CODES.M;
|
||||
|
||||
public static UnavailableFeatureDialog getInstance(int minVersionRequired) {
|
||||
UnavailableFeatureDialog fragment = new UnavailableFeatureDialog();
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(MIN_REQUIRED_VERSION_ARG, minVersionRequired);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
if (getArguments() != null && getArguments().containsKey(MIN_REQUIRED_VERSION_ARG))
|
||||
minVersionRequired = getArguments().getInt(MIN_REQUIRED_VERSION_ARG);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setMessage(getString(R.string.unavailable_feature_text, Build.VERSION.SDK_INT, minVersionRequired))
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) { }
|
||||
});
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,6 @@ public class StorageAF {
|
||||
if (!supportsStorageFramework()) { return false; }
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
return prefs.getBoolean(ctx.getString(R.string.settings_saf_key), ctx.getResources().getBoolean(R.bool.settings_saf_default));
|
||||
return prefs.getBoolean(ctx.getString(R.string.saf_key), ctx.getResources().getBoolean(R.bool.settings_saf_default));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -50,6 +51,14 @@ public class BinaryPool {
|
||||
return pool.entrySet();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
pool.clear();
|
||||
}
|
||||
|
||||
public Collection<ProtectedBinary> binaries() {
|
||||
return pool.values();
|
||||
}
|
||||
|
||||
private class AddBinaries extends EntryHandler<PwEntryV4> {
|
||||
|
||||
@Override
|
||||
@@ -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,6 +100,7 @@ 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";
|
||||
|
||||
@@ -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,21 +19,15 @@
|
||||
*/
|
||||
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;
|
||||
private Context ctx;
|
||||
@@ -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();
|
||||
|
||||
@@ -58,7 +58,7 @@ public class LoadDB extends RunnableOnFinish {
|
||||
mKey = key;
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
mRememberKeyfile = prefs.getBoolean(ctx.getString(R.string.settings_keyfile_key), ctx.getResources().getBoolean(R.bool.settings_keyfile_default));
|
||||
mRememberKeyfile = prefs.getBoolean(ctx.getString(R.string.keyfile_key), ctx.getResources().getBoolean(R.bool.keyfile_default));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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,
|
||||
InputStream keyInputStream, UpdateStatus status, long roundsFix) throws IOException,
|
||||
InvalidDBException {
|
||||
|
||||
db = createDB();
|
||||
|
||||
PwDbHeaderV4 header = new PwDbHeaderV4(db);
|
||||
header.binaries.clear();
|
||||
db.binPool.clear();
|
||||
|
||||
PwDbHeaderV4.HeaderAndHash hh = header.loadFromFile(inStream);
|
||||
version = header.version;
|
||||
@@ -118,7 +117,7 @@ public class ImporterV4 extends Importer {
|
||||
pbHeader = hh.header;
|
||||
|
||||
db.setMasterKey(password, keyInputStream);
|
||||
db.makeFinalKey(header.masterSeed, db.kdfParameters);
|
||||
db.makeFinalKey(header.masterSeed, db.kdfParameters, roundsFix);
|
||||
|
||||
CipherEngine engine;
|
||||
Cipher cipher;
|
||||
@@ -253,6 +252,7 @@ public class ImporterV4 extends Importer {
|
||||
byte[] bin = new byte[data.length - 1];
|
||||
System.arraycopy(data, 1, bin, 0, data.length-1);
|
||||
ProtectedBinary pb = new ProtectedBinary(prot, bin);
|
||||
db.binPool.poolAdd(pb);
|
||||
|
||||
if (prot) {
|
||||
Arrays.fill(data, (byte)0);
|
||||
@@ -511,7 +511,7 @@ public class ImporterV4 extends Importer {
|
||||
if ( key != null ) {
|
||||
ProtectedBinary pbData = ReadProtectedBinary(xpp);
|
||||
int id = Integer.parseInt(key);
|
||||
binPool.put(id, pbData);
|
||||
db.binPool.put(id, pbData);
|
||||
} else {
|
||||
ReadUnknown(xpp);
|
||||
}
|
||||
@@ -932,7 +932,7 @@ public class ImporterV4 extends Importer {
|
||||
} else {
|
||||
|
||||
try {
|
||||
utcDate = PwDatabaseV4XML.dateFormat.parse(sDate);
|
||||
utcDate = PwDatabaseV4XML.dateFormatter.get().parse(sDate);
|
||||
} catch (ParseException e) {
|
||||
// Catch with null test below
|
||||
}
|
||||
@@ -1061,7 +1061,7 @@ public class ImporterV4 extends Importer {
|
||||
xpp.next(); // Consume end tag
|
||||
|
||||
int id = Integer.parseInt(ref);
|
||||
return binPool.get(id);
|
||||
return db.binPool.get(id);
|
||||
}
|
||||
|
||||
boolean compressed = false;
|
||||
|
||||
@@ -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,7 +282,6 @@ public class PwDbV4Output extends PwDbOutput {
|
||||
}
|
||||
|
||||
private void outputDatabase(OutputStream os) throws IllegalArgumentException, IllegalStateException, IOException {
|
||||
binPool = new BinaryPool((PwGroupV4)mPM.rootGroup);
|
||||
|
||||
xml = Xml.newSerializer();
|
||||
|
||||
@@ -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()));
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import com.keepassdroid.compat.BuildCompat;
|
||||
public class ReadOnlyDialog extends WarningDialog {
|
||||
|
||||
public ReadOnlyDialog(Context context) {
|
||||
super(context, R.string.settings_show_read_only_warning);
|
||||
super(context, R.string.show_read_only_warning);
|
||||
|
||||
warning = context.getString(R.string.read_only_warning);
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
*/
|
||||
package com.keepassdroid.fileselect;
|
||||
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Intent;
|
||||
@@ -28,13 +28,13 @@ import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.Menu;
|
||||
@@ -44,18 +44,16 @@ import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.keepassdroid.AssignMasterKeyDialog;
|
||||
import com.keepassdroid.CreateFileDialog;
|
||||
import com.keepassdroid.GroupActivity;
|
||||
import com.keepassdroid.PasswordActivity;
|
||||
import com.keepassdroid.ProgressTask;
|
||||
import com.keepassdroid.SetPasswordDialog;
|
||||
import com.keepassdroid.app.App;
|
||||
import com.keepassdroid.compat.ContentResolverCompat;
|
||||
import com.keepassdroid.compat.StorageAF;
|
||||
@@ -69,18 +67,25 @@ import com.keepassdroid.utils.Interaction;
|
||||
import com.keepassdroid.utils.MenuUtil;
|
||||
import com.keepassdroid.utils.UriUtil;
|
||||
import com.keepassdroid.utils.Util;
|
||||
import com.keepassdroid.view.AssignPasswordHelper;
|
||||
import com.keepassdroid.view.FileNameView;
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.net.URLDecoder;
|
||||
|
||||
public class FileSelectActivity extends StylishActivity {
|
||||
public class FileSelectActivity extends StylishActivity implements
|
||||
CreateFileDialog.DefinePathDialogListener ,
|
||||
AssignMasterKeyDialog.AssignPasswordDialogListener {
|
||||
|
||||
private static final String TAG = "FileSelectActivity";
|
||||
|
||||
private static final int MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE = 111;
|
||||
private ListView mList;
|
||||
private ListAdapter mAdapter;
|
||||
private BaseAdapter mAdapter;
|
||||
|
||||
private static final int CMENU_CLEAR = Menu.FIRST;
|
||||
|
||||
@@ -93,6 +98,11 @@ public class FileSelectActivity extends StylishActivity {
|
||||
private boolean recentMode = false;
|
||||
private boolean autofillResponse = false;
|
||||
|
||||
private EditText openFileNameView;
|
||||
|
||||
private AssignPasswordHelper assignPasswordHelper;
|
||||
private Uri databaseUri;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -104,11 +114,11 @@ public class FileSelectActivity extends StylishActivity {
|
||||
|
||||
fileHistory = App.getFileHistory();
|
||||
|
||||
setContentView(R.layout.file_selection);
|
||||
if (fileHistory.hasRecentFiles()) {
|
||||
recentMode = true;
|
||||
setContentView(R.layout.file_selection);
|
||||
} else {
|
||||
setContentView(R.layout.file_selection_no_recent);
|
||||
findViewById(R.id.file_listtop).setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
@@ -119,21 +129,19 @@ public class FileSelectActivity extends StylishActivity {
|
||||
|
||||
mList.setOnItemClickListener(
|
||||
new AdapterView.OnItemClickListener() {
|
||||
public void onItemClick(AdapterView<?> parent, View v, int position, long id)
|
||||
{
|
||||
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
|
||||
onListItemClick((ListView)parent, v, position, id);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Open button
|
||||
Button openButton = (Button) findViewById(R.id.open);
|
||||
View openButton = findViewById(R.id.open_database);
|
||||
openButton.setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
public void onClick(View v) {
|
||||
String fileName = Util.getEditText(FileSelectActivity.this,
|
||||
R.id.file_filename);
|
||||
|
||||
try {
|
||||
PasswordActivity.Launch(FileSelectActivity.this, fileName, autofillResponse);
|
||||
}
|
||||
@@ -145,80 +153,16 @@ public class FileSelectActivity extends StylishActivity {
|
||||
Toast.makeText(FileSelectActivity.this,
|
||||
R.string.FileNotFound, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// Create button
|
||||
Button createButton = (Button) findViewById(R.id.create);
|
||||
View createButton = findViewById(R.id.create_database);
|
||||
createButton.setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
public void onClick(View v) {
|
||||
String filename = Util.getEditText(FileSelectActivity.this,
|
||||
R.id.file_filename);
|
||||
|
||||
// Make sure file name exists
|
||||
if (filename.length() == 0) {
|
||||
Toast
|
||||
.makeText(FileSelectActivity.this,
|
||||
R.string.error_filename_required,
|
||||
Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
CreateFileDialog createFileDialog = new CreateFileDialog();
|
||||
createFileDialog.show(getSupportFragmentManager(), "createFileDialog");
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
View browseButton = findViewById(R.id.browse_button);
|
||||
@@ -229,16 +173,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.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
i.setType("*/*");
|
||||
|
||||
@@ -253,7 +195,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)));
|
||||
@@ -262,7 +203,6 @@ public class FileSelectActivity extends StylishActivity {
|
||||
} catch (ActivityNotFoundException e) {
|
||||
showBrowserDialog();
|
||||
}
|
||||
|
||||
} else {
|
||||
showBrowserDialog();
|
||||
}
|
||||
@@ -274,6 +214,14 @@ public class FileSelectActivity extends StylishActivity {
|
||||
}
|
||||
});
|
||||
|
||||
// Set the initial value of the filename
|
||||
openFileNameView = (EditText) findViewById(R.id.file_filename);
|
||||
String defaultPath = Environment.getExternalStorageDirectory().getAbsolutePath()
|
||||
+ getString(R.string.database_file_path_default)
|
||||
+ getString(R.string.database_file_name_default)
|
||||
+ getString(R.string.database_file_extension_default);
|
||||
openFileNameView.setText(defaultPath);
|
||||
|
||||
fillData();
|
||||
|
||||
registerForContextMenu(mList);
|
||||
@@ -284,7 +232,9 @@ public class FileSelectActivity extends StylishActivity {
|
||||
|
||||
if (fileName.length() > 0) {
|
||||
Uri dbUri = UriUtil.parseDefaultFile(fileName);
|
||||
String scheme = dbUri.getScheme();
|
||||
String scheme = null;
|
||||
if (dbUri!=null)
|
||||
scheme = dbUri.getScheme();
|
||||
|
||||
if (!EmptyUtils.isNullOrEmpty(scheme) && scheme.equalsIgnoreCase("file")) {
|
||||
String path = dbUri.getPath();
|
||||
@@ -308,12 +258,135 @@ public class FileSelectActivity extends StylishActivity {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create file for database
|
||||
* @return If not created, return false
|
||||
*/
|
||||
private boolean createDatabaseFile(Uri path) {
|
||||
|
||||
String pathString = URLDecoder.decode(path.getPath());
|
||||
// Make sure file name exists
|
||||
if (pathString.length() == 0) {
|
||||
Log.e(TAG, getString(R.string.error_filename_required));
|
||||
Toast.makeText(FileSelectActivity.this,
|
||||
R.string.error_filename_required,
|
||||
Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to create the file
|
||||
File file = new File(pathString);
|
||||
try {
|
||||
if (file.exists()) {
|
||||
Log.e(TAG, getString(R.string.error_database_exists) + " " + file);
|
||||
Toast.makeText(FileSelectActivity.this,
|
||||
R.string.error_database_exists,
|
||||
Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
File parent = file.getParentFile();
|
||||
|
||||
if ( parent == null || (parent.exists() && ! parent.isDirectory()) ) {
|
||||
Log.e(TAG, getString(R.string.error_invalid_path) + " " + file);
|
||||
Toast.makeText(FileSelectActivity.this,
|
||||
R.string.error_invalid_path,
|
||||
Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! parent.exists() ) {
|
||||
// Create parent directory
|
||||
if ( ! parent.mkdirs() ) {
|
||||
Log.e(TAG, getString(R.string.error_could_not_create_parent) + " " + parent);
|
||||
Toast.makeText(FileSelectActivity.this,
|
||||
R.string.error_could_not_create_parent,
|
||||
Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, getString(R.string.error_could_not_create_parent) + " " + e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
Toast.makeText(
|
||||
FileSelectActivity.this,
|
||||
getText(R.string.error_file_not_create) + " "
|
||||
+ e.getLocalizedMessage(),
|
||||
Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDefinePathDialogPositiveClick(Uri pathFile) {
|
||||
databaseUri = pathFile;
|
||||
if(createDatabaseFile(pathFile)) {
|
||||
AssignMasterKeyDialog assignMasterKeyDialog = new AssignMasterKeyDialog();
|
||||
assignMasterKeyDialog.show(getSupportFragmentManager(), "passwordDialog");
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDefinePathDialogNegativeClick(Uri pathFile) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAssignKeyDialogPositiveClick(
|
||||
boolean masterPasswordChecked, String masterPassword,
|
||||
boolean keyFileChecked, Uri keyFile) {
|
||||
|
||||
String databaseFilename = databaseUri.getPath();
|
||||
|
||||
// Prep an object to collect a password once the database has
|
||||
// been created
|
||||
FileOnFinish launchActivityOnFinish = new FileOnFinish(
|
||||
new LaunchGroupActivity(databaseFilename));
|
||||
AssignPasswordOnFinish assignPasswordOnFinish =
|
||||
new AssignPasswordOnFinish(launchActivityOnFinish);
|
||||
|
||||
// Create the new database
|
||||
CreateDB create = new CreateDB(FileSelectActivity.this,
|
||||
databaseFilename, assignPasswordOnFinish, true);
|
||||
|
||||
ProgressTask createTask = new ProgressTask(
|
||||
FileSelectActivity.this, create,
|
||||
R.string.progress_create);
|
||||
createTask.run();
|
||||
assignPasswordHelper =
|
||||
new AssignPasswordHelper(this,
|
||||
masterPassword, keyFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAssignKeyDialogNegativeClick(
|
||||
boolean masterPasswordChecked, String masterPassword,
|
||||
boolean keyFileChecked, Uri keyFile) {
|
||||
|
||||
}
|
||||
|
||||
private class AssignPasswordOnFinish extends FileOnFinish {
|
||||
|
||||
AssignPasswordOnFinish(FileOnFinish fileOnFinish) {
|
||||
super(fileOnFinish);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (mSuccess) {
|
||||
assignPasswordHelper.assignPasswordInDatabase(mOnFinish);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class LaunchGroupActivity extends FileOnFinish {
|
||||
private Uri mUri;
|
||||
|
||||
public LaunchGroupActivity(String filename) {
|
||||
LaunchGroupActivity(String filename) {
|
||||
super(null);
|
||||
|
||||
mUri = UriUtil.parseDefaultFile(filename);
|
||||
}
|
||||
|
||||
@@ -322,61 +395,19 @@ public class FileSelectActivity extends StylishActivity {
|
||||
if (mSuccess) {
|
||||
// Add to recent files
|
||||
fileHistory.createFile(mUri, getFilename());
|
||||
|
||||
mAdapter.notifyDataSetChanged();
|
||||
GroupActivity.Launch(FileSelectActivity.this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class CollectPassword extends FileOnFinish {
|
||||
|
||||
public CollectPassword(FileOnFinish finish) {
|
||||
super(finish);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
SetPasswordDialog dialog = SetPasswordDialog.newInstance(mOnFinish);
|
||||
dialog.show(getSupportFragmentManager(), "passwordDialog");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void fillData() {
|
||||
// Set the initial value of the filename
|
||||
EditText filename = (EditText) findViewById(R.id.file_filename);
|
||||
filename.setText(Environment.getExternalStorageDirectory().getAbsolutePath() + getString(R.string.default_file_path));
|
||||
|
||||
mAdapter = new ArrayAdapter<String>(this, R.layout.file_row, R.id.file_filename, fileHistory.getDbList());
|
||||
mAdapter = new ArrayAdapter<>(FileSelectActivity.this, R.layout.file_row, R.id.file_filename, fileHistory.getDbList());
|
||||
mList.setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
protected void onListItemClick(ListView l, View v, int position, long id) {
|
||||
|
||||
new AsyncTask<Integer, Void, Void>() {
|
||||
String fileName;
|
||||
String keyFile;
|
||||
protected Void doInBackground(Integer... args) {
|
||||
int position = args[0];
|
||||
fileName = fileHistory.getDatabaseAt(position);
|
||||
keyFile = fileHistory.getKeyfileAt(position);
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void onPostExecute(Void v) {
|
||||
try {
|
||||
PasswordActivity.Launch(FileSelectActivity.this, fileName, keyFile, autofillResponse);
|
||||
}
|
||||
catch (ContentFileNotFoundException e) {
|
||||
Toast.makeText(FileSelectActivity.this, R.string.file_not_found_content, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
Toast.makeText(FileSelectActivity.this, R.string.FileNotFound, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
}.execute(position);
|
||||
new OpenFileHistoryAsyncTask(this, fileHistory, autofillResponse).execute(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -420,8 +451,7 @@ public class FileSelectActivity extends StylishActivity {
|
||||
}
|
||||
|
||||
if (filename != null) {
|
||||
EditText fn = (EditText) findViewById(R.id.file_filename);
|
||||
fn.setText(filename);
|
||||
openFileNameView.setText(filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,25 +558,67 @@ public class FileSelectActivity extends StylishActivity {
|
||||
|
||||
TextView tv = (TextView) acmi.targetView;
|
||||
String filename = tv.getText().toString();
|
||||
new AsyncTask<String, Void, Void>() {
|
||||
protected java.lang.Void doInBackground(String... args) {
|
||||
String filename = args[0];
|
||||
fileHistory.deleteFile(Uri.parse(args[0]));
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void onPostExecute(Void v) {
|
||||
refreshList();
|
||||
}
|
||||
}.execute(filename);
|
||||
new DeleteFileHistoryAsyncTask(fileHistory, mAdapter).execute(filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void refreshList() {
|
||||
((BaseAdapter) mAdapter).notifyDataSetChanged();
|
||||
private static class OpenFileHistoryAsyncTask extends AsyncTask<Integer, Void, Void> {
|
||||
|
||||
private WeakReference<Activity> weakActivity;
|
||||
private RecentFileHistory fileHistory;
|
||||
private String fileName;
|
||||
private String keyFile;
|
||||
private boolean autofillResponse;
|
||||
|
||||
OpenFileHistoryAsyncTask(Activity activity, RecentFileHistory fileHistory, boolean autofillResponse) {
|
||||
this.weakActivity = new WeakReference<>(activity);
|
||||
this.fileHistory = fileHistory;
|
||||
this.autofillResponse = autofillResponse;
|
||||
}
|
||||
|
||||
protected Void doInBackground(Integer... args) {
|
||||
int position = args[0];
|
||||
fileName = fileHistory.getDatabaseAt(position);
|
||||
keyFile = fileHistory.getKeyfileAt(position);
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void onPostExecute(Void v) {
|
||||
try {
|
||||
PasswordActivity.Launch(weakActivity.get(), fileName, keyFile, autofillResponse);
|
||||
}
|
||||
catch (ContentFileNotFoundException e) {
|
||||
Toast.makeText(weakActivity.get(), R.string.file_not_found_content, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
Toast.makeText(weakActivity.get(), R.string.FileNotFound, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class DeleteFileHistoryAsyncTask extends AsyncTask<String, Void, Void> {
|
||||
|
||||
private RecentFileHistory fileHistory;
|
||||
private BaseAdapter adapter;
|
||||
|
||||
DeleteFileHistoryAsyncTask(RecentFileHistory fileHistory, BaseAdapter adapter) {
|
||||
this.fileHistory = fileHistory;
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
protected java.lang.Void doInBackground(String... args) {
|
||||
fileHistory.deleteFile(Uri.parse(args[0]));
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void onPostExecute(Void v) {
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,14 +19,6 @@
|
||||
*/
|
||||
package com.keepassdroid.fileselect;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.keepassdroid.compat.EditorCompat;
|
||||
import com.keepassdroid.utils.UriUtil;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
@@ -34,6 +26,14 @@ import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.keepassdroid.compat.EditorCompat;
|
||||
import com.keepassdroid.utils.UriUtil;
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class RecentFileHistory {
|
||||
|
||||
private static String DB_KEY = "recent_databases";
|
||||
@@ -51,14 +51,14 @@ public class RecentFileHistory {
|
||||
ctx = c.getApplicationContext();
|
||||
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(c);
|
||||
enabled = prefs.getBoolean(ctx.getString(R.string.settings_recentfile_key), ctx.getResources().getBoolean(R.bool.settings_recentfile_default));
|
||||
enabled = prefs.getBoolean(ctx.getString(R.string.recentfile_key), ctx.getResources().getBoolean(R.bool.recentfile_default));
|
||||
listner = new OnSharedPreferenceChangeListener() {
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
|
||||
String key) {
|
||||
if (key.equals(ctx.getString(R.string.settings_recentfile_key))) {
|
||||
enabled = sharedPreferences.getBoolean(ctx.getString(R.string.settings_recentfile_key), ctx.getResources().getBoolean(R.bool.settings_recentfile_default));
|
||||
if (key.equals(ctx.getString(R.string.recentfile_key))) {
|
||||
enabled = sharedPreferences.getBoolean(ctx.getString(R.string.recentfile_key), ctx.getResources().getBoolean(R.bool.recentfile_default));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -19,19 +19,11 @@
|
||||
*/
|
||||
package com.keepassdroid.search;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Queue;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.keepassdroid.Database;
|
||||
import com.keepassdroid.database.PwDatabase;
|
||||
import com.keepassdroid.database.PwDatabaseV3;
|
||||
@@ -40,6 +32,14 @@ import com.keepassdroid.database.PwEntry;
|
||||
import com.keepassdroid.database.PwGroup;
|
||||
import com.keepassdroid.database.PwGroupV3;
|
||||
import com.keepassdroid.database.PwGroupV4;
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Queue;
|
||||
|
||||
public class SearchDbHelper {
|
||||
private final Context mCtx;
|
||||
@@ -50,7 +50,7 @@ public class SearchDbHelper {
|
||||
|
||||
private boolean omitBackup() {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mCtx);
|
||||
return prefs.getBoolean(mCtx.getString(R.string.settings_omitbackup_key), mCtx.getResources().getBoolean(R.bool.settings_omitbackup_default));
|
||||
return prefs.getBoolean(mCtx.getString(R.string.omitbackup_key), mCtx.getResources().getBoolean(R.bool.omitbackup_default));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.keepassdroid.settings;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
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 {
|
||||
|
||||
@@ -31,41 +30,43 @@ public class MainPreferenceFragment extends PreferenceFragmentCompat implements
|
||||
setPreferencesFromResource(R.xml.preferences, rootKey);
|
||||
|
||||
// add listeners for non-default actions
|
||||
Preference preference = findPreference(getString(R.string.settings_app_key));
|
||||
Preference preference = findPreference(getString(R.string.app_key));
|
||||
preference.setOnPreferenceClickListener(this);
|
||||
|
||||
preference = findPreference(getString(R.string.settings_db_key));
|
||||
Database db = App.getDB();
|
||||
if (!(db.Loaded() && db.pm.appSettingsEnabled())) {
|
||||
preference.setEnabled(false);
|
||||
} else {
|
||||
preference = findPreference(getString(R.string.db_key));
|
||||
preference.setOnPreferenceClickListener(this);
|
||||
|
||||
Database db = App.getDB();
|
||||
if (!(db.Loaded())) {
|
||||
preference.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
preference = findPreference(getString(R.string.settings_autofill_key));
|
||||
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
preference.setEnabled(false);
|
||||
} else {
|
||||
preference.setOnPreferenceClickListener(this);
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
// here you should use the same keys as you used in the xml-file
|
||||
if (preference.getKey().equals(getString(R.string.settings_app_key))) {
|
||||
if (preference.getKey().equals(getString(R.string.app_key))) {
|
||||
mCallback.onNestedPreferenceSelected(NestedSettingsFragment.NESTED_SCREEN_APP_KEY);
|
||||
}
|
||||
|
||||
if (preference.getKey().equals(getString(R.string.settings_db_key))) {
|
||||
if (preference.getKey().equals(getString(R.string.db_key))) {
|
||||
mCallback.onNestedPreferenceSelected(NestedSettingsFragment.NESTED_SCREEN_DB_KEY);
|
||||
}
|
||||
|
||||
if (preference.getKey().equals(getString(R.string.settings_autofill_key))) {
|
||||
Intent intent = new Intent(getContext(), SettingsAutofillActivity.class);
|
||||
getActivity().startActivity(intent);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,19 +19,25 @@
|
||||
*/
|
||||
package com.keepassdroid.settings;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v14.preference.SwitchPreference;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceFragmentCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import com.keepassdroid.UnavailableFeatureDialog;
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.keepassdroid.Database;
|
||||
import com.keepassdroid.app.App;
|
||||
import com.keepassdroid.database.PwEncryptionAlgorithm;
|
||||
import com.keepassdroid.stylish.Stylish;
|
||||
|
||||
public class NestedSettingsFragment extends PreferenceFragmentCompat {
|
||||
public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
implements Preference.OnPreferenceClickListener {
|
||||
|
||||
public static final int NESTED_SCREEN_APP_KEY = 1;
|
||||
public static final int NESTED_SCREEN_DB_KEY = 2;
|
||||
@@ -55,7 +61,7 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat {
|
||||
case NESTED_SCREEN_APP_KEY:
|
||||
setPreferencesFromResource(R.xml.app_preferences, rootKey);
|
||||
|
||||
Preference keyFile = findPreference(getString(R.string.settings_keyfile_key));
|
||||
Preference keyFile = findPreference(getString(R.string.keyfile_key));
|
||||
keyFile.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
Boolean value = (Boolean) newValue;
|
||||
|
||||
@@ -66,7 +72,7 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat {
|
||||
return true;
|
||||
});
|
||||
|
||||
Preference recentHistory = findPreference(getString(R.string.settings_recentfile_key));
|
||||
Preference recentHistory = findPreference(getString(R.string.recentfile_key));
|
||||
recentHistory.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
Boolean value = (Boolean) newValue;
|
||||
|
||||
@@ -81,7 +87,7 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat {
|
||||
return true;
|
||||
});
|
||||
|
||||
Preference stylePreference = findPreference(getString(R.string.settings_style_key));
|
||||
Preference stylePreference = findPreference(getString(R.string.setting_style_key));
|
||||
stylePreference.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
String styleString = (String) newValue;
|
||||
Stylish.assignStyle(getActivity(), styleString);
|
||||
@@ -89,25 +95,51 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat {
|
||||
return true;
|
||||
});
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
// False if under Marshmallow
|
||||
SwitchPreference preference = (SwitchPreference) findPreference(getString(R.string.fingerprint_enable_key));
|
||||
preference.setDefaultValue(false);
|
||||
preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
((SwitchPreference) preference).setChecked(false);
|
||||
UnavailableFeatureDialog.getInstance(Build.VERSION_CODES.M)
|
||||
.show(getFragmentManager(), "unavailableFeatureDialog");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Preference preferenceAutofill = findPreference(getString(R.string.settings_autofill_key));
|
||||
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
preferenceAutofill.setEnabled(false);
|
||||
} else {
|
||||
preferenceAutofill.setOnPreferenceClickListener(this);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NESTED_SCREEN_DB_KEY:
|
||||
setPreferencesFromResource(R.xml.db_preferences, rootKey);
|
||||
|
||||
Database db = App.getDB();
|
||||
if (db.Loaded() && db.pm.appSettingsEnabled()) {
|
||||
Preference algorithmPref = findPreference(getString(R.string.algorithm_key));
|
||||
Preference roundPref = findPreference(getString(R.string.rounds_key));
|
||||
|
||||
Preference rounds = findPreference(getString(R.string.settings_rounds_key));
|
||||
rounds.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if (!(db.Loaded() && db.pm.appSettingsEnabled())) {
|
||||
algorithmPref.setEnabled(false);
|
||||
roundPref.setEnabled(false);
|
||||
}
|
||||
|
||||
if (db.Loaded() && db.pm.appSettingsEnabled()) {
|
||||
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.settings_algorithm_key));
|
||||
setAlgorithm(db, algorithm);
|
||||
|
||||
setRounds(db, roundPref);
|
||||
setAlgorithm(db, algorithmPref);
|
||||
} else {
|
||||
Log.e(getClass().getName(), "Database isn't ready");
|
||||
}
|
||||
@@ -119,6 +151,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()));
|
||||
}
|
||||
@@ -144,4 +190,14 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat {
|
||||
return resources.getString(R.string.settings);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
if (preference.getKey().equals(getString(R.string.settings_autofill_key))) {
|
||||
Intent intent = new Intent(getContext(), SettingsAutofillActivity.class);
|
||||
getActivity().startActivity(intent);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,46 @@ import android.preference.PreferenceManager;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class PreferencesUtil {
|
||||
|
||||
public static float getListTextSize(Context ctx) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
return Float.parseFloat(prefs.getString(ctx.getString(R.string.settings_list_size_key), ctx.getString(R.string.list_size_default)));
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
private long mRounds;
|
||||
private String explanations;
|
||||
|
||||
@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;
|
||||
public RoundsPreference(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public RoundsPreference(Context context, AttributeSet attrs) {
|
||||
super(context, 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
|
||||
protected void onDialogClosed(boolean positiveResult) {
|
||||
super.onDialogClosed(positiveResult);
|
||||
|
||||
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;
|
||||
public int getDialogLayoutResource() {
|
||||
return R.layout.pref_dialog_rounds;
|
||||
}
|
||||
|
||||
if ( rounds < 1 ) {
|
||||
rounds = 1;
|
||||
public String getExplanations() {
|
||||
return explanations;
|
||||
}
|
||||
|
||||
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);
|
||||
public void setExplanations(String explanations) {
|
||||
this.explanations = explanations;
|
||||
}
|
||||
|
||||
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 long getRounds() {
|
||||
return mRounds;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 void setRounds(long rounds) {
|
||||
this.mRounds = rounds;
|
||||
// Save to Shared Preferences
|
||||
persistLong(rounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if ( mSuccess ) {
|
||||
OnPreferenceChangeListener listner = getOnPreferenceChangeListener();
|
||||
if ( listner != null ) {
|
||||
listner.onPreferenceChange(RoundsPreference.this, null);
|
||||
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 {
|
||||
displayMessage(mCtx);
|
||||
mPM.setNumRounds(mOldRounds);
|
||||
}
|
||||
|
||||
super.run();
|
||||
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,12 +9,12 @@ 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.settings_style_key);
|
||||
stylishPrefKey = context.getString(R.string.setting_style_key);
|
||||
Log.d(Stylish.class.getName(), "Attatching to " + context.getPackageName());
|
||||
themeString = PreferenceManager.getDefaultSharedPreferences(context).getString(stylishPrefKey, context.getString(R.string.list_style_name_light));
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -39,7 +39,7 @@ public class TimeoutHelper {
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(act);
|
||||
SharedPreferences.Editor edit = prefs.edit();
|
||||
edit.putLong(act.getString(R.string.settings_timeout_key), time);
|
||||
edit.putLong(act.getString(R.string.timeout_key), time);
|
||||
|
||||
EditorCompat.apply(edit);
|
||||
|
||||
@@ -59,14 +59,14 @@ public class TimeoutHelper {
|
||||
long cur_time = System.currentTimeMillis();
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(act);
|
||||
long timeout_start = prefs.getLong(act.getString(R.string.settings_timeout_key), -1);
|
||||
long timeout_start = prefs.getLong(act.getString(R.string.timeout_key), -1);
|
||||
// The timeout never started
|
||||
if (timeout_start == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
String sTimeout = prefs.getString(act.getString(R.string.settings_app_timeout_key), act.getString(R.string.clipboard_timeout_default));
|
||||
String sTimeout = prefs.getString(act.getString(R.string.app_timeout_key), act.getString(R.string.clipboard_timeout_default));
|
||||
long timeout;
|
||||
try {
|
||||
timeout = Long.parseLong(sTimeout);
|
||||
|
||||
@@ -28,7 +28,7 @@ public class Timeout {
|
||||
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
String sTimeout = prefs.getString(ctx.getString(R.string.settings_app_timeout_key), ctx.getString(R.string.clipboard_timeout_default));
|
||||
String sTimeout = prefs.getString(ctx.getString(R.string.app_timeout_key), ctx.getString(R.string.clipboard_timeout_default));
|
||||
|
||||
long timeout;
|
||||
try {
|
||||
|
||||
@@ -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_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,7 +17,11 @@
|
||||
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"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
@@ -27,12 +31,10 @@
|
||||
layout="@layout/toolbar_default" />
|
||||
|
||||
<com.keepassdroid.view.FileNameView android:id="@+id/file_select"
|
||||
android:layout_marginBottom="@dimen/default_margin"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<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"
|
||||
@@ -45,4 +47,17 @@
|
||||
<ListView android:id="@+id/file_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/create_database"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
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,10 +17,26 @@
|
||||
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.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<android.support.v7.widget.CardView
|
||||
android:id="@+id/filename_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="32dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/default_margin"
|
||||
android:layout_marginLeft="@dimen/default_margin"
|
||||
android:layout_marginStart="@dimen/default_margin"
|
||||
android:layout_marginRight="@dimen/default_margin"
|
||||
android:layout_marginEnd="@dimen/default_margin"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<TextView android:id="@+id/label_warning"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -55,24 +71,22 @@
|
||||
android:layout_toLeftOf="@+id/browse_button"
|
||||
android:layout_toStartOf="@+id/browse_button"
|
||||
android:maxLines="1" />
|
||||
|
||||
<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"/>
|
||||
|
||||
<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>
|
||||
|
||||
</android.support.v7.widget.CardView>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/open_database"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/filename_container"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginLeft="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginRight="24dp"
|
||||
app:fabSize="mini"
|
||||
app:layout_anchor="@id/filename_container"
|
||||
app:layout_anchorGravity="bottom|start"
|
||||
android:src="@drawable/ic_open_folder_white_24dp" />
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
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">
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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: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>
|
||||
|
||||
</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,19 +59,14 @@
|
||||
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">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/password_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/password_label"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Title"
|
||||
@@ -79,40 +74,29 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/entry_and_or" />
|
||||
|
||||
<!-- 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" />
|
||||
<include
|
||||
layout="@layout/fingerprint_show" />
|
||||
|
||||
<!-- Password Input -->
|
||||
<RelativeLayout
|
||||
android:id="@+id/password_input_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<android.support.v7.widget.AppCompatCheckBox
|
||||
android:id="@+id/password_checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:paddingBottom="20dp"
|
||||
android:gravity="center_vertical" />
|
||||
|
||||
<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" />
|
||||
|
||||
<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.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: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: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"
|
||||
<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">
|
||||
<EditText android:id="@+id/pass_password"
|
||||
<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:layout_below="@id/pass_password"
|
||||
android:inputType="textPassword"
|
||||
android:maxLines="1"
|
||||
android:hint="@string/hint_conf_pass"/>
|
||||
<EditText android:id="@+id/pass_keyfile"
|
||||
</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_below="@id/pass_conf_password"
|
||||
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:hint="@string/hint_keyfile"/>
|
||||
android:singleLine="true"/>
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
</android.support.v7.widget.CardView>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
<string name="entry_confpassword">Confirma contrasenya:</string>
|
||||
<string name="entry_created">Creada: </string>
|
||||
<string name="entry_expires">Expira: </string>
|
||||
<string name="entry_keyfile">Arxiu clau (opcional)</string>
|
||||
<string name="entry_keyfile">Arxiu clau</string>
|
||||
<string name="entry_modified">Modificada: </string>
|
||||
<string name="entry_password">Contrasenya:</string>
|
||||
<string name="entry_save">Guarda</string>
|
||||
@@ -80,7 +80,7 @@
|
||||
<string name="error_invalid_db">Base de dades invàlida.</string>
|
||||
<string name="error_invalid_path">Camí invàlid.</string>
|
||||
<string name="error_no_name">És necessari un nom.</string>
|
||||
<string name="error_nopass">És necessaria una contrasenya o un arxiu clau.</string>
|
||||
<string name="error_nokeyfile">És necessaria una contrasenya o un arxiu clau.</string>
|
||||
<string name="error_out_of_memory">El telèfon sha quedat sense memòria processant la teva base de dades. Potser és massa gran pel teu telèfon.</string>
|
||||
<string name="error_pass_gen_type">Has de seleccionar almenys un tipus de generador de contrasenyes</string>
|
||||
<string name="error_pass_match">Les contrasenyes no coincideixen.</string>
|
||||
@@ -99,7 +99,7 @@
|
||||
<string name="hint_keyfile">arxiu clau</string>
|
||||
<string name="hint_length">longitud</string>
|
||||
<string name="hint_pass">contrasenya</string>
|
||||
<string name="hint_login_pass">Contrasenya</string>
|
||||
<string name="password">Contrasenya</string>
|
||||
<string name="hint_title">nom</string>
|
||||
<string name="hint_url">url</string>
|
||||
<string name="hint_username">usuari</string>
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
<string name="entry_confpassword">Potvrďte heslo:</string>
|
||||
<string name="entry_created">Vytvořeno: </string>
|
||||
<string name="entry_expires">Vyprší: </string>
|
||||
<string name="entry_keyfile">Klíčový soubor (nepovinné)</string>
|
||||
<string name="entry_keyfile">Klíčový soubor</string>
|
||||
<string name="entry_modified">Změněno: </string>
|
||||
<string name="entry_not_found">Vstupní data nenalezena.</string>
|
||||
<string name="entry_password">Heslo:</string>
|
||||
@@ -86,7 +86,7 @@
|
||||
<string name="error_invalid_db">Chybná databáze.</string>
|
||||
<string name="error_invalid_path">Chybná cesta.</string>
|
||||
<string name="error_no_name">Jméno je povinné.</string>
|
||||
<string name="error_nopass">Heslo nebo klíčový soubor jsou povinné.</string>
|
||||
<string name="error_nokeyfile">Heslo nebo klíčový soubor jsou povinné.</string>
|
||||
<string name="error_out_of_memory">Přístroj má málo paměti pro zpracování databáze. Možná je příliš velká pro Váš přístroj.</string>
|
||||
<string name="error_pass_gen_type">Minimálně jeden typ generování hesla musí být zvolen</string>
|
||||
<string name="error_pass_match">Hesla se neshodují.</string>
|
||||
@@ -108,7 +108,7 @@
|
||||
<string name="hint_keyfile">klíčový soubor</string>
|
||||
<string name="hint_length">délka</string>
|
||||
<string name="hint_pass">heslo</string>
|
||||
<string name="hint_login_pass">Heslo</string>
|
||||
<string name="password">Heslo</string>
|
||||
<string name="hint_title">název</string>
|
||||
<string name="hint_url">url</string>
|
||||
<string name="hint_username">uživatelské jméno</string>
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
<string name="entry_confpassword">Bekræft adgangskode:</string>
|
||||
<string name="entry_created">Oprettet: </string>
|
||||
<string name="entry_expires">Udløber: </string>
|
||||
<string name="entry_keyfile">Nøglefil (valgfri)</string>
|
||||
<string name="entry_keyfile">Nøglefil</string>
|
||||
<string name="entry_modified">Ændret: </string>
|
||||
<string name="entry_not_found">Data for posten blev ikke fundet.</string>
|
||||
<string name="entry_password">Adgangskode:</string>
|
||||
@@ -85,7 +85,7 @@
|
||||
<string name="error_invalid_db">Ugyldig database.</string>
|
||||
<string name="error_invalid_path">Ugyldig sti.</string>
|
||||
<string name="error_no_name">Et navn er påkrævet.</string>
|
||||
<string name="error_nopass">En adgangskode eller nøglefil er påkrævet.</string>
|
||||
<string name="error_nokeyfile">En adgangskode eller nøglefil er påkrævet.</string>
|
||||
<string name="error_out_of_memory">Telefonen løb tør for hukommelse under analysen af din database. Den kan være for stor til, at din telefon kan håndtere den.</string>
|
||||
<string name="error_pass_gen_type">Mindst én adgangskode-genererings-type skal vælges</string>
|
||||
<string name="error_pass_match">Adgangskoder matcher ikke.</string>
|
||||
@@ -107,7 +107,7 @@
|
||||
<string name="hint_keyfile">nøglefil</string>
|
||||
<string name="hint_length">længde</string>
|
||||
<string name="hint_pass">adgangskode</string>
|
||||
<string name="hint_login_pass">Adgangskode</string>
|
||||
<string name="password">Adgangskode</string>
|
||||
<string name="hint_title">navn</string>
|
||||
<string name="hint_url">url</string>
|
||||
<string name="hint_username">brugernavn</string>
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
<string name="entry_confpassword">Passwort wiederholen:</string>
|
||||
<string name="entry_created">Erstelldatum:</string>
|
||||
<string name="entry_expires">Ablaufdatum:</string>
|
||||
<string name="entry_keyfile">Schlüsseldatei (optional)</string>
|
||||
<string name="entry_keyfile">Schlüsseldatei</string>
|
||||
<string name="entry_modified">Änderungsdatum:</string>
|
||||
<string name="entry_not_found">Eintrag wurde nicht gefunden.</string>
|
||||
<string name="entry_password">Passwort:</string>
|
||||
@@ -89,7 +89,7 @@
|
||||
<string name="error_invalid_db">Ungültige Datenbank.</string>
|
||||
<string name="error_invalid_path">Ungültiger Pfad.</string>
|
||||
<string name="error_no_name">Ein Name wird benötigt.</string>
|
||||
<string name="error_nopass">Ein Passwort oder eine Schlüsseldatei wird benötigt.</string>
|
||||
<string name="error_nokeyfile">Ein Passwort oder eine Schlüsseldatei wird benötigt.</string>
|
||||
<string name="error_out_of_memory">Der Speicher Ihres Smartphones reicht nicht aus, um die Datenbank zu analysieren. Sie ist wahrscheinlich zu groß.</string>
|
||||
<string name="error_pass_gen_type">Mindestens ein Passwort-Generierungstyp muss ausgewählt werden.</string>
|
||||
<string name="error_pass_match">Die Passwörter stimmen nicht überein.</string>
|
||||
@@ -112,7 +112,7 @@
|
||||
<string name="hint_keyfile">Schlüsseldatei</string>
|
||||
<string name="hint_length">Länge</string>
|
||||
<string name="hint_pass">Passwort</string>
|
||||
<string name="hint_login_pass">Passwort</string>
|
||||
<string name="password">Passwort</string>
|
||||
<string name="hint_title">Name</string>
|
||||
<string name="hint_url">URL-Adresse</string>
|
||||
<string name="hint_username">Benutzername</string>
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
<string name="entry_confpassword">Επιβεβαίωση κωδικού πρόσβασης:</string>
|
||||
<string name="entry_created">Δημιουργήθηκε: </string>
|
||||
<string name="entry_expires">Λήγει: </string>
|
||||
<string name="entry_keyfile">Αρχείο Κλειδιού (προαιρετικό)</string>
|
||||
<string name="entry_keyfile">Αρχείο Κλειδιού</string>
|
||||
<string name="entry_modified">Τροποποιήθηκε: </string>
|
||||
<string name="entry_not_found">Δεν βρέθηκαν δεδομένα εγγραφών.</string>
|
||||
<string name="entry_password">Κωδικός Πρόσβασης:</string>
|
||||
@@ -83,7 +83,7 @@
|
||||
<string name="error_invalid_db">Μη έγκυρη βάση δεδομένων.</string>
|
||||
<string name="error_invalid_path">Μη έγκυρη διαδρομή.</string>
|
||||
<string name="error_no_name">Απαιτείται ένα όνομα.</string>
|
||||
<string name="error_nopass">Απαιτείται ο κωδικός πρόσβασης ή ένα αρχείο κλειδιού.</string>
|
||||
<string name="error_nokeyfile">Απαιτείται ο κωδικός πρόσβασης ή ένα αρχείο κλειδιού.</string>
|
||||
<string name="error_out_of_memory">Το τηλέφωνο ξέμεινε από μνήμη κατά τη διάρκεια προσπέλασης της βάσης δεδομένων σας. Μπορεί να είναι πολύ μεγάλη για το τηλέφωνο σας.</string>
|
||||
<string name="error_pass_gen_type">Πρέπει να επιλεγεί τουλάχιστον ένας τύπος δημιουργίας κωδικού πρόσβασης</string>
|
||||
<string name="error_pass_match">Οι κωδικοί δεν ταιριάζουν.</string>
|
||||
@@ -105,7 +105,7 @@
|
||||
<string name="hint_keyfile">αρχείο κλειδιού</string>
|
||||
<string name="hint_length">μήκος</string>
|
||||
<string name="hint_pass">κωδικός</string>
|
||||
<string name="hint_login_pass">Κωδικός Πρόσβασης</string>
|
||||
<string name="password">Κωδικός Πρόσβασης</string>
|
||||
<string name="hint_title">όνομα</string>
|
||||
<string name="hint_url">διεύθυνση url</string>
|
||||
<string name="hint_username">όνομα χρήστη</string>
|
||||
|
||||
@@ -60,7 +60,7 @@ Spanish translation by José I. Paños. Updated by David García-Abad (23-09-201
|
||||
<string name="entry_confpassword">Confirmar contraseña:</string>
|
||||
<string name="entry_created">Creación: </string>
|
||||
<string name="entry_expires">Caducidad: </string>
|
||||
<string name="entry_keyfile">Archivo de clave (opcional)</string>
|
||||
<string name="entry_keyfile">Archivo de clave</string>
|
||||
<string name="entry_modified">Modificación: </string>
|
||||
<string name="entry_password">Contraseña:</string>
|
||||
<string name="entry_save">Guardar</string>
|
||||
@@ -79,7 +79,7 @@ Spanish translation by José I. Paños. Updated by David García-Abad (23-09-201
|
||||
<string name="error_invalid_db">Base de datos no válida.</string>
|
||||
<string name="error_invalid_path">Ruta no válida.</string>
|
||||
<string name="error_no_name">Se necesita un nombre.</string>
|
||||
<string name="error_nopass">Se necesita una contraseña o un archivo de clave.</string>
|
||||
<string name="error_nokeyfile">Se necesita una contraseña o un archivo de clave.</string>
|
||||
<string name="error_out_of_memory">El dispositivo se quedó sin memory mientras analizada la base de datos. Puede ser demasiado grande para este dispositivo.</string>
|
||||
<string name="error_pass_gen_type">Debe seleccionar al menos un tipo de generación de contraseñas</string>
|
||||
<string name="error_pass_match">Las contraseñas no coinciden.</string>
|
||||
@@ -97,7 +97,7 @@ Spanish translation by José I. Paños. Updated by David García-Abad (23-09-201
|
||||
<string name="hint_group_name">Nombre de grupo</string>
|
||||
<string name="hint_keyfile">archivo clave</string>
|
||||
<string name="hint_length">longitud</string>
|
||||
<string name="hint_login_pass">Contraseña</string>
|
||||
<string name="password">Contraseña</string>
|
||||
<string name="hint_pass">contraseña</string>
|
||||
<string name="hint_title">nombre</string>
|
||||
<string name="hint_url">url</string>
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
<string name="entry_confpassword">Pasahitza berretsi:</string>
|
||||
<string name="entry_created">Sortua: </string>
|
||||
<string name="entry_expires">Iraungitzen da: </string>
|
||||
<string name="entry_keyfile">Gako fitxategia (aukerazkoa)</string>
|
||||
<string name="entry_keyfile">Gako fitxategia</string>
|
||||
<string name="entry_modified">Aldatua: </string>
|
||||
<string name="entry_not_found">Sarreraren datuak ez aurkituak.</string>
|
||||
<string name="entry_password">Pasahitza:</string>
|
||||
@@ -85,7 +85,7 @@
|
||||
<string name="error_invalid_db">Datubase baliogabea.</string>
|
||||
<string name="error_invalid_path">Fitxategirako bide baliogabea.</string>
|
||||
<string name="error_no_name">Izen bat behar da.</string>
|
||||
<string name="error_nopass">Pasahitz edo gako fitxategi bat beharrezkoak dira.</string>
|
||||
<string name="error_nokeyfile">Pasahitz edo gako fitxategi bat beharrezkoak dira.</string>
|
||||
<string name="error_out_of_memory">Telefonoa memoriarik gabe gelditu da zure datubasea arakatzean. Handiegia izan daiteke zure telefonorako.</string>
|
||||
<string name="error_pass_gen_type">Pasahitza sortzeko mota bat gutxienez aukeratu behar da</string>
|
||||
<string name="error_pass_match">Pasahitzak ez datoz bat.</string>
|
||||
@@ -107,7 +107,7 @@
|
||||
<string name="hint_keyfile">gako fitxategia</string>
|
||||
<string name="hint_length">luzera</string>
|
||||
<string name="hint_pass">pasahitza</string>
|
||||
<string name="hint_login_pass">Pasahitza</string>
|
||||
<string name="password">Pasahitza</string>
|
||||
<string name="hint_title">izena</string>
|
||||
<string name="hint_url">url</string>
|
||||
<string name="hint_username">erabiltzaile izena</string>
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
<string name="entry_confpassword">Vahvista salasana:</string>
|
||||
<string name="entry_created">Luotu: </string>
|
||||
<string name="entry_expires">Vanhenee: </string>
|
||||
<string name="entry_keyfile">Avaintiedosto (valinnainen)</string>
|
||||
<string name="entry_keyfile">Avaintiedosto</string>
|
||||
<string name="entry_modified">Muokattu: </string>
|
||||
<string name="entry_not_found">Tietueen tietoja ei löytynyt.</string>
|
||||
<string name="entry_password">Salasana:</string>
|
||||
@@ -83,7 +83,7 @@
|
||||
<string name="error_invalid_db">Viallinen salasanatietokanta.</string>
|
||||
<string name="error_invalid_path">Viallinen hakemistopolku.</string>
|
||||
<string name="error_no_name">Nimi puuttuu.</string>
|
||||
<string name="error_nopass">Salasana tai avaintiedosto puuttuu.</string>
|
||||
<string name="error_nokeyfile">Salasana tai avaintiedosto puuttuu.</string>
|
||||
<string name="error_out_of_memory">Puhelimesta loppui muisti salasanatietokantaa avatessa. Tietokanta voi olla liian suuri tälle puhelinmallille.</string>
|
||||
<string name="error_pass_gen_type">Vähintään yksi salasanagenerointitapa täytyy olla valittuna.</string>
|
||||
<string name="error_pass_match">Salasanat eivät täsmää.</string>
|
||||
@@ -105,7 +105,7 @@
|
||||
<string name="hint_keyfile">avaintiedosto</string>
|
||||
<string name="hint_length">pituus</string>
|
||||
<string name="hint_pass">salasana</string>
|
||||
<string name="hint_login_pass">Salasana</string>
|
||||
<string name="password">Salasana</string>
|
||||
<string name="hint_title">nimi</string>
|
||||
<string name="hint_url">url-osoite</string>
|
||||
<string name="hint_username">käyttäjänimi</string>
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
<string name="entry_confpassword">Confirmer mot de passe</string>
|
||||
<string name="entry_created">Créé</string>
|
||||
<string name="entry_expires">Expire</string>
|
||||
<string name="entry_keyfile">Clé (facultative)</string>
|
||||
<string name="entry_keyfile">Fichier clé</string>
|
||||
<string name="entry_modified">Modifié</string>
|
||||
<string name="entry_not_found">Entry data not found.</string>
|
||||
<string name="entry_password">Mot de passe</string>
|
||||
@@ -86,12 +86,12 @@
|
||||
<string name="error_invalid_db">Base de données invalide.</string>
|
||||
<string name="error_invalid_path">Chemin invalide.</string>
|
||||
<string name="error_no_name">Le nom est obligatoire.</string>
|
||||
<string name="error_nopass">Un mot de passe ou clé de fichier est requis.</string>
|
||||
<string name="error_nokeyfile">Un fichier clé est requis.</string>
|
||||
<string name="error_out_of_memory">Votre appareil ne dispose pas de suffisamment de mémoire pour ouvrir votre base de données. Elle est probablement trop grosse pour votre appareil.</string>
|
||||
<string name="error_pass_gen_type">Au moins un type de génération de mot de passe doit être sélectionné</string>
|
||||
<string name="error_pass_match">Les mots de passe ne correspondent pas.</string>
|
||||
<string name="error_rounds_not_number">La série doit être un nombre.</string>
|
||||
<string name="error_rounds_too_large">Rounds too big. Setting to 2147483648.</string>
|
||||
<string name="error_rounds_too_large">Niveau trop gros. Paramètres à 2147483648.</string>
|
||||
<string name="error_string_key">A field name is required for each string.</string>
|
||||
<string name="error_title_required">Le titre est obligatoire.</string>
|
||||
<string name="error_wrong_length">Entrez un entier positif pour la longueur du champ</string>
|
||||
@@ -109,7 +109,7 @@
|
||||
<string name="hint_keyfile">clé de fichier</string>
|
||||
<string name="hint_length">longueur</string>
|
||||
<string name="hint_pass">mot de passe</string>
|
||||
<string name="hint_login_pass">Mot de passe</string>
|
||||
<string name="password">Mot de passe</string>
|
||||
<string name="hint_title">nom</string>
|
||||
<string name="hint_url">URL</string>
|
||||
<string name="hint_username">nom d\'utilisateur</string>
|
||||
@@ -172,6 +172,9 @@
|
||||
<string name="rounds">Niveau du chiffrement</string>
|
||||
<string name="rounds_explaination">Un niveau de chiffrement supérieur assure une protection supplémentaire contre les attaques de force brute, mais peut considérablement ralentir l\'ouverture et l\'enregistrement.</string>
|
||||
<string name="rounds_hint">niveaux</string>
|
||||
<string name="rounds_fix_title">Résolution de la base de données</string>
|
||||
<string name="rounds_fix">Clé de niveau de chiffrement avant corruption</string>
|
||||
<string name="rounds_fix_explanation">Si votre base de données a été corrompue par KeePassDroid version 2.2.0.0 à 2.2.0.6, entrez le niveau de chiffrement utilisé précédemment et cela vous permettra d\'ouvrir votre base.</string>
|
||||
<string name="saving_database">Enregistrement de la base de données…</string>
|
||||
<string name="space">Espace</string>
|
||||
<string name="search_label">Rechercher</string>
|
||||
@@ -191,6 +194,8 @@
|
||||
<string name="warning_password_encoding">Le format .kdb ne supporte que le jeu de caractère Latin1. Votre mot de passe doit contenir des caractères en dehors de ce jeu. Tous les caractères non-Latin1 sont convertis en un même caractère, ce qui diminue la sécurité de votre mot de passe. Le changement de votre mot de passe est recommandé.</string>
|
||||
<string name="warning_read_only">Votre carte SD est actuellement en lecture seule. Vous ne pourrez pas enregistrer les changements dans la base de données.</string>
|
||||
<string name="warning_unmounted">Votre carte SD n\'est actuellement pas montée sur votre appareil. Vous ne pourrez pas charger ou créer votre base de données.</string>
|
||||
<string name="warning_empty_password">Voulez-vous vraiment utiliser une chaine de caractères vide comme mot de passe ?</string>
|
||||
<string name="warning_no_encryption_key">Etes-vous sûr de ne vouloir utiliser aucune clé de chiffrement.</string>
|
||||
<string name="version_label">Version\u00A0:</string>
|
||||
<string name="configure_fingerprint">Reconnaissance d\'empreinte digitale non configuré pour cet appareil</string>
|
||||
<string name="scanning_fingerprint">Attente d\'une reconnaissance d\'empreinte digitale</string>
|
||||
@@ -199,6 +204,32 @@
|
||||
<string name="fingerprint_error">Problème d\'empreinte digitale</string>
|
||||
<string name="store_with_fingerprint">Utiliser l\'empreinte digitale pour stocker le mot de passe</string>
|
||||
<string name="no_password_stored">Pas de mot de passe encore stocké pour cette base de données</string>
|
||||
<string name="history">Historique</string>
|
||||
<string name="appearance">Apparence</string>
|
||||
<string name="general">Générale</string>
|
||||
<string name="password_size_title">Taille de mot de passe</string>
|
||||
<string name="password_size_summary">Définir la taille par défaut du mot de passe généré</string>
|
||||
<string name="list_password_generator_options_title">Caractères de mot de passe</string>
|
||||
<string name="list_password_generator_options_summary">Définir les caractères par défaut du générateur de mot de passe</string>
|
||||
<string name="clipboard_notifications_title">Notifications du presse-papiers</string>
|
||||
<string name="clipboard_notifications_summary">Activer les notifications du presse-papiers pour copier le nom d\'utilisateur et le mot de passe</string>
|
||||
<string name="lock_database_screen_off_title">Verrouillage d\'écran</string>
|
||||
<string name="lock_database_screen_off_summary">Verrouiller la base de données quand l\'écran est éteint</string>
|
||||
<string name="fingerprint_quick_unlock_title">Comment configurer l\'empreinte digitale pour un déverrouillage rapide?</string>
|
||||
<string name="fingerprint_setting_text">Définissez votre empreinte digitale personnelle pour votre appareil dans </string>
|
||||
<string name="fingerprint_setting_way_text">Paramètres -> Sécurité -> Empreinte digitale</string>
|
||||
<string name="fingerprint_type_password_text">Tapez votre mot de passe dans Keepass DX</string>
|
||||
<string name="fingerprint_scan_to_store">Scannez votre empreinte digitale pour stocker votre mot de passe maître en toute sécurité</string>
|
||||
<string name="fingerprint_scan_to_open">Il suffit de scanner votre empreinte digitale dans Keepass DX lorsque le champ mot de passe est vide pour ouvrir la base de données</string>
|
||||
<string name="usage">Usage</string>
|
||||
<string name="fingerprint">Empreinte digitale</string>
|
||||
<string name="fingerprint_enable_title">Écoute d\'empreintes digitales</string>
|
||||
<string name="fingerprint_enable_summary">Activer l\'ouverture de la base de données par empreinte digitale</string>
|
||||
<string name="unavailable_feature_text">Impossible de démarrer cette fonctionnalité\nVotre version Android %1$d n\'est pas la version minimale %2$d requise</string>
|
||||
<string name="file_name">Nom de fichier</string>
|
||||
<string name="path">Chemin</string>
|
||||
<string name="assign_master_key">Assigner une clé maître</string>
|
||||
<string name="create_keepass_file">Créer un fichier keepass</string>
|
||||
|
||||
<string-array name="clipboard_timeout_options">
|
||||
<item>30 secondes</item>
|
||||
@@ -218,7 +249,5 @@
|
||||
<item>Light Theme</item>
|
||||
<item>Night Theme</item>
|
||||
</string-array>
|
||||
<string name="history">Historique</string>
|
||||
<string name="appearance">Apparence</string>
|
||||
<string name="general">Générale</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -1,4 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2009-2016 Brian Pellin.
|
||||
|
||||
This file is part of KeePassDroid.
|
||||
KeePassDroid is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
KeePassDroid is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<resources>
|
||||
<string name="about_feedback">Visszajelzés:</string>
|
||||
<string name="about_homepage">Weboldal:</string>
|
||||
@@ -35,7 +50,7 @@
|
||||
<string name="decrypting_entry">Bejegyzés dekódolása</string>
|
||||
<string name="default_checkbox">Adatbázis beállítása alapértelmezettként</string>
|
||||
<string name="digits">Számok</string>
|
||||
<string name="disclaimer_formal">KeePass DX Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft. Ehhez a programhoz SEMMILYEN GARANCIA NEM JÁR; Ez egy szabad szoftver, GNU General Public License v2 vagy későbbi verziójának feltételei mellett terjeszthető, illetve módosítható. Fordította: intel</string>
|
||||
<string name="disclaimer_formal">KeePass DX Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft. Ehhez a programhoz SEMMILYEN GARANCIA NEM JÁR; Ez egy szabad szoftver, GNU General Public License v2 vagy későbbi verziójának feltételei mellett terjeszthető, illetve módosítható. Fordította: Eversmann</string>
|
||||
<string name="ellipsis">…</string>
|
||||
<string name="enter_filename">Adja meg az adatbázis fájlnevét:</string>
|
||||
<string name="entry_accessed">Utolsó hozzáférés:</string>
|
||||
@@ -45,7 +60,7 @@
|
||||
<string name="entry_confpassword">Jelszó megerősítése:</string>
|
||||
<string name="entry_created">Létrehozva:</string>
|
||||
<string name="entry_expires">Lejárat:</string>
|
||||
<string name="entry_keyfile">Kulcsfájl (opcionális)</string>
|
||||
<string name="entry_keyfile">Kulcsfájl</string>
|
||||
<string name="entry_modified">Módosítva:</string>
|
||||
<string name="entry_password">Jelszó:</string>
|
||||
<string name="entry_save">Mentés</string>
|
||||
@@ -63,19 +78,20 @@
|
||||
<string name="error_file_not_create">Nem sikerült létrehozni a fájlt:</string>
|
||||
<string name="error_invalid_db">Érvénytelen adatbázis.</string>
|
||||
<string name="error_invalid_path">Érvénytelen útvonal.</string>
|
||||
<string name="error_no_name">Egy névre van szükség.</string>
|
||||
<string name="error_nopass">Jelszóra vagy kulcsfájlra van szükség.</string>
|
||||
<string name="error_no_name">Név szükséges.</string>
|
||||
<string name="error_nokeyfile">Jelszóra vagy kulcsfájlra van szükség.</string>
|
||||
<string name="error_out_of_memory">A telefon memóriája megtelt az adatbázis feldolgozása közben. Lehet túl sok ez a telefonnak.</string>
|
||||
<string name="error_pass_gen_type">Legalább egy jelszógenerálási típust kell választania</string>
|
||||
<string name="error_pass_match">A jelszavak nem egyeznek meg.</string>
|
||||
<string name="error_rounds_not_number">A mező csak számokat tartalmazhat.</string>
|
||||
<string name="error_rounds_too_large">A menetek száma túl nagy. A maximális 2147483648.</string>
|
||||
<string name="error_string_key">A megnevezés mező kitöltése kötelező.</string>
|
||||
<string name="error_title_required">Cím szükséges.</string>
|
||||
<string name="error_string_key">Az érték mező kitöltése kötelező.</string>
|
||||
<string name="error_title_required">Név szükséges.</string>
|
||||
<string name="error_wrong_length">Írjon be egy pozitív egész számot a hossz mezőbe</string>
|
||||
<string name="field_name">Megnevezés</string>
|
||||
<string name="field_value">Érték</string>
|
||||
<string name="FileNotFound">A fájl nem található.</string>
|
||||
<string name="FileNotFound">A fájl nem található</string>
|
||||
<string name="file_not_found_content">A fájl nem található. Próbálja meg újra megnyitni.</string>
|
||||
<string name="file_browser">Fájlkezelő</string>
|
||||
<string name="generate_password">Jelszó generálás</string>
|
||||
<string name="group">Csoport</string>
|
||||
@@ -86,7 +102,7 @@
|
||||
<string name="hint_keyfile">kulcsfájl</string>
|
||||
<string name="hint_length">hosszúság</string>
|
||||
<string name="hint_pass">jelszó</string>
|
||||
<string name="hint_login_pass">Jelszó</string>
|
||||
<string name="password">Jelszó</string>
|
||||
<string name="hint_title">név</string>
|
||||
<string name="hint_url">url</string>
|
||||
<string name="hint_username">felhasználónév</string>
|
||||
@@ -114,7 +130,7 @@
|
||||
<string name="menu_db_settings">Adatbázis beállítások</string>
|
||||
<string name="menu_delete">Törlés</string>
|
||||
<string name="menu_donate">Támogatás</string>
|
||||
<string name="menu_edit">Szerkeszt</string>
|
||||
<string name="menu_edit">Szerkesztés</string>
|
||||
<string name="menu_hide_password">Jelszó elrejtése</string>
|
||||
<string name="menu_homepage">Weboldal megtekintése</string>
|
||||
<string name="menu_lock">Adatbázis lezárása</string>
|
||||
@@ -132,10 +148,15 @@
|
||||
<string name="omitbackup_title">Keresési kivételek</string>
|
||||
<string name="omitbackup_summary">A Backup és Lomtár csoportok kihagyása a keresésből</string>
|
||||
<string name="pass_filename">KeePass adatbázis fájlnév:</string>
|
||||
<string name="password_title">Adatbázis jelszó megadása</string>
|
||||
<string name="password_title">Adatbázis jelszó</string>
|
||||
<string name="progress_create">Új adatbázis létrehozása…</string>
|
||||
<string name="progress_title">Feldolgozás…</string>
|
||||
<string name="protection">Memórián belüli védelem</string>
|
||||
<string name="read_only">Csak olvasható</string>
|
||||
<string name="read_only_warning">A programnak nincs engedélye az adatbázis írásához a jelenlegi helyén, ezért a megnyitása után csak olvasható lesz.</string>
|
||||
<string name="read_only_kitkat_warning">A KitKat-es android verziótól kezdődően a futó alkalmazásoknak nincs jogosultságuk írni a külső SD kártyára.</string>
|
||||
<string name="recentfile_title">Adatbázis mentése</string>
|
||||
<string name="recentfile_summary">Jegyezze meg az adatbázisok helyét</string>
|
||||
<string name="remember_keyfile_summary">Jegyezze meg a kulcsfájlok helyét</string>
|
||||
<string name="remember_keyfile_title">Kulcsfájl mentése</string>
|
||||
<string name="remove_from_filelist">Eltávolítás</string>
|
||||
@@ -151,15 +172,26 @@
|
||||
<string name="sort_name">Rendezés név alapján</string>
|
||||
<string name="sort_db">Rendezés dátum alapján</string>
|
||||
<string name="special">Speciális</string>
|
||||
<string name="search_hint">Bejegyzés cím/leírás</string>
|
||||
<string name="search_hint">Bejegyzés név/leírás</string>
|
||||
<string name="search_results">Keresés eredménye</string>
|
||||
<string name="twofish">Twofish</string>
|
||||
<string name="underline">Aláhúzás</string>
|
||||
<string name="unsupported_db_version">Nem támogatott adatbázis.</string>
|
||||
<string name="uppercase">Nagybetűk</string>
|
||||
<string name="use_saf_summary">Használja az Android Storage Access Framework-öt a fájlok böngészéséhez (KitKat vagy későbbi)</string>
|
||||
<string name="use_saf_title">Storage Access Framework</string>
|
||||
<string name="warning">Figyelmeztetés</string>
|
||||
<string name="warning_password_encoding">A .kdb formátum csak a Latin1 karakterkészletet támogatja. A jelenlegi jelszó olyan karaktereket is tartalmazhat, amik ezen kívül esnek. Az összes ilyen karakter át lesz lesz konvertálva, viszont ez nagyban csökkenteni fogja a jelszó erősségét. Mielőbbi megváltoztatása ajánlott.</string>
|
||||
<string name="warning_read_only">A memóriakártya jelenleg csak olvasható. Lehet, hogy nem tudja menteni a módosításokat az adatbázisban.</string>
|
||||
<string name="warning_unmounted">A memóriakártya jelenleg el van távolítva. Nem fogja tudni az adatbázist betölteni vagy módosítani.</string>
|
||||
<string name="version_label">Verzió:</string>
|
||||
<string name="configure_fingerprint">Az ujjlenyomat használat nincs még beállítva az eszközön</string>
|
||||
<string name="scanning_fingerprint">Várakozás az ujjelnyomat megadására</string>
|
||||
<string name="encrypted_value_stored">Titkosított jelszó elmentve</string>
|
||||
<string name="fingerprint_invalid_key">Érvénytelen kulcs</string>
|
||||
<string name="fingerprint_error">Érvénytelen ujjlenyomat</string>
|
||||
<string name="store_with_fingerprint">Használjon ujjlenyomatot a jelszó elmentéséhez</string>
|
||||
<string name="no_password_stored">Nincs még jelszó beállítva ehhez az adatbázishoz</string>
|
||||
|
||||
<string-array name="clipboard_timeout_options">
|
||||
<item>30 másodperc</item>
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
<string name="entry_confpassword">Conferma password:</string>
|
||||
<string name="entry_created">Creato: </string>
|
||||
<string name="entry_expires">Scade: </string>
|
||||
<string name="entry_keyfile">File chiave (opzionale)</string>
|
||||
<string name="entry_keyfile">File chiave</string>
|
||||
<string name="entry_modified">Modificato: </string>
|
||||
<string name="entry_password">Password</string>
|
||||
<string name="entry_save">Salva</string>
|
||||
@@ -80,7 +80,7 @@
|
||||
<string name="error_invalid_db">Database non valido.</string>
|
||||
<string name="error_invalid_path">Percorso non valido.</string>
|
||||
<string name="error_no_name">E\' necessario un nome.</string>
|
||||
<string name="error_nopass">E\' necessaria una password o un file chiave.</string>
|
||||
<string name="error_nokeyfile">E\' necessaria una password o un file chiave.</string>
|
||||
<string name="error_out_of_memory">Il telefono ha esaurito la memoria durante l\'elaborazione del database. Potrebbe essere troppo grande per il tuo telefono.</string>
|
||||
<string name="error_pass_gen_type">Almeno un tipo di generazione password deve essere selezionato</string>
|
||||
<string name="error_pass_match">Le password non corrispondono.</string>
|
||||
@@ -98,7 +98,7 @@
|
||||
<string name="hint_group_name">Nome gruppo</string>
|
||||
<string name="hint_keyfile">file chiave</string>
|
||||
<string name="hint_length">lunghezza</string>
|
||||
<string name="hint_login_pass">Password</string>
|
||||
<string name="password">Password</string>
|
||||
<string name="hint_pass">password</string>
|
||||
<string name="hint_title">nome</string>
|
||||
<string name="hint_url">url</string>
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<string name="entry_confpassword">אשר סיסמה:</string>
|
||||
<string name="entry_created">תאריך יצירה: </string>
|
||||
<string name="entry_expires">פג תוקף: </string>
|
||||
<string name="entry_keyfile">קובץ מפתח (רשות)</string>
|
||||
<string name="entry_keyfile">קובץ מפתח</string>
|
||||
<string name="entry_modified">נערך לאחרונה: </string>
|
||||
<string name="entry_not_found">נתוני ערך לא נמצאו.</string>
|
||||
<string name="entry_password">סיסמה:</string>
|
||||
@@ -81,7 +81,7 @@
|
||||
<string name="error_invalid_db">מסד נתונים לא חוקי.</string>
|
||||
<string name="error_invalid_path">נתיב לא חוקי.</string>
|
||||
<string name="error_no_name">שם נדרש.</string>
|
||||
<string name="error_nopass">סיסמה או קובץ מפתח נדרשים.</string>
|
||||
<string name="error_nokeyfile">סיסמה או קובץ מפתח נדרשים.</string>
|
||||
<string name="error_out_of_memory">זיכרון המכשיר אזל בזמן ניתוח מסד הנתונים. יתכן והוא גדול מדי למכשירך.</string>
|
||||
<string name="error_pass_gen_type">לפחות סוג אחד ליצירת סיסמה צריך להיבחר</string>
|
||||
<string name="error_pass_match">הסיסמאות לא תואמות.</string>
|
||||
@@ -103,7 +103,7 @@
|
||||
<string name="hint_keyfile">קובץ המפתח</string>
|
||||
<string name="hint_length">אורך</string>
|
||||
<string name="hint_pass">סיסמה</string>
|
||||
<string name="hint_login_pass">סיסמה</string>
|
||||
<string name="password">סיסמה</string>
|
||||
<string name="hint_title">שם</string>
|
||||
<string name="hint_username">שם משתמש</string>
|
||||
<string name="install_from_market">התקן מחנות Play</string>
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
<string name="entry_confpassword">パスワードの確認:</string>
|
||||
<string name="entry_created">作成日: </string>
|
||||
<string name="entry_expires">有効期限: </string>
|
||||
<string name="entry_keyfile">キーファイル(オプション)</string>
|
||||
<string name="entry_keyfile">キーファイル</string>
|
||||
<string name="entry_modified">更新日: </string>
|
||||
<string name="entry_password">パスワード:</string>
|
||||
<string name="entry_save">保存</string>
|
||||
@@ -77,7 +77,7 @@
|
||||
<string name="error_invalid_db">無効なデータベースです。</string>
|
||||
<string name="error_invalid_path">パスが無効です。</string>
|
||||
<string name="error_no_name">タイトルは必須入力です。</string>
|
||||
<string name="error_nopass">パスワードかキーファイルが必要です。</string>
|
||||
<string name="error_nokeyfile">パスワードかキーファイルが必要です。</string>
|
||||
<string name="error_out_of_memory">データベース解析中にメモリ不足になりました。</string>
|
||||
<string name="error_pass_gen_type">少なくとも1つ以上のパスワード生成タイプを選択する必要があります。</string>
|
||||
<string name="error_pass_match">パスワードが一致しません</string>
|
||||
@@ -95,7 +95,7 @@
|
||||
<string name="hint_group_name">グループ名</string>
|
||||
<string name="hint_keyfile">キーファイル</string>
|
||||
<string name="hint_length">長さ</string>
|
||||
<string name="hint_login_pass">パスワード</string>
|
||||
<string name="password">パスワード</string>
|
||||
<string name="hint_pass">パスワード</string>
|
||||
<string name="hint_title">タイトル</string>
|
||||
<string name="hint_url">url</string>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<string name="entry_confpassword">Apstipriniet paroli:</string>
|
||||
<string name="entry_created">Izveidots:</string>
|
||||
<string name="entry_expires">Derīguma termiņš beidzas:</string>
|
||||
<string name="entry_keyfile">Atslēgas fails (pēc izvēles)</string>
|
||||
<string name="entry_keyfile">Atslēgas fails</string>
|
||||
<string name="entry_modified">Modificēts:</string>
|
||||
<string name="entry_password">Parole:</string>
|
||||
<string name="entry_save">Saglabāt</string>
|
||||
@@ -64,7 +64,7 @@
|
||||
<string name="error_invalid_db">Nederīga datu bāze.</string>
|
||||
<string name="error_invalid_path">Nederīgs ceļš.</string>
|
||||
<string name="error_no_name">Vajag ievadīt faila nosaukumu</string>
|
||||
<string name="error_nopass">Vajadzīga parole vai atslēgas fails.</string>
|
||||
<string name="error_nokeyfile">Vajadzīga parole vai atslēgas fails.</string>
|
||||
<string name="error_out_of_memory">Darbam ar datu bāzi, tālrunī nepietiek atmiņas.</string>
|
||||
<string name="error_pass_gen_type">Ir jāatlasa vismaz viens paroles ģenerēšanas tips</string>
|
||||
<string name="error_pass_match">Paroles nesakrīt.</string>
|
||||
@@ -86,7 +86,7 @@
|
||||
<string name="hint_keyfile">atslēgas fails</string>
|
||||
<string name="hint_length">garums</string>
|
||||
<string name="hint_pass">parole</string>
|
||||
<string name="hint_login_pass">Parole</string>
|
||||
<string name="password">Parole</string>
|
||||
<string name="hint_title">vārds</string>
|
||||
<string name="hint_url">url</string>
|
||||
<string name="hint_username">lietotājvārds</string>
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
<string name="entry_confpassword">Bevestig wachtwoord:</string>
|
||||
<string name="entry_created">Aangemaakt op: </string>
|
||||
<string name="entry_expires">Verloopt op: </string>
|
||||
<string name="entry_keyfile">Sleutelbestand (optioneel)</string>
|
||||
<string name="entry_keyfile">Sleutelbestand</string>
|
||||
<string name="entry_modified">Gewijzigd op: </string>
|
||||
<string name="entry_password">Wachtwoord:</string>
|
||||
<string name="entry_save">Opslaan</string>
|
||||
@@ -79,7 +79,7 @@
|
||||
<string name="error_invalid_db">Ongeldige database.</string>
|
||||
<string name="error_invalid_path">Ongeldige padnaam.</string>
|
||||
<string name="error_no_name">Een naam ontbreekt.</string>
|
||||
<string name="error_nopass">Een wachtwoord of sleutenbestand ontbreekt.</string>
|
||||
<string name="error_nokeyfile">Een wachtwoord of sleutenbestand ontbreekt.</string>
|
||||
<string name="error_out_of_memory">Onvoldoende vrij geheugen om de database te lezen. Misschien is de database te groot voor deze telefoon.</string>
|
||||
<string name="error_pass_gen_type">U moet minstens één type van wachtwoordgeneratie kiezen.</string>
|
||||
<string name="error_pass_match">Wachtwoorden zijn niet gelijk.</string>
|
||||
@@ -97,7 +97,7 @@
|
||||
<string name="hint_group_name">Groepnaam</string>
|
||||
<string name="hint_keyfile">sleutelbestand</string>
|
||||
<string name="hint_length">lengte</string>
|
||||
<string name="hint_login_pass">Wachtwoord</string>
|
||||
<string name="password">Wachtwoord</string>
|
||||
<string name="hint_pass">wachtwoord</string>
|
||||
<string name="hint_title">naam</string>
|
||||
<string name="hint_url">url</string>
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
<string name="entry_confpassword">Stadfest passordet:</string>
|
||||
<string name="entry_created">Laga: </string>
|
||||
<string name="entry_expires">Går ut: </string>
|
||||
<string name="entry_keyfile">Nøkkelfil (valfri)</string>
|
||||
<string name="entry_keyfile">Nøkkelfil</string>
|
||||
<string name="entry_modified">Endra: </string>
|
||||
<string name="entry_password">Passord:</string>
|
||||
<string name="entry_save">Lagra</string>
|
||||
@@ -77,7 +77,7 @@
|
||||
<string name="error_invalid_db">Ugyldig database.</string>
|
||||
<string name="error_invalid_path">Ugyldig stig.</string>
|
||||
<string name="error_no_name">Treng eit namn.</string>
|
||||
<string name="error_nopass">Treng eit passord eller ei nøkkelfil.</string>
|
||||
<string name="error_nokeyfile">Treng eit passord eller ei nøkkelfil.</string>
|
||||
<string name="error_out_of_memory">Telefonen gjekk tom for minne ved lesinga av databasen din. Databasen er kanskje for stor.</string>
|
||||
<string name="error_pass_gen_type">Du må velja minst éin passordlagingstype</string>
|
||||
<string name="error_pass_match">Passorda samsvarer ikkje.</string>
|
||||
@@ -95,7 +95,7 @@
|
||||
<string name="hint_group_name">Gruppenamn</string>
|
||||
<string name="hint_keyfile">nøkkelfil</string>
|
||||
<string name="hint_length">lengd</string>
|
||||
<string name="hint_login_pass">Passord</string>
|
||||
<string name="password">Passord</string>
|
||||
<string name="hint_pass">passord</string>
|
||||
<string name="hint_title">namn</string>
|
||||
<string name="hint_url">adresse</string>
|
||||
|
||||
@@ -56,7 +56,7 @@ along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
<string name="entry_confpassword">Potwierdź hasło:</string>
|
||||
<string name="entry_created">Utworzono: </string>
|
||||
<string name="entry_expires">Wygasa: </string>
|
||||
<string name="entry_keyfile">Plik klucza (opcjonalnie)</string>
|
||||
<string name="entry_keyfile">Plik klucza</string>
|
||||
<string name="entry_modified">Zmodyfikowano: </string>
|
||||
<string name="entry_password">Hasło</string>
|
||||
<string name="entry_save">Zapisz</string>
|
||||
@@ -75,7 +75,7 @@ along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
<string name="error_invalid_db">Nieprawidłowa baza danych.</string>
|
||||
<string name="error_invalid_path">Nieprawidłowa ścieżka dostępu.</string>
|
||||
<string name="error_no_name">Wymagana nazwa.</string>
|
||||
<string name="error_nopass">Wymagane hasło lub plik klucza.</string>
|
||||
<string name="error_nokeyfile">Wymagane hasło lub plik klucza.</string>
|
||||
<string name="error_out_of_memory">Podczas parsowania bazy danych zabrakło pamięci. Być może ta baza danych jest za duża dla Twojego urządzenia.</string>
|
||||
<string name="error_pass_gen_type">Przynajmniej jeden sposób generowania hasła musi być wybrany</string>
|
||||
<string name="error_pass_match">Hasła nie pasują do siebie.</string>
|
||||
@@ -93,7 +93,7 @@ along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
<string name="hint_group_name">Nazwa grupy</string>
|
||||
<string name="hint_keyfile">plik klucza</string>
|
||||
<string name="hint_length">długość</string>
|
||||
<string name="hint_login_pass">Hasło</string>
|
||||
<string name="password">Hasło</string>
|
||||
<string name="hint_pass">hasło</string>
|
||||
<string name="hint_title">nazwa</string>
|
||||
<string name="hint_url">url</string>
|
||||
@@ -134,10 +134,14 @@ along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
<string name="no_results">Brak wyników wyszukiwania</string>
|
||||
<string name="no_url_handler">Brak obsługi dla tego urla.</string>
|
||||
<string name="open_recent">Otwórz ostatnio używaną bazę danych (kliknij by otworzyć):</string>
|
||||
<string name="omitbackup_title">Nie wyszukuj zapasowych wpisów</string>
|
||||
<string name="omitbackup_summary">Pomiń kopię zapasową grupy z wyników wyszukiwania (dotyczy tylko .kdb)</string>
|
||||
<string name="pass_filename">Nazwa pliku bazy danych KeePass:</string>
|
||||
<string name="password_title">Wprowadź hasło bazy danych</string>
|
||||
<string name="progress_create">Tworzenie nowej bazy danych…</string>
|
||||
<string name="progress_title">Pracuję…</string>
|
||||
<string name="recentfile_title">Najnowsza historia plików</string>
|
||||
<string name="recentfile_summary">Zapamiętaj ostatnio uzywane nazwy plików</string>
|
||||
<string name="remember_keyfile_summary">Zapamiętaj lokację plików kluczy</string>
|
||||
<string name="remember_keyfile_title">Zapisz plik klucza</string>
|
||||
<string name="remove_from_filelist">Usuń</string>
|
||||
@@ -145,6 +149,8 @@ along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
<string name="root">Root</string>
|
||||
<string name="rounds">Złożoność szyfrowania</string>
|
||||
<string name="rounds_explaination">Większa złożoność szyfrowania zapewnia dodatkowe zabezpieczenie przed atakiem brute force, ale może spowolnić wczytywanie i zapisywanie bazy danych.</string>
|
||||
<string name="rounds_fix">Kluczowe rundy szyfrowania przed zniszczeniem</string>
|
||||
<string name="rounds_fix_explanation">Jeśli twoja baza danych została uszkodzona przez KeePassDroid w wersji 2.2.0.0 do 2.2.0.6, wprowadź liczbę rund użytych poprzednio, a to pozwoli ci otworzyć twoją bazę danych.</string>
|
||||
<string name="rounds_hint">złożoność</string>
|
||||
<string name="saving_database">Zapisywanie bazy danych…</string>
|
||||
<string name="space">Spacja</string>
|
||||
@@ -158,6 +164,8 @@ along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
<string name="underline">Podkreślenie</string>
|
||||
<string name="unsupported_db_version">Nieobsługiwana wersja bazy danych.</string>
|
||||
<string name="uppercase">Wielkie litery</string>
|
||||
<string name="use_saf_summary">Użyj przeglądarki Android Storage Access Framework do przeglądania plików (KitKat i nowsze)</string>
|
||||
<string name="use_saf_title">Storage Access Framework</string>
|
||||
<string name="warning_read_only">Karta SD jest obecnie w trybie tylko do odczytu. Możesz nie być w stanie zapisać zmian w bazie danych.</string>
|
||||
<string name="warning_unmounted">Karta SD nie jest obecnie zamontowana w urządzeniu. Możesz nie być w stanie wczytać lub utworzyć bazy danych.</string>
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
<string name="entry_confpassword">Confirmar senha:</string>
|
||||
<string name="entry_created">Criado: </string>
|
||||
<string name="entry_expires">Expira: </string>
|
||||
<string name="entry_keyfile">Arquivo de chave (opcional)</string>
|
||||
<string name="entry_keyfile">Arquivo de chave</string>
|
||||
<string name="entry_modified">Modificado: </string>
|
||||
<string name="entry_password">Senha:</string>
|
||||
<string name="entry_save">Salvar</string>
|
||||
@@ -80,7 +80,7 @@
|
||||
<string name="error_invalid_db">Banco de dados inválido.</string>
|
||||
<string name="error_invalid_path">Caminho inválido.</string>
|
||||
<string name="error_no_name">É necessário um nome.</string>
|
||||
<string name="error_nopass">São necessários uma senha ou um arquivo de chaves.</string>
|
||||
<string name="error_nokeyfile">São necessários uma senha ou um arquivo de chaves.</string>
|
||||
<string name="error_out_of_memory">Foi atingida a capacidade máxima de memória do seu dispositivo ao carregar o banco de dados. O banco de dados pode ser muito grande para este dispositivo.</string>
|
||||
<string name="error_pass_gen_type">Pelo menos um tipo de geração de senhas deve ser selecionado</string>
|
||||
<string name="error_pass_match">As senhas não combinam.</string>
|
||||
@@ -98,7 +98,7 @@
|
||||
<string name="hint_group_name">Nome do Grupo</string>
|
||||
<string name="hint_keyfile">arquivo de chave</string>
|
||||
<string name="hint_length">tamanho</string>
|
||||
<string name="hint_login_pass">Senha</string>
|
||||
<string name="password">Senha</string>
|
||||
<string name="hint_pass">senha</string>
|
||||
<string name="hint_title">nome</string>
|
||||
<string name="hint_url">url</string>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user