mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Empty Magikeyboard memory when the main service is killed #1261
This commit is contained in:
@@ -8,7 +8,7 @@ KeePassDX(3.4.0)
|
||||
* Fix small bugs #1282
|
||||
* Better search implementation #175 #1254
|
||||
* Setting to change keyboard during a search #1267
|
||||
* Manage package name from Magikeyboard #1010
|
||||
* Manage package name from Magikeyboard #1010 #1261
|
||||
* Ask confirmation to lock if changes without save #970
|
||||
|
||||
KeePassDX(3.3.3)
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
|
||||
@@ -60,7 +61,7 @@ class EntrySelectionLauncherActivity : DatabaseModeActivity() {
|
||||
keySelectionBundle.getParcelable<SearchInfo>(KEY_SEARCH_INFO)?.let { mSearchInfo ->
|
||||
searchInfo = mSearchInfo
|
||||
}
|
||||
launch(database, searchInfo)
|
||||
launch(database, searchInfo, true)
|
||||
} else {
|
||||
// To manage share
|
||||
var sharedWebDomain: String? = null
|
||||
@@ -102,112 +103,95 @@ class EntrySelectionLauncherActivity : DatabaseModeActivity() {
|
||||
}
|
||||
|
||||
private fun launch(database: Database?,
|
||||
searchInfo: SearchInfo) {
|
||||
searchInfo: SearchInfo,
|
||||
forceSelection: Boolean = false) {
|
||||
|
||||
if (!searchInfo.containsOnlyNullValues()) {
|
||||
// Setting to integrate Magikeyboard
|
||||
val searchShareForMagikeyboard = PreferencesUtil.isKeyboardSearchShareEnable(this)
|
||||
// Setting to integrate Magikeyboard
|
||||
val searchShareForMagikeyboard = PreferencesUtil.isKeyboardSearchShareEnable(this)
|
||||
|
||||
// If database is open
|
||||
val readOnly = database?.isReadOnly != false
|
||||
SearchHelper.checkAutoSearchInfo(this,
|
||||
database,
|
||||
searchInfo,
|
||||
{ openedDatabase, items ->
|
||||
// Items found
|
||||
if (searchInfo.otpString != null) {
|
||||
if (!readOnly) {
|
||||
GroupActivity.launchForSaveResult(
|
||||
this,
|
||||
openedDatabase,
|
||||
searchInfo,
|
||||
false)
|
||||
} else {
|
||||
Toast.makeText(applicationContext,
|
||||
R.string.autofill_read_only_save,
|
||||
Toast.LENGTH_LONG)
|
||||
.show()
|
||||
}
|
||||
} else if (searchShareForMagikeyboard) {
|
||||
if (items.size == 1) {
|
||||
// Automatically populate keyboard
|
||||
val entryPopulate = items[0]
|
||||
populateKeyboardAndMoveAppToBackground(
|
||||
this,
|
||||
entryPopulate,
|
||||
intent)
|
||||
} else {
|
||||
// Select the one we want
|
||||
GroupActivity.launchForKeyboardSelectionResult(this,
|
||||
openedDatabase,
|
||||
searchInfo,
|
||||
true)
|
||||
}
|
||||
// If database is open
|
||||
val readOnly = database?.isReadOnly != false
|
||||
SearchHelper.checkAutoSearchInfo(this,
|
||||
database,
|
||||
searchInfo,
|
||||
{ openedDatabase, items ->
|
||||
// Items found
|
||||
if (searchInfo.otpString != null) {
|
||||
if (!readOnly) {
|
||||
GroupActivity.launchForSaveResult(
|
||||
this,
|
||||
openedDatabase,
|
||||
searchInfo,
|
||||
false)
|
||||
} else {
|
||||
GroupActivity.launchForSearchResult(this,
|
||||
Toast.makeText(applicationContext,
|
||||
R.string.autofill_read_only_save,
|
||||
Toast.LENGTH_LONG)
|
||||
.show()
|
||||
}
|
||||
} else if (searchShareForMagikeyboard) {
|
||||
if (items.size == 1 && !forceSelection) {
|
||||
// Automatically populate keyboard
|
||||
val entryPopulate = items[0]
|
||||
populateKeyboardAndMoveAppToBackground(
|
||||
this,
|
||||
entryPopulate,
|
||||
intent)
|
||||
Log.e("TEST", "One item activity")
|
||||
} else {
|
||||
// Select the one we want
|
||||
GroupActivity.launchForKeyboardSelectionResult(this,
|
||||
openedDatabase,
|
||||
searchInfo,
|
||||
true)
|
||||
}
|
||||
},
|
||||
{ openedDatabase ->
|
||||
// Show the database UI to select the entry
|
||||
if (searchInfo.otpString != null) {
|
||||
if (!readOnly) {
|
||||
GroupActivity.launchForSaveResult(this,
|
||||
openedDatabase,
|
||||
searchInfo,
|
||||
false)
|
||||
} else {
|
||||
Toast.makeText(applicationContext,
|
||||
R.string.autofill_read_only_save,
|
||||
Toast.LENGTH_LONG)
|
||||
.show()
|
||||
}
|
||||
} else if (readOnly || searchShareForMagikeyboard) {
|
||||
GroupActivity.launchForKeyboardSelectionResult(this,
|
||||
openedDatabase,
|
||||
searchInfo,
|
||||
false)
|
||||
} else {
|
||||
} else {
|
||||
GroupActivity.launchForSearchResult(this,
|
||||
openedDatabase,
|
||||
searchInfo,
|
||||
true)
|
||||
}
|
||||
},
|
||||
{ openedDatabase ->
|
||||
// Show the database UI to select the entry
|
||||
if (searchInfo.otpString != null) {
|
||||
if (!readOnly) {
|
||||
GroupActivity.launchForSaveResult(this,
|
||||
openedDatabase,
|
||||
searchInfo,
|
||||
false)
|
||||
}
|
||||
},
|
||||
{
|
||||
// If database not open
|
||||
if (searchInfo.otpString != null) {
|
||||
FileDatabaseSelectActivity.launchForSaveResult(this,
|
||||
searchInfo)
|
||||
} else if (searchShareForMagikeyboard) {
|
||||
FileDatabaseSelectActivity.launchForKeyboardSelectionResult(this,
|
||||
searchInfo)
|
||||
} else {
|
||||
FileDatabaseSelectActivity.launchForSearchResult(this,
|
||||
searchInfo)
|
||||
Toast.makeText(applicationContext,
|
||||
R.string.autofill_read_only_save,
|
||||
Toast.LENGTH_LONG)
|
||||
.show()
|
||||
}
|
||||
} else if (readOnly || searchShareForMagikeyboard) {
|
||||
GroupActivity.launchForKeyboardSelectionResult(this,
|
||||
openedDatabase,
|
||||
searchInfo,
|
||||
false)
|
||||
} else {
|
||||
GroupActivity.launchForSaveResult(this,
|
||||
openedDatabase,
|
||||
searchInfo,
|
||||
false)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
SearchHelper.checkAutoSearchInfo(this,
|
||||
database,
|
||||
null,
|
||||
{ _, _ ->
|
||||
// Not called
|
||||
// if items found directly returns before calling this activity
|
||||
},
|
||||
{ openedDatabase ->
|
||||
// Select if not found
|
||||
GroupActivity.launchForKeyboardSelectionResult(this, openedDatabase)
|
||||
},
|
||||
{
|
||||
// Pass extra to get entry
|
||||
FileDatabaseSelectActivity.launchForKeyboardSelectionResult(this)
|
||||
// If database not open
|
||||
if (searchInfo.otpString != null) {
|
||||
FileDatabaseSelectActivity.launchForSaveResult(this,
|
||||
searchInfo)
|
||||
} else if (searchShareForMagikeyboard) {
|
||||
FileDatabaseSelectActivity.launchForKeyboardSelectionResult(this,
|
||||
searchInfo)
|
||||
} else {
|
||||
FileDatabaseSelectActivity.launchForSearchResult(this,
|
||||
searchInfo)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
finish()
|
||||
}
|
||||
|
||||
@@ -225,7 +209,7 @@ class EntrySelectionLauncherActivity : DatabaseModeActivity() {
|
||||
}
|
||||
// New task needed because don't launch from an Activity context
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or
|
||||
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
|
||||
Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,15 +96,9 @@ abstract class DatabaseModeActivity : DatabaseActivity() {
|
||||
|
||||
private fun backToTheMainAppAndFinish() {
|
||||
// To move the app in background and return to the main app
|
||||
// Not visible as opened with FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
|
||||
moveTaskToBack(true)
|
||||
// To remove this instance in the OS app selector
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
finishAndRemoveTask()
|
||||
} else {
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
finish()
|
||||
}, 500)
|
||||
}
|
||||
// Not finish() to prevent service kill
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
@@ -39,12 +39,15 @@ 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.element.Field
|
||||
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
||||
import com.kunzisoft.keepass.database.search.SearchHelper
|
||||
import com.kunzisoft.keepass.model.EntryInfo
|
||||
import com.kunzisoft.keepass.model.SearchInfo
|
||||
import com.kunzisoft.keepass.otp.OtpEntryFields.OTP_TOKEN_FIELD
|
||||
import com.kunzisoft.keepass.services.KeyboardEntryNotificationService
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.utils.*
|
||||
import java.util.*
|
||||
|
||||
class MagikeyboardService : InputMethodService(), KeyboardView.OnKeyboardActionListener {
|
||||
|
||||
@@ -71,6 +74,7 @@ class MagikeyboardService : InputMethodService(), KeyboardView.OnKeyboardActionL
|
||||
mDatabaseTaskProvider?.registerProgressTask()
|
||||
mDatabaseTaskProvider?.onDatabaseRetrieved = { database ->
|
||||
this.mDatabase = database
|
||||
assignKeyboardView()
|
||||
}
|
||||
// Remove the entry and lock the keyboard when the lock signal is receive
|
||||
lockReceiver = LockReceiver {
|
||||
@@ -110,7 +114,7 @@ class MagikeyboardService : InputMethodService(), KeyboardView.OnKeyboardActionL
|
||||
fieldsAdapter = FieldsAdapter(this)
|
||||
fieldsAdapter?.onItemClickListener = object : FieldsAdapter.OnItemClickListener {
|
||||
override fun onItemClick(item: Field) {
|
||||
currentInputConnection.commitText(entryInfoKey?.getGeneratedFieldValue(item.name) , 1)
|
||||
currentInputConnection.commitText(getEntryInfo()?.getGeneratedFieldValue(item.name) , 1)
|
||||
actionTabAutomatically()
|
||||
}
|
||||
}
|
||||
@@ -120,17 +124,6 @@ class MagikeyboardService : InputMethodService(), KeyboardView.OnKeyboardActionL
|
||||
val closeView = popupFieldsView.findViewById<View>(R.id.keyboard_popup_close)
|
||||
closeView.setOnClickListener { popupCustomKeys?.dismiss() }
|
||||
|
||||
// Remove entry info if the database is not loaded
|
||||
// or if entry info timestamp is before database loaded timestamp
|
||||
val databaseTime = mDatabase?.loadTimestamp
|
||||
val entryTime = entryInfoTimestamp
|
||||
if (mDatabase == null
|
||||
|| mDatabase?.loaded != true
|
||||
|| databaseTime == null
|
||||
|| entryTime == null
|
||||
|| entryTime < databaseTime) {
|
||||
removeEntryInfo()
|
||||
}
|
||||
assignKeyboardView()
|
||||
keyboardView?.onKeyboardActionListener = this
|
||||
|
||||
@@ -140,12 +133,23 @@ class MagikeyboardService : InputMethodService(), KeyboardView.OnKeyboardActionL
|
||||
return super.onCreateInputView()
|
||||
}
|
||||
|
||||
private fun getEntryInfo(): EntryInfo? {
|
||||
var entryInfoRetrieved: EntryInfo? = null
|
||||
entryUUID?.let { entryId ->
|
||||
entryInfoRetrieved = mDatabase
|
||||
?.getEntryById(NodeIdUUID(entryId))
|
||||
?.getEntryInfo(mDatabase)
|
||||
}
|
||||
return entryInfoRetrieved
|
||||
}
|
||||
|
||||
private fun assignKeyboardView() {
|
||||
dismissCustomKeys()
|
||||
if (keyboardView != null) {
|
||||
if (entryInfoKey != null) {
|
||||
val entryInfo = getEntryInfo()
|
||||
if (entryInfo != null) {
|
||||
if (keyboardEntry != null) {
|
||||
populateEntryInfoInView()
|
||||
populateEntryInfoInView(entryInfo)
|
||||
keyboardView?.keyboard = keyboardEntry
|
||||
}
|
||||
} else {
|
||||
@@ -161,10 +165,10 @@ class MagikeyboardService : InputMethodService(), KeyboardView.OnKeyboardActionL
|
||||
}
|
||||
}
|
||||
|
||||
private fun populateEntryInfoInView() {
|
||||
private fun populateEntryInfoInView(entryInfo: EntryInfo) {
|
||||
entryText?.visibility = View.VISIBLE
|
||||
if (entryInfoKey?.title?.isNotEmpty() == true) {
|
||||
entryText?.text = entryInfoKey?.title
|
||||
if (entryInfo.title.isNotEmpty()) {
|
||||
entryText?.text = entryInfo.title
|
||||
} else {
|
||||
hideEntryInfo()
|
||||
}
|
||||
@@ -259,12 +263,13 @@ class MagikeyboardService : InputMethodService(), KeyboardView.OnKeyboardActionL
|
||||
dismissCustomKeys()
|
||||
}
|
||||
KEY_USERNAME -> {
|
||||
entryInfoKey?.username?.let { username ->
|
||||
getEntryInfo()?.username?.let { username ->
|
||||
currentInputConnection.commitText(username, 1)
|
||||
}
|
||||
actionTabAutomatically()
|
||||
}
|
||||
KEY_PASSWORD -> {
|
||||
val entryInfoKey = getEntryInfo()
|
||||
entryInfoKey?.password?.let { password ->
|
||||
currentInputConnection.commitText(password, 1)
|
||||
}
|
||||
@@ -272,14 +277,14 @@ class MagikeyboardService : InputMethodService(), KeyboardView.OnKeyboardActionL
|
||||
actionGoAutomatically(!otpFieldExists)
|
||||
}
|
||||
KEY_OTP -> {
|
||||
entryInfoKey?.let { entryInfo ->
|
||||
getEntryInfo()?.let { entryInfo ->
|
||||
currentInputConnection.commitText(
|
||||
entryInfo.getGeneratedFieldValue(OTP_TOKEN_FIELD), 1)
|
||||
}
|
||||
actionGoAutomatically()
|
||||
}
|
||||
KEY_OTP_ALT -> {
|
||||
entryInfoKey?.let { entryInfo ->
|
||||
getEntryInfo()?.let { entryInfo ->
|
||||
val otpToken = entryInfo.getGeneratedFieldValue(OTP_TOKEN_FIELD)
|
||||
if (otpToken.isNotEmpty()) {
|
||||
// Cut to fill each digit separatelyKeyEvent.KEYCODE_TAB
|
||||
@@ -296,13 +301,13 @@ class MagikeyboardService : InputMethodService(), KeyboardView.OnKeyboardActionL
|
||||
actionGoAutomatically()
|
||||
}
|
||||
KEY_URL -> {
|
||||
entryInfoKey?.url?.let { url ->
|
||||
getEntryInfo()?.url?.let { url ->
|
||||
currentInputConnection.commitText(url, 1)
|
||||
}
|
||||
actionGoAutomatically()
|
||||
}
|
||||
KEY_FIELDS -> {
|
||||
entryInfoKey?.customFields?.let { customFields ->
|
||||
getEntryInfo()?.customFields?.let { customFields ->
|
||||
fieldsAdapter?.apply {
|
||||
setFields(customFields.filter { it.name != OTP_TOKEN_FIELD})
|
||||
notifyDataSetChanged()
|
||||
@@ -318,8 +323,41 @@ class MagikeyboardService : InputMethodService(), KeyboardView.OnKeyboardActionL
|
||||
}
|
||||
|
||||
private fun actionKeyEntry(searchInfo: SearchInfo? = null) {
|
||||
// Stop current service and reinit entry
|
||||
stopService(Intent(this, KeyboardEntryNotificationService::class.java))
|
||||
SearchHelper.checkAutoSearchInfo(this,
|
||||
mDatabase,
|
||||
searchInfo,
|
||||
{ _, items ->
|
||||
if (items.size == 1) {
|
||||
if (entryUUID == null) {
|
||||
// Automatically populate keyboard
|
||||
removeEntryInfo()
|
||||
addEntryAndLaunchNotificationIfAllowed(
|
||||
this,
|
||||
items[0],
|
||||
true
|
||||
)
|
||||
assignKeyboardView()
|
||||
} else {
|
||||
// Choose another one
|
||||
launchEntrySelection(null)
|
||||
}
|
||||
} else {
|
||||
// Select if multiple
|
||||
launchEntrySelection(searchInfo)
|
||||
}
|
||||
},
|
||||
{ _ ->
|
||||
// Select if not found
|
||||
launchEntrySelection(searchInfo)
|
||||
},
|
||||
{
|
||||
// Select if database not opened
|
||||
launchEntrySelection(searchInfo)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun launchEntrySelection(searchInfo: SearchInfo?) {
|
||||
removeEntryInfo()
|
||||
EntrySelectionLauncherActivity.launch(this, searchInfo)
|
||||
}
|
||||
@@ -390,13 +428,10 @@ class MagikeyboardService : InputMethodService(), KeyboardView.OnKeyboardActionL
|
||||
const val KEY_URL = 520
|
||||
const val KEY_FIELDS = 530
|
||||
|
||||
// TODO Retrieve entry info from id and service when database is open
|
||||
private var entryInfoKey: EntryInfo? = null
|
||||
private var entryInfoTimestamp: Long? = null
|
||||
private var entryUUID: UUID? = null
|
||||
|
||||
private fun removeEntryInfo() {
|
||||
entryInfoKey = null
|
||||
entryInfoTimestamp = null
|
||||
entryUUID = null
|
||||
}
|
||||
|
||||
fun removeEntry(context: Context) {
|
||||
@@ -405,8 +440,7 @@ class MagikeyboardService : InputMethodService(), KeyboardView.OnKeyboardActionL
|
||||
|
||||
fun addEntryAndLaunchNotificationIfAllowed(context: Context, entry: EntryInfo, toast: Boolean = false) {
|
||||
// Add a new entry
|
||||
entryInfoKey = entry
|
||||
entryInfoTimestamp = System.currentTimeMillis()
|
||||
entryUUID = entry.id
|
||||
// Launch notification if allowed
|
||||
KeyboardEntryNotificationService.launchNotificationIfAllowed(context, entry, toast)
|
||||
}
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
* Fix small bugs #1282
|
||||
* Better search implementation #175 #1254
|
||||
* Setting to change keyboard during a search #1267
|
||||
* Manage package name from Magikeyboard #1010
|
||||
* Manage package name from Magikeyboard #1010 #1261
|
||||
* Ask confirmation to lock if changes without save #970
|
||||
@@ -7,5 +7,5 @@
|
||||
* Correction de petits bugs #1282
|
||||
* Meilleure implémentation de la recherche #175 #1254
|
||||
* Paramètre pour changer de clavier lors d'une recherche #1267
|
||||
* Gestion du nom de package du Magiclavier #1010
|
||||
* Gestion du nom de package du Magiclavier #1010 #1261
|
||||
* Demande de confirmation de verouiller si chanegement sans sauvegarde #970
|
||||
Reference in New Issue
Block a user