Merge branch 'feature/Unexpected_Lock' into develop

This commit is contained in:
J-Jamet
2018-12-19 12:07:28 +01:00
50 changed files with 544 additions and 552 deletions

View File

@@ -1,4 +1,6 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 27
@@ -81,6 +83,7 @@ def spongycastleVersion = "1.58.0.0"
def permissionDispatcherVersion = "3.1.0"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "com.android.support:appcompat-v7:$supportVersion"
implementation "com.android.support:design:$supportVersion"
implementation "com.android.support:preference-v7:$supportVersion"

View File

@@ -47,13 +47,13 @@ import com.kunzisoft.keepass.database.ExtraFields;
import com.kunzisoft.keepass.database.PwDatabase;
import com.kunzisoft.keepass.database.PwEntry;
import com.kunzisoft.keepass.database.security.ProtectedString;
import com.kunzisoft.keepass.lock.LockingActivity;
import com.kunzisoft.keepass.lock.LockingHideActivity;
import com.kunzisoft.keepass.activities.lock.LockingHideActivity;
import com.kunzisoft.keepass.notifications.NotificationCopyingService;
import com.kunzisoft.keepass.notifications.NotificationField;
import com.kunzisoft.keepass.settings.PreferencesUtil;
import com.kunzisoft.keepass.settings.SettingsAutofillActivity;
import com.kunzisoft.keepass.timeout.ClipboardHelper;
import com.kunzisoft.keepass.timeout.TimeoutHelper;
import com.kunzisoft.keepass.utils.EmptyUtils;
import com.kunzisoft.keepass.utils.MenuUtil;
import com.kunzisoft.keepass.utils.Types;
@@ -85,12 +85,12 @@ public class EntryActivity extends LockingHideActivity {
private int iconColor;
public static void launch(Activity act, PwEntry pw, boolean readOnly) {
if (LockingActivity.checkTimeIsAllowedOrFinish(act)) {
Intent intent = new Intent(act, EntryActivity.class);
public static void launch(Activity activity, PwEntry pw, boolean readOnly) {
if (TimeoutHelper.INSTANCE.checkTime(activity)) {
Intent intent = new Intent(activity, EntryActivity.class);
intent.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pw.getUUID()));
ReadOnlyHelper.putReadOnlyInIntent(intent, readOnly);
act.startActivityForResult(intent, EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
activity.startActivityForResult(intent, EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
}
}
@@ -113,7 +113,7 @@ public class EntryActivity extends LockingHideActivity {
finish();
return;
}
readOnly = db.isReadOnly() || readOnly;
setReadOnly(db.isReadOnly() || getReadOnly());
mShowPassword = !PreferencesUtil.isPasswordMask(this);
@@ -428,7 +428,7 @@ public class EntryActivity extends LockingHideActivity {
inflater.inflate(R.menu.entry, menu);
inflater.inflate(R.menu.database_lock, menu);
if (readOnly) {
if (getReadOnly()) {
MenuItem edit = menu.findItem(R.id.menu_edit);
if (edit != null)
edit.setVisible(false);

View File

@@ -56,11 +56,11 @@ import com.kunzisoft.keepass.database.action.node.UpdateEntryRunnable;
import com.kunzisoft.keepass.database.security.ProtectedString;
import com.kunzisoft.keepass.dialogs.GeneratePasswordDialogFragment;
import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment;
import com.kunzisoft.keepass.lock.LockingActivity;
import com.kunzisoft.keepass.lock.LockingHideActivity;
import com.kunzisoft.keepass.activities.lock.LockingHideActivity;
import com.kunzisoft.keepass.settings.PreferencesUtil;
import com.kunzisoft.keepass.tasks.SaveDatabaseProgressTaskDialogFragment;
import com.kunzisoft.keepass.tasks.UpdateProgressTaskStatus;
import com.kunzisoft.keepass.timeout.TimeoutHelper;
import com.kunzisoft.keepass.utils.MenuUtil;
import com.kunzisoft.keepass.utils.Types;
import com.kunzisoft.keepass.utils.Util;
@@ -113,28 +113,28 @@ public class EntryEditActivity extends LockingHideActivity
/**
* Launch EntryEditActivity to update an existing entry
*
* @param act from activity
* @param pw Entry to update
* @param activity from activity
* @param pwEntry Entry to update
*/
public static void launch(Activity act, PwEntry pw) {
if (LockingActivity.checkTimeIsAllowedOrFinish(act)) {
Intent intent = new Intent(act, EntryEditActivity.class);
intent.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pw.getUUID()));
act.startActivityForResult(intent, ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
public static void launch(Activity activity, PwEntry pwEntry) {
if (TimeoutHelper.INSTANCE.checkTime(activity)) {
Intent intent = new Intent(activity, EntryEditActivity.class);
intent.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pwEntry.getUUID()));
activity.startActivityForResult(intent, ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
}
}
/**
* Launch EntryEditActivity to add a new entry
*
* @param act from activity
* @param activity from activity
* @param pwGroup Group who will contains new entry
*/
public static void launch(Activity act, PwGroup pwGroup) {
if (LockingActivity.checkTimeIsAllowedOrFinish(act)) {
Intent intent = new Intent(act, EntryEditActivity.class);
public static void launch(Activity activity, PwGroup pwGroup) {
if (TimeoutHelper.INSTANCE.checkTime(activity)) {
Intent intent = new Intent(activity, EntryEditActivity.class);
intent.putExtra(KEY_PARENT, pwGroup.getId());
act.startActivityForResult(intent, ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
activity.startActivityForResult(intent, ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
}
}
@@ -149,17 +149,28 @@ public class EntryEditActivity extends LockingHideActivity
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
scrollView = findViewById(R.id.entry_scroll);
scrollView = findViewById(R.id.entry_edit_scroll);
scrollView.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
entryTitleView = findViewById(R.id.entry_title);
entryIconView = findViewById(R.id.icon_button);
entryUserNameView = findViewById(R.id.entry_user_name);
entryUrlView = findViewById(R.id.entry_url);
entryPasswordView = findViewById(R.id.entry_password);
entryConfirmationPasswordView = findViewById(R.id.entry_confpassword);
entryCommentView = findViewById(R.id.entry_comment);
entryExtraFieldsContainer = findViewById(R.id.advanced_container);
entryTitleView = findViewById(R.id.entry_edit_title);
entryIconView = findViewById(R.id.entry_edit_icon_button);
entryUserNameView = findViewById(R.id.entry_edit_user_name);
entryUrlView = findViewById(R.id.entry_edit_url);
entryPasswordView = findViewById(R.id.entry_edit_password);
entryConfirmationPasswordView = findViewById(R.id.entry_edit_confirmation_password);
entryCommentView = findViewById(R.id.entry_edit_notes);
entryExtraFieldsContainer = findViewById(R.id.entry_edit_advanced_container);
// Focus view to reinitialize timeout
resetAppTimeoutWhenViewFocusedOrChanged(
entryTitleView,
entryIconView,
entryUserNameView,
entryUrlView,
entryPasswordView,
entryConfirmationPasswordView,
entryCommentView,
entryExtraFieldsContainer);
// Likely the app has been killed exit the activity
database = App.getDB();
@@ -207,16 +218,16 @@ public class EntryEditActivity extends LockingHideActivity
IconPickerDialogFragment.launch(EntryEditActivity.this));
// Generate password button
generatePasswordView = findViewById(R.id.generate_button);
generatePasswordView = findViewById(R.id.entry_edit_generate_button);
generatePasswordView.setOnClickListener(v -> openPasswordGenerator());
// Save button
saveView = findViewById(R.id.entry_save);
saveView = findViewById(R.id.entry_edit_save);
saveView.setOnClickListener(v -> saveEntry());
if (mEntry.allowExtraFields()) {
addNewFieldView = findViewById(R.id.add_new_field);
addNewFieldView = findViewById(R.id.entry_edit_add_new_field);
addNewFieldView.setVisibility(View.VISIBLE);
addNewFieldView.setOnClickListener(v -> addNewCustomField());
}
@@ -510,7 +521,7 @@ public class EntryEditActivity extends LockingHideActivity
}
if (mEntry.allowExtraFields()) {
LinearLayout container = findViewById(R.id.advanced_container);
LinearLayout container = findViewById(R.id.entry_edit_advanced_container);
mEntry.getFields().doActionToAllCustomProtectedField((key, value) -> {
EntryEditCustomField entryEditCustomField = new EntryEditCustomField(EntryEditActivity.this);
entryEditCustomField.setData(key, value);

View File

@@ -80,13 +80,14 @@ import com.kunzisoft.keepass.dialogs.GroupEditDialogFragment;
import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment;
import com.kunzisoft.keepass.dialogs.ReadOnlyDialog;
import com.kunzisoft.keepass.dialogs.SortDialogFragment;
import com.kunzisoft.keepass.lock.LockingActivity;
import com.kunzisoft.keepass.activities.lock.LockingActivity;
import com.kunzisoft.keepass.password.AssignPasswordHelper;
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
import com.kunzisoft.keepass.settings.PreferencesUtil;
import com.kunzisoft.keepass.tasks.SaveDatabaseProgressTaskDialogFragment;
import com.kunzisoft.keepass.tasks.UIToastTask;
import com.kunzisoft.keepass.tasks.UpdateProgressTaskStatus;
import com.kunzisoft.keepass.timeout.TimeoutHelper;
import com.kunzisoft.keepass.utils.MenuUtil;
import com.kunzisoft.keepass.view.AddNodeButtonView;
@@ -144,13 +145,13 @@ public class GroupActivity extends LockingActivity
}
public static void launch(Activity act, boolean readOnly) {
startRecordTime(act);
TimeoutHelper.INSTANCE.recordTime(act);
launch(act, null, readOnly);
}
private static void buildAndLaunchIntent(Activity activity, PwGroup group, boolean readOnly,
IntentBuildLauncher intentBuildLauncher) {
if (checkTimeIsAllowedOrFinish(activity)) {
if (TimeoutHelper.INSTANCE.checkTime(activity)) {
Intent intent = new Intent(activity, GroupActivity.class);
if (group != null) {
intent.putExtra(GROUP_ID_KEY, group.getId());
@@ -165,9 +166,9 @@ public class GroupActivity extends LockingActivity
(intent) -> activity.startActivityForResult(intent, 0));
}
public static void launchForKeyboardResult(Activity act, boolean readOnly) {
startRecordTime(act);
launchForKeyboardResult(act, null, readOnly);
public static void launchForKeyboardResult(Activity activity, boolean readOnly) {
TimeoutHelper.INSTANCE.recordTime(activity);
launchForKeyboardResult(activity, null, readOnly);
}
public static void launchForKeyboardResult(Activity activity, PwGroup group, boolean readOnly) {
@@ -179,12 +180,12 @@ public class GroupActivity extends LockingActivity
}
@RequiresApi(api = Build.VERSION_CODES.O)
public static void launchForAutofillResult(Activity act, AssistStructure assistStructure, boolean readOnly) {
public static void launchForAutofillResult(Activity activity, AssistStructure assistStructure, boolean readOnly) {
if ( assistStructure != null ) {
startRecordTime(act);
launchForAutofillResult(act, null, assistStructure, readOnly);
TimeoutHelper.INSTANCE.recordTime(activity);
launchForAutofillResult(activity, null, assistStructure, readOnly);
} else {
launch(act, readOnly);
launch(activity, readOnly);
}
}
@@ -228,10 +229,13 @@ public class GroupActivity extends LockingActivity
toolbarPasteExpandableLayout = findViewById(R.id.expandable_toolbar_paste_layout);
toolbarPaste = findViewById(R.id.toolbar_paste);
// Focus view to reinitialize timeout
resetAppTimeoutWhenViewFocusedOrChanged(addNodeButtonView);
invalidateOptionsMenu();
// Get arg from intent or instance state
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrIntent(savedInstanceState, getIntent());
setReadOnly(ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrIntent(savedInstanceState, getIntent()));
// Retrieve elements after an orientation change
if (savedInstanceState != null) {
@@ -282,7 +286,7 @@ public class GroupActivity extends LockingActivity
listNodesFragment = (ListNodesFragment) getSupportFragmentManager()
.findFragmentByTag(fragmentTag);
if (listNodesFragment == null)
listNodesFragment = ListNodesFragment.newInstance(mCurrentGroup, readOnly, currentGroupIsASearch);
listNodesFragment = ListNodesFragment.newInstance(mCurrentGroup, getReadOnly(), currentGroupIsASearch);
// Attach fragment to content view
getSupportFragmentManager().beginTransaction().replace(
@@ -340,35 +344,34 @@ public class GroupActivity extends LockingActivity
}
private void openGroup(PwGroup group, boolean isASearch) {
// Check Timeout
if (checkTimeIsAllowedOrFinish(this)) {
startRecordTime(this);
// Check TimeoutHelper
TimeoutHelper.INSTANCE.resetTime(this, () -> {
// Open a group in a new fragment
ListNodesFragment newListNodeFragment = ListNodesFragment.newInstance(group, getReadOnly(), isASearch);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
// Different animation
String fragmentTag;
if (isASearch) {
fragmentTransaction.setCustomAnimations(R.anim.slide_in_top, R.anim.slide_out_bottom,
R.anim.slide_in_bottom, R.anim.slide_out_top);
fragmentTag = SEARCH_FRAGMENT_TAG;
} else {
fragmentTransaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left,
R.anim.slide_in_left, R.anim.slide_out_right);
fragmentTag = LIST_NODES_FRAGMENT_TAG;
}
// Open a group in a new fragment
ListNodesFragment newListNodeFragment = ListNodesFragment.newInstance(group, readOnly, isASearch);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
// Different animation
String fragmentTag;
if (isASearch) {
fragmentTransaction.setCustomAnimations(R.anim.slide_in_top, R.anim.slide_out_bottom,
R.anim.slide_in_bottom, R.anim.slide_out_top);
fragmentTag = SEARCH_FRAGMENT_TAG;
} else {
fragmentTransaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left,
R.anim.slide_in_left, R.anim.slide_out_right);
fragmentTag = LIST_NODES_FRAGMENT_TAG;
}
fragmentTransaction.replace(R.id.nodes_list_fragment_container,
newListNodeFragment,
fragmentTag);
fragmentTransaction.addToBackStack(fragmentTag);
fragmentTransaction.commit();
fragmentTransaction.replace(R.id.nodes_list_fragment_container,
newListNodeFragment,
fragmentTag);
fragmentTransaction.addToBackStack(fragmentTag);
fragmentTransaction.commit();
listNodesFragment = newListNodeFragment;
mCurrentGroup = group;
assignGroupViewElements();
}
listNodesFragment = newListNodeFragment;
mCurrentGroup = group;
assignGroupViewElements();
return null;
});
}
@Override
@@ -380,7 +383,7 @@ public class GroupActivity extends LockingActivity
outState.putParcelable(NODE_TO_COPY_KEY, nodeToCopy);
if (nodeToMove != null)
outState.putParcelable(NODE_TO_MOVE_KEY, nodeToMove);
ReadOnlyHelper.onSaveInstanceState(outState, readOnly);
ReadOnlyHelper.onSaveInstanceState(outState, getReadOnly());
super.onSaveInstanceState(outState);
}
@@ -401,7 +404,7 @@ public class GroupActivity extends LockingActivity
pwGroupId = intent.getParcelableExtra(GROUP_ID_KEY);
}
readOnly = database.isReadOnly() || readOnly; // Force read only if the database is like that
setReadOnly(database.isReadOnly() || getReadOnly()); // Force read only if the database is like that
Log.w(TAG, "Creating tree view");
PwGroup currentGroup;
@@ -463,8 +466,8 @@ public class GroupActivity extends LockingActivity
if (addNodeButtonView != null) {
// To enable add button
boolean addGroupEnabled = !readOnly && !currentGroupIsASearch;
boolean addEntryEnabled = !readOnly && !currentGroupIsASearch;
boolean addGroupEnabled = !getReadOnly() && !currentGroupIsASearch;
boolean addEntryEnabled = !getReadOnly() && !currentGroupIsASearch;
if (mCurrentGroup != null) {
boolean isRoot = (mCurrentGroup == rootGroup);
if (!mCurrentGroup.allowAddEntryIfIsRoot())
@@ -524,7 +527,7 @@ public class GroupActivity extends LockingActivity
openChildGroup((PwGroup) node);
break;
case ENTRY:
EntryActivity.launch(this, (PwEntry) node, readOnly);
EntryActivity.launch(this, (PwEntry) node, getReadOnly());
break;
}
}
@@ -858,7 +861,7 @@ public class GroupActivity extends LockingActivity
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.search, menu);
if (!readOnly)
if (!getReadOnly())
inflater.inflate(R.menu.database_master_key, menu);
inflater.inflate(R.menu.database_lock, menu);
@@ -945,7 +948,7 @@ public class GroupActivity extends LockingActivity
return true;
case R.id.menu_lock:
lockAndExit();
lockAndExit();
return true;
case R.id.menu_change_master_key:
@@ -953,7 +956,7 @@ public class GroupActivity extends LockingActivity
return true;
default:
// Check the time lock before launching settings
MenuUtil.onDefaultMenuOptionsItemSelected(this, item, readOnly, true);
MenuUtil.onDefaultMenuOptionsItemSelected(this, item, getReadOnly(), true);
return super.onOptionsItemSelected(item);
}
}
@@ -1197,17 +1200,13 @@ public class GroupActivity extends LockingActivity
@Override
public void onBackPressed() {
if (checkTimeIsAllowedOrFinish(this)) {
startRecordTime(this);
super.onBackPressed();
super.onBackPressed();
listNodesFragment = (ListNodesFragment) getSupportFragmentManager().findFragmentByTag(LIST_NODES_FRAGMENT_TAG);
// to refresh fragment
listNodesFragment.rebuildList();
mCurrentGroup = listNodesFragment.getMainGroup();
removeSearchInIntent(getIntent());
assignGroupViewElements();
}
listNodesFragment = (ListNodesFragment) getSupportFragmentManager().findFragmentByTag(LIST_NODES_FRAGMENT_TAG);
// to refresh fragment
listNodesFragment.rebuildList();
mCurrentGroup = listNodesFragment.getMainGroup();
removeSearchInIntent(getIntent());
assignGroupViewElements();
}
}

View File

@@ -0,0 +1,159 @@
/*
* 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 3 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.kunzisoft.keepass.activities.lock
import android.app.Activity
import android.app.NotificationManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import android.util.Log
import android.view.View
import com.kunzisoft.keepass.activities.ReadOnlyHelper
import com.kunzisoft.keepass.app.App
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.stylish.StylishActivity
import com.kunzisoft.keepass.timeout.TimeoutHelper
abstract class LockingActivity : StylishActivity() {
companion object {
const val LOCK_ACTION = "com.kunzisoft.keepass.LOCK"
const val RESULT_EXIT_LOCK = 1450
}
private var lockReceiver: LockReceiver? = null
private var exitLock: Boolean = false
protected var readOnly: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (PreferencesUtil.isLockDatabaseWhenScreenShutOffEnable(this)) {
lockReceiver = LockReceiver()
val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_SCREEN_OFF)
intentFilter.addAction(LOCK_ACTION)
registerReceiver(lockReceiver, IntentFilter(intentFilter))
} else
lockReceiver = null
exitLock = false
readOnly = false
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrIntent(savedInstanceState, intent)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_EXIT_LOCK) {
exitLock = true
checkShutdown()
}
}
override fun onResume() {
super.onResume()
// After the first creation
// or If simply swipe with another application
// If the time is out -> close the Activity
TimeoutHelper.checkTime(this)
// If onCreate already record time
if (!exitLock)
TimeoutHelper.recordTime(this)
}
override fun onSaveInstanceState(outState: Bundle) {
ReadOnlyHelper.onSaveInstanceState(outState, readOnly)
super.onSaveInstanceState(outState)
}
override fun onPause() {
super.onPause()
// If the time is out during our navigation in activity -> close the Activity
TimeoutHelper.checkTime(this)
}
override fun onDestroy() {
super.onDestroy()
if (lockReceiver != null)
unregisterReceiver(lockReceiver)
}
inner class LockReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
if (action != null) {
when (action) {
Intent.ACTION_SCREEN_OFF -> if (PreferencesUtil.isLockDatabaseWhenScreenShutOffEnable(this@LockingActivity)) {
lockAndExit()
}
LOCK_ACTION -> lockAndExit()
}
}
}
}
protected fun lockAndExit() {
lock()
}
private fun checkShutdown() {
if (App.isShutdown() && App.getDB().loaded) {
lockAndExit()
}
}
/**
* To reset the app timeout when a view is focused or changed
*/
protected fun resetAppTimeoutWhenViewFocusedOrChanged(vararg views: View) {
views.forEach {
it.setOnFocusChangeListener { _, hasFocus ->
if (hasFocus) {
TimeoutHelper.resetTime(this)
}
}
}
}
override fun onBackPressed() {
TimeoutHelper.resetTime(this) {
super.onBackPressed()
}
}
}
fun Activity.lock() {
App.setShutdown()
Log.i(Activity::class.java.name, "Shutdown " + localClassName +
" after inactivity or manual lock")
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).apply {
cancelAll()
}
setResult(LockingActivity.RESULT_EXIT_LOCK)
finish()
}

View File

@@ -0,0 +1,55 @@
/*
* 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 3 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.kunzisoft.keepass.activities.lock
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Bundle
import android.view.WindowManager
/**
* Locking Hide Activity that sets FLAG_SECURE to prevent screenshots, and from
* appearing in the recent app preview
*/
abstract class LockingHideActivity : LockingActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Several gingerbread devices have problems with FLAG_SECURE
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
}
/* (non-Javadoc) Workaround for HTC Linkify issues
* @see android.app.Activity#startActivity(android.content.Intent)
*/
override fun startActivity(intent: Intent) {
try {
if (intent.component != null && intent.component!!.shortClassName == ".HtcLinkifyDispatcherActivity") {
intent.component = null
}
super.startActivity(intent)
} catch (e: ActivityNotFoundException) {
/* Catch the bad HTC implementation case */
super.startActivity(Intent.createChooser(intent, null))
}
}
}

View File

@@ -109,8 +109,8 @@ public class GroupEditDialogFragment extends DialogFragment
assert getActivity() != null;
LayoutInflater inflater = getActivity().getLayoutInflater();
View root = inflater.inflate(R.layout.group_edit, null);
TextView nameField = root.findViewById(R.id.group_name);
iconButton = root.findViewById(R.id.icon_button);
TextView nameField = root.findViewById(R.id.group_edit_name);
iconButton = root.findViewById(R.id.group_edit_icon_button);
// Retrieve the textColor to tint the icon
int[] attrs = {android.R.attr.textColorPrimary};

View File

@@ -1,163 +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 3 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.kunzisoft.keepass.lock;
import android.app.Activity;
import android.app.NotificationManager;
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 android.util.Log;
import com.kunzisoft.keepass.activities.ReadOnlyHelper;
import com.kunzisoft.keepass.app.App;
import com.kunzisoft.keepass.settings.PreferencesUtil;
import com.kunzisoft.keepass.stylish.StylishActivity;
import com.kunzisoft.keepass.timeout.TimeoutHelper;
public abstract class LockingActivity extends StylishActivity {
private static final String TAG = LockingActivity.class.getName();
public static final String LOCK_ACTION = "com.kunzisoft.keepass.LOCK";
public static final int RESULT_EXIT_LOCK = 1450;
private LockReceiver lockReceiver;
private boolean exitLock;
protected boolean readOnly;
/**
* Called to start a record time,
* Generally used for a first launch or for a fragment change
*/
protected static void startRecordTime(Activity activity) {
TimeoutHelper.recordTime(activity);
}
protected static boolean checkTimeIsAllowedOrFinish(Activity activity) {
return TimeoutHelper.checkTime(activity);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (PreferencesUtil.isLockDatabaseWhenScreenShutOffEnable(this)) {
lockReceiver = new LockReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
intentFilter.addAction(LOCK_ACTION);
registerReceiver(lockReceiver, new IntentFilter(intentFilter));
} else
lockReceiver = null;
exitLock = false;
readOnly = false;
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrIntent(savedInstanceState, getIntent());
}
public static void checkShutdown(Activity activity) {
if (App.isShutdown() && App.getDB().getLoaded()) {
lockAndExit(activity);
}
}
private static void lockAndExit(Activity activity) {
App.setShutdown();
Log.i(TAG, "Shutdown " + activity.getLocalClassName() +
" after inactivity or manual lock");
NotificationManager nm = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE);
if (nm != null)
nm.cancelAll();
activity.setResult(LockingActivity.RESULT_EXIT_LOCK);
activity.finish();
}
protected void lockAndExit() {
lockAndExit(this);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_EXIT_LOCK) {
exitLock = true;
checkShutdown(this);
}
}
@Override
protected void onResume() {
super.onResume();
// After the first creation
// or If simply swipe with another application
// If the time is out -> close the Activity
TimeoutHelper.checkTime(this);
// If onCreate already record time
if (!exitLock)
TimeoutHelper.recordTime(this);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
ReadOnlyHelper.onSaveInstanceState(outState, readOnly);
super.onSaveInstanceState(outState);
}
@Override
protected void onPause() {
super.onPause();
// If the time is out during our navigation in activity -> close the Activity
TimeoutHelper.checkTime(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
if(lockReceiver != null)
unregisterReceiver(lockReceiver);
}
public class LockReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action != null) {
switch (action) {
case Intent.ACTION_SCREEN_OFF:
if (PreferencesUtil.isLockDatabaseWhenScreenShutOffEnable(LockingActivity.this)) {
lockAndExit();
}
break;
case LOCK_ACTION:
lockAndExit();
break;
}
}
}
}
}

View File

@@ -1,56 +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 3 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.kunzisoft.keepass.lock;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.Bundle;
import android.view.WindowManager;
/**
* Locking Hide Activity that sets FLAG_SECURE to prevent screenshots, and from
* appearing in the recent app preview
*/
public abstract class LockingHideActivity extends LockingActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Several gingerbread devices have problems with FLAG_SECURE
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
}
/* (non-Javadoc) Workaround for HTC Linkify issues
* @see android.app.Activity#startActivity(android.content.Intent)
*/
@Override
public void startActivity(Intent intent) {
try {
if (intent.getComponent() != null && intent.getComponent().getShortClassName().equals(".HtcLinkifyDispatcherActivity")) {
intent.setComponent(null);
}
super.startActivity(intent);
} catch (ActivityNotFoundException e) {
/* Catch the bad HTC implementation case */
super.startActivity(Intent.createChooser(intent, null));
}
}
}

View File

@@ -69,7 +69,7 @@ import com.kunzisoft.keepass.fileselect.KeyFileHelper;
import com.kunzisoft.keepass.fingerprint.FingerPrintAnimatedVector;
import com.kunzisoft.keepass.fingerprint.FingerPrintExplanationDialog;
import com.kunzisoft.keepass.fingerprint.FingerPrintHelper;
import com.kunzisoft.keepass.lock.LockingActivity;
import com.kunzisoft.keepass.activities.lock.LockingActivity;
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
import com.kunzisoft.keepass.settings.PreferencesUtil;
import com.kunzisoft.keepass.stylish.StylishActivity;

View File

@@ -24,7 +24,7 @@ import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import com.kunzisoft.keepass.R;
import com.kunzisoft.keepass.lock.LockingActivity;
import com.kunzisoft.keepass.activities.lock.LockingActivity;
public class MagikIMESettings extends LockingActivity {

View File

@@ -29,7 +29,8 @@ import android.view.MenuItem;
import com.kunzisoft.keepass.R;
import com.kunzisoft.keepass.activities.ReadOnlyHelper;
import com.kunzisoft.keepass.lock.LockingActivity;
import com.kunzisoft.keepass.activities.lock.LockingActivity;
import com.kunzisoft.keepass.timeout.TimeoutHelper;
public class SettingsActivity extends LockingActivity implements MainPreferenceFragment.Callback {
@@ -50,7 +51,7 @@ public class SettingsActivity extends LockingActivity implements MainPreferenceF
// To avoid flickering when launch settings in a LockingActivity
if (!checkLock)
launch(activity, readOnly);
else if (LockingActivity.checkTimeIsAllowedOrFinish(activity)) {
else if (TimeoutHelper.INSTANCE.checkTime(activity)) {
launch(activity, readOnly);
}
}
@@ -116,7 +117,7 @@ public class SettingsActivity extends LockingActivity implements MainPreferenceF
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left,
R.anim.slide_in_left, R.anim.slide_out_right)
.replace(R.id.fragment_container, NestedSettingsFragment.newInstance(key, readOnly), TAG_NESTED)
.replace(R.id.fragment_container, NestedSettingsFragment.newInstance(key, getReadOnly()), TAG_NESTED)
.addToBackStack(TAG_NESTED)
.commit();

View File

@@ -1,78 +0,0 @@
/*
* Copyright 2018 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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.kunzisoft.keepass.timeout;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import com.kunzisoft.keepass.R;
import com.kunzisoft.keepass.lock.LockingActivity;
public class Timeout {
private static final int REQUEST_ID = 0;
private static final long DEFAULT_TIMEOUT = 5 * 60 * 1000; // 5 minutes
private static String TAG = "KeePass Timeout";
private static PendingIntent buildIntent(Context ctx) {
Intent intent = new Intent(LockingActivity.LOCK_ACTION);
return PendingIntent.getBroadcast(ctx, REQUEST_ID, intent, PendingIntent.FLAG_CANCEL_CURRENT);
}
public static void start(Context ctx) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
String sTimeout = prefs.getString(ctx.getString(R.string.app_timeout_key), ctx.getString(R.string.clipboard_timeout_default));
long timeout;
try {
timeout = Long.parseLong(sTimeout);
} catch (NumberFormatException e) {
timeout = DEFAULT_TIMEOUT;
}
if ( timeout == -1 ) {
// No timeout don't start timeout service
return;
}
long triggerTime = System.currentTimeMillis() + timeout;
AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
Log.d(TAG, "Timeout start");
if (am != null) {
am.set(AlarmManager.RTC, triggerTime, buildIntent(ctx));
}
}
public static void cancel(Context ctx) {
AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
Log.d(TAG, "Timeout cancel");
if (am != null) {
am.cancel(buildIntent(ctx));
}
}
}

View File

@@ -1,91 +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 3 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.kunzisoft.keepass.timeout;
import android.app.Activity;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import com.kunzisoft.keepass.R;
import com.kunzisoft.keepass.lock.LockingActivity;
import com.kunzisoft.keepass.app.App;
public class TimeoutHelper {
private static final String TAG = "TimeoutHelper";
public static final long DEFAULT_TIMEOUT = 5 * 60 * 1000; // 5 minutes
public static final long TIMEOUT_NEVER = -1; // Infinite
public static void recordTime(Activity act) {
// Record timeout time in case timeout service is killed
long time = System.currentTimeMillis();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(act);
SharedPreferences.Editor edit = prefs.edit();
edit.putLong(act.getString(R.string.timeout_key), time);
edit.apply();
if ( App.getDB().getLoaded() ) {
Timeout.start(act);
}
}
public static boolean checkTime(Activity act) {
if ( App.getDB().getLoaded() ) {
Timeout.cancel(act);
}
// Check whether the timeout has expired
long cur_time = System.currentTimeMillis();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(act);
long timeout_start = prefs.getLong(act.getString(R.string.timeout_key), TIMEOUT_NEVER);
// The timeout never started
if (timeout_start == TIMEOUT_NEVER) {
return true;
}
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);
} catch (NumberFormatException e) {
timeout = DEFAULT_TIMEOUT;
}
// We are set to never timeout
if (timeout == TIMEOUT_NEVER) {
return true;
}
long diff = cur_time - timeout_start;
if (diff >= timeout) {
// We have timed out
if ( App.getDB().getLoaded() ) {
App.setShutdown(act.getString(R.string.app_timeout));
LockingActivity.checkShutdown(act);
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright 2018 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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.kunzisoft.keepass.timeout
import android.app.Activity
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.preference.PreferenceManager
import android.util.Log
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.lock.LockingActivity
import com.kunzisoft.keepass.activities.lock.lock
import com.kunzisoft.keepass.app.App
object TimeoutHelper {
const val DEFAULT_TIMEOUT = (5 * 60 * 1000).toLong() // 5 minutes
const val TIMEOUT_NEVER: Long = -1 // Infinite
private const val REQUEST_ID = 140
private const val TAG = "TimeoutHelper"
private fun getLockPendingIntent(context: Context): PendingIntent {
return PendingIntent.getBroadcast(context,
REQUEST_ID,
Intent(LockingActivity.LOCK_ACTION),
PendingIntent.FLAG_CANCEL_CURRENT)
}
/**
* Record the current time to check it later with checkTime
*/
fun recordTime(context: Context) {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
// Record timeout time in case timeout service is killed
val time = System.currentTimeMillis()
val edit = prefs.edit()
edit.putLong(context.getString(R.string.timeout_backup_key), time)
edit.apply()
if (App.getDB().loaded) {
val timeout = try {
java.lang.Long.parseLong(prefs.getString(context.getString(R.string.app_timeout_key),
context.getString(R.string.clipboard_timeout_default)))
} catch (e: NumberFormatException) {
DEFAULT_TIMEOUT
}
// No timeout don't start timeout service
if (timeout != TIMEOUT_NEVER) {
val triggerTime = System.currentTimeMillis() + timeout
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
Log.d(TAG, "TimeoutHelper start")
am.set(AlarmManager.RTC, triggerTime, getLockPendingIntent(context))
}
}
}
/**
* Check the time previously record with recordTime and lock the activity if timeout
*/
fun checkTime(activity: Activity): Boolean {
return checkTime(activity) {
if (App.isShutdown() && App.getDB().loaded)
activity.lock()
}
}
/**
* Check the time previously record with recordTime and do the shutdown action if timeout
*/
fun checkTime(context: Context, shutdown: (() -> Unit)): Boolean {
// Cancel the lock PendingIntent
if (App.getDB().loaded) {
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
Log.d(TAG, "TimeoutHelper cancel")
am.cancel(getLockPendingIntent(context))
}
// Check whether the timeout has expired
val currentTime = System.currentTimeMillis()
// Retrieve the timeout programmatically backup
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val timeoutBackup = prefs.getLong(context.getString(R.string.timeout_backup_key),
TIMEOUT_NEVER)
// The timeout never started
if (timeoutBackup == TIMEOUT_NEVER) {
return true
}
// Retrieve the app timeout in settings
val appTimeout = try {
java.lang.Long.parseLong(prefs.getString(context.getString(R.string.app_timeout_key),
context.getString(R.string.clipboard_timeout_default)))
} catch (e: NumberFormatException) {
DEFAULT_TIMEOUT
}
// We are set to never timeout
if (appTimeout == TIMEOUT_NEVER) {
return true
}
// See if not a timeout
val diff = currentTime - timeoutBackup
if (diff >= appTimeout) {
// We have timed out
if (App.getDB().loaded) {
App.setShutdown(context.getString(R.string.app_timeout))
shutdown.invoke()
return false
}
}
return true
}
fun resetTime(activity: Activity, action: (() -> Unit)? = null) {
if (checkTime(activity)) {
recordTime(activity)
action?.invoke()
}
}
}

View File

@@ -104,8 +104,8 @@ public class EntryContentsView extends LinearLayout {
urlContainerView = findViewById(R.id.entry_url_container);
urlView = findViewById(R.id.entry_url);
commentContainerView = findViewById(R.id.entry_comment_container);
commentView = findViewById(R.id.entry_comment);
commentContainerView = findViewById(R.id.entry_notes_container);
commentView = findViewById(R.id.entry_notes);
extrasView = findViewById(R.id.extra_strings);

View File

@@ -30,7 +30,7 @@
layout="@layout/toolbar_default" />
<ScrollView
android:id="@+id/entry_scroll"
android:id="@+id/entry_edit_scroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/toolbar"
@@ -52,11 +52,11 @@
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@+id/icon_button"
android:layout_toStartOf="@+id/icon_button">
android:layout_toLeftOf="@+id/entry_edit_icon_button"
android:layout_toStartOf="@+id/entry_edit_icon_button">
<android.support.v7.widget.AppCompatEditText
android:id="@+id/entry_title"
android:id="@+id/entry_edit_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
@@ -66,7 +66,7 @@
</android.support.design.widget.TextInputLayout>
<android.support.v7.widget.AppCompatImageButton
android:id="@+id/icon_button"
android:id="@+id/entry_edit_icon_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="4dp"
@@ -81,7 +81,7 @@
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatEditText
android:id="@+id/entry_user_name"
android:id="@+id/entry_edit_user_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
@@ -96,17 +96,17 @@
android:layout_height="wrap_content">
<android.support.design.widget.TextInputLayout
android:id="@+id/container_entry_password"
android:id="@+id/entry_edit_container_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:passwordToggleEnabled="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@+id/generate_button"
android:layout_toStartOf="@+id/generate_button">
android:layout_toLeftOf="@+id/entry_edit_generate_button"
android:layout_toStartOf="@+id/entry_edit_generate_button">
<android.support.v7.widget.AppCompatEditText
android:id="@+id/entry_password"
android:id="@+id/entry_edit_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
@@ -122,12 +122,12 @@
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
app:passwordToggleEnabled="true"
android:layout_toLeftOf="@+id/generate_button"
android:layout_toStartOf="@+id/generate_button"
android:layout_below="@+id/container_entry_password">
android:layout_toLeftOf="@+id/entry_edit_generate_button"
android:layout_toStartOf="@+id/entry_edit_generate_button"
android:layout_below="@+id/entry_edit_container_password">
<android.support.v7.widget.AppCompatEditText
android:id="@+id/entry_confpassword"
android:id="@+id/entry_edit_confirmation_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
@@ -137,7 +137,7 @@
</android.support.design.widget.TextInputLayout>
<android.support.v7.widget.AppCompatImageView
android:id="@+id/generate_button"
android:id="@+id/entry_edit_generate_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
@@ -154,7 +154,7 @@
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatEditText
android:id="@+id/entry_url"
android:id="@+id/entry_edit_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textUri"
@@ -168,25 +168,25 @@
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatEditText
android:id="@+id/entry_comment"
android:id="@+id/entry_edit_notes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:lines="4"
android:maxLines="10"
android:inputType="textMultiLine"
android:hint="@string/entry_comment" />
android:hint="@string/entry_notes" />
</android.support.design.widget.TextInputLayout>
<LinearLayout
android:id="@+id/advanced_container"
android:id="@+id/entry_edit_advanced_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</LinearLayout>
<ImageView
android:id="@+id/add_new_field"
android:id="@+id/entry_edit_add_new_field"
android:layout_width="30sp"
android:layout_height="30sp"
android:contentDescription="@string/add_string"
@@ -198,7 +198,7 @@
</ScrollView >
<android.support.design.widget.FloatingActionButton
android:id="@+id/entry_save"
android:id="@+id/entry_edit_save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"

View File

@@ -17,7 +17,8 @@
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"
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_margin="@dimen/default_margin"
android:id="@+id/entry_table"
android:layout_height="wrap_content"
@@ -103,12 +104,14 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<android.support.v7.widget.AppCompatTextView android:id="@+id/entry_url_label"
<android.support.v7.widget.AppCompatTextView
android:id="@+id/entry_url_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/entry_url"
style="@style/KeepassDXStyle.TextAppearance.LabelTextStyle" />
<android.support.v7.widget.AppCompatTextView android:id="@+id/entry_url"
<android.support.v7.widget.AppCompatTextView
android:id="@+id/entry_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoLink="all"
@@ -118,18 +121,20 @@
<!-- Comment -->
<LinearLayout
android:id="@+id/entry_comment_container"
android:id="@+id/entry_notes_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<android.support.v7.widget.AppCompatTextView android:id="@+id/entry_comment_label"
<android.support.v7.widget.AppCompatTextView
android:id="@+id/entry_notes_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/entry_comment"
android:text="@string/entry_notes"
android:autoLink="all"
style="@style/KeepassDXStyle.TextAppearance.LabelTextStyle" />
<android.support.v7.widget.AppCompatTextView android:id="@+id/entry_comment"
<android.support.v7.widget.AppCompatTextView
android:id="@+id/entry_notes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textIsSelectable="true"

View File

@@ -25,7 +25,7 @@
android:importantForAutofill="noExcludeDescendants"
tools:targetApi="o">
<android.support.v7.widget.AppCompatImageButton
android:id="@+id/icon_button"
android:id="@+id/group_edit_icon_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_blank_32dp"
@@ -33,13 +33,13 @@
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"/>
<android.support.v7.widget.AppCompatEditText
android:id="@+id/group_name"
android:id="@+id/group_edit_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:layout_toLeftOf="@+id/icon_button"
android:layout_toStartOf="@+id/icon_button"
android:layout_toLeftOf="@+id/group_edit_icon_button"
android:layout_toStartOf="@+id/group_edit_icon_button"
android:maxLines="1"
android:singleLine="true"
android:hint="@string/hint_group_name"/>

View File

@@ -38,7 +38,7 @@
<string name="decrypting_db">فك تعمية محتويات قاعدة البيانات …</string>
<string name="digits">أرقام</string>
<string name="entry_cancel">إلغاء</string>
<string name="entry_comment">التعليقات</string>
<string name="entry_notes">التعليقات</string>
<string name="entry_confpassword">تأكيد الكلمة السرية</string>
<string name="entry_created">تم إنشاؤه</string>
<string name="entry_modified">معدل</string>

View File

@@ -48,7 +48,7 @@
<string name="select_database_file">Introdueix el nom de la base de dades</string>
<string name="entry_accessed">Accedida</string>
<string name="entry_cancel">Cancel·la</string>
<string name="entry_comment">Comentaris</string>
<string name="entry_notes">Comentaris</string>
<string name="entry_confpassword">Confirma contrasenya</string>
<string name="entry_created">Creada</string>
<string name="entry_expires">Expira</string>

View File

@@ -52,7 +52,7 @@
<string name="select_database_file">Vyberte existující databázi</string>
<string name="entry_accessed">Poslední přístup</string>
<string name="entry_cancel">Storno</string>
<string name="entry_comment">Poznámky</string>
<string name="entry_notes">Poznámky</string>
<string name="entry_confpassword">Potvrďte heslo</string>
<string name="entry_created">Vytvořeno</string>
<string name="entry_expires">Platnost skončí</string>

View File

@@ -51,7 +51,7 @@
<string name="select_database_file">Vælg en eksisterende database</string>
<string name="entry_accessed">Senest åbnet</string>
<string name="entry_cancel">Annuller</string>
<string name="entry_comment">Kommentarer</string>
<string name="entry_notes">Kommentarer</string>
<string name="entry_confpassword">Bekræft adgangskode</string>
<string name="entry_created">Oprettet</string>
<string name="entry_expires">Udløber</string>

View File

@@ -54,7 +54,7 @@
<string name="select_database_file">Dateinamen der Datenbank eingeben</string>
<string name="entry_accessed">Letzter Zugriff</string>
<string name="entry_cancel">Abbrechen</string>
<string name="entry_comment">Kommentare</string>
<string name="entry_notes">Kommentare</string>
<string name="entry_confpassword">Passwort wiederholen</string>
<string name="entry_created">Erstelldatum</string>
<string name="entry_expires">Ablaufdatum</string>

View File

@@ -49,7 +49,7 @@
<string name="select_database_file">Εισαγωγή ονόματος βάσης δεδομένων</string>
<string name="entry_accessed">Προσπελάσθηκε</string>
<string name="entry_cancel">Ακύρωση</string>
<string name="entry_comment">Σχόλια</string>
<string name="entry_notes">Σχόλια</string>
<string name="entry_confpassword">Επιβεβαίωση κωδικού πρόσβασης</string>
<string name="entry_created">Δημιουργήθηκε</string>
<string name="entry_expires">Λήγει</string>

View File

@@ -47,7 +47,7 @@ Spanish translation by José I. Paños. Updated by David García-Abad (23-09-201
<string name="select_database_file">Introduzca el nombre del archivo de base de datos</string>
<string name="entry_accessed">Acceso</string>
<string name="entry_cancel">Cancelar</string>
<string name="entry_comment">Comentario</string>
<string name="entry_notes">Comentario</string>
<string name="entry_confpassword">Confirmar contraseña</string>
<string name="entry_created">Creación</string>
<string name="entry_expires">Caducidad</string>

View File

@@ -51,7 +51,7 @@
<string name="select_database_file">Datubasearen fitxategiaren izena sartu</string>
<string name="entry_accessed">Akzesoa</string>
<string name="entry_cancel">Utzi</string>
<string name="entry_comment">Iruzkinak</string>
<string name="entry_notes">Iruzkinak</string>
<string name="entry_confpassword">Pasahitza berretsi</string>
<string name="entry_created">Sortua</string>
<string name="entry_expires">Iraungitzen da</string>

View File

@@ -49,7 +49,7 @@
<string name="select_database_file">Anna tietokannan tiedostonimi</string>
<string name="entry_accessed">Käytetty</string>
<string name="entry_cancel">Peruuta</string>
<string name="entry_comment">Kommentit</string>
<string name="entry_notes">Kommentit</string>
<string name="entry_confpassword">Vahvista salasana</string>
<string name="entry_created">Luotu</string>
<string name="entry_expires">Vanhenee</string>

View File

@@ -55,7 +55,7 @@
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Kunzisoft n\'offre ABSOLUMENT AUCUNE GARANTIE; il s\'agit d\'un logiciel libre, vous pouvez le redistribuer sous les conditions de la licence GPL v3 ou ultérieure.</string>
<string name="entry_accessed">Dernier accès</string>
<string name="entry_cancel">Annuler</string>
<string name="entry_comment">Commentaires</string>
<string name="entry_notes">Commentaires</string>
<string name="entry_confpassword">Confirmer mot de passe</string>
<string name="entry_created">Créé</string>
<string name="entry_expires">Expire</string>

View File

@@ -46,7 +46,7 @@
<string name="select_database_file">Adja meg az adatbázis fájlnevét</string>
<string name="entry_accessed">Utolsó hozzáférés</string>
<string name="entry_cancel">Mégsem</string>
<string name="entry_comment">Megjegyzés</string>
<string name="entry_notes">Megjegyzés</string>
<string name="entry_confpassword">Jelszó megerősítése</string>
<string name="entry_created">Létrehozva</string>
<string name="entry_expires">Lejárat</string>

View File

@@ -52,7 +52,7 @@
<string name="select_database_file">Seleziona un database esistente</string>
<string name="entry_accessed">Ultimo accesso</string>
<string name="entry_cancel">Annulla</string>
<string name="entry_comment">Commento</string>
<string name="entry_notes">Commento</string>
<string name="entry_confpassword">Conferma password</string>
<string name="entry_created">Creato</string>
<string name="entry_expires">Scade</string>

View File

@@ -49,7 +49,7 @@
<string name="select_database_file">הזן שם קובץ למסד נתונים:</string>
<string name="entry_accessed">ניגש לאחרונה</string>
<string name="entry_cancel">בטל</string>
<string name="entry_comment">הערות</string>
<string name="entry_notes">הערות</string>
<string name="entry_confpassword">אשר סיסמה</string>
<string name="entry_created">תאריך יצירה</string>
<string name="entry_expires">פג תוקף</string>

View File

@@ -45,7 +45,7 @@
<string name="select_database_file">データベースファイル</string>
<string name="entry_accessed">最終アクセス日</string>
<string name="entry_cancel">キャンセル</string>
<string name="entry_comment">備考</string>
<string name="entry_notes">備考</string>
<string name="entry_confpassword">パスワードの確認</string>
<string name="entry_created">作成日</string>
<string name="entry_expires">有効期限</string>

View File

@@ -20,7 +20,7 @@
<string name="database">Duomenų bazė</string>
<string name="digits">Skaitmenys</string>
<string name="entry_cancel">Atšaukti</string>
<string name="entry_comment">Komentarai</string>
<string name="entry_notes">Komentarai</string>
<string name="entry_created">Sukurta</string>
<string name="entry_modified">Keista</string>
<string name="entry_expires">Pasibaigia</string>

View File

@@ -30,7 +30,7 @@
<string name="select_database_file">Ievadiet datu bāzes nosaukumu</string>
<string name="entry_accessed">Piekļuve</string>
<string name="entry_cancel">Atcelt</string>
<string name="entry_comment">Komentāri</string>
<string name="entry_notes">Komentāri</string>
<string name="entry_confpassword">Apstipriniet paroli</string>
<string name="entry_created">Izveidots</string>
<string name="entry_expires">Derīguma termiņš beidzas</string>

View File

@@ -36,7 +36,7 @@
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Kunzisoft kommer UTEN NOEN FORM FOR GARANTI; Dette er fri programvare, og du er velkommen til å redistribuere det i henhold til vilkårene i GPL versjon 3 eller senere.</string>
<string name="entry_accessed">Brukt</string>
<string name="entry_cancel">Avbryt</string>
<string name="entry_comment">Kommentarer</string>
<string name="entry_notes">Kommentarer</string>
<string name="entry_confpassword">Bekreft passord</string>
<string name="entry_created">Opprettet</string>
<string name="entry_expires">Utløper</string>

View File

@@ -47,7 +47,7 @@
<string name="select_database_file">Kies een bestaande databank</string>
<string name="entry_accessed">Laatst geopend</string>
<string name="entry_cancel">Annuleren</string>
<string name="entry_comment">Opmerkingen</string>
<string name="entry_notes">Opmerkingen</string>
<string name="entry_confpassword">Wachtwoord bevestigen</string>
<string name="entry_created">Gecreëerd op</string>
<string name="entry_expires">Verloopt op</string>

View File

@@ -45,7 +45,7 @@
<string name="select_database_file">Skriv filnamnet til databasen</string>
<string name="entry_accessed">Brukt</string>
<string name="entry_cancel">Avbryt</string>
<string name="entry_comment">Merknader</string>
<string name="entry_notes">Merknader</string>
<string name="entry_confpassword">Stadfest passordet</string>
<string name="entry_created">Laga</string>
<string name="entry_expires">Går ut</string>

View File

@@ -43,7 +43,7 @@ along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
<string name="select_database_file">Wprowadź nazwę pliku bazy danych</string>
<string name="entry_accessed">Dostęp do pliku</string>
<string name="entry_cancel">Anuluj</string>
<string name="entry_comment">Komentarz</string>
<string name="entry_notes">Komentarz</string>
<string name="entry_confpassword">Potwierdź hasło</string>
<string name="entry_created">Utworzono</string>
<string name="entry_expires">Wygasa</string>

View File

@@ -48,7 +48,7 @@
<string name="select_database_file">Digite o nome do arquivo de banco de dados</string>
<string name="entry_accessed">Acessado</string>
<string name="entry_cancel">Cancelar</string>
<string name="entry_comment">Comentários</string>
<string name="entry_notes">Comentários</string>
<string name="entry_confpassword">Confirmar senha</string>
<string name="entry_created">Criado</string>
<string name="entry_expires">Expira</string>

View File

@@ -52,7 +52,7 @@
<string name="select_database_file">Introduza o nome do ficheiro da base de dados</string>
<string name="entry_accessed">Acedido</string>
<string name="entry_cancel">Cancelar</string>
<string name="entry_comment">Comentários</string>
<string name="entry_notes">Comentários</string>
<string name="entry_confpassword">Confirmar palavra-passe</string>
<string name="entry_created">Criado</string>
<string name="entry_expires">Expira</string>

View File

@@ -50,7 +50,7 @@
<string name="select_database_file">Выбрать существующую базу</string>
<string name="entry_accessed">Доступ</string>
<string name="entry_cancel">Отмена</string>
<string name="entry_comment">Комментарии</string>
<string name="entry_notes">Комментарии</string>
<string name="entry_confpassword">Подтверждение</string>
<string name="entry_created">Создано</string>
<string name="entry_expires">Истекает</string>

View File

@@ -45,7 +45,7 @@
<string name="select_database_file">Vložte názov Databázy</string>
<string name="entry_accessed">Pristupované</string>
<string name="entry_cancel">Zrušiť</string>
<string name="entry_comment">Poznámky</string>
<string name="entry_notes">Poznámky</string>
<string name="entry_confpassword">Potvrdiť heslo</string>
<string name="entry_created">Vytvorené</string>
<string name="entry_expires">Expirácia</string>

View File

@@ -51,7 +51,7 @@
<string name="select_database_file">Ange databasnamn</string>
<string name="entry_accessed">Senast använd</string>
<string name="entry_cancel">Avbryt</string>
<string name="entry_comment">Kommentarer</string>
<string name="entry_notes">Kommentarer</string>
<string name="entry_confpassword">Bekräfta lösenord</string>
<string name="entry_created">Skapad</string>
<string name="entry_expires">Upphör att gälla</string>

View File

@@ -45,7 +45,7 @@
<string name="select_database_file">Введіть ім’я бази даних</string>
<string name="entry_accessed">Доступ</string>
<string name="entry_cancel">Відміна</string>
<string name="entry_comment">Коментар</string>
<string name="entry_notes">Коментар</string>
<string name="entry_confpassword">Підтвердження паролю</string>
<string name="entry_created">Створено</string>
<string name="entry_expires">Закінчується</string>

View File

@@ -45,7 +45,7 @@
<string name="select_database_file">选择一个已有数据库</string>
<string name="entry_accessed">访问时间</string>
<string name="entry_cancel">取消</string>
<string name="entry_comment">备注</string>
<string name="entry_notes">备注</string>
<string name="entry_confpassword">确认密码</string>
<string name="entry_created">创建</string>
<string name="entry_expires">失效时间</string>

View File

@@ -45,7 +45,7 @@
<string name="select_database_file">選擇一個已存在之資料庫</string>
<string name="entry_accessed">訪問時間</string>
<string name="entry_cancel">取消</string>
<string name="entry_comment">備註</string>
<string name="entry_notes">備註</string>
<string name="entry_confpassword">確認密碼</string>
<string name="entry_created">創建</string>
<string name="entry_expires">失效時間</string>

View File

@@ -48,6 +48,7 @@
<string name="encryption_algorithm_key" translatable="false">algorithm</string>
<string name="key_derivation_function_key" translatable="false">key_derivation_function_key</string>
<string name="app_key" translatable="false">app</string>
<string name="timeout_backup_key" translatable="false">timeout_backup_key</string>
<string name="app_timeout_key" translatable="false">app_timeout_key</string>
<string name="clipboard_timeout_key" translatable="false">clip_timeout_key</string>
<string name="db_key" translatable="false">db</string>
@@ -66,7 +67,6 @@
<string name="sort_group_before_key" translatable="false">sort_group_before_key</string>
<string name="sort_ascending_key" translatable="false">sort_ascending_key</string>
<string name="sort_recycle_bin_bottom_key" translatable="false">sort_recycle_bin_bottom_key</string>
<string name="timeout_key" translatable="false">timeout_key</string>
<string name="saf_key" translatable="false">storage_access_framework_key</string>
<string name="setting_style_key" translatable="false">setting_style_key</string>
<string name="setting_icon_pack_choose_key" translatable="false">setting_icon_pack_choose_key</string>

View File

@@ -55,7 +55,7 @@
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Kunzisoft comes with ABSOLUTELY NO WARRANTY; This is libre software, and you are welcome to redistribute it under the conditions of the GPL version 3 or later.</string>
<string name="entry_accessed">Accessed</string>
<string name="entry_cancel">Cancel</string>
<string name="entry_comment">Notes</string>
<string name="entry_notes">Notes</string>
<string name="entry_confpassword">Confirm password</string>
<string name="entry_created">Created</string>
<string name="entry_expires">Expires</string>

View File

@@ -1,5 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.3.11'
repositories {
jcenter()
maven {
@@ -10,6 +11,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}