Merge branch 'feature/Module_Refactoring' into develop

This commit is contained in:
J-Jamet
2023-05-15 16:43:46 +02:00
570 changed files with 2933 additions and 2380 deletions

View File

@@ -6,7 +6,6 @@ apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 32
buildToolsVersion "32.0.0"
ndkVersion "21.4.7075529"
defaultConfig {
applicationId "com.kunzisoft.keepass"
@@ -129,11 +128,10 @@ dependencies {
implementation 'commons-codec:commons-codec:1.15'
// Password generator
implementation 'me.gosimple:nbvcxz:1.5.0'
// Encrypt lib
implementation project(path: ':crypto')
// Icon pack
implementation project(path: ':icon-pack-classic')
implementation project(path: ':icon-pack-material')
// Modules import
implementation project(path: ':database')
implementation project(path: ':icon-pack')
// Tests
androidTestImplementation "androidx.test:runner:$android_test_version"

View File

@@ -30,7 +30,7 @@ import androidx.core.text.HtmlCompat
import com.kunzisoft.keepass.BuildConfig
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.stylish.StylishActivity
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
import org.joda.time.DateTime
class AboutActivity : StylishActivity() {
@@ -46,7 +46,7 @@ class AboutActivity : StylishActivity() {
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
val appName = if (UriUtil.contributingUser(this))
val appName = if (this.isContributingUser())
getString(R.string.app_name) + " " + getString(R.string.app_name_part3)
else
getString(R.string.app_name)

View File

@@ -36,11 +36,12 @@ import com.kunzisoft.keepass.autofill.AutofillComponent
import com.kunzisoft.keepass.autofill.AutofillHelper
import com.kunzisoft.keepass.autofill.CompatInlineSuggestionsRequest
import com.kunzisoft.keepass.autofill.KeeAutofillService
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.search.SearchHelper
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.helper.SearchHelper
import com.kunzisoft.keepass.model.RegisterInfo
import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.WebDomain
@RequiresApi(api = Build.VERSION_CODES.O)
class AutofillLauncherActivity : DatabaseModeActivity() {
@@ -58,7 +59,7 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
return true
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
// Retrieve selection mode
@@ -73,7 +74,7 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
}
// Build search param
bundle.getParcelable<SearchInfo>(KEY_SEARCH_INFO)?.let { searchInfo ->
SearchInfo.getConcreteWebDomain(
WebDomain.getConcreteWebDomain(
this,
searchInfo.webDomain
) { concreteWebDomain ->
@@ -101,7 +102,7 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
// To register info
val registerInfo = intent.getParcelableExtra<RegisterInfo>(KEY_REGISTER_INFO)
val searchInfo = SearchInfo(registerInfo?.searchInfo)
SearchInfo.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
WebDomain.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
searchInfo.webDomain = concreteWebDomain
launchRegistration(database, searchInfo, registerInfo)
}
@@ -115,7 +116,7 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
}
}
private fun launchSelection(database: Database?,
private fun launchSelection(database: ContextualDatabase?,
autofillComponent: AutofillComponent?,
searchInfo: SearchInfo) {
if (autofillComponent == null) {
@@ -158,7 +159,7 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
}
}
private fun launchRegistration(database: Database?,
private fun launchRegistration(database: ContextualDatabase?,
searchInfo: SearchInfo,
registerInfo: RegisterInfo?) {
if (!KeeAutofillService.autofillAllowedFor(searchInfo.applicationId,

View File

@@ -36,11 +36,11 @@ import androidx.activity.result.ActivityResultLauncher
import androidx.activity.viewModels
import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.core.graphics.BlendModeColorFilterCompat
import androidx.core.graphics.BlendModeCompat
import androidx.core.graphics.ColorUtils
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.CollapsingToolbarLayout
import com.google.android.material.progressindicator.LinearProgressIndicator
@@ -51,8 +51,8 @@ import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
import com.kunzisoft.keepass.activities.helpers.SpecialMode
import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity
import com.kunzisoft.keepass.adapters.TagsAdapter
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.education.EntryActivityEducation
@@ -67,14 +67,14 @@ import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.UriUtil.openUrl
import com.kunzisoft.keepass.utils.UuidUtil
import com.kunzisoft.keepass.view.changeControlColor
import com.kunzisoft.keepass.view.changeTitleColor
import com.kunzisoft.keepass.view.hideByFading
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
import com.kunzisoft.keepass.viewmodels.EntryViewModel
import java.util.*
import java.util.UUID
class EntryActivity : DatabaseLockActivity() {
@@ -310,14 +310,14 @@ class EntryActivity : DatabaseLockActivity() {
return coordinatorLayout
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
mEntryViewModel.loadDatabase(database)
}
override fun onDatabaseActionFinished(
database: Database,
database: ContextualDatabase,
actionTask: String,
result: ActionRunnable.Result
) {
@@ -376,7 +376,7 @@ class EntryActivity : DatabaseLockActivity() {
.createBlendModeColorFilterCompat(backgroundDarker, BlendModeCompat.SRC_IN)
mIcon?.let { icon ->
titleIconView?.let { iconView ->
mIconDrawableFactory?.assignDatabaseIcon(
mDatabase?.iconDrawableFactory?.assignDatabaseIcon(
iconView,
icon,
mForegroundColor ?: mColorAccent
@@ -473,7 +473,7 @@ class EntryActivity : DatabaseLockActivity() {
}
R.id.menu_goto_url -> {
mUrl?.let { url ->
UriUtil.gotoUrl(this, url)
this.openUrl(url)
}
return true
}
@@ -526,7 +526,7 @@ class EntryActivity : DatabaseLockActivity() {
* Open standard Entry activity
*/
fun launch(activity: Activity,
database: Database,
database: ContextualDatabase,
entryId: NodeId<UUID>,
activityResultLauncher: ActivityResultLauncher<Intent>) {
if (database.loaded) {
@@ -542,7 +542,7 @@ class EntryActivity : DatabaseLockActivity() {
* Open history Entry activity
*/
fun launch(activity: Activity,
database: Database,
database: ContextualDatabase,
entryId: NodeId<UUID>,
historyPosition: Int,
activityResultLauncher: ActivityResultLauncher<Intent>) {

View File

@@ -32,7 +32,11 @@ import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.*
import android.widget.AdapterView
import android.widget.DatePicker
import android.widget.ProgressBar
import android.widget.Spinner
import android.widget.TimePicker
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
@@ -46,8 +50,14 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.google.android.material.snackbar.Snackbar
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.*
import com.kunzisoft.keepass.activities.dialogs.ColorPickerDialogFragment
import com.kunzisoft.keepass.activities.dialogs.DatePickerFragment
import com.kunzisoft.keepass.activities.dialogs.EntryCustomFieldDialogFragment
import com.kunzisoft.keepass.activities.dialogs.FileTooBigDialogFragment
import com.kunzisoft.keepass.activities.dialogs.FileTooBigDialogFragment.Companion.MAX_WARNING_BINARY_FILE
import com.kunzisoft.keepass.activities.dialogs.ReplaceFileDialogFragment
import com.kunzisoft.keepass.activities.dialogs.SetOTPDialogFragment
import com.kunzisoft.keepass.activities.dialogs.TimePickerFragment
import com.kunzisoft.keepass.activities.fragments.EntryEditFragment
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
@@ -55,7 +65,11 @@ import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity
import com.kunzisoft.keepass.adapters.TemplatesSelectorAdapter
import com.kunzisoft.keepass.autofill.AutofillComponent
import com.kunzisoft.keepass.autofill.AutofillHelper
import com.kunzisoft.keepass.database.element.*
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.database.element.DateInstant
import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.database.element.Field
import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.database.element.template.Template
@@ -76,12 +90,16 @@ import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.view.*
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
import com.kunzisoft.keepass.view.ToolbarAction
import com.kunzisoft.keepass.view.asError
import com.kunzisoft.keepass.view.hideByFading
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
import com.kunzisoft.keepass.view.updateLockPaddingLeft
import com.kunzisoft.keepass.viewmodels.ColorPickerViewModel
import com.kunzisoft.keepass.viewmodels.EntryEditViewModel
import org.joda.time.DateTime
import java.util.*
import java.util.UUID
class EntryEditActivity : DatabaseLockActivity(),
EntryCustomFieldDialogFragment.EntryCustomFieldListener,
@@ -185,7 +203,7 @@ class EntryEditActivity : DatabaseLockActivity(),
mExternalFileHelper = ExternalFileHelper(this)
mExternalFileHelper?.buildOpenDocument { uri ->
uri?.let { attachmentToUploadUri ->
UriUtil.getFileData(this, attachmentToUploadUri)?.also { documentFile ->
attachmentToUploadUri.getDocumentFile(this)?.also { documentFile ->
documentFile.name?.let { fileName ->
if (documentFile.length() > MAX_WARNING_BINARY_FILE) {
FileTooBigDialogFragment.build(attachmentToUploadUri, fileName)
@@ -221,7 +239,7 @@ class EntryEditActivity : DatabaseLockActivity(),
this@EntryEditActivity,
templates
).apply {
iconDrawableFactory = mIconDrawableFactory
iconDrawableFactory = mDatabase?.iconDrawableFactory
}
adapter = mTemplatesSelectorAdapter
val selectedTemplate = if (mTemplate != null)
@@ -368,19 +386,19 @@ class EntryEditActivity : DatabaseLockActivity(),
return true
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
mAllowCustomFields = database?.allowEntryCustomFields() == true
mAllowOTP = database?.allowOTP == true
mEntryEditViewModel.loadDatabase(database)
mTemplatesSelectorAdapter?.apply {
iconDrawableFactory = mIconDrawableFactory
iconDrawableFactory = mDatabase?.iconDrawableFactory
notifyDataSetChanged()
}
}
override fun onDatabaseActionFinished(
database: Database,
database: ContextualDatabase,
actionTask: String,
result: ActionRunnable.Result
) {
@@ -433,7 +451,7 @@ class EntryEditActivity : DatabaseLockActivity(),
finishForEntryResult(entry)
}
private fun entryValidatedForKeyboardSelection(database: Database, entry: Entry) {
private fun entryValidatedForKeyboardSelection(database: ContextualDatabase, entry: Entry) {
// Populate Magikeyboard with entry
MagikeyboardService.populateKeyboardAndMoveAppToBackground(
this,
@@ -444,7 +462,7 @@ class EntryEditActivity : DatabaseLockActivity(),
finishForEntryResult(entry)
}
private fun entryValidatedForAutofillSelection(database: Database, entry: Entry) {
private fun entryValidatedForAutofillSelection(database: ContextualDatabase, entry: Entry) {
// Build Autofill response with the entry selected
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AutofillHelper.buildResponseAndSetResult(this@EntryEditActivity,
@@ -759,7 +777,7 @@ class EntryEditActivity : DatabaseLockActivity(),
* Launch EntryEditActivity to update an existing entry by his [entryId]
*/
fun launchToUpdate(activity: Activity,
database: Database,
database: ContextualDatabase,
entryId: NodeId<UUID>,
activityResultLauncher: ActivityResultLauncher<Intent>) {
if (database.loaded && !database.isReadOnly) {
@@ -775,7 +793,7 @@ class EntryEditActivity : DatabaseLockActivity(),
* Launch EntryEditActivity to add a new entry in an existent group
*/
fun launchToCreate(activity: Activity,
database: Database,
database: ContextualDatabase,
groupId: NodeId<*>,
activityResultLauncher: ActivityResultLauncher<Intent>) {
if (database.loaded && !database.isReadOnly) {
@@ -788,7 +806,7 @@ class EntryEditActivity : DatabaseLockActivity(),
}
fun launchToUpdateForSave(context: Context,
database: Database,
database: ContextualDatabase,
entryId: NodeId<UUID>,
searchInfo: SearchInfo) {
if (database.loaded && !database.isReadOnly) {
@@ -805,7 +823,7 @@ class EntryEditActivity : DatabaseLockActivity(),
}
fun launchToCreateForSave(context: Context,
database: Database,
database: ContextualDatabase,
groupId: NodeId<*>,
searchInfo: SearchInfo) {
if (database.loaded && !database.isReadOnly) {
@@ -825,7 +843,7 @@ class EntryEditActivity : DatabaseLockActivity(),
* Launch EntryEditActivity to add a new entry in keyboard selection
*/
fun launchForKeyboardSelectionResult(context: Context,
database: Database,
database: ContextualDatabase,
groupId: NodeId<*>,
searchInfo: SearchInfo? = null) {
if (database.loaded && !database.isReadOnly) {
@@ -846,7 +864,7 @@ class EntryEditActivity : DatabaseLockActivity(),
*/
@RequiresApi(api = Build.VERSION_CODES.O)
fun launchForAutofillResult(activity: AppCompatActivity,
database: Database,
database: ContextualDatabase,
activityResultLauncher: ActivityResultLauncher<Intent>?,
autofillComponent: AutofillComponent,
groupId: NodeId<*>,
@@ -870,7 +888,7 @@ class EntryEditActivity : DatabaseLockActivity(),
* Launch EntryEditActivity to register an updated entry (from autofill)
*/
fun launchToUpdateForRegistration(context: Context,
database: Database,
database: ContextualDatabase,
entryId: NodeId<UUID>,
registerInfo: RegisterInfo? = null) {
if (database.loaded && !database.isReadOnly) {
@@ -890,7 +908,7 @@ class EntryEditActivity : DatabaseLockActivity(),
* Launch EntryEditActivity to register a new entry (from autofill)
*/
fun launchToCreateForRegistration(context: Context,
database: Database,
database: ContextualDatabase,
groupId: NodeId<*>,
registerInfo: RegisterInfo? = null) {
if (database.loaded && !database.isReadOnly) {

View File

@@ -26,11 +26,12 @@ import android.os.Bundle
import android.widget.Toast
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.legacy.DatabaseModeActivity
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.search.SearchHelper
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.helper.SearchHelper
import com.kunzisoft.keepass.magikeyboard.MagikeyboardService
import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.otp.OtpEntryFields
import com.kunzisoft.keepass.utils.WebDomain
/**
* Activity to search or select entry in database,
@@ -46,7 +47,7 @@ class EntrySelectionLauncherActivity : DatabaseModeActivity() {
return false
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
val keySelectionBundle = intent.getBundleExtra(KEY_SELECTION_BUNDLE)
@@ -95,7 +96,7 @@ class EntrySelectionLauncherActivity : DatabaseModeActivity() {
finish()
}
private fun launchSelection(database: Database?,
private fun launchSelection(database: ContextualDatabase?,
sharedWebDomain: String?,
otpString: String?) {
// Build domain search param
@@ -104,13 +105,13 @@ class EntrySelectionLauncherActivity : DatabaseModeActivity() {
this.otpString = otpString
}
SearchInfo.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
WebDomain.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
searchInfo.webDomain = concreteWebDomain
launch(database, searchInfo)
}
}
private fun launch(database: Database?,
private fun launch(database: ContextualDatabase?,
searchInfo: SearchInfo) {
// Setting to integrate Magikeyboard

View File

@@ -53,9 +53,9 @@ import com.kunzisoft.keepass.adapters.FileDatabaseHistoryAdapter
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.autofill.AutofillComponent
import com.kunzisoft.keepass.autofill.AutofillHelper
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.education.FileDatabaseSelectActivityEducation
import com.kunzisoft.keepass.database.element.MainCredential
import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.model.RegisterInfo
import com.kunzisoft.keepass.model.SearchInfo
@@ -65,7 +65,12 @@ import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.DATABASE_URI_KEY
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.utils.*
import com.kunzisoft.keepass.utils.DexUtil
import com.kunzisoft.keepass.utils.MagikeyboardUtil
import com.kunzisoft.keepass.utils.MenuUtil
import com.kunzisoft.keepass.utils.UriHelper.parseUri
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
import com.kunzisoft.keepass.utils.UriUtil.openUrl
import com.kunzisoft.keepass.view.asError
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
import com.kunzisoft.keepass.viewmodels.DatabaseFilesViewModel
@@ -179,7 +184,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
&& savedInstanceState.getBoolean(EXTRA_STAY, false))) {
val databasePath = PreferencesUtil.getDefaultDatabasePath(this)
UriUtil.parse(databasePath)?.let { databaseFileUri ->
databasePath?.parseUri()?.let { databaseFileUri ->
launchPasswordActivityWithPath(databaseFileUri)
} ?: run {
Log.i(TAG, "No default database to prepare")
@@ -228,7 +233,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
}
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
if (database != null) {
launchGroupActivityIfLoaded(database)
@@ -236,7 +241,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
}
override fun onDatabaseActionFinished(
database: Database,
database: ContextualDatabase,
actionTask: String,
result: ActionRunnable.Result
) {
@@ -304,7 +309,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
mAutofillActivityResultLauncher)
}
private fun launchGroupActivityIfLoaded(database: Database) {
private fun launchGroupActivityIfLoaded(database: ContextualDatabase) {
if (database.loaded) {
GroupActivity.launch(this,
database,
@@ -326,7 +331,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
super.onResume()
// Define special title
specialTitle?.isVisible = UriUtil.contributingUser(this)
specialTitle?.isVisible = this.isContributingUser()
// Show open and create button or special mode
when (mSpecialMode) {
@@ -426,7 +431,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> UriUtil.gotoUrl(this, R.string.file_manager_explanation_url)
android.R.id.home -> this.openUrl(R.string.file_manager_explanation_url)
}
MenuUtil.onDefaultMenuOptionsItemSelected(this, item)
return super.onOptionsItemSelected(item)

View File

@@ -27,13 +27,23 @@ import android.content.Context
import android.content.Intent
import android.graphics.PorterDuff
import android.net.Uri
import android.os.*
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Parcel
import android.os.Parcelable
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.*
import android.widget.DatePicker
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import android.widget.TimePicker
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.viewModels
import androidx.annotation.RequiresApi
@@ -50,7 +60,12 @@ import androidx.core.view.isVisible
import androidx.drawerlayout.widget.DrawerLayout
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.*
import com.kunzisoft.keepass.activities.dialogs.DatePickerFragment
import com.kunzisoft.keepass.activities.dialogs.GroupDialogFragment
import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment
import com.kunzisoft.keepass.activities.dialogs.MainCredentialDialogFragment
import com.kunzisoft.keepass.activities.dialogs.SortDialogFragment
import com.kunzisoft.keepass.activities.dialogs.TimePickerFragment
import com.kunzisoft.keepass.activities.fragments.GroupFragment
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
@@ -59,17 +74,21 @@ import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity
import com.kunzisoft.keepass.adapters.BreadcrumbAdapter
import com.kunzisoft.keepass.autofill.AutofillComponent
import com.kunzisoft.keepass.autofill.AutofillHelper
import com.kunzisoft.keepass.database.element.*
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.database.element.DateInstant
import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.SortNodeEnum
import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.database.search.SearchHelper
import com.kunzisoft.keepass.database.helper.SearchHelper
import com.kunzisoft.keepass.database.search.SearchParameters
import com.kunzisoft.keepass.education.GroupActivityEducation
import com.kunzisoft.keepass.magikeyboard.MagikeyboardService
import com.kunzisoft.keepass.model.GroupInfo
import com.kunzisoft.keepass.database.element.MainCredential
import com.kunzisoft.keepass.model.RegisterInfo
import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_ENTRY_TASK
@@ -81,8 +100,14 @@ import com.kunzisoft.keepass.settings.SettingsActivity
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.utils.BACK_PREVIOUS_KEYBOARD_ACTION
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.view.*
import com.kunzisoft.keepass.utils.UriUtil.openUrl
import com.kunzisoft.keepass.view.AddNodeButtonView
import com.kunzisoft.keepass.view.NavigationDatabaseView
import com.kunzisoft.keepass.view.SearchFiltersView
import com.kunzisoft.keepass.view.ToolbarAction
import com.kunzisoft.keepass.view.hideByFading
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
import com.kunzisoft.keepass.view.updateLockPaddingLeft
import com.kunzisoft.keepass.viewmodels.GroupEditViewModel
import com.kunzisoft.keepass.viewmodels.GroupViewModel
import org.joda.time.DateTime
@@ -302,7 +327,7 @@ class GroupActivity : DatabaseLockActivity(),
lockAndExit()
}
R.id.menu_contribute -> {
UriUtil.gotoUrl(this@GroupActivity, R.string.contribution_url)
this@GroupActivity.openUrl(R.string.contribution_url)
}
R.id.menu_about -> {
startActivity(Intent(this@GroupActivity, AboutActivity::class.java))
@@ -570,7 +595,7 @@ class GroupActivity : DatabaseLockActivity(),
}
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
mGroupEditViewModel.setGroupNamesNotAllowed(database?.groupNamesNotAllowed)
@@ -614,7 +639,7 @@ class GroupActivity : DatabaseLockActivity(),
}
override fun onDatabaseActionFinished(
database: Database,
database: ContextualDatabase,
actionTask: String,
result: ActionRunnable.Result
) {
@@ -800,7 +825,7 @@ class GroupActivity : DatabaseLockActivity(),
}
override fun onNodeClick(
database: Database,
database: ContextualDatabase,
node: Node
) {
when (node.type) {
@@ -873,7 +898,7 @@ class GroupActivity : DatabaseLockActivity(),
reloadGroupIfSearch()
}
private fun entrySelectedForSave(database: Database, entry: Entry, searchInfo: SearchInfo) {
private fun entrySelectedForSave(database: ContextualDatabase, entry: Entry, searchInfo: SearchInfo) {
reloadCurrentGroup()
// Save to update the entry
EntryEditActivity.launchToUpdateForSave(
@@ -885,7 +910,7 @@ class GroupActivity : DatabaseLockActivity(),
onLaunchActivitySpecialMode()
}
private fun entrySelectedForKeyboardSelection(database: Database, entry: Entry) {
private fun entrySelectedForKeyboardSelection(database: ContextualDatabase, entry: Entry) {
reloadCurrentGroup()
// Populate Magikeyboard with entry
MagikeyboardService.populateKeyboardAndMoveAppToBackground(
@@ -895,7 +920,7 @@ class GroupActivity : DatabaseLockActivity(),
onValidateSpecialMode()
}
private fun entrySelectedForAutofillSelection(database: Database, entry: Entry) {
private fun entrySelectedForAutofillSelection(database: ContextualDatabase, entry: Entry) {
// Build response with the entry selected
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AutofillHelper.buildResponseAndSetResult(
@@ -908,7 +933,7 @@ class GroupActivity : DatabaseLockActivity(),
}
private fun entrySelectedForRegistration(
database: Database,
database: ContextualDatabase,
entry: Entry,
registerInfo: RegisterInfo?
) {
@@ -924,7 +949,7 @@ class GroupActivity : DatabaseLockActivity(),
}
private fun updateEntryWithSearchInfo(
database: Database,
database: ContextualDatabase,
entry: Entry,
searchInfo: SearchInfo
) {
@@ -964,7 +989,7 @@ class GroupActivity : DatabaseLockActivity(),
}
override fun onNodeSelected(
database: Database,
database: ContextualDatabase,
nodes: List<Node>
): Boolean {
if (nodes.isNotEmpty()) {
@@ -990,7 +1015,7 @@ class GroupActivity : DatabaseLockActivity(),
}
override fun onOpenMenuClick(
database: Database,
database: ContextualDatabase,
node: Node
): Boolean {
finishNodeAction()
@@ -999,7 +1024,7 @@ class GroupActivity : DatabaseLockActivity(),
}
override fun onEditMenuClick(
database: Database,
database: ContextualDatabase,
node: Node
): Boolean {
finishNodeAction()
@@ -1047,7 +1072,7 @@ class GroupActivity : DatabaseLockActivity(),
}
override fun onCopyMenuClick(
database: Database,
database: ContextualDatabase,
nodes: List<Node>
): Boolean {
actionNodeMode?.invalidate()
@@ -1057,7 +1082,7 @@ class GroupActivity : DatabaseLockActivity(),
}
override fun onMoveMenuClick(
database: Database,
database: ContextualDatabase,
nodes: List<Node>
): Boolean {
actionNodeMode?.invalidate()
@@ -1067,7 +1092,7 @@ class GroupActivity : DatabaseLockActivity(),
}
override fun onPasteMenuClick(
database: Database,
database: ContextualDatabase,
pasteMode: GroupFragment.PasteMode?,
nodes: List<Node>
): Boolean {
@@ -1092,7 +1117,7 @@ class GroupActivity : DatabaseLockActivity(),
}
override fun onDeleteMenuClick(
database: Database,
database: ContextualDatabase,
nodes: List<Node>
): Boolean {
deleteNodes(nodes)
@@ -1101,15 +1126,19 @@ class GroupActivity : DatabaseLockActivity(),
return true
}
override fun onAskMainCredentialDialogPositiveClick(databaseUri: Uri?,
mainCredential: MainCredential) {
override fun onAskMainCredentialDialogPositiveClick(
databaseUri: Uri?,
mainCredential: MainCredential
) {
databaseUri?.let {
mergeDatabaseFrom(it, mainCredential)
}
}
override fun onAskMainCredentialDialogNegativeClick(databaseUri: Uri?,
mainCredential: MainCredential) { }
override fun onAskMainCredentialDialogNegativeClick(
databaseUri: Uri?,
mainCredential: MainCredential
) { }
override fun onResume() {
super.onResume()
@@ -1475,7 +1504,7 @@ class GroupActivity : DatabaseLockActivity(),
* -------------------------
*/
fun launch(context: Context,
database: Database,
database: ContextualDatabase,
autoSearch: Boolean = false) {
if (database.loaded) {
checkTimeAndBuildIntent(context, null) { intent ->
@@ -1491,7 +1520,7 @@ class GroupActivity : DatabaseLockActivity(),
* -------------------------
*/
fun launchForSearchResult(context: Context,
database: Database,
database: ContextualDatabase,
searchInfo: SearchInfo,
autoSearch: Boolean = false) {
if (database.loaded) {
@@ -1512,7 +1541,7 @@ class GroupActivity : DatabaseLockActivity(),
* -------------------------
*/
fun launchForSaveResult(context: Context,
database: Database,
database: ContextualDatabase,
searchInfo: SearchInfo,
autoSearch: Boolean = false) {
if (database.loaded && !database.isReadOnly) {
@@ -1533,7 +1562,7 @@ class GroupActivity : DatabaseLockActivity(),
* -------------------------
*/
fun launchForKeyboardSelectionResult(context: Context,
database: Database,
database: ContextualDatabase,
searchInfo: SearchInfo? = null,
autoSearch: Boolean = false) {
if (database.loaded) {
@@ -1555,7 +1584,7 @@ class GroupActivity : DatabaseLockActivity(),
*/
@RequiresApi(api = Build.VERSION_CODES.O)
fun launchForAutofillResult(activity: AppCompatActivity,
database: Database,
database: ContextualDatabase,
activityResultLaunch: ActivityResultLauncher<Intent>?,
autofillComponent: AutofillComponent,
searchInfo: SearchInfo? = null,
@@ -1580,7 +1609,7 @@ class GroupActivity : DatabaseLockActivity(),
* -------------------------
*/
fun launchForRegistration(context: Context,
database: Database,
database: ContextualDatabase,
registerInfo: RegisterInfo? = null) {
if (database.loaded && !database.isReadOnly) {
checkTimeAndBuildIntent(context, null) { intent ->
@@ -1600,7 +1629,7 @@ class GroupActivity : DatabaseLockActivity(),
* -------------------------
*/
fun launch(activity: AppCompatActivity,
database: Database,
database: ContextualDatabase,
onValidateSpecialMode: () -> Unit,
onCancelSpecialMode: () -> Unit,
onLaunchActivitySpecialMode: () -> Unit,

View File

@@ -41,16 +41,22 @@ import com.kunzisoft.keepass.activities.fragments.IconPickerFragment
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
import com.kunzisoft.keepass.activities.helpers.setOpenDocumentClickListener
import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.BinaryDatabaseManager
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
import com.kunzisoft.keepass.utils.UriUtil.openUrl
import com.kunzisoft.keepass.view.asError
import com.kunzisoft.keepass.view.updateLockPaddingLeft
import com.kunzisoft.keepass.viewmodels.IconPickerViewModel
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class IconPickerActivity : DatabaseLockActivity() {
@@ -166,7 +172,7 @@ class IconPickerActivity : DatabaseLockActivity() {
return true
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
if (database?.allowCustomIcons == true) {
@@ -243,7 +249,7 @@ class IconPickerActivity : DatabaseLockActivity() {
}
}
R.id.menu_external_icon -> {
UriUtil.gotoUrl(this, R.string.external_icon_url)
this.openUrl(R.string.external_icon_url)
}
}
@@ -257,7 +263,7 @@ class IconPickerActivity : DatabaseLockActivity() {
// on Progress with thread
val asyncResult: Deferred<IconPickerViewModel.IconCustomState?> = async {
val iconCustomState = IconPickerViewModel.IconCustomState(null, true, R.string.error_upload_file)
UriUtil.getFileData(this@IconPickerActivity, iconToUploadUri)?.also { documentFile ->
iconToUploadUri?.getDocumentFile(this@IconPickerActivity)?.also { documentFile ->
if (documentFile.length() > MAX_ICON_SIZE) {
iconCustomState.errorStringId = R.string.error_file_to_big
} else {

View File

@@ -33,8 +33,8 @@ import androidx.appcompat.widget.Toolbar
import com.igreenwood.loupe.Loupe
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.tasks.BinaryDatabaseManager
import kotlin.math.max
@@ -100,7 +100,7 @@ class ImageViewerActivity : DatabaseLockActivity() {
return true
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
try {

View File

@@ -55,8 +55,8 @@ import com.kunzisoft.keepass.autofill.AutofillComponent
import com.kunzisoft.keepass.autofill.AutofillHelper
import com.kunzisoft.keepass.biometric.AdvancedUnlockFragment
import com.kunzisoft.keepass.biometric.AdvancedUnlockManager
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.MainCredential
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.database.exception.DuplicateUuidDatabaseException
import com.kunzisoft.keepass.database.exception.FileNotFoundDatabaseException
import com.kunzisoft.keepass.education.PasswordActivityEducation
@@ -72,7 +72,7 @@ import com.kunzisoft.keepass.settings.SettingsAdvancedUnlockActivity
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.utils.BACK_PREVIOUS_KEYBOARD_ACTION
import com.kunzisoft.keepass.utils.MenuUtil
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.UriUtil.getUri
import com.kunzisoft.keepass.view.MainCredentialView
import com.kunzisoft.keepass.view.asError
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
@@ -262,7 +262,7 @@ class MainCredentialActivity : DatabaseModeActivity(), AdvancedUnlockFragment.Bu
}
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
if (database != null) {
// Trying to load another database
@@ -279,7 +279,7 @@ class MainCredentialActivity : DatabaseModeActivity(), AdvancedUnlockFragment.Bu
}
override fun onDatabaseActionFinished(
database: Database,
database: ContextualDatabase,
actionTask: String,
result: ActionRunnable.Result
) {
@@ -344,7 +344,7 @@ class MainCredentialActivity : DatabaseModeActivity(), AdvancedUnlockFragment.Bu
if (action == VIEW_INTENT) {
fillCredentials(
intent.data,
UriUtil.getUriFromIntent(intent, KEY_KEYFILE),
intent.getUri(KEY_KEYFILE),
HardwareKey.getHardwareKeyFromString(intent.getStringExtra(KEY_HARDWARE_KEY))
)
} else {
@@ -357,7 +357,7 @@ class MainCredentialActivity : DatabaseModeActivity(), AdvancedUnlockFragment.Bu
try {
intent?.removeExtra(KEY_KEYFILE)
intent?.removeExtra(KEY_HARDWARE_KEY)
} catch (e: Exception) {}
} catch (_: Exception) {}
mDatabaseFileUri?.let {
mDatabaseFileViewModel.checkIfIsDefaultDatabase(it)
}
@@ -376,7 +376,7 @@ class MainCredentialActivity : DatabaseModeActivity(), AdvancedUnlockFragment.Bu
getUriFromIntent(intent)
}
private fun launchGroupActivityIfLoaded(database: Database) {
private fun launchGroupActivityIfLoaded(database: ContextualDatabase) {
// Check if database really loaded
if (database.loaded) {
clearCredentialsViews(clearKeyFile = true, clearHardwareKey = true)

View File

@@ -78,7 +78,8 @@ class DatabaseChangedDialogFragment : DatabaseDialogFragment() {
private const val NEW_FILE_DATABASE_INFO = "NEW_FILE_DATABASE_INFO"
fun getInstance(oldSnapFileDatabaseInfo: SnapFileDatabaseInfo,
newSnapFileDatabaseInfo: SnapFileDatabaseInfo)
newSnapFileDatabaseInfo: SnapFileDatabaseInfo
)
: DatabaseChangedDialogFragment {
val fragment = DatabaseChangedDialogFragment()
fragment.arguments = Bundle().apply {

View File

@@ -5,7 +5,8 @@ import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels
import com.kunzisoft.keepass.activities.legacy.DatabaseRetrieval
import com.kunzisoft.keepass.activities.legacy.resetAppTimeoutWhenViewTouchedOrFocused
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.icons.IconDrawableFactory
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
@@ -13,7 +14,9 @@ import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
abstract class DatabaseDialogFragment : DialogFragment(), DatabaseRetrieval {
private val mDatabaseViewModel: DatabaseViewModel by activityViewModels()
private var mDatabase: Database? = null
private var mDatabase: ContextualDatabase? = null
protected var mIconDrawableFactory: IconDrawableFactory? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -36,12 +39,12 @@ abstract class DatabaseDialogFragment : DialogFragment(), DatabaseRetrieval {
resetAppTimeoutOnTouchOrFocus()
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
// Can be overridden by a subclass
}
override fun onDatabaseActionFinished(
database: Database,
database: ContextualDatabase,
actionTask: String,
result: ActionRunnable.Result
) {

View File

@@ -21,12 +21,12 @@ package com.kunzisoft.keepass.activities.dialogs
import android.app.Dialog
import android.os.Bundle
import androidx.fragment.app.DialogFragment
import androidx.appcompat.app.AlertDialog
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.UriUtil.openUrl
class FileManagerDialogFragment : DialogFragment() {
@@ -42,7 +42,7 @@ class FileManagerDialogFragment : DialogFragment() {
textDescription.text = getString(R.string.file_manager_install_description)
root.findViewById<Button>(R.id.file_manager_button).setOnClickListener {
UriUtil.gotoUrl(requireContext(), R.string.file_manager_explanation_url)
context?.openUrl(R.string.file_manager_explanation_url)
dismiss()
}

View File

@@ -31,10 +31,11 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.adapters.TagsAdapter
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.model.GroupInfo
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.TimeUtil.getDateTimeString
import com.kunzisoft.keepass.utils.UuidUtil
import com.kunzisoft.keepass.view.DateTimeFieldView
@@ -60,10 +61,10 @@ class GroupDialogFragment : DatabaseDialogFragment() {
private lateinit var uuidContainerView: ViewGroup
private lateinit var uuidReferenceView: TextView
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
mPopulateIconMethod = { imageView, icon ->
database?.iconDrawableFactory?.assignDatabaseIcon(imageView, icon, mIconColor)
mIconDrawableFactory?.assignDatabaseIcon(imageView, icon, mIconColor)
}
mPopulateIconMethod?.invoke(iconView, mGroupInfo.icon)

View File

@@ -24,14 +24,18 @@ import android.graphics.Color
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.*
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.activityViewModels
import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment.EditGroupDialogAction.*
import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment.EditGroupDialogAction.CREATION
import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment.EditGroupDialogAction.NONE
import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment.EditGroupDialogAction.UPDATE
import com.kunzisoft.keepass.adapters.TagsProposalAdapter
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.DateInstant
import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.model.GroupInfo
@@ -116,7 +120,7 @@ class GroupEditDialogFragment : DatabaseDialogFragment() {
}
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
mPopulateIconMethod = { imageView, icon ->

View File

@@ -27,7 +27,7 @@ import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.activityViewModels
import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.DateInstant
import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
@@ -44,7 +44,7 @@ class IconEditDialogFragment : DatabaseDialogFragment() {
private var mCustomIcon: IconImageCustom? = null
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
mPopulateIconMethod = { imageView, icon ->
database?.iconDrawableFactory?.assignDatabaseIcon(imageView, icon)

View File

@@ -27,8 +27,8 @@ import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
import com.kunzisoft.keepass.database.element.MainCredential
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
import com.kunzisoft.keepass.view.MainCredentialView
class MainCredentialDialogFragment : DatabaseDialogFragment() {
@@ -74,7 +74,7 @@ class MainCredentialDialogFragment : DatabaseDialogFragment() {
mainCredentialView = root.findViewById(R.id.main_credential_view)
databaseUri?.let {
root.findViewById<TextView>(R.id.title_database)?.text =
UriUtil.getFileData(requireContext(), it)?.name
it.getDocumentFile(requireContext())?.name
}
builder.setView(root)
// Add action buttons

View File

@@ -26,7 +26,7 @@ import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.MainCredential
import com.kunzisoft.keepass.database.MainCredential
class PasswordEncodingDialogFragment : DialogFragment() {
@@ -78,8 +78,10 @@ class PasswordEncodingDialogFragment : DialogFragment() {
private const val DATABASE_URI_KEY = "DATABASE_URI_KEY"
private const val MAIN_CREDENTIAL = "MAIN_CREDENTIAL"
fun getInstance(databaseUri: Uri,
mainCredential: MainCredential): SortDialogFragment {
fun getInstance(
databaseUri: Uri,
mainCredential: MainCredential
): SortDialogFragment {
val fragment = SortDialogFragment()
fragment.arguments = Bundle().apply {
putParcelable(DATABASE_URI_KEY, databaseUri)

View File

@@ -28,7 +28,7 @@ import androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY
import androidx.fragment.app.DialogFragment
import com.kunzisoft.keepass.BuildConfig
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.UriUtil.openUrl
/**
* Custom Dialog that asks the user to download the pro version or make a donation.
@@ -45,7 +45,7 @@ class ProFeatureDialogFragment : DialogFragment() {
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_ad_free), FROM_HTML_MODE_LEGACY)).append("\n\n")
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_buy_pro), FROM_HTML_MODE_LEGACY))
builder.setPositiveButton(R.string.download) { _, _ ->
UriUtil.gotoUrl(activity,
activity.openUrl(
activity.getString(R.string.play_store_url,
activity.getString(R.string.keepro_app_id))
)
@@ -54,7 +54,7 @@ class ProFeatureDialogFragment : DialogFragment() {
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_feature_generosity), FROM_HTML_MODE_LEGACY)).append("\n\n")
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_donation), FROM_HTML_MODE_LEGACY))
builder.setPositiveButton(R.string.contribute) { _, _ ->
UriUtil.gotoUrl(activity, R.string.contribution_url)
activity.openUrl(R.string.contribution_url)
}
}
builder.setMessage(stringBuilder)

View File

@@ -35,11 +35,12 @@ import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
import com.kunzisoft.keepass.activities.helpers.setOpenDocumentClickListener
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.hardware.HardwareKeyActivity
import com.kunzisoft.keepass.database.element.MainCredential
import com.kunzisoft.keepass.password.PasswordEntropy
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
import com.kunzisoft.keepass.utils.UriUtil.openUrl
import com.kunzisoft.keepass.view.HardwareKeySelectionView
import com.kunzisoft.keepass.view.KeyFileSelectionView
import com.kunzisoft.keepass.view.PassKeyView
@@ -136,7 +137,7 @@ class SetMainCredentialDialogFragment : DatabaseDialogFragment() {
.setNegativeButton(android.R.string.cancel) { _, _ -> }
rootView.findViewById<View>(R.id.credentials_information)?.setOnClickListener {
UriUtil.gotoUrl(activity, R.string.credentials_explanation_url)
activity.openUrl(R.string.credentials_explanation_url)
}
passwordCheckBox = rootView.findViewById(R.id.password_checkbox)
@@ -154,7 +155,7 @@ class SetMainCredentialDialogFragment : DatabaseDialogFragment() {
mExternalFileHelper = ExternalFileHelper(this)
mExternalFileHelper?.buildOpenDocument { uri ->
uri?.let { pathUri ->
UriUtil.getFileData(requireContext(), uri)?.length()?.let { lengthFile ->
pathUri.getDocumentFile(requireContext())?.length()?.let { lengthFile ->
keyFileSelectionView.error = null
keyFileCheckBox.isChecked = true
keyFileSelectionView.uri = pathUri

View File

@@ -32,7 +32,6 @@ import android.view.inputmethod.EditorInfo
import android.widget.*
import androidx.appcompat.app.AlertDialog
import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.BuildConfig
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.model.OtpModel
import com.kunzisoft.keepass.otp.OtpElement
@@ -45,7 +44,8 @@ import com.kunzisoft.keepass.otp.OtpElement.Companion.MIN_TOTP_PERIOD
import com.kunzisoft.keepass.otp.OtpTokenType
import com.kunzisoft.keepass.otp.OtpType
import com.kunzisoft.keepass.otp.TokenCalculator
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
import com.kunzisoft.keepass.utils.UriUtil.openUrl
import java.util.*
class SetOTPDialogFragment : DatabaseDialogFragment() {
@@ -206,7 +206,7 @@ class SetOTPDialogFragment : DatabaseDialogFragment() {
}
// Proprietary only on full version
mTotpTokenTypeArray = OtpTokenType.getTotpTokenTypeValues(
UriUtil.contributingUser(activity)
activity.isContributingUser()
)
totpTokenTypeAdapter = ArrayAdapter(activity,
android.R.layout.simple_spinner_item, mTotpTokenTypeArray!!).apply {
@@ -242,7 +242,7 @@ class SetOTPDialogFragment : DatabaseDialogFragment() {
}
root?.findViewById<View>(R.id.otp_information)?.setOnClickListener {
UriUtil.gotoUrl(activity, R.string.otp_explanation_url)
activity.openUrl(R.string.otp_explanation_url)
}
return builder.create()

View File

@@ -26,7 +26,7 @@ import androidx.appcompat.app.AlertDialog
import androidx.core.text.HtmlCompat
import androidx.fragment.app.DialogFragment
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.UriUtil.openUrl
/**
* Custom Dialog that asks the user to download the pro version or make a donation.
@@ -40,7 +40,7 @@ class UnderDevelopmentFeatureDialogFragment : DialogFragment() {
val stringBuilder = SpannableStringBuilder()
/*
if (UriUtil.contributingUser(activity)) {
if (activity.isContributingUser()) {
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_thanks), HtmlCompat.FROM_HTML_MODE_LEGACY)).append("\n\n")
.append(HtmlCompat.fromHtml(getString(R.string.html_rose), HtmlCompat.FROM_HTML_MODE_LEGACY)).append("\n\n")
.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_work_hard), HtmlCompat.FROM_HTML_MODE_LEGACY)).append("\n")
@@ -52,7 +52,7 @@ class UnderDevelopmentFeatureDialogFragment : DialogFragment() {
.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_contibute), HtmlCompat.FROM_HTML_MODE_LEGACY)).append(" ")
.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_encourage), HtmlCompat.FROM_HTML_MODE_LEGACY))
builder.setPositiveButton(R.string.contribute) { _, _ ->
UriUtil.gotoUrl(requireContext(), R.string.contribution_url)
context?.openUrl(R.string.contribution_url)
}
//}
builder.setMessage(stringBuilder)

View File

@@ -6,7 +6,7 @@ import androidx.fragment.app.activityViewModels
import com.kunzisoft.keepass.activities.legacy.DatabaseRetrieval
import com.kunzisoft.keepass.activities.legacy.resetAppTimeoutWhenViewTouchedOrFocused
import com.kunzisoft.keepass.activities.stylish.StylishFragment
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.binary.BinaryData
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
@@ -14,7 +14,7 @@ import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
abstract class DatabaseFragment : StylishFragment(), DatabaseRetrieval {
private val mDatabaseViewModel: DatabaseViewModel by activityViewModels()
protected var mDatabase: Database? = null
protected var mDatabase: ContextualDatabase? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -38,7 +38,7 @@ abstract class DatabaseFragment : StylishFragment(), DatabaseRetrieval {
}
override fun onDatabaseActionFinished(
database: Database,
database: ContextualDatabase,
actionTask: String,
result: ActionRunnable.Result
) {

View File

@@ -35,14 +35,18 @@ import com.kunzisoft.keepass.activities.dialogs.ReplaceFileDialogFragment
import com.kunzisoft.keepass.activities.dialogs.SetOTPDialogFragment
import com.kunzisoft.keepass.adapters.EntryAttachmentsItemsAdapter
import com.kunzisoft.keepass.adapters.TagsProposalAdapter
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.template.Template
import com.kunzisoft.keepass.model.AttachmentState
import com.kunzisoft.keepass.model.EntryAttachmentState
import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.model.StreamDirection
import com.kunzisoft.keepass.view.*
import com.kunzisoft.keepass.view.TagsCompletionView
import com.kunzisoft.keepass.view.TemplateEditView
import com.kunzisoft.keepass.view.collapse
import com.kunzisoft.keepass.view.expand
import com.kunzisoft.keepass.view.showByFading
import com.kunzisoft.keepass.viewmodels.EntryEditViewModel
import com.tokenautocomplete.FilteredArrayAdapter
@@ -268,7 +272,7 @@ class EntryEditFragment: DatabaseFragment() {
}
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
templateView.populateIconMethod = { imageView, icon ->
database?.iconDrawableFactory?.assignDatabaseIcon(imageView, icon, mIconColor)

View File

@@ -14,14 +14,16 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SimpleItemAnimator
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.adapters.EntryAttachmentsItemsAdapter
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.template.TemplateField
import com.kunzisoft.keepass.database.helper.getLocalizedName
import com.kunzisoft.keepass.model.EntryAttachmentState
import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.model.StreamDirection
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.timeout.ClipboardHelper
import com.kunzisoft.keepass.utils.TimeUtil.getDateTimeString
import com.kunzisoft.keepass.utils.UuidUtil
import com.kunzisoft.keepass.view.TemplateView
import com.kunzisoft.keepass.view.hideByFading
@@ -132,7 +134,7 @@ class EntryFragment: DatabaseFragment() {
}
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
context?.let { context ->
attachmentsAdapter = EntryAttachmentsItemsAdapter(context)
attachmentsAdapter?.database = database

View File

@@ -22,7 +22,12 @@ package com.kunzisoft.keepass.activities.fragments
import android.content.Context
import android.os.Bundle
import android.util.Log
import android.view.*
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.view.ActionMode
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.LinearLayoutManager
@@ -34,7 +39,7 @@ import com.kunzisoft.keepass.activities.dialogs.SortDialogFragment
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.activities.helpers.SpecialMode
import com.kunzisoft.keepass.adapters.NodesAdapter
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.SortNodeEnum
import com.kunzisoft.keepass.database.element.node.Node
@@ -42,7 +47,7 @@ import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.viewmodels.GroupViewModel
import java.util.*
import java.util.LinkedList
class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListener {
@@ -143,7 +148,7 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
setHasOptionsMenu(true)
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
mRecycleBinEnable = database?.isRecycleBinEnabled == true
mRecycleBin = database?.recycleBin
@@ -151,7 +156,7 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
database?.let { database ->
mAdapter = NodesAdapter(context, database).apply {
setOnNodeClickListener(object : NodesAdapter.NodeClickCallback {
override fun onNodeClick(database: Database, node: Node) {
override fun onNodeClick(database: ContextualDatabase, node: Node) {
if (mCurrentGroup?.isVirtual == false
&& nodeActionSelectionMode) {
if (listActionNodes.contains(node)) {
@@ -169,7 +174,7 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
}
}
override fun onNodeLongClick(database: Database, node: Node): Boolean {
override fun onNodeLongClick(database: ContextualDatabase, node: Node): Boolean {
if (mCurrentGroup?.isVirtual == false
&& nodeActionPasteMode == PasteMode.UNDEFINED) {
// Select the first item after a long click
@@ -191,7 +196,7 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
}
override fun onDatabaseActionFinished(
database: Database,
database: ContextualDatabase,
actionTask: String,
result: ActionRunnable.Result
) {
@@ -329,7 +334,7 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
}
}
fun actionNodesCallback(database: Database,
fun actionNodesCallback(database: ContextualDatabase,
nodes: List<Node>,
menuListener: NodesActionMenuListener?,
onDestroyActionMode: (mode: ActionMode?) -> Unit) : ActionMode.Callback {
@@ -433,20 +438,20 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
* Callback listener to redefine to do an action when a node is click
*/
interface NodeClickListener {
fun onNodeClick(database: Database, node: Node)
fun onNodeSelected(database: Database, nodes: List<Node>): Boolean
fun onNodeClick(database: ContextualDatabase, node: Node)
fun onNodeSelected(database: ContextualDatabase, nodes: List<Node>): Boolean
}
/**
* Menu listener to redefine to do an action in menu
*/
interface NodesActionMenuListener {
fun onOpenMenuClick(database: Database, node: Node): Boolean
fun onEditMenuClick(database: Database, node: Node): Boolean
fun onCopyMenuClick(database: Database, nodes: List<Node>): Boolean
fun onMoveMenuClick(database: Database, nodes: List<Node>): Boolean
fun onDeleteMenuClick(database: Database, nodes: List<Node>): Boolean
fun onPasteMenuClick(database: Database, pasteMode: PasteMode?, nodes: List<Node>): Boolean
fun onOpenMenuClick(database: ContextualDatabase, node: Node): Boolean
fun onEditMenuClick(database: ContextualDatabase, node: Node): Boolean
fun onCopyMenuClick(database: ContextualDatabase, nodes: List<Node>): Boolean
fun onMoveMenuClick(database: ContextualDatabase, nodes: List<Node>): Boolean
fun onDeleteMenuClick(database: ContextualDatabase, nodes: List<Node>): Boolean
fun onPasteMenuClick(database: ContextualDatabase, pasteMode: PasteMode?, nodes: List<Node>): Boolean
}
enum class PasteMode {

View File

@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.activities.fragments
import android.os.Bundle
import android.view.View
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
@@ -32,7 +32,7 @@ class IconCustomFragment : IconFragment<IconImageCustom>() {
return R.layout.fragment_icon_grid
}
override fun defineIconList(database: Database?) {
override fun defineIconList(database: ContextualDatabase?) {
database?.doForEachCustomIcons { customIcon, _ ->
iconPickerAdapter.addIcon(customIcon, false)
}

View File

@@ -28,7 +28,7 @@ import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.adapters.IconPickerAdapter
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.icon.IconImageDraw
import com.kunzisoft.keepass.viewmodels.IconPickerViewModel
import kotlinx.coroutines.CoroutineScope
@@ -47,7 +47,7 @@ abstract class IconFragment<T: IconImageDraw> : DatabaseFragment(),
abstract fun retrieveMainLayoutId(): Int
abstract fun defineIconList(database: Database?)
abstract fun defineIconList(database: ContextualDatabase?)
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
@@ -71,7 +71,7 @@ abstract class IconFragment<T: IconImageDraw> : DatabaseFragment(),
resetAppTimeoutWhenViewFocusedOrChanged(view)
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
iconPickerAdapter.iconDrawableFactory = database?.iconDrawableFactory
CoroutineScope(Dispatchers.IO).launch {

View File

@@ -10,7 +10,7 @@ import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.adapters.IconPickerPagerAdapter
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.viewmodels.IconPickerViewModel
class IconPickerFragment : DatabaseFragment() {
@@ -48,7 +48,7 @@ class IconPickerFragment : DatabaseFragment() {
}
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
iconPickerPagerAdapter = IconPickerPagerAdapter(this,
if (database?.allowCustomIcons == true) 2 else 1)
viewPager.adapter = iconPickerPagerAdapter

View File

@@ -20,7 +20,7 @@
package com.kunzisoft.keepass.activities.fragments
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
@@ -30,7 +30,7 @@ class IconStandardFragment : IconFragment<IconImageStandard>() {
return R.layout.fragment_icon_grid
}
override fun defineIconList(database: Database?) {
override fun defineIconList(database: ContextualDatabase?) {
database?.doForEachStandardIcons { standardIcon ->
iconPickerAdapter.addIcon(standardIcon, false)
}

View File

@@ -30,7 +30,7 @@ import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.adapters.KeyGeneratorPagerAdapter
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.viewmodels.KeyGeneratorViewModel
class KeyGeneratorFragment : DatabaseFragment() {
@@ -107,7 +107,7 @@ class KeyGeneratorFragment : DatabaseFragment() {
super.onDestroyView()
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
// Nothing here
}

View File

@@ -30,7 +30,7 @@ import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.activityViewModels
import com.google.android.material.slider.Slider
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.password.PassphraseGenerator
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.timeout.ClipboardHelper
@@ -244,7 +244,7 @@ class PassphraseGeneratorFragment : DatabaseFragment() {
}
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
// Nothing here
}

View File

@@ -32,7 +32,7 @@ import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.activityViewModels
import com.google.android.material.slider.Slider
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.password.PasswordGenerator
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.timeout.ClipboardHelper
@@ -318,7 +318,7 @@ class PasswordGeneratorFragment : DatabaseFragment() {
super.onDestroy()
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
// Nothing here
}

View File

@@ -33,7 +33,7 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.kunzisoft.keepass.activities.dialogs.FileManagerDialogFragment
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.UriUtil.takeUriPermission
class ExternalFileHelper {
@@ -57,10 +57,8 @@ class ExternalFileHelper {
fun buildOpenDocument(onFileSelected: ((uri: Uri?) -> Unit)?) {
val resultCallback = ActivityResultCallback<Uri?> { result ->
result?.let { uri ->
UriUtil.takeUriPermission(activity?.contentResolver, uri)
onFileSelected?.invoke(uri)
}
activity?.contentResolver?.takeUriPermission(result)
onFileSelected?.invoke(result)
}
getContentResultLauncher = if (fragment != null) {

View File

@@ -4,18 +4,19 @@ import android.net.Uri
import android.os.Bundle
import androidx.activity.viewModels
import com.kunzisoft.keepass.activities.stylish.StylishActivity
import com.kunzisoft.keepass.database.action.DatabaseTaskProvider
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.MainCredential
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.database.DatabaseTaskProvider
import com.kunzisoft.keepass.model.CipherEncryptDatabase
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.utils.UriHelper.getBinaryDir
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
abstract class DatabaseActivity: StylishActivity(), DatabaseRetrieval {
protected val mDatabaseViewModel: DatabaseViewModel by viewModels()
protected var mDatabaseTaskProvider: DatabaseTaskProvider? = null
protected var mDatabase: Database? = null
protected var mDatabase: ContextualDatabase? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -47,14 +48,14 @@ abstract class DatabaseActivity: StylishActivity(), DatabaseRetrieval {
super.onDestroy()
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
mDatabase = database
mDatabaseViewModel.defineDatabase(database)
// optional method implementation
}
override fun onDatabaseActionFinished(
database: Database,
database: ContextualDatabase,
actionTask: String,
result: ActionRunnable.Result
) {
@@ -62,21 +63,25 @@ abstract class DatabaseActivity: StylishActivity(), DatabaseRetrieval {
// optional method implementation
}
fun createDatabase(databaseUri: Uri,
mainCredential: MainCredential) {
fun createDatabase(
databaseUri: Uri,
mainCredential: MainCredential
) {
mDatabaseTaskProvider?.startDatabaseCreate(databaseUri, mainCredential)
}
fun loadDatabase(databaseUri: Uri,
mainCredential: MainCredential,
readOnly: Boolean,
cipherEncryptDatabase: CipherEncryptDatabase?,
fixDuplicateUuid: Boolean) {
fun loadDatabase(
databaseUri: Uri,
mainCredential: MainCredential,
readOnly: Boolean,
cipherEncryptDatabase: CipherEncryptDatabase?,
fixDuplicateUuid: Boolean
) {
mDatabaseTaskProvider?.startDatabaseLoad(databaseUri, mainCredential, readOnly, cipherEncryptDatabase, fixDuplicateUuid)
}
protected fun closeDatabase() {
mDatabase?.clearAndClose(this)
mDatabase?.clearAndClose(this.getBinaryDir())
}
override fun onResume() {

View File

@@ -36,14 +36,13 @@ import com.kunzisoft.keepass.activities.dialogs.DeleteNodesDialogFragment
import com.kunzisoft.keepass.activities.dialogs.PasswordEncodingDialogFragment
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.activities.helpers.SpecialMode
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.icons.IconDrawableFactory
import com.kunzisoft.keepass.model.GroupInfo
import com.kunzisoft.keepass.database.element.MainCredential
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable
@@ -67,8 +66,6 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
protected var mMergeDataAllowed: Boolean = false
private var mAutoSaveEnable: Boolean = true
protected var mIconDrawableFactory: IconDrawableFactory? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -167,7 +164,7 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
return true
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
// End activity if database not loaded
@@ -207,7 +204,6 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
mDatabaseReadOnly = database.isReadOnly
mMergeDataAllowed = database.isMergeDataAllowed()
mIconDrawableFactory = database.iconDrawableFactory
checkRegister()
}
@@ -216,7 +212,7 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
abstract fun viewToInvalidateTimeout(): View?
override fun onDatabaseActionFinished(
database: Database,
database: ContextualDatabase,
actionTask: String,
result: ActionRunnable.Result
) {
@@ -238,15 +234,19 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
}
}
override fun onPasswordEncodingValidateListener(databaseUri: Uri?,
mainCredential: MainCredential) {
override fun onPasswordEncodingValidateListener(
databaseUri: Uri?,
mainCredential: MainCredential
) {
assignDatabasePassword(databaseUri, mainCredential)
}
private fun assignDatabasePassword(databaseUri: Uri?,
mainCredential: MainCredential) {
private fun assignDatabasePassword(
databaseUri: Uri?,
mainCredential: MainCredential
) {
if (databaseUri != null) {
mDatabaseTaskProvider?.startDatabaseAssignPassword(databaseUri, mainCredential)
mDatabaseTaskProvider?.startDatabaseAssignCredential(databaseUri, mainCredential)
}
}
@@ -254,7 +254,7 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
mDatabase?.let { database ->
database.fileUri?.let { databaseUri ->
// Show the progress dialog now or after dialog confirmation
if (database.validatePasswordEncoding(mainCredential)) {
if (database.isValidCredential(mainCredential.toMasterCredential(contentResolver))) {
assignDatabasePassword(databaseUri, mainCredential)
} else {
PasswordEncodingDialogFragment.getInstance(databaseUri, mainCredential)
@@ -306,7 +306,7 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
mDatabaseTaskProvider?.startDatabaseMoveNodes(nodesToMove, newParent, mAutoSaveEnable)
}
private fun eachNodeRecyclable(database: Database, nodes: List<Node>): Boolean {
private fun eachNodeRecyclable(database: ContextualDatabase, nodes: List<Node>): Boolean {
return nodes.find { node ->
var cannotRecycle = true
if (node is Entry) {
@@ -322,7 +322,7 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
mDatabase?.let { database ->
// If recycle bin enabled, ensure it exists
if (database.isRecycleBinEnabled) {
database.ensureRecycleBinExists(resources)
database.ensureRecycleBinExists(resources.getString(R.string.recycle_bin))
}
// If recycle bin enabled and not in recycle bin, move in recycle bin

View File

@@ -1,11 +1,11 @@
package com.kunzisoft.keepass.activities.legacy
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.tasks.ActionRunnable
interface DatabaseRetrieval {
fun onDatabaseRetrieved(database: Database?)
fun onDatabaseActionFinished(database: Database,
fun onDatabaseRetrieved(database: ContextualDatabase?)
fun onDatabaseActionFinished(database: ContextualDatabase,
actionTask: String,
result: ActionRunnable.Result)
}

View File

@@ -112,7 +112,11 @@ class BreadcrumbAdapter(val context: Context)
holder.groupNumbersView?.apply {
if (mShowNumberEntries) {
group.refreshNumberOfChildEntries(Group.ChildFilter.getDefaults(context))
group.refreshNumberOfChildEntries(
Group.ChildFilter.getDefaults(
PreferencesUtil.showExpiredEntries(context)
)
)
text = group.numberOfChildEntries.toString()
visibility = View.VISIBLE
} else {

View File

@@ -32,8 +32,9 @@ import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.ImageViewerActivity
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
import com.kunzisoft.keepass.database.helper.getLocalizedName
import com.kunzisoft.keepass.model.AttachmentState
import com.kunzisoft.keepass.model.EntryAttachmentState
import com.kunzisoft.keepass.model.StreamDirection
@@ -45,7 +46,7 @@ import kotlin.math.max
class EntryAttachmentsItemsAdapter(context: Context)
: AnimatedItemsAdapter<EntryAttachmentState, EntryAttachmentsItemsAdapter.EntryBinariesViewHolder>(context) {
var database: Database? = null
var database: ContextualDatabase? = null
var onItemClickListener: ((item: EntryAttachmentState)->Unit)? = null
var onBinaryPreviewLoaded: ((item: EntryAttachmentState) -> Unit)? = null
@@ -130,7 +131,7 @@ class EntryAttachmentsItemsAdapter(context: Context)
holder.binaryFileSize.text = Formatter.formatFileSize(context, size)
holder.binaryFileCompression.apply {
if (entryAttachmentState.attachment.binaryData.isCompressed) {
text = CompressionAlgorithm.GZip.getName(context.resources)
text = CompressionAlgorithm.GZIP.getLocalizedName(context.resources)
visibility = View.VISIBLE
} else {
text = ""

View File

@@ -27,6 +27,7 @@ import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.utils.TimeUtil.getDateTimeString
class EntryHistoryAdapter(val context: Context) : RecyclerView.Adapter<EntryHistoryAdapter.EntryHistoryViewHolder>() {

View File

@@ -34,7 +34,7 @@ import androidx.recyclerview.widget.SortedList
import androidx.recyclerview.widget.SortedListAdapterCallback
import com.google.android.material.progressindicator.CircularProgressIndicator
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.SortNodeEnum
@@ -42,21 +42,23 @@ import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeVersionedInterface
import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.database.element.template.TemplateField
import com.kunzisoft.keepass.database.helper.getLocalizedName
import com.kunzisoft.keepass.otp.OtpElement
import com.kunzisoft.keepass.otp.OtpType
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.timeout.ClipboardHelper
import com.kunzisoft.keepass.view.setTextSize
import com.kunzisoft.keepass.view.strikeOut
import java.util.*
import java.util.LinkedList
/**
* Create node list adapter with contextMenu or not
* @param context Context to use
*/
class NodesAdapter (private val context: Context,
private val database: Database)
: RecyclerView.Adapter<NodesAdapter.NodeViewHolder>() {
class NodesAdapter (
private val context: Context,
private val database: ContextualDatabase
) : RecyclerView.Adapter<NodesAdapter.NodeViewHolder>() {
private var mNodeComparator: Comparator<NodeVersionedInterface<Group>>? = null
private val mNodeSortedListCallback: NodeSortedListCallback
@@ -152,7 +154,9 @@ class NodesAdapter (private val context: Context,
this.mShowOTP = PreferencesUtil.showOTPToken(context)
this.mShowUUID = PreferencesUtil.showUUID(context)
this.mEntryFilters = Group.ChildFilter.getDefaults(context)
this.mEntryFilters = Group.ChildFilter.getDefaults(
PreferencesUtil.showExpiredEntries(context)
)
// Reinit textSize for all view type
mCalculateViewTypeTextSize.forEachIndexed { index, _ -> mCalculateViewTypeTextSize[index] = true }
@@ -562,8 +566,8 @@ class NodesAdapter (private val context: Context,
* Callback listener to redefine to do an action when a node is click
*/
interface NodeClickCallback {
fun onNodeClick(database: Database, node: Node)
fun onNodeLongClick(database: Database, node: Node): Boolean
fun onNodeClick(database: ContextualDatabase, node: Node)
fun onNodeLongClick(database: ContextualDatabase, node: Node): Boolean
}
class NodeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

View File

@@ -11,6 +11,7 @@ import android.widget.TextView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.template.Template
import com.kunzisoft.keepass.database.element.template.TemplateField
import com.kunzisoft.keepass.database.helper.getLocalizedName
import com.kunzisoft.keepass.icons.IconDrawableFactory

View File

@@ -19,24 +19,27 @@
*/
package com.kunzisoft.keepass.app.database
import android.content.*
import android.content.ComponentName
import android.content.Context
import android.content.IntentFilter
import android.content.ServiceConnection
import android.net.Uri
import android.os.IBinder
import android.util.Base64
import android.util.Log
import com.kunzisoft.keepass.database.element.binary.BinaryData.Companion.BASE64_FLAG
import com.kunzisoft.keepass.model.CipherEncryptDatabase
import com.kunzisoft.keepass.services.AdvancedUnlockNotificationService
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.IOActionTask
import com.kunzisoft.keepass.utils.SingletonHolderParameter
import java.util.*
import java.util.LinkedList
class CipherDatabaseAction(context: Context) {
private val applicationContext = context.applicationContext
private val cipherDatabaseDao =
AppDatabase
.getDatabase(applicationContext)
.cipherDatabaseDao()
AppDatabase.getDatabase(applicationContext).cipherDatabaseDao()
// Temp DAO to easily remove content if object no longer in memory
private var useTempDao = PreferencesUtil.isTempAdvancedUnlockEnable(applicationContext)
@@ -83,7 +86,7 @@ class CipherDatabaseAction(context: Context) {
try {
AdvancedUnlockNotificationService.bindService(applicationContext,
mServiceConnection!!,
Context.BIND_AUTO_CREATE)
Context.BIND_AUTO_CREATE)
} catch (e: Exception) {
Log.e(TAG, "Unable to start cipher action", e)
performedAction.invoke()
@@ -136,11 +139,11 @@ class CipherDatabaseAction(context: Context) {
this.databaseUri = Uri.parse(cipherDatabaseEntity.databaseUri)
this.encryptedValue = Base64.decode(
cipherDatabaseEntity.encryptedValue,
Base64.NO_WRAP
BASE64_FLAG
)
this.specParameters = Base64.decode(
cipherDatabaseEntity.specParameters,
Base64.NO_WRAP
BASE64_FLAG
)
}
}
@@ -148,8 +151,9 @@ class CipherDatabaseAction(context: Context) {
}
} else {
IOActionTask(
{
cipherDatabaseDao.getByDatabaseUri(databaseUri.toString())?.let { cipherDatabaseEntity ->
{
cipherDatabaseDao.getByDatabaseUri(databaseUri.toString())
?.let { cipherDatabaseEntity ->
CipherEncryptDatabase().apply {
this.databaseUri = Uri.parse(cipherDatabaseEntity.databaseUri)
this.encryptedValue = Base64.decode(
@@ -162,10 +166,10 @@ class CipherDatabaseAction(context: Context) {
)
}
}
},
{
cipherDatabaseResultListener.invoke(it)
}
},
{
cipherDatabaseResultListener.invoke(it)
}
).execute()
}
}
@@ -183,8 +187,8 @@ class CipherDatabaseAction(context: Context) {
val cipherDatabaseEntity = CipherDatabaseEntity(
databaseUri.toString(),
Base64.encodeToString(cipherEncryptDatabase.encryptedValue, Base64.NO_WRAP),
Base64.encodeToString(cipherEncryptDatabase.specParameters, Base64.NO_WRAP),
Base64.encodeToString(cipherEncryptDatabase.encryptedValue, BASE64_FLAG),
Base64.encodeToString(cipherEncryptDatabase.specParameters, BASE64_FLAG),
)
if (useTempDao) {
@@ -222,12 +226,12 @@ class CipherDatabaseAction(context: Context) {
}
} else {
IOActionTask(
{
cipherDatabaseDao.deleteByDatabaseUri(databaseUri.toString())
},
{
cipherDatabaseResultListener?.invoke()
}
{
cipherDatabaseDao.deleteByDatabaseUri(databaseUri.toString())
},
{
cipherDatabaseResultListener?.invoke()
}
).execute()
}
}
@@ -240,9 +244,9 @@ class CipherDatabaseAction(context: Context) {
}
// To erase the residues
IOActionTask(
{
cipherDatabaseDao.deleteAll()
}
{
cipherDatabaseDao.deleteAll()
}
).execute()
// Unbind
removeAllDataAndDetach()

View File

@@ -25,88 +25,96 @@ import android.util.Log
import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.model.DatabaseFile
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.IOActionTask
import com.kunzisoft.keepass.utils.SingletonHolderParameter
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.UriHelper.decodeUri
import com.kunzisoft.keepass.utils.UriHelper.parseUri
import com.kunzisoft.keepass.viewmodels.FileDatabaseInfo
class FileDatabaseHistoryAction(private val applicationContext: Context) {
private val databaseFileHistoryDao =
AppDatabase
.getDatabase(applicationContext)
.fileDatabaseHistoryDao()
AppDatabase.getDatabase(applicationContext).fileDatabaseHistoryDao()
fun getDatabaseFile(databaseUri: Uri,
databaseFileResult: (DatabaseFile?) -> Unit) {
IOActionTask(
{
val fileDatabaseHistoryEntity = databaseFileHistoryDao.getByDatabaseUri(databaseUri.toString())
val fileDatabaseInfo = FileDatabaseInfo(applicationContext, databaseUri)
DatabaseFile(
databaseUri,
UriUtil.parse(fileDatabaseHistoryEntity?.keyFileUri),
HardwareKey.getHardwareKeyFromString(fileDatabaseHistoryEntity?.hardwareKey),
UriUtil.decode(fileDatabaseHistoryEntity?.databaseUri),
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistoryEntity?.databaseAlias ?: ""),
fileDatabaseInfo.exists,
fileDatabaseInfo.getLastModificationString(),
fileDatabaseInfo.getSizeString()
)
},
{
databaseFileResult.invoke(it)
}
{
val fileDatabaseHistoryEntity =
databaseFileHistoryDao.getByDatabaseUri(databaseUri.toString())
val fileDatabaseInfo = FileDatabaseInfo(
applicationContext,
databaseUri)
DatabaseFile(
databaseUri,
fileDatabaseHistoryEntity?.keyFileUri?.parseUri(),
HardwareKey.getHardwareKeyFromString(fileDatabaseHistoryEntity?.hardwareKey),
fileDatabaseHistoryEntity?.databaseUri?.decodeUri(),
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistoryEntity?.databaseAlias
?: ""),
fileDatabaseInfo.exists,
fileDatabaseInfo.getLastModificationString(),
fileDatabaseInfo.getSizeString()
)
},
{
databaseFileResult.invoke(it)
}
).execute()
}
fun getKeyFileUriByDatabaseUri(databaseUri: Uri,
keyFileUriResultListener: (Uri?) -> Unit) {
IOActionTask(
{
databaseFileHistoryDao.getByDatabaseUri(databaseUri.toString())
},
{
it?.let { fileHistoryEntity ->
fileHistoryEntity.keyFileUri?.let { keyFileUri ->
keyFileUriResultListener.invoke(UriUtil.parse(keyFileUri))
}
} ?: keyFileUriResultListener.invoke(null)
}
{
databaseFileHistoryDao.getByDatabaseUri(databaseUri.toString())
},
{
it?.let { fileHistoryEntity ->
fileHistoryEntity.keyFileUri?.let { keyFileUri ->
keyFileUriResultListener.invoke(keyFileUri.parseUri())
}
} ?: keyFileUriResultListener.invoke(null)
}
).execute()
}
fun getDatabaseFileList(databaseFileListResult: (List<DatabaseFile>) -> Unit) {
IOActionTask(
{
val hideBrokenLocations = PreferencesUtil.hideBrokenLocations(applicationContext)
// Show only uri accessible
val databaseFileListLoaded = ArrayList<DatabaseFile>()
databaseFileHistoryDao.getAll().forEach { fileDatabaseHistoryEntity ->
val fileDatabaseInfo = FileDatabaseInfo(applicationContext, fileDatabaseHistoryEntity.databaseUri)
if (hideBrokenLocations && fileDatabaseInfo.exists
|| !hideBrokenLocations) {
databaseFileListLoaded.add(
DatabaseFile(
UriUtil.parse(fileDatabaseHistoryEntity.databaseUri),
UriUtil.parse(fileDatabaseHistoryEntity.keyFileUri),
HardwareKey.getHardwareKeyFromString(fileDatabaseHistoryEntity.hardwareKey),
UriUtil.decode(fileDatabaseHistoryEntity.databaseUri),
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistoryEntity.databaseAlias),
fileDatabaseInfo.exists,
fileDatabaseInfo.getLastModificationString(),
fileDatabaseInfo.getSizeString()
)
{
val hideBrokenLocations =
PreferencesUtil.hideBrokenLocations(
applicationContext)
// Show only uri accessible
val databaseFileListLoaded = ArrayList<DatabaseFile>()
databaseFileHistoryDao.getAll().forEach { fileDatabaseHistoryEntity ->
val fileDatabaseInfo = FileDatabaseInfo(
applicationContext,
fileDatabaseHistoryEntity.databaseUri)
if (hideBrokenLocations && fileDatabaseInfo.exists
|| !hideBrokenLocations
) {
databaseFileListLoaded.add(
DatabaseFile(
fileDatabaseHistoryEntity.databaseUri.parseUri(),
fileDatabaseHistoryEntity.keyFileUri?.parseUri(),
HardwareKey.getHardwareKeyFromString(fileDatabaseHistoryEntity.hardwareKey),
fileDatabaseHistoryEntity.databaseUri.decodeUri(),
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistoryEntity.databaseAlias),
fileDatabaseInfo.exists,
fileDatabaseInfo.getLastModificationString(),
fileDatabaseInfo.getSizeString()
)
}
}
databaseFileListLoaded
},
{
databaseFileList ->
databaseFileList?.let {
databaseFileListResult.invoke(it)
)
}
}
databaseFileListLoaded
},
{ databaseFileList ->
databaseFileList?.let {
databaseFileListResult.invoke(it)
}
}
).execute()
}
@@ -124,111 +132,115 @@ class FileDatabaseHistoryAction(private val applicationContext: Context) {
fun addOrUpdateDatabaseFile(databaseFileToAddOrUpdate: DatabaseFile,
databaseFileAddedOrUpdatedResult: ((DatabaseFile?) -> Unit)? = null) {
IOActionTask(
{
databaseFileToAddOrUpdate.databaseUri?.let { databaseUri ->
// Try to get info in database first
val fileDatabaseHistoryRetrieve = databaseFileHistoryDao.getByDatabaseUri(databaseUri.toString())
{
databaseFileToAddOrUpdate.databaseUri?.let { databaseUri ->
// Try to get info in database first
val fileDatabaseHistoryRetrieve =
databaseFileHistoryDao.getByDatabaseUri(databaseUri.toString())
// Complete alias if not exists
val fileDatabaseHistory = FileDatabaseHistoryEntity(
databaseUri.toString(),
databaseFileToAddOrUpdate.databaseAlias
?: fileDatabaseHistoryRetrieve?.databaseAlias
?: "",
databaseFileToAddOrUpdate.keyFileUri?.toString(),
databaseFileToAddOrUpdate.hardwareKey?.value,
System.currentTimeMillis()
// Complete alias if not exists
val fileDatabaseHistory =
FileDatabaseHistoryEntity(
databaseUri.toString(),
databaseFileToAddOrUpdate.databaseAlias
?: fileDatabaseHistoryRetrieve?.databaseAlias
?: "",
databaseFileToAddOrUpdate.keyFileUri?.toString(),
databaseFileToAddOrUpdate.hardwareKey?.value,
System.currentTimeMillis()
)
// Update values if history element not yet in the database
try {
if (fileDatabaseHistoryRetrieve == null) {
databaseFileHistoryDao.add(fileDatabaseHistory)
} else {
databaseFileHistoryDao.update(fileDatabaseHistory)
}
} catch (e: Exception) {
Log.e(TAG, "Unable to add or update database history", e)
// Update values if history element not yet in the database
try {
if (fileDatabaseHistoryRetrieve == null) {
databaseFileHistoryDao.add(fileDatabaseHistory)
} else {
databaseFileHistoryDao.update(fileDatabaseHistory)
}
val fileDatabaseInfo = FileDatabaseInfo(applicationContext,
fileDatabaseHistory.databaseUri)
DatabaseFile(
UriUtil.parse(fileDatabaseHistory.databaseUri),
UriUtil.parse(fileDatabaseHistory.keyFileUri),
HardwareKey.getHardwareKeyFromString(fileDatabaseHistory.hardwareKey),
UriUtil.decode(fileDatabaseHistory.databaseUri),
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistory.databaseAlias),
fileDatabaseInfo.exists,
fileDatabaseInfo.getLastModificationString(),
fileDatabaseInfo.getSizeString()
)
} catch (e: Exception) {
Log.e(TAG, "Unable to add or update database history", e)
}
},
{
databaseFileAddedOrUpdatedResult?.invoke(it)
val fileDatabaseInfo =
FileDatabaseInfo(applicationContext,
fileDatabaseHistory.databaseUri)
DatabaseFile(
fileDatabaseHistory.databaseUri.parseUri(),
fileDatabaseHistory.keyFileUri?.parseUri(),
HardwareKey.getHardwareKeyFromString(fileDatabaseHistory.hardwareKey),
fileDatabaseHistory.databaseUri.decodeUri(),
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistory.databaseAlias),
fileDatabaseInfo.exists,
fileDatabaseInfo.getLastModificationString(),
fileDatabaseInfo.getSizeString()
)
}
},
{
databaseFileAddedOrUpdatedResult?.invoke(it)
}
).execute()
}
fun deleteDatabaseFile(databaseFileToDelete: DatabaseFile,
databaseFileDeletedResult: (DatabaseFile?) -> Unit) {
IOActionTask(
{
databaseFileToDelete.databaseUri?.let { databaseUri ->
databaseFileHistoryDao.getByDatabaseUri(databaseUri.toString())?.let { fileDatabaseHistory ->
{
databaseFileToDelete.databaseUri?.let { databaseUri ->
databaseFileHistoryDao.getByDatabaseUri(databaseUri.toString())
?.let { fileDatabaseHistory ->
val returnValue = databaseFileHistoryDao.delete(fileDatabaseHistory)
if (returnValue > 0) {
DatabaseFile(
UriUtil.parse(fileDatabaseHistory.databaseUri),
UriUtil.parse(fileDatabaseHistory.keyFileUri),
fileDatabaseHistory.databaseUri.parseUri(),
fileDatabaseHistory.keyFileUri?.parseUri(),
HardwareKey.getHardwareKeyFromString(fileDatabaseHistory.hardwareKey),
UriUtil.decode(fileDatabaseHistory.databaseUri),
fileDatabaseHistory.databaseUri.decodeUri(),
databaseFileToDelete.databaseAlias
)
} else {
null
}
}
}
},
{
databaseFileDeletedResult.invoke(it)
}
},
{
databaseFileDeletedResult.invoke(it)
}
).execute()
}
fun deleteKeyFileByDatabaseUri(databaseUri: Uri,
result: (() ->Unit)? = null) {
IOActionTask(
{
databaseFileHistoryDao.deleteKeyFileByDatabaseUri(databaseUri.toString())
},
{
result?.invoke()
}
{
databaseFileHistoryDao.deleteKeyFileByDatabaseUri(databaseUri.toString())
},
{
result?.invoke()
}
).execute()
}
fun deleteAllKeyFiles(result: (() ->Unit)? = null) {
IOActionTask(
{
databaseFileHistoryDao.deleteAllKeyFiles()
},
{
result?.invoke()
}
{
databaseFileHistoryDao.deleteAllKeyFiles()
},
{
result?.invoke()
}
).execute()
}
fun deleteAll(result: (() ->Unit)? = null) {
IOActionTask(
{
databaseFileHistoryDao.deleteAll()
},
{
result?.invoke()
}
{
databaseFileHistoryDao.deleteAll()
},
{
result?.invoke()
}
).execute()
}

View File

@@ -48,7 +48,7 @@ import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.AutofillLauncherActivity
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.activities.helpers.SpecialMode
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.database.element.template.TemplateField
import com.kunzisoft.keepass.model.EntryInfo
@@ -89,7 +89,7 @@ object AutofillHelper {
}
private fun newRemoteViews(context: Context,
database: Database,
database: ContextualDatabase,
remoteViewsText: String,
remoteViewsIcon: IconImage? = null): RemoteViews {
val presentation = RemoteViews(context.packageName, R.layout.item_autofill_entry)
@@ -108,7 +108,7 @@ object AutofillHelper {
}
private fun buildDataset(context: Context,
database: Database,
database: ContextualDatabase,
entryInfo: EntryInfo,
struct: StructureParser.Result,
additionalBuild: ((build: Dataset.Builder) -> Unit)? = null): Dataset? {
@@ -214,7 +214,7 @@ object AutofillHelper {
* Method to assign a drawable to a new icon from a database icon
*/
private fun buildIconFromEntry(context: Context,
database: Database,
database: ContextualDatabase,
entryInfo: EntryInfo): Icon? {
try {
database.iconDrawableFactory.getBitmapFromIcon(context,
@@ -230,7 +230,7 @@ object AutofillHelper {
@RequiresApi(Build.VERSION_CODES.R)
@SuppressLint("RestrictedApi")
private fun buildInlinePresentationForEntry(context: Context,
database: Database,
database: ContextualDatabase,
compatInlineSuggestionsRequest: CompatInlineSuggestionsRequest,
positionItem: Int,
entryInfo: EntryInfo): InlinePresentation? {
@@ -302,7 +302,7 @@ object AutofillHelper {
}
fun buildResponse(context: Context,
database: Database,
database: ContextualDatabase,
entriesInfo: List<EntryInfo>,
parseResult: StructureParser.Result,
compatInlineSuggestionsRequest: CompatInlineSuggestionsRequest?): FillResponse? {
@@ -395,7 +395,7 @@ object AutofillHelper {
* Build the Autofill response for one entry
*/
fun buildResponseAndSetResult(activity: Activity,
database: Database,
database: ContextualDatabase,
entryInfo: EntryInfo) {
buildResponseAndSetResult(activity, database, ArrayList<EntryInfo>().apply { add(entryInfo) })
}
@@ -404,7 +404,7 @@ object AutofillHelper {
* Build the Autofill response for many entry
*/
fun buildResponseAndSetResult(activity: Activity,
database: Database,
database: ContextualDatabase,
entriesInfo: List<EntryInfo>) {
if (entriesInfo.isEmpty()) {
activity.setResult(Activity.RESULT_CANCELED)

View File

@@ -29,21 +29,21 @@ import android.os.CancellationSignal
import android.service.autofill.*
import android.util.Log
import android.view.autofill.AutofillId
import android.view.inputmethod.InlineSuggestionsRequest
import android.widget.RemoteViews
import androidx.annotation.RequiresApi
import androidx.autofill.inline.UiVersions
import androidx.autofill.inline.v1.InlineSuggestionUi
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.AutofillLauncherActivity
import com.kunzisoft.keepass.database.action.DatabaseTaskProvider
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.search.SearchHelper
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.DatabaseTaskProvider
import com.kunzisoft.keepass.database.helper.SearchHelper
import com.kunzisoft.keepass.model.CreditCard
import com.kunzisoft.keepass.model.RegisterInfo
import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.settings.AutofillSettingsActivity
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.WebDomain
import org.joda.time.DateTime
import java.util.concurrent.atomic.AtomicBoolean
@@ -52,7 +52,7 @@ import java.util.concurrent.atomic.AtomicBoolean
class KeeAutofillService : AutofillService() {
private var mDatabaseTaskProvider: DatabaseTaskProvider? = null
private var mDatabase: Database? = null
private var mDatabase: ContextualDatabase? = null
private var applicationIdBlocklist: Set<String>? = null
private var webDomainBlocklist: Set<String>? = null
private var askToSaveData: Boolean = false
@@ -105,7 +105,7 @@ class KeeAutofillService : AutofillService() {
webDomain = parseResult.webDomain
webScheme = parseResult.webScheme
}
SearchInfo.getConcreteWebDomain(this, searchInfo.webDomain) { webDomainWithoutSubDomain ->
WebDomain.getConcreteWebDomain(this, searchInfo.webDomain) { webDomainWithoutSubDomain ->
searchInfo.webDomain = webDomainWithoutSubDomain
val inlineSuggestionsRequest = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
&& autofillInlineSuggestionsEnabled) {
@@ -124,7 +124,7 @@ class KeeAutofillService : AutofillService() {
}
}
private fun launchSelection(database: Database?,
private fun launchSelection(database: ContextualDatabase?,
searchInfo: SearchInfo,
parseResult: StructureParser.Result,
inlineSuggestionsRequest: CompatInlineSuggestionsRequest?,
@@ -153,7 +153,7 @@ class KeeAutofillService : AutofillService() {
@SuppressLint("RestrictedApi")
private fun showUIForEntrySelection(parseResult: StructureParser.Result,
database: Database?,
database: ContextualDatabase?,
searchInfo: SearchInfo,
inlineSuggestionsRequest: CompatInlineSuggestionsRequest?,
callback: FillCallback) {

View File

@@ -0,0 +1,37 @@
package com.kunzisoft.keepass.database
import android.net.Uri
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
import com.kunzisoft.keepass.icons.IconDrawableFactory
import com.kunzisoft.keepass.utils.SingletonHolder
import java.io.File
class ContextualDatabase: Database() {
var fileUri: Uri? = null
val iconDrawableFactory = IconDrawableFactory(
retrieveBinaryCache = { binaryCache },
retrieveCustomIconBinary = { iconId -> getBinaryForCustomIcon(iconId) }
)
override fun removeCustomIcon(customIcon: IconImageCustom) {
iconDrawableFactory.clearFromCache(customIcon)
super.removeCustomIcon(customIcon)
}
override fun clearIndexesAndBinaries(filesDirectory: File?) {
iconDrawableFactory.clearCache()
super.clearIndexesAndBinaries(filesDirectory)
}
override fun clearAndClose(filesDirectory: File?) {
super.clearAndClose(filesDirectory)
this.fileUri = null
}
companion object : SingletonHolder<ContextualDatabase>(::ContextualDatabase) {
private val TAG = ContextualDatabase::class.java.name
}
}

View File

@@ -17,16 +17,23 @@
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.database.action
package com.kunzisoft.keepass.database
import android.content.*
import android.content.Context.*
import android.app.AlertDialog
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Context.BIND_ABOVE_CLIENT
import android.content.Context.BIND_AUTO_CREATE
import android.content.Context.BIND_IMPORTANT
import android.content.Intent
import android.content.IntentFilter
import android.content.ServiceConnection
import android.net.Uri
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope
import com.kunzisoft.keepass.R
@@ -34,20 +41,17 @@ import com.kunzisoft.keepass.activities.dialogs.DatabaseChangedDialogFragment
import com.kunzisoft.keepass.activities.dialogs.DatabaseChangedDialogFragment.Companion.DATABASE_CHANGED_DIALOG_TAG
import com.kunzisoft.keepass.database.crypto.EncryptionAlgorithm
import com.kunzisoft.keepass.database.crypto.kdf.KdfEngine
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.MainCredential
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.model.CipherEncryptDatabase
import com.kunzisoft.keepass.model.ProgressMessage
import com.kunzisoft.keepass.model.SnapFileDatabaseInfo
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_CHALLENGE_RESPONDED
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_ASSIGN_PASSWORD_TASK
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_ASSIGN_CREDENTIAL_TASK
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_COPY_NODES_TASK
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_CREATE_ENTRY_TASK
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_CREATE_GROUP_TASK
@@ -84,22 +88,24 @@ import com.kunzisoft.keepass.tasks.ProgressTaskDialogFragment.Companion.PROGRESS
import com.kunzisoft.keepass.utils.DATABASE_START_TASK_ACTION
import com.kunzisoft.keepass.utils.DATABASE_STOP_TASK_ACTION
import kotlinx.coroutines.launch
import java.util.*
import java.util.UUID
/**
* Utility class to connect an activity or a service to the DatabaseTaskNotificationService,
* Useful to retrieve a database instance and sending tasks commands
*/
class DatabaseTaskProvider(private var context: Context,
private var showDialog: Boolean = true) {
class DatabaseTaskProvider(
private var context: Context,
private var showDialog: Boolean = true
) {
// To show dialog only if context is an activity
private var activity: FragmentActivity? = try { context as? FragmentActivity? }
catch (_: Exception) { null }
var onDatabaseRetrieved: ((database: Database?) -> Unit)? = null
var onDatabaseRetrieved: ((database: ContextualDatabase?) -> Unit)? = null
var onActionFinish: ((database: Database,
var onActionFinish: ((database: ContextualDatabase,
actionTask: String,
result: ActionRunnable.Result) -> Unit)? = null
@@ -128,26 +134,34 @@ class DatabaseTaskProvider(private var context: Context,
}
private val actionTaskListener = object: DatabaseTaskNotificationService.ActionTaskListener {
override fun onActionStarted(database: Database,
progressMessage: ProgressMessage) {
override fun onActionStarted(
database: ContextualDatabase,
progressMessage: ProgressMessage
) {
if (showDialog)
startDialog(progressMessage)
}
override fun onActionUpdated(database: Database,
progressMessage: ProgressMessage) {
override fun onActionUpdated(
database: ContextualDatabase,
progressMessage: ProgressMessage
) {
if (showDialog)
updateDialog(progressMessage)
}
override fun onActionStopped(database: Database) {
override fun onActionStopped(
database: ContextualDatabase
) {
// Remove the progress task
stopDialog()
}
override fun onActionFinished(database: Database,
actionTask: String,
result: ActionRunnable.Result) {
override fun onActionFinished(
database: ContextualDatabase,
actionTask: String,
result: ActionRunnable.Result
) {
onActionFinish?.invoke(database, actionTask, result)
onActionStopped(database)
}
@@ -159,7 +173,8 @@ class DatabaseTaskProvider(private var context: Context,
}
}
private var databaseInfoListener = object: DatabaseTaskNotificationService.DatabaseInfoListener {
private var databaseInfoListener = object:
DatabaseTaskNotificationService.DatabaseInfoListener {
override fun onDatabaseInfoChanged(previousDatabaseInfo: SnapFileDatabaseInfo,
newDatabaseInfo: SnapFileDatabaseInfo) {
activity?.let { activity ->
@@ -188,7 +203,7 @@ class DatabaseTaskProvider(private var context: Context,
}
private var databaseListener = object: DatabaseTaskNotificationService.DatabaseListener {
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
onDatabaseRetrieved?.invoke(database)
}
}
@@ -399,15 +414,15 @@ class DatabaseTaskProvider(private var context: Context,
}
}
fun startDatabaseAssignPassword(databaseUri: Uri,
mainCredential: MainCredential
fun startDatabaseAssignCredential(databaseUri: Uri,
mainCredential: MainCredential
) {
start(Bundle().apply {
putParcelable(DatabaseTaskNotificationService.DATABASE_URI_KEY, databaseUri)
putParcelable(DatabaseTaskNotificationService.MAIN_CREDENTIAL_KEY, mainCredential)
}
, ACTION_DATABASE_ASSIGN_PASSWORD_TASK)
, ACTION_DATABASE_ASSIGN_CREDENTIAL_TASK)
}
/*

View File

@@ -0,0 +1,100 @@
/*
* Copyright 2022 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
import android.content.ContentResolver
import android.net.Uri
import android.os.Parcel
import android.os.Parcelable
import com.kunzisoft.keepass.database.element.MasterCredential
import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.utils.UriHelper.getUriInputStream
import com.kunzisoft.keepass.utils.readEnum
import com.kunzisoft.keepass.utils.writeEnum
data class MainCredential(var password: String? = null,
var keyFileUri: Uri? = null,
var hardwareKey: HardwareKey? = null): Parcelable {
constructor(parcel: Parcel) : this() {
password = parcel.readString()
keyFileUri = parcel.readParcelable(Uri::class.java.classLoader)
hardwareKey = parcel.readEnum<HardwareKey>()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(password)
parcel.writeParcelable(keyFileUri, flags)
parcel.writeEnum(hardwareKey)
}
override fun describeContents(): Int {
return 0
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as MainCredential
if (password != other.password) return false
if (keyFileUri != other.keyFileUri) return false
if (hardwareKey != other.hardwareKey) return false
return true
}
override fun hashCode(): Int {
var result = password?.hashCode() ?: 0
result = 31 * result + (keyFileUri?.hashCode() ?: 0)
result = 31 * result + (hardwareKey?.hashCode() ?: 0)
return result
}
fun toMasterCredential(contentResolver: ContentResolver): MasterCredential {
return MasterCredential(
this.password,
this.keyFileUri?.let {
getKeyFileData(contentResolver, it)
},
this.hardwareKey
)
}
private fun getKeyFileData(contentResolver: ContentResolver,
keyFileUri: Uri): ByteArray? {
contentResolver.getUriInputStream(keyFileUri)?.use { keyFileInputStream ->
return keyFileInputStream.readBytes()
}
return null
}
companion object CREATOR : Parcelable.Creator<MainCredential> {
override fun createFromParcel(parcel: Parcel): MainCredential {
return MainCredential(parcel)
}
override fun newArray(size: Int): Array<MainCredential?> {
return arrayOfNulls(size)
}
private val TAG = MainCredential::class.java.simpleName
}
}

View File

@@ -1,4 +1,4 @@
package com.kunzisoft.keepass.model
package com.kunzisoft.keepass.database
import androidx.annotation.StringRes

View File

@@ -1,81 +0,0 @@
/*
* 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 android.net.Uri
import com.kunzisoft.keepass.app.database.CipherDatabaseAction
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.database.element.MainCredential
open class AssignMainCredentialInDatabaseRunnable (
context: Context,
database: Database,
protected val mDatabaseUri: Uri,
mainCredential: MainCredential,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray)
: SaveDatabaseRunnable(context, database, true, mainCredential, challengeResponseRetriever) {
private var mBackupKey: ByteArray? = null
override fun onStartRun() {
// Set key
try {
mBackupKey = ByteArray(database.masterKey.size)
database.masterKey.copyInto(mBackupKey!!)
} catch (e: Exception) {
erase(mBackupKey)
setError(e)
}
super.onStartRun()
}
override fun onFinishRun() {
super.onFinishRun()
// Erase the biometric
CipherDatabaseAction.getInstance(context)
.deleteByDatabaseUri(mDatabaseUri)
// Erase the register keyfile
FileDatabaseHistoryAction.getInstance(context)
.deleteKeyFileByDatabaseUri(mDatabaseUri)
if (!result.isSuccess) {
// Erase the current master key
erase(database.masterKey)
mBackupKey?.let {
database.masterKey = it
}
}
}
/**
* Overwrite the array as soon as we don't need it to avoid keeping the extra data in memory
*/
private fun erase(array: ByteArray?) {
if (array == null) return
for (i in array.indices) {
array[i] = 0
}
}
}

View File

@@ -21,65 +21,46 @@ package com.kunzisoft.keepass.database.action
import android.content.Context
import android.net.Uri
import android.util.Log
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.database.element.MainCredential
import com.kunzisoft.keepass.settings.PreferencesUtil
class CreateDatabaseRunnable(context: Context,
private val mDatabase: Database,
databaseUri: Uri,
private val databaseName: String,
private val rootName: String,
private val templateGroupName: String?,
val mainCredential: MainCredential,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray,
private val createDatabaseResult: ((Result) -> Unit)?)
: AssignMainCredentialInDatabaseRunnable(context, mDatabase, databaseUri, mainCredential, challengeResponseRetriever) {
import com.kunzisoft.keepass.utils.UriHelper.getBinaryDir
class CreateDatabaseRunnable(
context: Context,
private val mDatabase: ContextualDatabase,
private val databaseUri: Uri,
private val databaseName: String,
private val rootName: String,
private val templateGroupName: String?,
val mainCredential: MainCredential,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray
) : SaveDatabaseRunnable(
context,
mDatabase,
true,
mainCredential,
challengeResponseRetriever
) {
override fun onStartRun() {
try {
// Create new database record
mDatabase.apply {
createData(mDatabaseUri, databaseName, rootName, templateGroupName)
this.fileUri = databaseUri
createData(databaseName, rootName, templateGroupName)
}
} catch (e: Exception) {
mDatabase.clearAndClose(context)
mDatabase.clearAndClose(context.getBinaryDir())
setError(e)
}
super.onStartRun()
}
override fun onActionRun() {
super.onActionRun()
if (result.isSuccess) {
// Add database to recent files
if (PreferencesUtil.rememberDatabaseLocations(context)) {
FileDatabaseHistoryAction.getInstance(context.applicationContext)
.addOrUpdateDatabaseUri(
mDatabaseUri,
if (PreferencesUtil.rememberKeyFileLocations(context)) mainCredential.keyFileUri else null,
if (PreferencesUtil.rememberHardwareKey(context)) mainCredential.hardwareKey else null,
)
}
// Register the current time to init the lock timer
PreferencesUtil.saveCurrentTime(context)
} else {
Log.e("CreateDatabaseRunnable", "Unable to create the database")
}
}
override fun onFinishRun() {
super.onFinishRun()
if (result.isSuccess) {
mDatabase.loaded = true
}
createDatabaseResult?.invoke(result)
super.onFinishRun()
}
}

View File

@@ -21,81 +21,65 @@ package com.kunzisoft.keepass.database.action
import android.content.Context
import android.net.Uri
import com.kunzisoft.keepass.app.database.CipherDatabaseAction
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.database.element.binary.BinaryData
import com.kunzisoft.keepass.database.exception.DatabaseInputException
import com.kunzisoft.keepass.database.exception.UnknownDatabaseLocationException
import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.model.CipherEncryptDatabase
import com.kunzisoft.keepass.database.element.MainCredential
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.UriHelper.getBinaryDir
import com.kunzisoft.keepass.utils.UriHelper.getUriInputStream
class LoadDatabaseRunnable(private val context: Context,
private val mDatabase: Database,
private val mDatabaseUri: Uri,
private val mMainCredential: MainCredential,
private val mChallengeResponseRetriever: (hardwareKey: HardwareKey, seed: ByteArray?) -> ByteArray,
private val mReadonly: Boolean,
private val mCipherEncryptDatabase: CipherEncryptDatabase?,
private val mFixDuplicateUUID: Boolean,
private val progressTaskUpdater: ProgressTaskUpdater?,
private val mLoadDatabaseResult: ((Result) -> Unit)?)
: ActionRunnable() {
class LoadDatabaseRunnable(
private val context: Context,
private val mDatabase: ContextualDatabase,
private val mDatabaseUri: Uri,
private val mMainCredential: MainCredential,
private val mChallengeResponseRetriever: (hardwareKey: HardwareKey, seed: ByteArray?) -> ByteArray,
private val mReadonly: Boolean,
private val mFixDuplicateUUID: Boolean,
private val progressTaskUpdater: ProgressTaskUpdater?
) : ActionRunnable() {
var afterLoadDatabase : ((Result) -> Unit)? = null
private val binaryDir = context.getBinaryDir()
override fun onStartRun() {
// Clear before we load
mDatabase.clearAndClose(context)
mDatabase.clearAndClose(binaryDir)
}
override fun onActionRun() {
try {
val contentResolver = context.contentResolver
// Save database URI
mDatabase.fileUri = mDatabaseUri
mDatabase.loadData(
context.contentResolver,
mDatabaseUri,
mMainCredential,
contentResolver.getUriInputStream(mDatabaseUri)
?: throw UnknownDatabaseLocationException(),
mMainCredential.toMasterCredential(contentResolver),
mChallengeResponseRetriever,
mReadonly,
UriUtil.getBinaryDir(context),
binaryDir,
{ memoryWanted ->
BinaryData.canMemoryBeAllocatedInRAM(context, memoryWanted)
},
mFixDuplicateUUID,
progressTaskUpdater
)
}
catch (e: DatabaseInputException) {
} catch (e: DatabaseInputException) {
setError(e)
}
if (result.isSuccess) {
// Save keyFile in app database
if (PreferencesUtil.rememberDatabaseLocations(context)) {
FileDatabaseHistoryAction.getInstance(context)
.addOrUpdateDatabaseUri(
mDatabaseUri,
if (PreferencesUtil.rememberKeyFileLocations(context)) mMainCredential.keyFileUri else null,
if (PreferencesUtil.rememberHardwareKey(context)) mMainCredential.hardwareKey else null,
)
}
// Register the biometric
mCipherEncryptDatabase?.let { cipherDatabase ->
CipherDatabaseAction.getInstance(context)
.addOrUpdateCipherDatabase(cipherDatabase) // return value not called
}
// Register the current time to init the lock timer
PreferencesUtil.saveCurrentTime(context)
} else {
mDatabase.clearAndClose(context)
if (!result.isSuccess) {
mDatabase.clearAndClose(binaryDir)
}
}
override fun onFinishRun() {
mLoadDatabaseResult?.invoke(result)
afterLoadDatabase?.invoke(result)
}
}

View File

@@ -21,26 +21,31 @@ package com.kunzisoft.keepass.database.action
import android.content.Context
import android.net.Uri
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.MainCredential
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.database.element.binary.BinaryData
import com.kunzisoft.keepass.database.exception.DatabaseException
import com.kunzisoft.keepass.database.exception.UnknownDatabaseLocationException
import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import com.kunzisoft.keepass.utils.UriHelper.getUriInputStream
class MergeDatabaseRunnable(
context: Context,
private val mDatabaseToMergeUri: Uri?,
private val mDatabaseToMergeMainCredential: MainCredential?,
private val mDatabaseToMergeChallengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray,
database: Database,
database: ContextualDatabase,
saveDatabase: Boolean,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray,
private val progressTaskUpdater: ProgressTaskUpdater?,
private val mLoadDatabaseResult: ((Result) -> Unit)?)
: SaveDatabaseRunnable(context, database, saveDatabase, null, challengeResponseRetriever) {
) : SaveDatabaseRunnable(
context,
database,
saveDatabase,
null,
challengeResponseRetriever
) {
override fun onStartRun() {
database.wasReloaded = true
super.onStartRun()
@@ -48,10 +53,12 @@ class MergeDatabaseRunnable(
override fun onActionRun() {
try {
val contentResolver = context.contentResolver
database.mergeData(
context.contentResolver,
mDatabaseToMergeUri,
mDatabaseToMergeMainCredential,
context.contentResolver.getUriInputStream(
mDatabaseToMergeUri ?: database.fileUri
) ?: throw UnknownDatabaseLocationException(),
mDatabaseToMergeMainCredential?.toMasterCredential(contentResolver),
mDatabaseToMergeChallengeResponseRetriever,
{ memoryWanted ->
BinaryData.canMemoryBeAllocatedInRAM(context, memoryWanted)
@@ -62,15 +69,6 @@ class MergeDatabaseRunnable(
setError(e)
}
if (result.isSuccess) {
// Register the current time to init the lock timer
PreferencesUtil.saveCurrentTime(context)
}
super.onActionRun()
}
override fun onFinishRun() {
super.onFinishRun()
mLoadDatabaseResult?.invoke(result)
}
}

View File

@@ -20,46 +20,50 @@
package com.kunzisoft.keepass.database.action
import android.content.Context
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.binary.BinaryData
import com.kunzisoft.keepass.database.exception.DatabaseException
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.database.exception.UnknownDatabaseLocationException
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.UriHelper.getBinaryDir
import com.kunzisoft.keepass.utils.UriHelper.getUriInputStream
class ReloadDatabaseRunnable(private val context: Context,
private val mDatabase: Database,
private val progressTaskUpdater: ProgressTaskUpdater?,
private val mLoadDatabaseResult: ((Result) -> Unit)?)
: ActionRunnable() {
class ReloadDatabaseRunnable(
private val context: Context,
private val mDatabase: ContextualDatabase,
private val progressTaskUpdater: ProgressTaskUpdater?
) : ActionRunnable() {
var afterReloadDatabase : ((Result) -> Unit)? = null
private val binaryDir = context.getBinaryDir()
override fun onStartRun() {
// Clear before we load
mDatabase.clearIndexesAndBinaries(UriUtil.getBinaryDir(context))
mDatabase.clearIndexesAndBinaries(binaryDir)
mDatabase.wasReloaded = true
}
override fun onActionRun() {
try {
mDatabase.reloadData(context.contentResolver,
{ memoryWanted ->
BinaryData.canMemoryBeAllocatedInRAM(context, memoryWanted)
},
progressTaskUpdater)
mDatabase.reloadData(
context.contentResolver.getUriInputStream(mDatabase.fileUri)
?: throw UnknownDatabaseLocationException(),
{ memoryWanted ->
BinaryData.canMemoryBeAllocatedInRAM(context, memoryWanted)
},
progressTaskUpdater)
} catch (e: DatabaseException) {
setError(e)
}
if (result.isSuccess) {
// Register the current time to init the lock timer
PreferencesUtil.saveCurrentTime(context)
} else {
mDatabase.clearAndClose(context)
if (!result.isSuccess) {
mDatabase.clearAndClose(binaryDir)
}
}
override fun onFinishRun() {
mLoadDatabaseResult?.invoke(result)
afterReloadDatabase?.invoke(result)
}
}

View File

@@ -20,15 +20,21 @@
package com.kunzisoft.keepass.database.action
import android.content.Context
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.hardware.HardwareKey
class RemoveUnlinkedDataDatabaseRunnable (
context: Context,
database: Database,
saveDatabase: Boolean,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray)
: SaveDatabaseRunnable(context, database, saveDatabase, null, challengeResponseRetriever) {
context: Context,
database: ContextualDatabase,
saveDatabase: Boolean,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray
) : SaveDatabaseRunnable(
context,
database,
saveDatabase,
null,
challengeResponseRetriever
) {
override fun onActionRun() {
try {

View File

@@ -21,21 +21,24 @@ package com.kunzisoft.keepass.database.action
import android.content.Context
import android.net.Uri
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.database.exception.DatabaseException
import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.database.element.MainCredential
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.utils.UriHelper.getUriOutputStream
import java.io.File
open class SaveDatabaseRunnable(protected var context: Context,
protected var database: Database,
private var saveDatabase: Boolean,
private var mainCredential: MainCredential?, // If null, uses composite Key
private var challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray,
private var databaseCopyUri: Uri? = null)
: ActionRunnable() {
open class SaveDatabaseRunnable(
protected var context: Context,
protected var database: ContextualDatabase,
private var saveDatabase: Boolean,
private var mainCredential: MainCredential?, // If null, uses composite Key
private var challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray,
private var databaseCopyUri: Uri? = null
) : ActionRunnable() {
var mAfterSaveDatabase: ((Result) -> Unit)? = null
var afterSaveDatabase: ((Result) -> Unit)? = null
override fun onStartRun() {}
@@ -43,11 +46,14 @@ open class SaveDatabaseRunnable(protected var context: Context,
database.checkVersion()
if (saveDatabase && result.isSuccess) {
try {
val contentResolver = context.contentResolver
// Build temp database file to avoid file corruption if error
database.saveData(
context.contentResolver,
context.cacheDir,
databaseCopyUri,
mainCredential,
cacheFile = File(context.cacheDir, databaseCopyUri.hashCode().toString()),
databaseOutputStream = contentResolver
.getUriOutputStream(databaseCopyUri ?: database.fileUri),
isNewLocation = databaseCopyUri == null,
mainCredential?.toMasterCredential(contentResolver),
challengeResponseRetriever)
} catch (e: DatabaseException) {
setError(e)
@@ -57,6 +63,6 @@ open class SaveDatabaseRunnable(protected var context: Context,
override fun onFinishRun() {
// Need to call super.onFinishRun() in child class
mAfterSaveDatabase?.invoke(result)
afterSaveDatabase?.invoke(result)
}
}

View File

@@ -20,18 +20,24 @@
package com.kunzisoft.keepass.database.action
import android.content.Context
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
import com.kunzisoft.keepass.hardware.HardwareKey
class UpdateCompressionBinariesDatabaseRunnable (
context: Context,
database: Database,
private val oldCompressionAlgorithm: CompressionAlgorithm,
private val newCompressionAlgorithm: CompressionAlgorithm,
saveDatabase: Boolean,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray)
: SaveDatabaseRunnable(context, database, saveDatabase, null, challengeResponseRetriever) {
context: Context,
database: ContextualDatabase,
private val oldCompressionAlgorithm: CompressionAlgorithm,
private val newCompressionAlgorithm: CompressionAlgorithm,
saveDatabase: Boolean,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray
) : SaveDatabaseRunnable(
context,
database,
saveDatabase,
null,
challengeResponseRetriever
) {
override fun onStartRun() {
// Set new compression

View File

@@ -20,19 +20,19 @@
package com.kunzisoft.keepass.database.action.history
import android.content.Context
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.action.SaveDatabaseRunnable
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.hardware.HardwareKey
class DeleteEntryHistoryDatabaseRunnable (
context: Context,
database: Database,
private val mainEntry: Entry,
private val entryHistoryPosition: Int,
saveDatabase: Boolean,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray)
: SaveDatabaseRunnable(context, database, saveDatabase, null, challengeResponseRetriever) {
context: Context,
database: ContextualDatabase,
private val mainEntry: Entry,
private val entryHistoryPosition: Int,
saveDatabase: Boolean,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray
) : SaveDatabaseRunnable(context, database, saveDatabase, null, challengeResponseRetriever) {
override fun onStartRun() {
try {

View File

@@ -20,20 +20,20 @@
package com.kunzisoft.keepass.database.action.history
import android.content.Context
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.action.node.UpdateEntryRunnable
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.tasks.ActionRunnable
class RestoreEntryHistoryDatabaseRunnable (
private val context: Context,
private val database: Database,
private val mainEntry: Entry,
private val entryHistoryPosition: Int,
private val saveDatabase: Boolean,
private val challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray)
: ActionRunnable() {
private val context: Context,
private val database: ContextualDatabase,
private val mainEntry: Entry,
private val entryHistoryPosition: Int,
private val saveDatabase: Boolean,
private val challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray
) : ActionRunnable() {
private var updateEntryRunnable: UpdateEntryRunnable? = null

View File

@@ -20,17 +20,17 @@
package com.kunzisoft.keepass.database.action.node
import android.content.Context
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.action.SaveDatabaseRunnable
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.hardware.HardwareKey
abstract class ActionNodeDatabaseRunnable(
context: Context,
database: Database,
private val afterActionNodesFinish: AfterActionNodesFinish?,
save: Boolean,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray)
: SaveDatabaseRunnable(context, database, save, null, challengeResponseRetriever) {
context: Context,
database: ContextualDatabase,
private val afterActionNodesFinish: AfterActionNodesFinish?,
save: Boolean,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray
) : SaveDatabaseRunnable(context, database, save, null, challengeResponseRetriever) {
/**
* Function do to a node action

View File

@@ -20,21 +20,21 @@
package com.kunzisoft.keepass.database.action.node
import android.content.Context
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.hardware.HardwareKey
class AddEntryRunnable constructor(
context: Context,
database: Database,
private val mNewEntry: Entry,
private val mParent: Group,
save: Boolean,
afterActionNodesFinish: AfterActionNodesFinish?,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray)
: ActionNodeDatabaseRunnable(context, database, afterActionNodesFinish, save, challengeResponseRetriever) {
context: Context,
database: ContextualDatabase,
private val mNewEntry: Entry,
private val mParent: Group,
save: Boolean,
afterActionNodesFinish: AfterActionNodesFinish?,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray
) : ActionNodeDatabaseRunnable(context, database, afterActionNodesFinish, save, challengeResponseRetriever) {
override fun nodeAction() {
mNewEntry.touch(modified = true, touchParents = true)

View File

@@ -20,20 +20,20 @@
package com.kunzisoft.keepass.database.action.node
import android.content.Context
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.hardware.HardwareKey
class AddGroupRunnable constructor(
context: Context,
database: Database,
private val mNewGroup: Group,
private val mParent: Group,
save: Boolean,
afterActionNodesFinish: AfterActionNodesFinish?,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray)
: ActionNodeDatabaseRunnable(context, database, afterActionNodesFinish, save, challengeResponseRetriever) {
context: Context,
database: ContextualDatabase,
private val mNewGroup: Group,
private val mParent: Group,
save: Boolean,
afterActionNodesFinish: AfterActionNodesFinish?,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray
) : ActionNodeDatabaseRunnable(context, database, afterActionNodesFinish, save, challengeResponseRetriever) {
override fun nodeAction() {
mNewGroup.touch(modified = true, touchParents = true)

View File

@@ -21,7 +21,7 @@ package com.kunzisoft.keepass.database.action.node
import android.content.Context
import android.util.Log
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.node.Node
@@ -31,14 +31,14 @@ import com.kunzisoft.keepass.database.exception.CopyGroupDatabaseException
import com.kunzisoft.keepass.hardware.HardwareKey
class CopyNodesRunnable constructor(
context: Context,
database: Database,
private val mNodesToCopy: List<Node>,
private val mNewParent: Group,
save: Boolean,
afterActionNodesFinish: AfterActionNodesFinish?,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray)
: ActionNodeDatabaseRunnable(context, database, afterActionNodesFinish, save, challengeResponseRetriever) {
context: Context,
database: ContextualDatabase,
private val mNodesToCopy: List<Node>,
private val mNewParent: Group,
save: Boolean,
afterActionNodesFinish: AfterActionNodesFinish?,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray
) : ActionNodeDatabaseRunnable(context, database, afterActionNodesFinish, save, challengeResponseRetriever) {
private var mEntriesCopied = ArrayList<Entry>()

View File

@@ -20,20 +20,22 @@
package com.kunzisoft.keepass.database.action.node
import android.content.Context
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.hardware.HardwareKey
class DeleteNodesRunnable(context: Context,
database: Database,
private val mNodesToDelete: List<Node>,
save: Boolean,
afterActionNodesFinish: AfterActionNodesFinish,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray)
: ActionNodeDatabaseRunnable(context, database, afterActionNodesFinish, save, challengeResponseRetriever) {
class DeleteNodesRunnable(
context: Context,
database: ContextualDatabase,
private val mNodesToDelete: List<Node>,
private val recyclerBinTitle: String,
save: Boolean,
afterActionNodesFinish: AfterActionNodesFinish,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray
) : ActionNodeDatabaseRunnable(context, database, afterActionNodesFinish, save, challengeResponseRetriever) {
private var mOldParent: Group? = null
private var mCanRecycle: Boolean = false
@@ -54,7 +56,7 @@ class DeleteNodesRunnable(context: Context,
// Remove Node from parent
mCanRecycle = database.canRecycle(groupToDelete)
if (mCanRecycle) {
database.recycle(groupToDelete, context.resources)
database.recycle(groupToDelete, recyclerBinTitle)
groupToDelete.setPreviousParentGroup(mOldParent)
groupToDelete.touch(modified = true, touchParents = true)
} else {
@@ -68,7 +70,7 @@ class DeleteNodesRunnable(context: Context,
// Remove Node from parent
mCanRecycle = database.canRecycle(entryToDelete)
if (mCanRecycle) {
database.recycle(entryToDelete, context.resources)
database.recycle(entryToDelete, recyclerBinTitle)
entryToDelete.setPreviousParentGroup(mOldParent)
entryToDelete.touch(modified = true, touchParents = true)
} else {

View File

@@ -21,7 +21,7 @@ package com.kunzisoft.keepass.database.action.node
import android.content.Context
import android.util.Log
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.node.Node
@@ -31,14 +31,14 @@ import com.kunzisoft.keepass.database.exception.MoveGroupDatabaseException
import com.kunzisoft.keepass.hardware.HardwareKey
class MoveNodesRunnable constructor(
context: Context,
database: Database,
private val mNodesToMove: List<Node>,
private val mNewParent: Group,
save: Boolean,
afterActionNodesFinish: AfterActionNodesFinish?,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray)
: ActionNodeDatabaseRunnable(context, database, afterActionNodesFinish, save, challengeResponseRetriever) {
context: Context,
database: ContextualDatabase,
private val mNodesToMove: List<Node>,
private val mNewParent: Group,
save: Boolean,
afterActionNodesFinish: AfterActionNodesFinish?,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray
) : ActionNodeDatabaseRunnable(context, database, afterActionNodesFinish, save, challengeResponseRetriever) {
private var mOldParent: Group? = null

View File

@@ -20,21 +20,21 @@
package com.kunzisoft.keepass.database.action.node
import android.content.Context
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.hardware.HardwareKey
class UpdateEntryRunnable constructor(
context: Context,
database: Database,
private val mOldEntry: Entry,
private val mNewEntry: Entry,
save: Boolean,
afterActionNodesFinish: AfterActionNodesFinish?,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray)
: ActionNodeDatabaseRunnable(context, database, afterActionNodesFinish, save, challengeResponseRetriever) {
context: Context,
database: ContextualDatabase,
private val mOldEntry: Entry,
private val mNewEntry: Entry,
save: Boolean,
afterActionNodesFinish: AfterActionNodesFinish?,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray
) : ActionNodeDatabaseRunnable(context, database, afterActionNodesFinish, save, challengeResponseRetriever) {
override fun nodeAction() {
if (mOldEntry.nodeId == mNewEntry.nodeId) {

View File

@@ -20,20 +20,20 @@
package com.kunzisoft.keepass.database.action.node
import android.content.Context
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.hardware.HardwareKey
class UpdateGroupRunnable constructor(
context: Context,
database: Database,
private val mOldGroup: Group,
private val mNewGroup: Group,
save: Boolean,
afterActionNodesFinish: AfterActionNodesFinish?,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray)
: ActionNodeDatabaseRunnable(context, database, afterActionNodesFinish, save, challengeResponseRetriever) {
context: Context,
database: ContextualDatabase,
private val mOldGroup: Group,
private val mNewGroup: Group,
save: Boolean,
afterActionNodesFinish: AfterActionNodesFinish?,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray
) : ActionNodeDatabaseRunnable(context, database, afterActionNodesFinish, save, challengeResponseRetriever) {
override fun nodeAction() {
if (mOldGroup.nodeId == mNewGroup.nodeId) {

View File

@@ -1,125 +0,0 @@
/*
* Copyright 2021 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.element.template
import android.content.Context
import com.kunzisoft.keepass.R
object TemplateField {
const val LABEL_STANDARD = "Standard"
const val LABEL_TEMPLATE = "Template"
const val LABEL_VERSION = "Version"
const val LABEL_TITLE = "Title"
const val LABEL_USERNAME = "Username"
const val LABEL_PASSWORD = "Password"
const val LABEL_URL = "URL"
const val LABEL_EXPIRATION = "Expires"
const val LABEL_NOTES = "Notes"
const val LABEL_DEBIT_CREDIT_CARD = "Debit / Credit Card"
const val LABEL_HOLDER = "Holder"
const val LABEL_NUMBER = "Number"
const val LABEL_CVV = "CVV"
const val LABEL_PIN = "PIN"
const val LABEL_ID_CARD = "ID Card"
const val LABEL_NAME = "Name"
const val LABEL_PLACE_OF_ISSUE = "Place of issue"
const val LABEL_DATE_OF_ISSUE = "Date of issue"
const val LABEL_EMAIL = "Email"
const val LABEL_EMAIL_ADDRESS = "Email address"
const val LABEL_WIRELESS = "Wi-Fi"
const val LABEL_SSID = "SSID"
const val LABEL_TYPE = "Type"
const val LABEL_CRYPTOCURRENCY = "Cryptocurrency wallet"
const val LABEL_TOKEN = "Token"
const val LABEL_PUBLIC_KEY = "Public key"
const val LABEL_PRIVATE_KEY = "Private key"
const val LABEL_SEED = "Seed"
const val LABEL_ACCOUNT = "Account"
const val LABEL_BANK = "Bank"
const val LABEL_BIC = "BIC"
const val LABEL_IBAN = "IBAN"
const val LABEL_SECURE_NOTE = "Secure Note"
const val LABEL_MEMBERSHIP = "Membership"
fun isStandardPasswordName(context: Context, name: String): Boolean {
return name.equals(LABEL_PASSWORD, true)
|| name == getLocalizedName(context, LABEL_PASSWORD)
}
fun isStandardFieldName(name: String): Boolean {
return arrayOf(
LABEL_TITLE,
LABEL_USERNAME,
LABEL_PASSWORD,
LABEL_URL,
LABEL_EXPIRATION,
LABEL_NOTES
).firstOrNull { it.equals(name, true) } != null
}
fun getLocalizedName(context: Context?, name: String): String {
if (context == null
|| TemplateEngine.containsTemplateDecorator(name))
return name
return when {
LABEL_STANDARD.equals(name, true) -> context.getString(R.string.standard)
LABEL_TEMPLATE.equals(name, true) -> context.getString(R.string.template)
LABEL_VERSION.equals(name, true) -> context.getString(R.string.version)
LABEL_TITLE.equals(name, true) -> context.getString(R.string.entry_title)
LABEL_USERNAME.equals(name, true) -> context.getString(R.string.entry_user_name)
LABEL_PASSWORD.equals(name, true) -> context.getString(R.string.entry_password)
LABEL_URL.equals(name, true) -> context.getString(R.string.entry_url)
LABEL_EXPIRATION.equals(name, true) -> context.getString(R.string.entry_expires)
LABEL_NOTES.equals(name, true) -> context.getString(R.string.entry_notes)
LABEL_DEBIT_CREDIT_CARD.equals(name, true) -> context.getString(R.string.debit_credit_card)
LABEL_HOLDER.equals(name, true) -> context.getString(R.string.holder)
LABEL_NUMBER.equals(name, true) -> context.getString(R.string.number)
LABEL_CVV.equals(name, true) -> context.getString(R.string.card_verification_value)
LABEL_PIN.equals(name, true) -> context.getString(R.string.personal_identification_number)
LABEL_ID_CARD.equals(name, true) -> context.getString(R.string.id_card)
LABEL_NAME.equals(name, true) -> context.getString(R.string.name)
LABEL_PLACE_OF_ISSUE.equals(name, true) -> context.getString(R.string.place_of_issue)
LABEL_DATE_OF_ISSUE.equals(name, true) -> context.getString(R.string.date_of_issue)
LABEL_EMAIL.equals(name, true) -> context.getString(R.string.email)
LABEL_EMAIL_ADDRESS.equals(name, true) -> context.getString(R.string.email_address)
LABEL_WIRELESS.equals(name, true) -> context.getString(R.string.wireless)
LABEL_SSID.equals(name, true) -> context.getString(R.string.ssid)
LABEL_TYPE.equals(name, true) -> context.getString(R.string.type)
LABEL_CRYPTOCURRENCY.equals(name, true) -> context.getString(R.string.cryptocurrency)
LABEL_TOKEN.equals(name, false) -> context.getString(R.string.token)
LABEL_PUBLIC_KEY.equals(name, true) -> context.getString(R.string.public_key)
LABEL_PRIVATE_KEY.equals(name, true) -> context.getString(R.string.private_key)
LABEL_SEED.equals(name, true) -> context.getString(R.string.seed)
LABEL_ACCOUNT.equals(name, true) -> context.getString(R.string.account)
LABEL_BANK.equals(name, true) -> context.getString(R.string.bank)
LABEL_BIC.equals(name, true) -> context.getString(R.string.bank_identifier_code)
LABEL_IBAN.equals(name, true) -> context.getString(R.string.international_bank_account_number)
LABEL_SECURE_NOTE.equals(name, true) -> context.getString(R.string.secure_note)
LABEL_MEMBERSHIP.equals(name, true) -> context.getString(R.string.membership)
else -> name
}
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2021 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.helper
import android.content.Context
import android.content.res.Resources
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
import com.kunzisoft.keepass.database.element.template.TemplateEngine
import com.kunzisoft.keepass.database.element.template.TemplateField
import com.kunzisoft.keepass.database.exception.*
fun DatabaseException.getLocalizedMessage(resources: Resources): String = parameters?.let {
when (this) {
is FileNotFoundDatabaseException -> resources.getString(R.string.file_not_found_content)
is CorruptedDatabaseException -> resources.getString(R.string.corrupted_file)
is InvalidAlgorithmDatabaseException -> resources.getString(R.string.invalid_algorithm)
is UnknownDatabaseLocationException -> resources.getString(R.string.error_location_unknown)
is HardwareKeyDatabaseException -> resources.getString(R.string.error_hardware_key_unsupported)
is EmptyKeyDatabaseException -> resources.getString(R.string.error_empty_key)
is SignatureDatabaseException -> resources.getString(R.string.invalid_db_sig)
is VersionDatabaseException -> resources.getString(R.string.unsupported_db_version)
is InvalidCredentialsDatabaseException -> resources.getString(R.string.invalid_credentials)
is KDFMemoryDatabaseException -> resources.getString(R.string.error_load_database_KDF_memory)
is NoMemoryDatabaseException -> resources.getString(R.string.error_out_of_memory)
is DuplicateUuidDatabaseException -> resources.getString(R.string.invalid_db_same_uuid)
is XMLMalformedDatabaseException -> resources.getString(R.string.error_XML_malformed)
is MergeDatabaseKDBException -> resources.getString(R.string.error_unable_merge_database_kdb)
is MoveEntryDatabaseException -> resources.getString(R.string.error_move_entry_here)
is MoveGroupDatabaseException -> resources.getString(R.string.error_move_group_here)
is CopyEntryDatabaseException -> resources.getString(R.string.error_copy_entry_here)
is CopyGroupDatabaseException -> resources.getString(R.string.error_copy_group_here)
is DatabaseInputException -> resources.getString(R.string.error_load_database)
is DatabaseOutputException -> resources.getString(R.string.error_save_database)
else -> (mThrowable as? DatabaseException)?.getLocalizedMessage(resources)
}
} ?: resources.getString(R.string.error_load_database)
fun CompressionAlgorithm.getLocalizedName(resources: Resources): String {
return when (this) {
CompressionAlgorithm.NONE -> resources.getString(R.string.compression_none)
CompressionAlgorithm.GZIP -> resources.getString(R.string.compression_gzip)
}
}
fun TemplateField.isStandardPasswordName(context: Context, name: String): Boolean {
return name.equals(LABEL_PASSWORD, true)
|| name == getLocalizedName(context, LABEL_PASSWORD)
}
fun TemplateField.getLocalizedName(context: Context?, name: String): String {
if (context == null
|| TemplateEngine.containsTemplateDecorator(name)
)
return name
return when {
LABEL_STANDARD.equals(name, true) -> context.getString(R.string.standard)
LABEL_TEMPLATE.equals(name, true) -> context.getString(R.string.template)
LABEL_VERSION.equals(name, true) -> context.getString(R.string.version)
LABEL_TITLE.equals(name, true) -> context.getString(R.string.entry_title)
LABEL_USERNAME.equals(name, true) -> context.getString(R.string.entry_user_name)
LABEL_PASSWORD.equals(name, true) -> context.getString(R.string.entry_password)
LABEL_URL.equals(name, true) -> context.getString(R.string.entry_url)
LABEL_EXPIRATION.equals(name, true) -> context.getString(R.string.entry_expires)
LABEL_NOTES.equals(name, true) -> context.getString(R.string.entry_notes)
LABEL_DEBIT_CREDIT_CARD.equals(name, true) -> context.getString(R.string.debit_credit_card)
LABEL_HOLDER.equals(name, true) -> context.getString(R.string.holder)
LABEL_NUMBER.equals(name, true) -> context.getString(R.string.number)
LABEL_CVV.equals(name, true) -> context.getString(R.string.card_verification_value)
LABEL_PIN.equals(name, true) -> context.getString(R.string.personal_identification_number)
LABEL_ID_CARD.equals(name, true) -> context.getString(R.string.id_card)
LABEL_NAME.equals(name, true) -> context.getString(R.string.name)
LABEL_PLACE_OF_ISSUE.equals(name, true) -> context.getString(R.string.place_of_issue)
LABEL_DATE_OF_ISSUE.equals(name, true) -> context.getString(R.string.date_of_issue)
LABEL_EMAIL.equals(name, true) -> context.getString(R.string.email)
LABEL_EMAIL_ADDRESS.equals(name, true) -> context.getString(R.string.email_address)
LABEL_WIRELESS.equals(name, true) -> context.getString(R.string.wireless)
LABEL_SSID.equals(name, true) -> context.getString(R.string.ssid)
LABEL_TYPE.equals(name, true) -> context.getString(R.string.type)
LABEL_CRYPTOCURRENCY.equals(name, true) -> context.getString(R.string.cryptocurrency)
LABEL_TOKEN.equals(name, false) -> context.getString(R.string.token)
LABEL_PUBLIC_KEY.equals(name, true) -> context.getString(R.string.public_key)
LABEL_PRIVATE_KEY.equals(name, true) -> context.getString(R.string.private_key)
LABEL_SEED.equals(name, true) -> context.getString(R.string.seed)
LABEL_ACCOUNT.equals(name, true) -> context.getString(R.string.account)
LABEL_BANK.equals(name, true) -> context.getString(R.string.bank)
LABEL_BIC.equals(name, true) -> context.getString(R.string.bank_identifier_code)
LABEL_IBAN.equals(name, true) -> context.getString(R.string.international_bank_account_number)
LABEL_SECURE_NOTE.equals(name, true) -> context.getString(R.string.secure_note)
LABEL_MEMBERSHIP.equals(name, true) -> context.getString(R.string.membership)
else -> name
}
}

View File

@@ -0,0 +1,77 @@
/*
* 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.helper
import android.content.Context
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.timeout.TimeoutHelper
object SearchHelper {
const val MAX_SEARCH_ENTRY = 1000
/**
* Method to show the number of search results with max results
*/
fun showNumberOfSearchResults(number: Int): String {
return if (number >= MAX_SEARCH_ENTRY) {
(MAX_SEARCH_ENTRY -1).toString() + "+"
} else {
number.toString()
}
}
/**
* Utility method to perform actions if item is found or not after an auto search in [database]
*/
fun checkAutoSearchInfo(context: Context,
database: ContextualDatabase?,
searchInfo: SearchInfo?,
onItemsFound: (openedDatabase: ContextualDatabase,
items: List<EntryInfo>) -> Unit,
onItemNotFound: (openedDatabase: ContextualDatabase) -> Unit,
onDatabaseClosed: () -> Unit) {
if (database == null || !database.loaded) {
onDatabaseClosed.invoke()
} else if (TimeoutHelper.checkTime(context)) {
var searchWithoutUI = false
if (searchInfo != null
&& !searchInfo.manualSelection
&& !searchInfo.containsOnlyNullValues()) {
// If search provide results
database.createVirtualGroupFromSearchInfo(
searchInfo.toString(),
MAX_SEARCH_ENTRY
)?.let { searchGroup ->
if (searchGroup.numberOfChildEntries > 0) {
searchWithoutUI = true
onItemsFound.invoke(database,
searchGroup.getChildEntriesInfo(database))
}
}
}
if (!searchWithoutUI) {
onItemNotFound.invoke(database)
}
}
}
}

View File

@@ -11,11 +11,10 @@ import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import com.kunzisoft.keepass.BuildConfig
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.legacy.DatabaseModeActivity
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.utils.UriUtil.openExternalApp
/**
* Special activity to deal with hardware key drivers,
@@ -49,7 +48,7 @@ class HardwareKeyActivity: DatabaseModeActivity(){
return false
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
val hardwareKey = HardwareKey.getHardwareKeyFromString(
@@ -158,8 +157,7 @@ class HardwareKeyActivity: DatabaseModeActivity(){
context.getString(R.string.error_driver_required, hardwareKey.toString())
)
.setPositiveButton(R.string.download) { _, _ ->
UriUtil.openExternalApp(
context,
context.openExternalApp(
context.getString(R.string.key_driver_app_id),
context.getString(R.string.key_driver_url)
)

View File

@@ -0,0 +1,144 @@
package com.kunzisoft.keepass.hardware
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.utils.UriUtil.openExternalApp
import kotlinx.coroutines.launch
class HardwareKeyResponseHelper {
private var activity: FragmentActivity? = null
private var fragment: Fragment? = null
private var getChallengeResponseResultLauncher: ActivityResultLauncher<Intent>? = null
constructor(context: FragmentActivity) {
this.activity = context
this.fragment = null
}
constructor(context: Fragment) {
this.activity = context.activity
this.fragment = context
}
fun buildHardwareKeyResponse(onChallengeResponded: (challengeResponse: ByteArray?,
extra: Bundle?) -> Unit) {
val resultCallback = ActivityResultCallback<ActivityResult> { result ->
if (result.resultCode == Activity.RESULT_OK) {
val challengeResponse: ByteArray? = result.data?.getByteArrayExtra(HARDWARE_KEY_RESPONSE_KEY)
Log.d(TAG, "Response form challenge")
onChallengeResponded.invoke(challengeResponse,
result.data?.getBundleExtra(EXTRA_BUNDLE_KEY))
} else {
Log.e(TAG, "Response from challenge error")
onChallengeResponded.invoke(null,
result.data?.getBundleExtra(EXTRA_BUNDLE_KEY))
}
}
getChallengeResponseResultLauncher = if (fragment != null) {
fragment?.registerForActivityResult(
ActivityResultContracts.StartActivityForResult(),
resultCallback
)
} else {
activity?.registerForActivityResult(
ActivityResultContracts.StartActivityForResult(),
resultCallback
)
}
}
fun launchChallengeForResponse(hardwareKey: HardwareKey, seed: ByteArray?) {
when (hardwareKey) {
/*
HardwareKey.FIDO2_SECRET -> {
// TODO FIDO2 under development
throw Exception("FIDO2 not implemented")
}
*/
HardwareKey.CHALLENGE_RESPONSE_YUBIKEY -> {
// Transform the seed before sending
var challenge: ByteArray? = null
if (seed != null) {
challenge = ByteArray(64)
seed.copyInto(challenge, 0, 0, 32)
challenge.fill(32, 32, 64)
}
// Send to the driver
getChallengeResponseResultLauncher!!.launch(
Intent(YUBIKEY_CHALLENGE_RESPONSE_INTENT).apply {
putExtra(HARDWARE_KEY_CHALLENGE_KEY, challenge)
}
)
Log.d(TAG, "Challenge sent")
}
}
}
companion object {
private val TAG = HardwareKeyResponseHelper::class.java.simpleName
private const val YUBIKEY_CHALLENGE_RESPONSE_INTENT = "android.yubikey.intent.action.CHALLENGE_RESPONSE"
private const val HARDWARE_KEY_CHALLENGE_KEY = "challenge"
private const val HARDWARE_KEY_RESPONSE_KEY = "response"
private const val EXTRA_BUNDLE_KEY = "EXTRA_BUNDLE_KEY"
fun isHardwareKeyAvailable(
activity: FragmentActivity,
hardwareKey: HardwareKey,
showDialog: Boolean = true
): Boolean {
return when (hardwareKey) {
/*
HardwareKey.FIDO2_SECRET -> {
// TODO FIDO2 under development
if (showDialog)
UnderDevelopmentFeatureDialogFragment()
.show(activity.supportFragmentManager, "underDevFeatureDialog")
false
}
*/
HardwareKey.CHALLENGE_RESPONSE_YUBIKEY -> {
// Check available intent
val yubikeyDriverAvailable =
Intent(YUBIKEY_CHALLENGE_RESPONSE_INTENT)
.resolveActivity(activity.packageManager) != null
if (showDialog && !yubikeyDriverAvailable)
showHardwareKeyDriverNeeded(activity, hardwareKey)
yubikeyDriverAvailable
}
}
}
private fun showHardwareKeyDriverNeeded(
activity: FragmentActivity,
hardwareKey: HardwareKey
) {
activity.lifecycleScope.launch {
val builder = AlertDialog.Builder(activity)
builder
.setMessage(
activity.getString(R.string.error_driver_required, hardwareKey.toString())
)
.setPositiveButton(R.string.download) { _, _ ->
activity.openExternalApp(activity.getString(R.string.key_driver_app_id))
}
.setNegativeButton(android.R.string.cancel) { _, _ -> }
builder.create().show()
}
}
}
}

View File

@@ -32,25 +32,25 @@ import android.widget.RemoteViews
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.toBitmap
import androidx.core.widget.ImageViewCompat
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.binary.BinaryCache
import com.kunzisoft.keepass.database.element.binary.BinaryData
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
import com.kunzisoft.keepass.database.element.icon.IconImageDraw
import com.kunzisoft.keepass.icon.IconPack
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.lang.ref.WeakReference
import java.util.*
import kotlin.collections.HashMap
/**
* Factory class who build database icons dynamically, can assign an icon of IconPack, or a custom icon to an ImageView with a tint
*/
class IconDrawableFactory(private val retrieveBinaryCache : () -> BinaryCache?,
private val retrieveCustomIconBinary : (iconId: UUID) -> BinaryData?) {
class IconDrawableFactory(
private val retrieveBinaryCache: () -> BinaryCache?,
private val retrieveCustomIconBinary: (iconId: UUID) -> BinaryData?,
) {
/** customIconMap
* Cache for icon drawable.
@@ -72,10 +72,12 @@ class IconDrawableFactory(private val retrieveBinaryCache : () -> BinaryCache?,
/**
* Get the [SuperDrawable] [iconDraw] (from cache, or build it and add it to the cache if not exists yet), then tint it with [tintColor] if needed
*/
private fun getIconSuperDrawable(context: Context,
iconDraw: IconImageDraw,
width: Int,
tintColor: Int = Color.WHITE): SuperDrawable {
private fun getIconSuperDrawable(
context: Context,
iconDraw: IconImageDraw,
width: Int,
tintColor: Int = Color.WHITE,
): SuperDrawable {
val icon = iconDraw.getIconImageToDraw()
val customIconBinary = retrieveCustomIconBinary(icon.custom.uuid)
val binaryCache = retrieveBinaryCache()
@@ -90,24 +92,29 @@ class IconDrawableFactory(private val retrieveBinaryCache : () -> BinaryCache?,
this.clearCache()
}
iconPack?.iconToResId(icon.standard.id)?.let { iconId ->
return SuperDrawable(getIconDrawable(context.resources, iconId, width, tintColor), iconPack.tintable())
return SuperDrawable(getIconDrawable(context.resources, iconId, width, tintColor),
iconPack.tintable())
} ?: run {
return SuperDrawable(PatternIcon(context.resources).blankDrawable)
return SuperDrawable(PatternIcon(IconPackChooser.defaultIconSize).blankDrawable)
}
}
/**
* Build a custom [Drawable] from custom [icon]
*/
private fun getIconDrawable(resources: Resources, icon: IconImageCustom, iconCustomBinary: BinaryData?): Drawable? {
val patternIcon = PatternIcon(resources)
val binaryManager = retrieveBinaryCache()
if (binaryManager != null) {
private fun getIconDrawable(
resources: Resources,
icon: IconImageCustom,
iconCustomBinary: BinaryData?,
): Drawable? {
val patternIcon = PatternIcon(IconPackChooser.defaultIconSize)
retrieveBinaryCache()?.let { binaryCache ->
val draw: Drawable? = customIconMap[icon.uuid]?.get()
if (draw == null) {
iconCustomBinary?.let { binaryFile ->
try {
var bitmap: Bitmap? = BitmapFactory.decodeStream(binaryFile.getInputDataStream(binaryManager))
var bitmap: Bitmap? =
BitmapFactory.decodeStream(binaryFile.getInputDataStream(binaryCache))
bitmap?.let { bitmapIcon ->
bitmap = resize(bitmapIcon, patternIcon)
val createdDraw = BitmapDrawable(resources, bitmap)
@@ -130,7 +137,12 @@ class IconDrawableFactory(private val retrieveBinaryCache : () -> BinaryCache?,
* Get the standard [Drawable] icon from [iconId] (cache or build it and add it to the cache if not exists yet)
* , then tint it with [tintColor] if needed
*/
private fun getIconDrawable(resources: Resources, iconId: Int, width: Int, tintColor: Int): Drawable {
private fun getIconDrawable(
resources: Resources,
iconId: Int,
width: Int,
tintColor: Int,
): Drawable {
val newCacheKey = CacheKey(iconId, width, true, tintColor)
var draw: Drawable? = standardIconMap[newCacheKey]?.get()
@@ -147,7 +159,7 @@ class IconDrawableFactory(private val retrieveBinaryCache : () -> BinaryCache?,
}
if (draw == null) {
draw = PatternIcon(resources).blankDrawable
draw = PatternIcon(IconPackChooser.defaultIconSize).blankDrawable
}
draw.isFilterBitmap = false
@@ -166,28 +178,34 @@ class IconDrawableFactory(private val retrieveBinaryCache : () -> BinaryCache?,
return if (width == dimensionPattern.width && height == dimensionPattern.height) {
bitmap
} else Bitmap.createScaledBitmap(bitmap, dimensionPattern.width, dimensionPattern.height, true)
} else Bitmap.createScaledBitmap(bitmap,
dimensionPattern.width,
dimensionPattern.height,
true)
}
/**
* Assign a database [icon] to an ImageView and tint it with [tintColor] if needed
*/
fun assignDatabaseIcon(imageView: ImageView,
icon: IconImageDraw,
tintColor: Int = Color.WHITE) {
fun assignDatabaseIcon(
imageView: ImageView,
icon: IconImageDraw,
tintColor: Int = Color.WHITE,
) {
try {
val context = imageView.context
CoroutineScope(Dispatchers.IO).launch {
addToCustomCache(context.resources, icon)
withContext(Dispatchers.Main) {
val superDrawable = getIconSuperDrawable(context,
icon,
imageView.width,
tintColor)
icon,
imageView.width,
tintColor)
imageView.setImageDrawable(superDrawable.drawable)
if (superDrawable.tintable) {
ImageViewCompat.setImageTintList(imageView, ColorStateList.valueOf(tintColor))
ImageViewCompat.setImageTintList(imageView,
ColorStateList.valueOf(tintColor))
} else {
ImageViewCompat.setImageTintList(imageView, null)
}
@@ -201,14 +219,16 @@ class IconDrawableFactory(private val retrieveBinaryCache : () -> BinaryCache?,
/**
* Build a bitmap from a database [icon]
*/
fun getBitmapFromIcon(context: Context,
icon: IconImageDraw,
tintColor: Int = Color.BLACK): Bitmap? {
fun getBitmapFromIcon(
context: Context,
icon: IconImageDraw,
tintColor: Int = Color.BLACK,
): Bitmap? {
try {
val superDrawable = getIconSuperDrawable(context,
icon,
24,
tintColor)
icon,
24,
tintColor)
val bitmap = superDrawable.drawable.toBitmap()
// Tint bitmap if it's not a custom icon
if (superDrawable.tintable && bitmap.isMutable) {
@@ -230,8 +250,9 @@ class IconDrawableFactory(private val retrieveBinaryCache : () -> BinaryCache?,
val icon = iconDraw.getIconImageToDraw()
val customIconBinary = retrieveCustomIconBinary(icon.custom.uuid)
if (customIconBinary != null
&& customIconBinary.dataExists()
&& !customIconMap.containsKey(icon.custom.uuid))
&& customIconBinary.dataExists()
&& !customIconMap.containsKey(icon.custom.uuid)
)
getIconDrawable(resources, icon.custom, customIconBinary)
}
@@ -254,15 +275,15 @@ class IconDrawableFactory(private val retrieveBinaryCache : () -> BinaryCache?,
* Build a blankDrawable drawable
* @param res Resource to build the drawable
*/
private class PatternIcon(res: Resources) {
private class PatternIcon(defaultIconSize : Int) {
var blankDrawable: Drawable = ColorDrawable(Color.TRANSPARENT)
var width = -1
var height = -1
init {
width = res.getDimension(R.dimen.icon_size).toInt()
height = res.getDimension(R.dimen.icon_size).toInt()
width = defaultIconSize
height = defaultIconSize
blankDrawable.setBounds(0, 0, width, height)
}
}
@@ -275,7 +296,12 @@ class IconDrawableFactory(private val retrieveBinaryCache : () -> BinaryCache?,
/**
* Key class to retrieve a Drawable in the cache if it's tinted or not
*/
private inner class CacheKey(var resId: Int, var density: Int, var isTint: Boolean, var color: Int) {
private inner class CacheKey(
var resId: Int,
var density: Int,
var isTint: Boolean,
var color: Int,
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true

View File

@@ -22,8 +22,8 @@ package com.kunzisoft.keepass.icons
import android.content.Context
import android.util.Log
import com.kunzisoft.keepass.BuildConfig
import com.kunzisoft.keepass.icon.IconPack
import com.kunzisoft.keepass.settings.PreferencesUtil
import java.util.*
/**
* Utility class to built and select an IconPack dynamically by libraries importation
@@ -36,9 +36,11 @@ object IconPackChooser {
private val iconPackList = ArrayList<IconPack>()
private var iconPackSelected: IconPack? = null
var defaultIconSize: Int = 0
private var isIconPackChooserBuilt: Boolean = false
/**
* Built the icon pack chooser based on imports made in *build.gradle*
*
@@ -50,7 +52,7 @@ object IconPackChooser {
* @param context Context to construct each pack with the resources
* @return An unique instance of [IconPackChooser], recall [.build] provide the same instance
*/
fun build(context: Context) {
private fun build(context: Context) {
synchronized(IconPackChooser::class.java) {
if (!isIconPackChooserBuilt) {
isIconPackChooserBuilt = true
@@ -62,6 +64,9 @@ object IconPackChooser {
Log.e(TAG, "Icon packs can't be load, retry with one by default")
addDefaultIconPack(context)
}
if(defaultIconSize == 0) {
defaultIconSize = IconPack.defaultIconSize(context)
}
}
}
}
@@ -79,10 +84,14 @@ object IconPackChooser {
*/
private fun addOrCatchNewIconPack(context: Context, iconPackString: String) {
try {
iconPackList.add(IconPack(context.packageName, context.resources, context.resources.getIdentifier(
iconPackList.add(
IconPack(context.packageName,
context.resources,
context.resources.getIdentifier(
iconPackString + "_resource_id",
"string",
context.packageName)))
context.packageName))
)
} catch (e: Exception) {
Log.w(TAG, "Icon pack $iconPackString can't be load")
}

View File

@@ -43,11 +43,11 @@ import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.EntrySelectionLauncherActivity
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.adapters.FieldsAdapter
import com.kunzisoft.keepass.database.action.DatabaseTaskProvider
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.DatabaseTaskProvider
import com.kunzisoft.keepass.database.element.Field
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
import com.kunzisoft.keepass.database.search.SearchHelper
import com.kunzisoft.keepass.database.helper.SearchHelper
import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.otp.OtpEntryFields.OTP_TOKEN_FIELD
@@ -59,7 +59,7 @@ import java.util.*
class MagikeyboardService : InputMethodService(), KeyboardView.OnKeyboardActionListener {
private var mDatabaseTaskProvider: DatabaseTaskProvider? = null
private var mDatabase: Database? = null
private var mDatabase: ContextualDatabase? = null
private var keyboardView: KeyboardView? = null
private var entryContainer: View? = null

View File

@@ -26,7 +26,7 @@ import android.os.Parcelable
import android.text.format.Formatter
import com.kunzisoft.keepass.viewmodels.FileDatabaseInfo
import java.text.DateFormat
import java.util.*
import java.util.Date
/**
* Utility data class to get FileDatabaseInfo at a `t` time
@@ -92,10 +92,10 @@ data class SnapFileDatabaseInfo(var fileUri: Uri?,
fun fromFileDatabaseInfo(fileDatabaseInfo: FileDatabaseInfo): SnapFileDatabaseInfo {
return SnapFileDatabaseInfo(
fileDatabaseInfo.fileUri,
fileDatabaseInfo.exists,
fileDatabaseInfo.getLastModification(),
fileDatabaseInfo.getSize())
fileDatabaseInfo.fileUri,
fileDatabaseInfo.exists,
fileDatabaseInfo.getLastModification(),
fileDatabaseInfo.getSize())
}
}
}

View File

@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.password
import android.content.res.Resources
import android.graphics.Color
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.app.database.IOActionTask
import com.kunzisoft.keepass.utils.IOActionTask
import kotlinx.coroutines.*
import me.gosimple.nbvcxz.Nbvcxz
import me.gosimple.nbvcxz.resources.Configuration

View File

@@ -2,7 +2,10 @@ package com.kunzisoft.keepass.services
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.*
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.net.Uri
import android.os.Binder
import android.os.Build
@@ -122,7 +125,7 @@ class AdvancedUnlockNotificationService : NotificationService() {
// Only one service connection
fun bindService(context: Context, serviceConnection: ServiceConnection, flags: Int) {
context.bindService(Intent(context,
AdvancedUnlockNotificationService::class.java),
AdvancedUnlockNotificationService::class.java),
serviceConnection,
flags)
}

View File

@@ -29,14 +29,14 @@ import android.os.IBinder
import android.util.Log
import androidx.core.app.ServiceCompat
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.action.DatabaseTaskProvider
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.DatabaseTaskProvider
import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.model.AttachmentState
import com.kunzisoft.keepass.model.EntryAttachmentState
import com.kunzisoft.keepass.model.StreamDirection
import com.kunzisoft.keepass.tasks.BinaryDatabaseManager
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -48,7 +48,7 @@ import java.util.concurrent.CopyOnWriteArrayList
class AttachmentFileNotificationService: LockNotificationService() {
private var mDatabaseTaskProvider: DatabaseTaskProvider? = null
private var mDatabase: Database? = null
private var mDatabase: ContextualDatabase? = null
private val mPendingCommands: MutableList<Intent?> = mutableListOf()
override val notificationId: Int = 10000
@@ -218,7 +218,7 @@ class AttachmentFileNotificationService: LockNotificationService() {
}
)
val fileName = UriUtil.getFileData(this, attachmentNotification.uri)?.name
val fileName = attachmentNotification.uri.getDocumentFile(this)?.name
?: attachmentNotification.uri.path
val builder = buildNewNotification().apply {
@@ -365,9 +365,9 @@ class AttachmentFileNotificationService: LockNotificationService() {
}
private class AttachmentFileAction(
private val attachmentNotification: AttachmentNotification,
private val database: Database,
private val contentResolver: ContentResolver) {
private val attachmentNotification: AttachmentNotification,
private val database: ContextualDatabase,
private val contentResolver: ContentResolver) {
private val updateMinFrequency = 1000
private var previousSaveTime = System.currentTimeMillis()

View File

@@ -47,7 +47,9 @@ import com.kunzisoft.keepass.icons.IconPackChooser
import com.kunzisoft.keepass.services.ClipboardEntryNotificationService
import com.kunzisoft.keepass.settings.preference.IconPackListPreference
import com.kunzisoft.keepass.settings.preferencedialogfragment.DurationDialogFragmentCompat
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
import com.kunzisoft.keepass.utils.UriUtil.openUrl
import com.kunzisoft.keepass.utils.UriUtil.releaseAllUnnecessaryPermissionUris
class NestedAppSettingsFragment : NestedSettingsFragment() {
@@ -81,7 +83,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
findPreference<Preference>(getString(R.string.remember_database_locations_key))?.setOnPreferenceChangeListener { _, newValue ->
if (!(newValue as Boolean)) {
FileDatabaseHistoryAction.getInstance(activity.applicationContext).deleteAll {
UriUtil.releaseAllUnnecessaryPermissionUris(activity.applicationContext)
activity.releaseAllUnnecessaryPermissionUris()
}
}
true
@@ -90,7 +92,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
findPreference<Preference>(getString(R.string.remember_keyfile_locations_key))?.setOnPreferenceChangeListener { _, newValue ->
if (!(newValue as Boolean)) {
FileDatabaseHistoryAction.getInstance(activity.applicationContext).deleteAllKeyFiles {
UriUtil.releaseAllUnnecessaryPermissionUris(activity.applicationContext)
activity.releaseAllUnnecessaryPermissionUris()
}
}
true
@@ -168,7 +170,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
}
findPreference<Preference>(getString(R.string.magic_keyboard_explanation_key))?.setOnPreferenceClickListener {
UriUtil.gotoUrl(requireContext(), R.string.magic_keyboard_explanation_url)
context?.openUrl(R.string.magic_keyboard_explanation_url)
false
}
@@ -185,7 +187,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
}
findPreference<Preference>(getString(R.string.autofill_explanation_key))?.setOnPreferenceClickListener {
UriUtil.gotoUrl(requireContext(), R.string.autofill_explanation_url)
context?.openUrl(R.string.autofill_explanation_url)
false
}
@@ -202,7 +204,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
}
findPreference<Preference>(getString(R.string.clipboard_explanation_key))?.setOnPreferenceClickListener {
UriUtil.gotoUrl(requireContext(), R.string.clipboard_explanation_url)
context?.openUrl(R.string.clipboard_explanation_url)
false
}
@@ -360,7 +362,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
}
findPreference<Preference>(getString(R.string.advanced_unlock_explanation_key))?.setOnPreferenceClickListener {
UriUtil.gotoUrl(requireContext(), R.string.advanced_unlock_explanation_url)
context?.openUrl(R.string.advanced_unlock_explanation_url)
false
}
}
@@ -404,7 +406,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
findPreference<ListPreference>(getString(R.string.setting_style_key))?.setOnPreferenceChangeListener { _, newValue ->
var styleEnabled = true
val styleIdString = newValue as String
if (!UriUtil.contributingUser(activity)) {
if (!activity.isContributingUser()) {
for (themeIdDisabled in BuildConfig.STYLES_DISABLED) {
if (themeIdDisabled == styleIdString) {
styleEnabled = false
@@ -435,7 +437,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
findPreference<IconPackListPreference>(getString(R.string.setting_icon_pack_choose_key))?.setOnPreferenceChangeListener { _, newValue ->
var iconPackEnabled = true
val iconPackId = newValue as String
if (!UriUtil.contributingUser(activity)) {
if (!activity.isContributingUser()) {
for (iconPackIdDisabled in BuildConfig.ICON_PACKS_DISABLED) {
if (iconPackIdDisabled == iconPackId) {
iconPackEnabled = false

View File

@@ -33,12 +33,12 @@ import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.SetMainCredentialDialogFragment
import com.kunzisoft.keepass.activities.legacy.DatabaseRetrieval
import com.kunzisoft.keepass.activities.legacy.resetAppTimeoutWhenViewTouchedOrFocused
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.crypto.EncryptionAlgorithm
import com.kunzisoft.keepass.database.crypto.kdf.KdfEngine
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
import com.kunzisoft.keepass.database.element.template.TemplateEngine
import com.kunzisoft.keepass.database.helper.*
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService
import com.kunzisoft.keepass.settings.preference.*
import com.kunzisoft.keepass.settings.preferencedialogfragment.*
@@ -48,7 +48,7 @@ import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetrieval {
private val mDatabaseViewModel: DatabaseViewModel by activityViewModels()
private var mDatabase: Database? = null
private var mDatabase: ContextualDatabase? = null
private var mDatabaseReadOnly: Boolean = false
private var mMergeDataAllowed: Boolean = false
private var mDatabaseAutoSaveEnabled: Boolean = true
@@ -123,7 +123,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
mDatabaseViewModel.reloadDatabase(false)
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
mDatabase = database
mDatabaseReadOnly = database?.isReadOnly == true
mMergeDataAllowed = database?.isMergeDataAllowed() == true
@@ -149,7 +149,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
}
}
private fun onCreateDatabasePreference(database: Database) {
private fun onCreateDatabasePreference(database: ContextualDatabase) {
val dbGeneralPrefCategory: PreferenceCategory? = findPreference(getString(R.string.database_category_general_key))
// Database name
@@ -199,7 +199,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
dbDataCompressionPref = findPreference(getString(R.string.database_data_compression_key))
if (database.allowDataCompression) {
dbDataCompressionPref?.summary = (database.compressionAlgorithm
?: CompressionAlgorithm.None).getName(resources)
?: CompressionAlgorithm.NONE).getLocalizedName(resources)
} else {
dbCompressionPrefCategory?.isVisible = false
}
@@ -215,7 +215,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
isEnabled = if (!mDatabaseReadOnly) {
setOnPreferenceChangeListener { _, newValue ->
val recycleBinEnabled = newValue as Boolean
database.enableRecycleBin(recycleBinEnabled, resources)
database.enableRecycleBin(recycleBinEnabled, resources.getString(R.string.recycle_bin))
refreshRecycleBinGroup(database)
// Save the database if not in readonly mode
saveDatabase(mDatabaseAutoSaveEnabled)
@@ -249,7 +249,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
setOnPreferenceChangeListener { _, newValue ->
val templatesEnabled = newValue as Boolean
database.enableTemplates(templatesEnabled,
TemplateEngine.getDefaultTemplateGroupName(resources)
resources.getString(R.string.templates)
)
refreshTemplatesGroup(database)
// Save the database if not in readonly mode
@@ -282,7 +282,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
}
}
private fun refreshRecycleBinGroup(database: Database?) {
private fun refreshRecycleBinGroup(database: ContextualDatabase?) {
recycleBinGroupPref?.apply {
if (database?.isRecycleBinEnabled == true) {
summary = database.recycleBin?.toString()
@@ -294,7 +294,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
}
}
private fun refreshTemplatesGroup(database: Database?) {
private fun refreshTemplatesGroup(database: ContextualDatabase?) {
templatesGroupPref?.apply {
if (database?.isTemplatesEnabled == true) {
summary = database.templatesGroup?.toString()
@@ -306,7 +306,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
}
}
private fun onCreateDatabaseSecurityPreference(database: Database) {
private fun onCreateDatabaseSecurityPreference(database: ContextualDatabase) {
// Encryption Algorithm
mEncryptionAlgorithmPref = findPreference<DialogListExplanationPreference>(getString(R.string.encryption_algorithm_key))?.apply {
summary = database.getEncryptionAlgorithmName()
@@ -333,7 +333,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
}
}
private fun onCreateDatabaseMasterKeyPreference(database: Database) {
private fun onCreateDatabaseMasterKeyPreference(database: ContextualDatabase) {
findPreference<Preference>(getString(R.string.settings_database_change_credentials_key))?.apply {
isEnabled = if (!mDatabaseReadOnly) {
onPreferenceClickListener = Preference.OnPreferenceClickListener {
@@ -371,7 +371,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
}
// TODO check error
override fun onDatabaseActionFinished(database: Database,
override fun onDatabaseActionFinished(database: ContextualDatabase,
actionTask: String,
result: ActionRunnable.Result) {
result.data?.let { data ->
@@ -442,7 +442,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
mDatabase?.compressionAlgorithm = oldCompression
oldCompression
}
dbDataCompressionPref?.summary = algorithmToShow.getName(resources)
dbDataCompressionPref?.summary = algorithmToShow.getLocalizedName(resources)
}
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_RECYCLE_BIN_TASK -> {
val oldRecycleBin = data.getParcelable<Group?>(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)

View File

@@ -36,7 +36,7 @@ import com.kunzisoft.keepass.education.Education
import com.kunzisoft.keepass.magikeyboard.MagikeyboardService
import com.kunzisoft.keepass.password.PassphraseGenerator
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
import java.util.*
object PreferencesUtil {
@@ -75,25 +75,25 @@ object PreferencesUtil {
fun rememberDatabaseLocations(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.remember_database_locations_key),
context.resources.getBoolean(R.bool.remember_database_locations_default))
context.resources.getBoolean(R.bool.remember_database_locations_default))
}
fun showRecentFiles(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.show_recent_files_key),
context.resources.getBoolean(R.bool.show_recent_files_default))
context.resources.getBoolean(R.bool.show_recent_files_default))
}
fun hideBrokenLocations(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.hide_broken_locations_key),
context.resources.getBoolean(R.bool.hide_broken_locations_default))
context.resources.getBoolean(R.bool.hide_broken_locations_default))
}
fun rememberKeyFileLocations(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.remember_keyfile_locations_key),
context.resources.getBoolean(R.bool.remember_keyfile_locations_default))
context.resources.getBoolean(R.bool.remember_keyfile_locations_default))
}
fun rememberHardwareKey(context: Context): Boolean {
@@ -105,13 +105,13 @@ object PreferencesUtil {
fun automaticallyFocusSearch(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.auto_focus_search_key),
context.resources.getBoolean(R.bool.auto_focus_search_default))
context.resources.getBoolean(R.bool.auto_focus_search_default))
}
fun searchSubdomains(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.subdomain_search_key),
context.resources.getBoolean(R.bool.subdomain_search_default))
context.resources.getBoolean(R.bool.subdomain_search_default))
}
fun showEntryColors(context: Context): Boolean {
@@ -135,13 +135,13 @@ object PreferencesUtil {
fun showUsernamesListEntries(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.list_entries_show_username_key),
context.resources.getBoolean(R.bool.list_entries_show_username_default))
context.resources.getBoolean(R.bool.list_entries_show_username_default))
}
fun showNumberEntries(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.list_groups_show_number_entries_key),
context.resources.getBoolean(R.bool.list_groups_show_number_entries_default))
context.resources.getBoolean(R.bool.list_groups_show_number_entries_default))
}
fun showOTPToken(context: Context): Boolean {
@@ -159,21 +159,21 @@ object PreferencesUtil {
fun showExpiredEntries(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return ! prefs.getBoolean(context.getString(R.string.hide_expired_entries_key),
context.resources.getBoolean(R.bool.hide_expired_entries_default))
context.resources.getBoolean(R.bool.hide_expired_entries_default))
}
fun getStyle(context: Context): String {
val defaultStyleString = Stylish.defaultStyle(context)
val styleString = PreferenceManager.getDefaultSharedPreferences(context)
.getString(context.getString(R.string.setting_style_key), defaultStyleString)
?: defaultStyleString
.getString(context.getString(R.string.setting_style_key), defaultStyleString)
?: defaultStyleString
// Return the system style
return Stylish.retrieveEquivalentSystemStyle(context, styleString)
}
fun setStyle(context: Context, styleString: String) {
var tempThemeString = styleString
if (!UriUtil.contributingUser(context)) {
if (!context.isContributingUser()) {
if (tempThemeString in BuildConfig.STYLES_DISABLED) {
tempThemeString = Stylish.defaultStyle(context)
}
@@ -181,16 +181,16 @@ object PreferencesUtil {
// Store light style to show selection in array list
tempThemeString = Stylish.retrieveEquivalentLightStyle(context, tempThemeString)
PreferenceManager.getDefaultSharedPreferences(context)
.edit()
.putString(context.getString(R.string.setting_style_key), tempThemeString)
.apply()
.edit()
.putString(context.getString(R.string.setting_style_key), tempThemeString)
.apply()
Stylish.load(context)
}
fun getStyleBrightness(context: Context): String? {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getString(context.getString(R.string.setting_style_brightness_key),
context.getString(R.string.list_style_brightness_follow_system))
context.getString(R.string.list_style_brightness_follow_system))
}
/**
@@ -200,7 +200,7 @@ object PreferencesUtil {
val index = try {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val listSizeString = prefs.getString(context.getString(R.string.list_size_key),
context.getString(R.string.list_size_string_medium))
context.getString(R.string.list_size_string_medium))
context.resources.getStringArray(R.array.list_size_string_values).indexOf(listSizeString)
} catch (e: Exception) {
1
@@ -214,7 +214,7 @@ object PreferencesUtil {
fun getDefaultPasswordLength(context: Context): Int {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getInt(context.getString(R.string.password_generator_length_key),
context.resources.getInteger(R.integer.password_generator_length_default))
context.resources.getInteger(R.integer.password_generator_length_default))
}
fun setDefaultPasswordLength(context: Context, passwordLength: Int) {
@@ -406,7 +406,7 @@ object PreferencesUtil {
fun isClipboardNotificationsEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.clipboard_notifications_key),
context.resources.getBoolean(R.bool.clipboard_notifications_default))
context.resources.getBoolean(R.bool.clipboard_notifications_default))
}
/**
@@ -425,7 +425,7 @@ object PreferencesUtil {
fun getTimeSaved(context: Context): Long {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getLong(context.getString(R.string.timeout_backup_key),
TimeoutHelper.NEVER)
TimeoutHelper.NEVER)
}
/**
@@ -435,7 +435,7 @@ object PreferencesUtil {
return try {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
(prefs.getString(context.getString(R.string.app_timeout_key),
context.getString(R.string.timeout_default)) ?: "300000").toLong()
context.getString(R.string.timeout_default)) ?: "300000").toLong()
} catch (e: NumberFormatException) {
TimeoutHelper.DEFAULT_TIMEOUT
}
@@ -444,39 +444,39 @@ object PreferencesUtil {
fun getClipboardTimeout(context: Context): Long {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getString(context.getString(R.string.clipboard_timeout_key),
context.getString(R.string.clipboard_timeout_default))?.toLong()
?: TimeoutHelper.DEFAULT_TIMEOUT
context.getString(R.string.clipboard_timeout_default))?.toLong()
?: TimeoutHelper.DEFAULT_TIMEOUT
}
fun getAdvancedUnlockTimeout(context: Context): Long {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getString(context.getString(R.string.temp_advanced_unlock_timeout_key),
context.getString(R.string.temp_advanced_unlock_timeout_default))?.toLong()
?: TimeoutHelper.DEFAULT_TIMEOUT
context.getString(R.string.temp_advanced_unlock_timeout_default))?.toLong()
?: TimeoutHelper.DEFAULT_TIMEOUT
}
fun isLockDatabaseWhenScreenShutOffEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.lock_database_screen_off_key),
context.resources.getBoolean(R.bool.lock_database_screen_off_default))
context.resources.getBoolean(R.bool.lock_database_screen_off_default))
}
fun isLockDatabaseWhenBackButtonOnRootClicked(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.lock_database_back_root_key),
context.resources.getBoolean(R.bool.lock_database_back_root_default))
context.resources.getBoolean(R.bool.lock_database_back_root_default))
}
fun showLockDatabaseButton(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.lock_database_show_button_key),
context.resources.getBoolean(R.bool.lock_database_show_button_default))
context.resources.getBoolean(R.bool.lock_database_show_button_default))
}
fun isAutoSaveDatabaseEnabled(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.enable_auto_save_database_key),
context.resources.getBoolean(R.bool.enable_auto_save_database_default))
context.resources.getBoolean(R.bool.enable_auto_save_database_default))
}
fun isKeepScreenOnEnabled(context: Context): Boolean {
@@ -498,39 +498,39 @@ object PreferencesUtil {
fun isBiometricUnlockEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.biometric_unlock_enable_key),
context.resources.getBoolean(R.bool.biometric_unlock_enable_default))
context.resources.getBoolean(R.bool.biometric_unlock_enable_default))
&& (if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
AdvancedUnlockManager.biometricUnlockSupported(context)
} else {
false
})
AdvancedUnlockManager.biometricUnlockSupported(context)
} else {
false
})
}
fun isDeviceCredentialUnlockEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
// Priority to biometric unlock
return prefs.getBoolean(context.getString(R.string.device_credential_unlock_enable_key),
context.resources.getBoolean(R.bool.device_credential_unlock_enable_default))
context.resources.getBoolean(R.bool.device_credential_unlock_enable_default))
&& !isBiometricUnlockEnable(context)
}
fun isTempAdvancedUnlockEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.temp_advanced_unlock_enable_key),
context.resources.getBoolean(R.bool.temp_advanced_unlock_enable_default))
context.resources.getBoolean(R.bool.temp_advanced_unlock_enable_default))
}
fun isAdvancedUnlockPromptAutoOpenEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.biometric_auto_open_prompt_key),
context.resources.getBoolean(R.bool.biometric_auto_open_prompt_default))
context.resources.getBoolean(R.bool.biometric_auto_open_prompt_default))
}
fun getListSort(context: Context): SortNodeEnum {
try {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
prefs.getString(context.getString(R.string.sort_node_key),
SortNodeEnum.DB.name)?.let {
SortNodeEnum.DB.name)?.let {
return SortNodeEnum.valueOf(it)
}
} catch (e: Exception) {}
@@ -540,94 +540,94 @@ object PreferencesUtil {
fun getGroupsBeforeSort(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.sort_group_before_key),
context.resources.getBoolean(R.bool.sort_group_before_default))
context.resources.getBoolean(R.bool.sort_group_before_default))
}
fun getAscendingSort(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.sort_ascending_key),
context.resources.getBoolean(R.bool.sort_ascending_default))
context.resources.getBoolean(R.bool.sort_ascending_default))
}
fun getRecycleBinBottomSort(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.sort_recycle_bin_bottom_key),
context.resources.getBoolean(R.bool.sort_recycle_bin_bottom_default))
context.resources.getBoolean(R.bool.sort_recycle_bin_bottom_default))
}
fun fieldFontIsInVisibility(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.monospace_font_fields_enable_key),
context.resources.getBoolean(R.bool.monospace_font_fields_enable_default))
context.resources.getBoolean(R.bool.monospace_font_fields_enable_default))
}
fun isFirstTimeAskAllowCopyProtectedFields(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.allow_copy_password_first_time_key),
context.resources.getBoolean(R.bool.allow_copy_password_first_time_default))
context.resources.getBoolean(R.bool.allow_copy_password_first_time_default))
}
fun allowCopyProtectedFields(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.allow_copy_password_key),
context.resources.getBoolean(R.bool.allow_copy_password_default))
context.resources.getBoolean(R.bool.allow_copy_password_default))
}
fun isClearClipboardNotificationEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.clear_clipboard_notification_key),
context.resources.getBoolean(R.bool.clear_clipboard_notification_default))
context.resources.getBoolean(R.bool.clear_clipboard_notification_default))
}
fun isClearKeyboardNotificationEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.keyboard_notification_entry_clear_close_key),
context.resources.getBoolean(R.bool.keyboard_notification_entry_clear_close_default))
context.resources.getBoolean(R.bool.keyboard_notification_entry_clear_close_default))
}
fun setAllowCopyPasswordAndProtectedFields(context: Context, allowCopy: Boolean) {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
prefs.edit()
.putBoolean(context.getString(R.string.allow_copy_password_first_time_key), false)
.putBoolean(context.getString(R.string.allow_copy_password_key), allowCopy)
.apply()
.putBoolean(context.getString(R.string.allow_copy_password_first_time_key), false)
.putBoolean(context.getString(R.string.allow_copy_password_key), allowCopy)
.apply()
}
fun getIconPackSelectedId(context: Context): String? {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getString(
context.getString(R.string.setting_icon_pack_choose_key),
context.getString(R.string.setting_icon_pack_choose_default))
context.getString(R.string.setting_icon_pack_choose_key),
context.getString(R.string.setting_icon_pack_choose_default))
}
fun emptyPasswordAllowed(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.allow_no_password_key),
context.resources.getBoolean(R.bool.allow_no_password_default))
context.resources.getBoolean(R.bool.allow_no_password_default))
}
fun enableReadOnlyDatabase(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.enable_read_only_key),
context.resources.getBoolean(R.bool.enable_read_only_default))
context.resources.getBoolean(R.bool.enable_read_only_default))
}
fun deletePasswordAfterConnexionAttempt(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.delete_entered_password_key),
context.resources.getBoolean(R.bool.delete_entered_password_default))
context.resources.getBoolean(R.bool.delete_entered_password_default))
}
fun isKeyboardNotificationEntryEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.keyboard_notification_entry_key),
context.resources.getBoolean(R.bool.keyboard_notification_entry_default))
context.resources.getBoolean(R.bool.keyboard_notification_entry_default))
}
fun isKeyboardEntrySelectionEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.keyboard_selection_entry_key),
context.resources.getBoolean(R.bool.keyboard_selection_entry_default))
context.resources.getBoolean(R.bool.keyboard_selection_entry_default))
}
fun isKeyboardSaveSearchInfoEnable(context: Context): Boolean {
@@ -635,79 +635,79 @@ object PreferencesUtil {
return false
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.keyboard_save_search_info_key),
context.resources.getBoolean(R.bool.keyboard_save_search_info_default))
context.resources.getBoolean(R.bool.keyboard_save_search_info_default))
}
fun isAutoGoActionEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.keyboard_auto_go_action_key),
context.resources.getBoolean(R.bool.keyboard_auto_go_action_default))
context.resources.getBoolean(R.bool.keyboard_auto_go_action_default))
}
fun isKeyboardVibrationEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.keyboard_key_vibrate_key),
context.resources.getBoolean(R.bool.keyboard_key_vibrate_default))
context.resources.getBoolean(R.bool.keyboard_key_vibrate_default))
}
fun isKeyboardSoundEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.keyboard_key_sound_key),
context.resources.getBoolean(R.bool.keyboard_key_sound_default))
context.resources.getBoolean(R.bool.keyboard_key_sound_default))
}
fun isKeyboardPreviousDatabaseCredentialsEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.keyboard_previous_database_credentials_key),
context.resources.getBoolean(R.bool.keyboard_previous_database_credentials_default))
context.resources.getBoolean(R.bool.keyboard_previous_database_credentials_default))
}
fun isKeyboardPreviousSearchEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.keyboard_previous_search_key),
context.resources.getBoolean(R.bool.keyboard_previous_search_default))
context.resources.getBoolean(R.bool.keyboard_previous_search_default))
}
fun isKeyboardPreviousFillInEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.keyboard_previous_fill_in_key),
context.resources.getBoolean(R.bool.keyboard_previous_fill_in_default))
context.resources.getBoolean(R.bool.keyboard_previous_fill_in_default))
}
fun isKeyboardPreviousLockEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.keyboard_previous_lock_key),
context.resources.getBoolean(R.bool.keyboard_previous_lock_default))
context.resources.getBoolean(R.bool.keyboard_previous_lock_default))
}
fun isAutofillCloseDatabaseEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.autofill_close_database_key),
context.resources.getBoolean(R.bool.autofill_close_database_default))
context.resources.getBoolean(R.bool.autofill_close_database_default))
}
fun isAutofillInlineSuggestionsEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.autofill_inline_suggestions_key),
context.resources.getBoolean(R.bool.autofill_inline_suggestions_default))
context.resources.getBoolean(R.bool.autofill_inline_suggestions_default))
}
fun isAutofillManualSelectionEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.autofill_manual_selection_key),
context.resources.getBoolean(R.bool.autofill_manual_selection_default))
context.resources.getBoolean(R.bool.autofill_manual_selection_default))
}
fun isAutofillSaveSearchInfoEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.autofill_save_search_info_key),
context.resources.getBoolean(R.bool.autofill_save_search_info_default))
context.resources.getBoolean(R.bool.autofill_save_search_info_default))
}
fun askToSaveAutofillData(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.autofill_ask_to_save_data_key),
context.resources.getBoolean(R.bool.autofill_ask_to_save_data_default))
context.resources.getBoolean(R.bool.autofill_ask_to_save_data_default))
}
/**
@@ -715,23 +715,23 @@ object PreferencesUtil {
*/
fun getDefaultApplicationIdBlocklist(resources: Resources?): Set<String> {
return resources?.getStringArray(R.array.autofill_application_id_blocklist_default)
?.toMutableSet()?.apply {
add(BuildConfig.APPLICATION_ID)
} ?: emptySet()
?.toMutableSet()?.apply {
add(BuildConfig.APPLICATION_ID)
} ?: emptySet()
}
fun applicationIdBlocklist(context: Context): Set<String> {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getStringSet(context.getString(R.string.autofill_application_id_blocklist_key),
getDefaultApplicationIdBlocklist(context.resources))
?: emptySet()
getDefaultApplicationIdBlocklist(context.resources))
?: emptySet()
}
fun webDomainBlocklist(context: Context): Set<String> {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getStringSet(context.getString(R.string.autofill_web_domain_blocklist_key),
context.resources.getStringArray(R.array.autofill_web_domain_blocklist_default).toMutableSet())
?: emptySet()
context.resources.getStringArray(R.array.autofill_web_domain_blocklist_default).toMutableSet())
?: emptySet()
}
fun addApplicationIdToBlocklist(context: Context, applicationId: String) {
@@ -739,8 +739,8 @@ object PreferencesUtil {
val setItems: MutableSet<String> = applicationIdBlocklist(context).toMutableSet()
setItems.add(applicationId)
prefs.edit()
.putStringSet(context.getString(R.string.autofill_application_id_blocklist_key), setItems)
.apply()
.putStringSet(context.getString(R.string.autofill_application_id_blocklist_key), setItems)
.apply()
}
fun addWebDomainToBlocklist(context: Context, webDomain: String) {
@@ -748,8 +748,8 @@ object PreferencesUtil {
val setItems: MutableSet<String> = webDomainBlocklist(context).toMutableSet()
setItems.add(webDomain)
prefs.edit()
.putStringSet(context.getString(R.string.autofill_web_domain_blocklist_key), setItems)
.apply()
.putStringSet(context.getString(R.string.autofill_web_domain_blocklist_key), setItems)
.apply()
}
fun getAppProperties(context: Context): Properties {
@@ -765,9 +765,9 @@ object PreferencesUtil {
private fun getStringSetFromProperties(value: String): Set<String> {
return value.removePrefix("[")
.removeSuffix("]")
.split(", ")
.toSet()
.removeSuffix("]")
.split(", ")
.toSet()
}
private fun putPropertiesInPreferences(properties: Properties,
@@ -788,7 +788,7 @@ object PreferencesUtil {
fun setAppProperties(context: Context, properties: Properties) {
putPropertiesInPreferences(properties,
PreferenceManager.getDefaultSharedPreferences(context)) { editor, name, value ->
PreferenceManager.getDefaultSharedPreferences(context)) { editor, name, value ->
when (name) {
context.getString(R.string.allow_no_password_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.delete_entered_password_key) -> editor.putBoolean(name, value.toBoolean())
@@ -869,7 +869,7 @@ object PreferencesUtil {
}
putPropertiesInPreferences(properties,
Education.getEducationSharedPreferences(context)) { editor, name, value ->
Education.getEducationSharedPreferences(context)) { editor, name, value ->
Education.putPropertiesInEducationPreferences(context, editor, name, value)
}
}

View File

@@ -35,13 +35,13 @@ import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.SetMainCredentialDialogFragment
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.MainCredential
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
import org.joda.time.DateTime
import java.util.*
import java.util.Properties
open class SettingsActivity
: DatabaseLockActivity(),
@@ -150,7 +150,7 @@ open class SettingsActivity
}
override fun onDatabaseActionFinished(
database: Database,
database: ContextualDatabase,
actionTask: String,
result: ActionRunnable.Result
) {

View File

@@ -23,7 +23,6 @@ import android.content.Context
import androidx.preference.ListPreference
import android.util.AttributeSet
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.icons.IconPackChooser
import java.util.*
@@ -37,9 +36,9 @@ class IconPackListPreference @JvmOverloads constructor(context: Context,
val entries = ArrayList<String>()
val values = ArrayList<String>()
for (iconPack in IconPackChooser.getIconPackList(context)) {
if (iconPack.id != null) {
iconPack.id?.let { iconPackId ->
entries.add(iconPack.name)
values.add(iconPack.id!!)
values.add(iconPackId)
}
}

View File

@@ -22,7 +22,6 @@ package com.kunzisoft.keepass.settings.preferencedialogfragment
import android.app.Dialog
import android.graphics.Color
import android.os.Bundle
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -30,14 +29,9 @@ import android.view.Window
import android.widget.CompoundButton
import androidx.annotation.ColorInt
import androidx.appcompat.app.AlertDialog
import com.kunzisoft.androidclearchroma.IndicatorMode
import com.kunzisoft.androidclearchroma.colormode.ColorMode
import com.kunzisoft.androidclearchroma.fragment.ChromaColorFragment
import com.kunzisoft.androidclearchroma.fragment.ChromaColorFragment.*
import com.kunzisoft.androidclearchroma.view.ChromaColorView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.ColorPickerDialogFragment
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
class DatabaseColorPreferenceDialogFragmentCompat : DatabaseSavePreferenceDialogFragmentCompat() {
@@ -101,7 +95,7 @@ class DatabaseColorPreferenceDialogFragmentCompat : DatabaseSavePreferenceDialog
return dialog
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
database?.let {
@@ -117,7 +111,7 @@ class DatabaseColorPreferenceDialogFragmentCompat : DatabaseSavePreferenceDialog
}
}
override fun onDialogClosed(database: Database?, positiveResult: Boolean) {
override fun onDialogClosed(database: ContextualDatabase?, positiveResult: Boolean) {
super.onDialogClosed(database, positiveResult)
if (positiveResult) {
val newColor: Int? = if (enableSwitchView.isChecked)

View File

@@ -24,7 +24,7 @@ import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
import com.kunzisoft.keepass.settings.preferencedialogfragment.adapter.ListRadioItemAdapter
@@ -50,7 +50,7 @@ class DatabaseDataCompressionPreferenceDialogFragmentCompat
}
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
setExplanationText(R.string.database_data_compression_summary)
@@ -62,7 +62,7 @@ class DatabaseDataCompressionPreferenceDialogFragmentCompat
}
}
override fun onDialogClosed(database: Database?, positiveResult: Boolean) {
override fun onDialogClosed(database: ContextualDatabase?, positiveResult: Boolean) {
super.onDialogClosed(database, positiveResult)
if (positiveResult) {
database?.let {

View File

@@ -20,16 +20,16 @@
package com.kunzisoft.keepass.settings.preferencedialogfragment
import android.os.Bundle
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
class DatabaseDefaultUsernamePreferenceDialogFragmentCompat : DatabaseSavePreferenceDialogFragmentCompat() {
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
inputText = database?.defaultUsername?: ""
}
override fun onDialogClosed(database: Database?, positiveResult: Boolean) {
override fun onDialogClosed(database: ContextualDatabase?, positiveResult: Boolean) {
super.onDialogClosed(database, positiveResult)
database?.let {
if (positiveResult) {

View File

@@ -20,16 +20,16 @@
package com.kunzisoft.keepass.settings.preferencedialogfragment
import android.os.Bundle
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
class DatabaseDescriptionPreferenceDialogFragmentCompat : DatabaseSavePreferenceDialogFragmentCompat() {
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
inputText = database?.description ?: ""
}
override fun onDialogClosed(database: Database?, positiveResult: Boolean) {
override fun onDialogClosed(database: ContextualDatabase?, positiveResult: Boolean) {
super.onDialogClosed(database, positiveResult)
database?.let {
if (positiveResult) {

View File

@@ -24,8 +24,8 @@ import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.crypto.EncryptionAlgorithm
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.settings.preferencedialogfragment.adapter.ListRadioItemAdapter
class DatabaseEncryptionAlgorithmPreferenceDialogFragmentCompat
@@ -51,7 +51,7 @@ class DatabaseEncryptionAlgorithmPreferenceDialogFragmentCompat
}
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
database?.let {
algorithmSelected = database.encryptionAlgorithm
@@ -59,7 +59,7 @@ class DatabaseEncryptionAlgorithmPreferenceDialogFragmentCompat
}
}
override fun onDialogClosed(database: Database?, positiveResult: Boolean) {
override fun onDialogClosed(database: ContextualDatabase?, positiveResult: Boolean) {
super.onDialogClosed(database, positiveResult)
if (positiveResult) {
database?.let {

View File

@@ -25,8 +25,8 @@ import androidx.preference.Preference
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.crypto.kdf.KdfEngine
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.settings.preferencedialogfragment.adapter.ListRadioItemAdapter
class DatabaseKeyDerivationPreferenceDialogFragmentCompat
@@ -54,7 +54,7 @@ class DatabaseKeyDerivationPreferenceDialogFragmentCompat
}
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
database?.let {
kdfEngineSelected = database.kdfEngine
@@ -62,7 +62,7 @@ class DatabaseKeyDerivationPreferenceDialogFragmentCompat
}
}
override fun onDialogClosed(database: Database?, positiveResult: Boolean) {
override fun onDialogClosed(database: ContextualDatabase?, positiveResult: Boolean) {
super.onDialogClosed(database, positiveResult)
if (positiveResult) {
database?.let {

View File

@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.settings.preferencedialogfragment
import android.os.Bundle
import android.view.View
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
class DatabaseMaxHistoryItemsPreferenceDialogFragmentCompat : DatabaseSavePreferenceDialogFragmentCompat() {
@@ -31,7 +31,7 @@ class DatabaseMaxHistoryItemsPreferenceDialogFragmentCompat : DatabaseSavePrefer
setExplanationText(R.string.max_history_items_summary)
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
database?.historyMaxItems?.let { maxItemsDatabase ->
inputText = maxItemsDatabase.toString()
@@ -46,7 +46,7 @@ class DatabaseMaxHistoryItemsPreferenceDialogFragmentCompat : DatabaseSavePrefer
}
}
override fun onDialogClosed(database: Database?, positiveResult: Boolean) {
override fun onDialogClosed(database: ContextualDatabase?, positiveResult: Boolean) {
super.onDialogClosed(database, positiveResult)
if (positiveResult) {
database?.let {

View File

@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.settings.preferencedialogfragment
import android.os.Bundle
import android.view.View
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.utils.DataByte
class DatabaseMaxHistorySizePreferenceDialogFragmentCompat : DatabaseSavePreferenceDialogFragmentCompat() {
@@ -34,7 +34,7 @@ class DatabaseMaxHistorySizePreferenceDialogFragmentCompat : DatabaseSavePrefere
setExplanationText(R.string.max_history_size_summary)
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
database?.historyMaxSize?.let { maxItemsDatabase ->
dataByte = DataByte(maxItemsDatabase, DataByte.ByteFormat.BYTE)
@@ -61,7 +61,7 @@ class DatabaseMaxHistorySizePreferenceDialogFragmentCompat : DatabaseSavePrefere
}
}
override fun onDialogClosed(database: Database?, positiveResult: Boolean) {
override fun onDialogClosed(database: ContextualDatabase?, positiveResult: Boolean) {
super.onDialogClosed(database, positiveResult)
if (positiveResult) {
database?.let {

View File

@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.settings.preferencedialogfragment
import android.os.Bundle
import android.view.View
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.utils.DataByte
class DatabaseMemoryUsagePreferenceDialogFragmentCompat : DatabaseSavePreferenceDialogFragmentCompat() {
@@ -34,7 +34,7 @@ class DatabaseMemoryUsagePreferenceDialogFragmentCompat : DatabaseSavePreference
setExplanationText(R.string.memory_usage_explanation)
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
database?.let {
val memoryBytes = database.memoryUsage
@@ -45,7 +45,7 @@ class DatabaseMemoryUsagePreferenceDialogFragmentCompat : DatabaseSavePreference
}
}
override fun onDialogClosed(database: Database?, positiveResult: Boolean) {
override fun onDialogClosed(database: ContextualDatabase?, positiveResult: Boolean) {
if (positiveResult) {
database?.let {
var newMemoryUsage: Long = try {

View File

@@ -20,16 +20,16 @@
package com.kunzisoft.keepass.settings.preferencedialogfragment
import android.os.Bundle
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
class DatabaseNamePreferenceDialogFragmentCompat : DatabaseSavePreferenceDialogFragmentCompat() {
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
inputText = database?.name ?: ""
}
override fun onDialogClosed(database: Database?, positiveResult: Boolean) {
override fun onDialogClosed(database: ContextualDatabase?, positiveResult: Boolean) {
super.onDialogClosed(database, positiveResult)
if (positiveResult) {
database?.let {

View File

@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.settings.preferencedialogfragment
import android.os.Bundle
import android.view.View
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
class DatabaseParallelismPreferenceDialogFragmentCompat : DatabaseSavePreferenceDialogFragmentCompat() {
@@ -31,12 +31,12 @@ class DatabaseParallelismPreferenceDialogFragmentCompat : DatabaseSavePreference
setExplanationText(R.string.parallelism_explanation)
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
inputText = database?.parallelism?.toString() ?: MIN_PARALLELISM.toString()
}
override fun onDialogClosed(database: Database?, positiveResult: Boolean) {
override fun onDialogClosed(database: ContextualDatabase?, positiveResult: Boolean) {
if (positiveResult) {
database?.let {
val parallelism: Long = try {

View File

@@ -24,7 +24,7 @@ import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.settings.preferencedialogfragment.adapter.ListRadioItemAdapter
@@ -48,7 +48,7 @@ class DatabaseRecycleBinGroupPreferenceDialogFragmentCompat
}
}
override fun onDatabaseRetrieved(database: Database?) {
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
database?.let {
mGroupRecycleBin = database.recycleBin
@@ -60,7 +60,7 @@ class DatabaseRecycleBinGroupPreferenceDialogFragmentCompat
mGroupRecycleBin = item
}
override fun onDialogClosed(database: Database?, positiveResult: Boolean) {
override fun onDialogClosed(database: ContextualDatabase?, positiveResult: Boolean) {
super.onDialogClosed(database, positiveResult)
if (positiveResult) {
database?.let {

View File

@@ -23,7 +23,7 @@ import android.os.Bundle
import android.text.SpannableStringBuilder
import android.view.View
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.ContextualDatabase
class DatabaseRemoveUnlinkedDataPreferenceDialogFragmentCompat : DatabaseSavePreferenceDialogFragmentCompat() {
@@ -37,7 +37,7 @@ class DatabaseRemoveUnlinkedDataPreferenceDialogFragmentCompat : DatabaseSavePre
}.toString()
}
override fun onDialogClosed(database: Database?, positiveResult: Boolean) {
override fun onDialogClosed(database: ContextualDatabase?, positiveResult: Boolean) {
super.onDialogClosed(database, positiveResult)
database?.let {
if (positiveResult) {

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