Add database reloading #794

This commit is contained in:
J-Jamet
2021-01-07 16:25:05 +01:00
parent 455fd0cd6d
commit 27eb095720
21 changed files with 305 additions and 80 deletions

View File

@@ -53,6 +53,7 @@ import com.kunzisoft.keepass.model.StreamDirection
import com.kunzisoft.keepass.notifications.AttachmentFileNotificationService
import com.kunzisoft.keepass.notifications.ClipboardEntryNotificationService
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_DELETE_ENTRY_HISTORY
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RELOAD_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RESTORE_ENTRY_HISTORY
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
@@ -151,6 +152,10 @@ class EntryActivity : LockingActivity() {
if (result.isSuccess)
finish()
}
ACTION_DATABASE_RELOAD_TASK -> {
// Close the current activity
finish()
}
}
coordinatorLayout?.showActionError(result)
}
@@ -501,6 +506,9 @@ class EntryActivity : LockingActivity() {
R.id.menu_save_database -> {
mProgressDatabaseTaskProvider?.startDatabaseSave(!mReadOnly)
}
R.id.menu_reload_database -> {
mProgressDatabaseTaskProvider?.startDatabaseReload(false)
}
android.R.id.home -> finish() // close this activity and return to preview activity (if there is any)
}
return super.onOptionsItemSelected(item)

View File

@@ -61,6 +61,7 @@ import com.kunzisoft.keepass.notifications.AttachmentFileNotificationService
import com.kunzisoft.keepass.notifications.ClipboardEntryNotificationService
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_CREATE_ENTRY_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RELOAD_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_ENTRY_TASK
import com.kunzisoft.keepass.notifications.KeyboardEntryNotificationService
import com.kunzisoft.keepass.otp.OtpElement
@@ -335,6 +336,10 @@ class EntryEditActivity : LockingActivity(),
Log.e(TAG, "Unable to retrieve entry after database action", e)
}
}
ACTION_DATABASE_RELOAD_TASK -> {
// Close the current activity
finish()
}
}
coordinatorLayout?.showActionError(result)
}
@@ -610,13 +615,7 @@ class EntryEditActivity : LockingActivity(),
override fun onCreateOptionsMenu(menu: Menu): Boolean {
super.onCreateOptionsMenu(menu)
val inflater = menuInflater
inflater.inflate(R.menu.database, menu)
// Save database not needed here
menu.findItem(R.id.menu_save_database)?.isVisible = false
MenuUtil.contributionMenuInflater(inflater, menu)
MenuUtil.contributionMenuInflater(menuInflater, menu)
return true
}
@@ -673,9 +672,6 @@ class EntryEditActivity : LockingActivity(),
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.menu_save_database -> {
mProgressDatabaseTaskProvider?.startDatabaseSave(!mReadOnly)
}
R.id.menu_contribute -> {
MenuUtil.onContributionItemSelected(this)
return true

View File

@@ -70,6 +70,7 @@ import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Compa
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_CREATE_GROUP_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_DELETE_NODES_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_MOVE_NODES_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RELOAD_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_ENTRY_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_GROUP_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.NEW_NODES_KEY
@@ -342,6 +343,11 @@ class GroupActivity : LockingActivity(),
}
}
}
ACTION_DATABASE_RELOAD_TASK -> {
// Reload the current activity
startActivity(intent)
finish()
}
}
coordinatorLayout?.showActionError(result)
@@ -1003,6 +1009,10 @@ class GroupActivity : LockingActivity(),
mProgressDatabaseTaskProvider?.startDatabaseSave(!mReadOnly)
return true
}
R.id.menu_reload_database -> {
mProgressDatabaseTaskProvider?.startDatabaseReload(false)
return true
}
R.id.menu_empty_recycle_bin -> {
mCurrentGroup?.getChildren()?.let { listChildren ->
// Automatically delete all elements

View File

@@ -720,7 +720,7 @@ open class PasswordActivity : SpecialModeActivity(), AdvancedUnlockFragment.Buil
when (resultCode) {
LockingActivity.RESULT_EXIT_LOCK -> {
clearCredentialsViews()
Database.getInstance().closeAndClear(UriUtil.getBinaryDir(this))
Database.getInstance().clearAndClose(UriUtil.getBinaryDir(this))
}
Activity.RESULT_CANCELED -> {
clearCredentialsViews()

View File

@@ -34,7 +34,7 @@ class App : MultiDexApplication() {
}
override fun onTerminate() {
Database.getInstance().closeAndClear(UriUtil.getBinaryDir(this))
Database.getInstance().clearAndClose(UriUtil.getBinaryDir(this))
super.onTerminate()
}
}

View File

@@ -26,7 +26,6 @@ import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.closeDatabase
class CreateDatabaseRunnable(context: Context,
private val mDatabase: Database,
@@ -47,7 +46,7 @@ class CreateDatabaseRunnable(context: Context,
createData(mDatabaseUri, databaseName, rootName)
}
} catch (e: Exception) {
mDatabase.closeAndClear(UriUtil.getBinaryDir(context))
mDatabase.clearAndClose(UriUtil.getBinaryDir(context))
setError(e)
}

View File

@@ -31,7 +31,6 @@ import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.closeDatabase
class LoadDatabaseRunnable(private val context: Context,
private val mDatabase: Database,
@@ -47,7 +46,7 @@ class LoadDatabaseRunnable(private val context: Context,
override fun onStartRun() {
// Clear before we load
mDatabase.closeAndClear(UriUtil.getBinaryDir(context))
mDatabase.clearAndClose(UriUtil.getBinaryDir(context))
}
override fun onActionRun() {
@@ -83,7 +82,7 @@ class LoadDatabaseRunnable(private val context: Context,
// Register the current time to init the lock timer
PreferencesUtil.saveCurrentTime(context)
} else {
mDatabase.closeAndClear(UriUtil.getBinaryDir(context))
mDatabase.clearAndClose(UriUtil.getBinaryDir(context))
}
}

View File

@@ -47,6 +47,7 @@ import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Compa
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_DELETE_ENTRY_HISTORY
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_DELETE_NODES_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_LOAD_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RELOAD_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_MOVE_NODES_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_REMOVE_UNLINKED_DATA_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RESTORE_ENTRY_HISTORY
@@ -294,6 +295,13 @@ class ProgressDatabaseTaskProvider(private val activity: FragmentActivity) {
, ACTION_DATABASE_LOAD_TASK)
}
fun startDatabaseReload(fixDuplicateUuid: Boolean) {
start(Bundle().apply {
putBoolean(DatabaseTaskNotificationService.FIX_DUPLICATE_UUID_KEY, fixDuplicateUuid)
}
, ACTION_DATABASE_RELOAD_TASK)
}
fun startDatabaseAssignPassword(databaseUri: Uri,
masterPasswordChecked: Boolean,
masterPassword: String?,

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2019 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX 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.
*
* KeePassDX 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 KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.database.action
import android.content.Context
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.exception.DuplicateUuidDatabaseException
import com.kunzisoft.keepass.database.exception.LoadDatabaseException
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import com.kunzisoft.keepass.utils.UriUtil
class ReloadDatabaseRunnable(private val context: Context,
private val mDatabase: Database,
private val mFixDuplicateUUID: Boolean,
private val progressTaskUpdater: ProgressTaskUpdater?,
private val mLoadDatabaseResult: ((Result) -> Unit)?)
: ActionRunnable() {
override fun onStartRun() {
// Clear before we load
mDatabase.clear(UriUtil.getBinaryDir(context))
}
override fun onActionRun() {
try {
mDatabase.reloadData(context.contentResolver,
UriUtil.getBinaryDir(context),
mFixDuplicateUUID,
progressTaskUpdater)
}
catch (e: DuplicateUuidDatabaseException) {
setError(e)
}
catch (e: LoadDatabaseException) {
setError(e)
}
if (result.isSuccess) {
// Register the current time to init the lock timer
PreferencesUtil.saveCurrentTime(context)
} else {
mDatabase.clearAndClose(UriUtil.getBinaryDir(context))
}
}
override fun onFinishRun() {
mLoadDatabaseResult?.invoke(result)
}
}

View File

@@ -31,10 +31,7 @@ import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.database.element.node.NodeIdInt
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
import com.kunzisoft.keepass.database.element.security.EncryptionAlgorithm
import com.kunzisoft.keepass.database.exception.DatabaseOutputException
import com.kunzisoft.keepass.database.exception.FileNotFoundDatabaseException
import com.kunzisoft.keepass.database.exception.LoadDatabaseException
import com.kunzisoft.keepass.database.exception.SignatureDatabaseException
import com.kunzisoft.keepass.database.exception.*
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDB
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX
import com.kunzisoft.keepass.database.file.input.DatabaseInputKDB
@@ -330,29 +327,11 @@ class Database {
}
@Throws(LoadDatabaseException::class)
fun loadData(uri: Uri, password: String?, keyfile: Uri?,
readOnly: Boolean,
contentResolver: ContentResolver,
cacheDirectory: File,
fixDuplicateUUID: Boolean,
progressTaskUpdater: ProgressTaskUpdater?) {
this.fileUri = uri
isReadOnly = readOnly
if (uri.scheme == "file") {
val file = File(uri.path!!)
isReadOnly = !file.canWrite()
}
// Pass KeyFile Uri as InputStreams
private fun readDatabaseStream(contentResolver: ContentResolver, uri: Uri,
openDatabaseKDB: (InputStream) -> DatabaseKDB,
openDatabaseKDBX: (InputStream) -> DatabaseKDBX) {
var databaseInputStream: InputStream? = null
var keyFileInputStream: InputStream? = null
try {
// Get keyFile inputStream
keyfile?.let {
keyFileInputStream = UriUtil.getUriInputStream(contentResolver, keyfile)
}
// Load Data, pass Uris as InputStreams
val databaseStream = UriUtil.getUriInputStream(contentResolver, uri)
?: throw IOException("Database input stream cannot be retrieve")
@@ -374,22 +353,10 @@ class Database {
when {
// Header of database KDB
DatabaseHeaderKDB.matchesHeader(sig1, sig2) -> setDatabaseKDB(DatabaseInputKDB(
cacheDirectory,
fixDuplicateUUID)
.openDatabase(databaseInputStream,
password,
keyFileInputStream,
progressTaskUpdater))
DatabaseHeaderKDB.matchesHeader(sig1, sig2) -> setDatabaseKDB(openDatabaseKDB(databaseInputStream))
// Header of database KDBX
DatabaseHeaderKDBX.matchesHeader(sig1, sig2) -> setDatabaseKDBX(DatabaseInputKDBX(
cacheDirectory,
fixDuplicateUUID)
.openDatabase(databaseInputStream,
password,
keyFileInputStream,
progressTaskUpdater))
DatabaseHeaderKDBX.matchesHeader(sig1, sig2) -> setDatabaseKDBX(openDatabaseKDBX(databaseInputStream))
// Header not recognized
else -> throw SignatureDatabaseException()
@@ -397,17 +364,92 @@ class Database {
this.mSearchHelper = SearchHelper()
loaded = true
} catch (e: LoadDatabaseException) {
throw e
} finally {
databaseInputStream?.close()
}
}
@Throws(LoadDatabaseException::class)
fun loadData(uri: Uri, password: String?, keyfile: Uri?,
readOnly: Boolean,
contentResolver: ContentResolver,
cacheDirectory: File,
fixDuplicateUUID: Boolean,
progressTaskUpdater: ProgressTaskUpdater?) {
// Save database URI
this.fileUri = uri
// Check if the file is writable
this.isReadOnly = readOnly
if (uri.scheme == "file") {
val file = File(uri.path!!)
isReadOnly = !file.canWrite()
}
// Pass KeyFile Uri as InputStreams
var keyFileInputStream: InputStream? = null
try {
// Get keyFile inputStream
keyfile?.let {
keyFileInputStream = UriUtil.getUriInputStream(contentResolver, keyfile)
}
// Read database stream for the first time
readDatabaseStream(contentResolver, uri,
{ databaseInputStream ->
DatabaseInputKDB(cacheDirectory)
.openDatabase(databaseInputStream,
password,
keyFileInputStream,
fixDuplicateUUID,
progressTaskUpdater)
},
{ databaseInputStream ->
DatabaseInputKDBX(cacheDirectory)
.openDatabase(databaseInputStream,
password,
keyFileInputStream,
fixDuplicateUUID,
progressTaskUpdater)
}
)
} catch (e: Exception) {
throw FileNotFoundDatabaseException()
} finally {
keyFileInputStream?.close()
databaseInputStream?.close()
}
}
@Throws(LoadDatabaseException::class)
fun reloadData(contentResolver: ContentResolver,
cacheDirectory: File,
fixDuplicateUUID: Boolean,
progressTaskUpdater: ProgressTaskUpdater?) {
// Retrieve the stream from the old database URI
fileUri?.let { oldDatabaseUri ->
readDatabaseStream(contentResolver, oldDatabaseUri,
{ databaseInputStream ->
DatabaseInputKDB(cacheDirectory)
.openDatabase(databaseInputStream,
masterKey,
fixDuplicateUUID,
progressTaskUpdater)
},
{ databaseInputStream ->
DatabaseInputKDBX(cacheDirectory)
.openDatabase(databaseInputStream,
masterKey,
fixDuplicateUUID,
progressTaskUpdater)
}
)
} ?: throw IODatabaseException()
}
fun isGroupSearchable(group: Group, omitBackup: Boolean): Boolean {
return mDatabaseKDB?.isGroupSearchable(group.groupKDB, omitBackup) ?:
mDatabaseKDBX?.isGroupSearchable(group.groupKDBX, omitBackup) ?:
@@ -531,7 +573,7 @@ class Database {
this.fileUri = uri
}
fun closeAndClear(filesDirectory: File? = null) {
fun clear(filesDirectory: File? = null) {
drawFactory.clearCache()
// Delete the cache of the database if present
mDatabaseKDB?.clearCache()
@@ -544,7 +586,10 @@ class Database {
} catch (e: Exception) {
Log.e(TAG, "Unable to clear the directory cache.", e)
}
}
fun clearAndClose(filesDirectory: File? = null) {
clear(filesDirectory)
this.mDatabaseKDB = null
this.mDatabaseKDBX = null
this.fileUri = null

View File

@@ -41,6 +41,13 @@ abstract class DatabaseInput<PwDb : DatabaseVersioned<*, *, *, *>>
abstract fun openDatabase(databaseInputStream: InputStream,
password: String?,
keyInputStream: InputStream?,
fixDuplicateUUID: Boolean,
progressTaskUpdater: ProgressTaskUpdater?): PwDb
@Throws(LoadDatabaseException::class)
abstract fun openDatabase(databaseInputStream: InputStream,
masterKey: ByteArray,
fixDuplicateUUID: Boolean,
progressTaskUpdater: ProgressTaskUpdater?): PwDb
}

View File

@@ -45,8 +45,7 @@ import javax.crypto.spec.SecretKeySpec
/**
* Load a KDB database file.
*/
class DatabaseInputKDB(cacheDirectory: File,
private val fixDuplicateUUID: Boolean = false)
class DatabaseInputKDB(cacheDirectory: File)
: DatabaseInput<DatabaseKDB>(cacheDirectory) {
private lateinit var mDatabaseToOpen: DatabaseKDB
@@ -55,7 +54,28 @@ class DatabaseInputKDB(cacheDirectory: File,
override fun openDatabase(databaseInputStream: InputStream,
password: String?,
keyInputStream: InputStream?,
fixDuplicateUUID: Boolean,
progressTaskUpdater: ProgressTaskUpdater?): DatabaseKDB {
return openDatabase(databaseInputStream, fixDuplicateUUID, progressTaskUpdater) {
mDatabaseToOpen.retrieveMasterKey(password, keyInputStream)
}
}
@Throws(LoadDatabaseException::class)
override fun openDatabase(databaseInputStream: InputStream,
masterKey: ByteArray,
fixDuplicateUUID: Boolean,
progressTaskUpdater: ProgressTaskUpdater?): DatabaseKDB {
return openDatabase(databaseInputStream, fixDuplicateUUID, progressTaskUpdater) {
mDatabaseToOpen.masterKey = masterKey
}
}
@Throws(LoadDatabaseException::class)
private fun openDatabase(databaseInputStream: InputStream,
fixDuplicateUUID: Boolean,
progressTaskUpdater: ProgressTaskUpdater?,
assignMasterKey: (() -> Unit)? = null): DatabaseKDB {
try {
// Load entire file, most of it's encrypted.
@@ -84,7 +104,7 @@ class DatabaseInputKDB(cacheDirectory: File,
mDatabaseToOpen = DatabaseKDB()
mDatabaseToOpen.changeDuplicateId = fixDuplicateUUID
mDatabaseToOpen.retrieveMasterKey(password, keyInputStream)
assignMasterKey?.invoke()
// Select algorithm
when {

View File

@@ -63,8 +63,7 @@ import javax.crypto.Cipher
import javax.crypto.CipherInputStream
import kotlin.math.min
class DatabaseInputKDBX(cacheDirectory: File,
private val fixDuplicateUUID: Boolean = false)
class DatabaseInputKDBX(cacheDirectory: File)
: DatabaseInput<DatabaseKDBX>(cacheDirectory) {
private var randomStream: StreamCipher? = null
@@ -98,12 +97,30 @@ class DatabaseInputKDBX(cacheDirectory: File,
override fun openDatabase(databaseInputStream: InputStream,
password: String?,
keyInputStream: InputStream?,
fixDuplicateUUID: Boolean,
progressTaskUpdater: ProgressTaskUpdater?): DatabaseKDBX {
return openDatabase(databaseInputStream, fixDuplicateUUID, progressTaskUpdater) { header ->
mDatabase.retrieveMasterKey(password, keyInputStream)
}
}
@Throws(LoadDatabaseException::class)
override fun openDatabase(databaseInputStream: InputStream,
masterKey: ByteArray,
fixDuplicateUUID: Boolean,
progressTaskUpdater: ProgressTaskUpdater?): DatabaseKDBX {
return openDatabase(databaseInputStream, fixDuplicateUUID, progressTaskUpdater) {
mDatabase.masterKey = masterKey
}
}
@Throws(LoadDatabaseException::class)
private fun openDatabase(databaseInputStream: InputStream,
fixDuplicateUUID: Boolean,
progressTaskUpdater: ProgressTaskUpdater?,
assignMasterKey: ((header: DatabaseHeaderKDBX) -> Unit)? = null): DatabaseKDBX {
try {
// TODO performance
progressTaskUpdater?.updateMessage(R.string.retrieving_db_key)
mDatabase = DatabaseKDBX()
mDatabase.changeDuplicateId = fixDuplicateUUID
@@ -116,9 +133,8 @@ class DatabaseInputKDBX(cacheDirectory: File,
hashOfHeader = headerAndHash.hash
val pbHeader = headerAndHash.header
mDatabase.retrieveMasterKey(password, keyInputStream)
assignMasterKey?.invoke(header)
mDatabase.makeFinalKey(header.masterSeed)
// TODO performance
progressTaskUpdater?.updateMessage(R.string.decrypting_db)
val engine: CipherEngine

View File

@@ -180,6 +180,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
val actionRunnable: ActionRunnable? = when (intentAction) {
ACTION_DATABASE_CREATE_TASK -> buildDatabaseCreateActionTask(intent)
ACTION_DATABASE_LOAD_TASK -> buildDatabaseLoadActionTask(intent)
ACTION_DATABASE_RELOAD_TASK -> buildDatabaseReloadActionTask(intent)
ACTION_DATABASE_ASSIGN_PASSWORD_TASK -> buildDatabaseAssignPasswordActionTask(intent)
ACTION_DATABASE_CREATE_GROUP_TASK -> buildDatabaseCreateGroupActionTask(intent)
ACTION_DATABASE_UPDATE_GROUP_TASK -> buildDatabaseUpdateGroupActionTask(intent)
@@ -258,7 +259,9 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
}
return when (intentAction) {
ACTION_DATABASE_LOAD_TASK, null -> {
ACTION_DATABASE_LOAD_TASK,
ACTION_DATABASE_RELOAD_TASK,
null -> {
START_STICKY
}
else -> {
@@ -292,7 +295,8 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
else -> {
when (intentAction) {
ACTION_DATABASE_CREATE_TASK -> R.string.creating_database
ACTION_DATABASE_LOAD_TASK -> R.string.loading_database
ACTION_DATABASE_LOAD_TASK,
ACTION_DATABASE_RELOAD_TASK -> R.string.loading_database
ACTION_DATABASE_SAVE -> R.string.saving_database
else -> {
R.string.command_execution
@@ -302,13 +306,15 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
}
mMessageId = when (intentAction) {
ACTION_DATABASE_LOAD_TASK -> null
ACTION_DATABASE_LOAD_TASK,
ACTION_DATABASE_RELOAD_TASK -> null
else -> null
}
mWarningId =
if (!saveAction
|| intentAction == ACTION_DATABASE_LOAD_TASK)
|| intentAction == ACTION_DATABASE_LOAD_TASK
|| intentAction == ACTION_DATABASE_RELOAD_TASK)
null
else
R.string.do_not_kill_app
@@ -509,6 +515,23 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
}
}
private fun buildDatabaseReloadActionTask(intent: Intent): ActionRunnable? {
return if (intent.hasExtra(FIX_DUPLICATE_UUID_KEY)) {
ReloadDatabaseRunnable(
this,
mDatabase,
intent.getBooleanExtra(FIX_DUPLICATE_UUID_KEY, false),
this
) { result ->
// No need to add each info to reload database
result.data = Bundle()
}
} else {
null
}
}
private fun buildDatabaseAssignPasswordActionTask(intent: Intent): ActionRunnable? {
return if (intent.hasExtra(DATABASE_URI_KEY)
&& intent.hasExtra(MASTER_PASSWORD_CHECKED_KEY)
@@ -814,6 +837,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
const val ACTION_DATABASE_CREATE_TASK = "ACTION_DATABASE_CREATE_TASK"
const val ACTION_DATABASE_LOAD_TASK = "ACTION_DATABASE_LOAD_TASK"
const val ACTION_DATABASE_RELOAD_TASK = "ACTION_DATABASE_RELOAD_TASK"
const val ACTION_DATABASE_ASSIGN_PASSWORD_TASK = "ACTION_DATABASE_ASSIGN_PASSWORD_TASK"
const val ACTION_DATABASE_CREATE_GROUP_TASK = "ACTION_DATABASE_CREATE_GROUP_TASK"
const val ACTION_DATABASE_UPDATE_GROUP_TASK = "ACTION_DATABASE_UPDATE_GROUP_TASK"

View File

@@ -552,6 +552,10 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
settingActivity?.mProgressDatabaseTaskProvider?.startDatabaseSave(!mDatabaseReadOnly)
true
}
R.id.menu_reload_database -> {
settingActivity?.mProgressDatabaseTaskProvider?.startDatabaseReload(false)
return true
}
else -> {
// Check the time lock before launching settings

View File

@@ -37,6 +37,7 @@ import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
import com.kunzisoft.keepass.activities.lock.LockingActivity
import com.kunzisoft.keepass.activities.lock.resetAppTimeoutWhenViewFocusedOrChanged
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.view.showActionError
@@ -95,12 +96,19 @@ open class SettingsActivity
backupManager = BackupManager(this)
mProgressDatabaseTaskProvider?.onActionFinish = { actionTask, result ->
// Call result in fragment
(supportFragmentManager
.findFragmentByTag(TAG_NESTED) as NestedSettingsFragment?)
?.onProgressDialogThreadResult(actionTask, result)
coordinatorLayout?.showActionError(result)
when (actionTask) {
DatabaseTaskNotificationService.ACTION_DATABASE_RELOAD_TASK -> {
// Close the current activity
finish()
}
else -> {
// Call result in fragment
(supportFragmentManager
.findFragmentByTag(TAG_NESTED) as NestedSettingsFragment?)
?.onProgressDialogThreadResult(actionTask, result)
coordinatorLayout?.showActionError(result)
}
}
}
}

View File

@@ -138,5 +138,5 @@ fun Context.closeDatabase() {
cancelAll()
}
// Clear data
Database.getInstance().closeAndClear(UriUtil.getBinaryDir(this))
Database.getInstance().clearAndClose(UriUtil.getBinaryDir(this))
}

View File

@@ -0,0 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportHeight="24"
android:viewportWidth="24" >
<path android:fillColor="#FFFFFF" android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z"/>
</vector>

View File

@@ -22,6 +22,6 @@
<item android:id="@+id/menu_contribute"
android:icon="@drawable/ic_heart_white_24dp"
android:title="@string/contribute"
android:orderInCategory="95"
android:orderInCategory="99"
app:showAsAction="ifRoom" />
</menu>

View File

@@ -24,4 +24,9 @@
android:title="@string/menu_save_database"
android:orderInCategory="95"
app:showAsAction="ifRoom" />
<item android:id="@+id/menu_reload_database"
android:icon="@drawable/ic_reload_white_24dp"
android:title="@string/menu_reload_database"
android:orderInCategory="96"
app:showAsAction="ifRoom" />
</menu>

View File

@@ -185,6 +185,7 @@
<string name="menu_hide_password">Hide password</string>
<string name="menu_lock">Lock database</string>
<string name="menu_save_database">Save database</string>
<string name="menu_reload_database">Reload database</string>
<string name="menu_open">Open</string>
<string name="menu_search">Search</string>
<string name="menu_showpass">Show password</string>