mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Better notification implementation
This commit is contained in:
@@ -43,7 +43,7 @@ import com.kunzisoft.keepass.database.element.PwNodeId
|
||||
import com.kunzisoft.keepass.education.EntryActivityEducation
|
||||
import com.kunzisoft.keepass.icons.assignDatabaseIcon
|
||||
import com.kunzisoft.keepass.magikeyboard.MagikIME
|
||||
import com.kunzisoft.keepass.notifications.NotificationEntryCopyManager
|
||||
import com.kunzisoft.keepass.notifications.CopyingEntryNotificationService
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil.isFirstTimeAskAllowCopyPasswordAndProtectedFields
|
||||
import com.kunzisoft.keepass.settings.SettingsAutofillActivity
|
||||
@@ -127,13 +127,17 @@ class EntryActivity : LockingHideActivity() {
|
||||
fillEntryDataInContentsView(entry)
|
||||
// Refresh Menu
|
||||
invalidateOptionsMenu()
|
||||
|
||||
val entryInfo = entry.getEntryInfo(Database.getInstance())
|
||||
|
||||
// Manage entry copy to start notification if allowed
|
||||
NotificationEntryCopyManager.launchNotificationIfAllowed(this,
|
||||
firstLaunchOfActivity,
|
||||
entry)
|
||||
// Manage entry to init Magikeyboard
|
||||
if (PreferencesUtil.enableKeyboardEntrySelection(this)) {
|
||||
MagikIME.initMagikeyboardForEntry(this, entry.getEntryInfo(Database.getInstance()))
|
||||
if (firstLaunchOfActivity) {
|
||||
// Manage entry to launch copying notification if allowed
|
||||
CopyingEntryNotificationService.launchNotificationIfAllowed(this, entryInfo)
|
||||
// Manage entry to populate Magikeyboard and launch keyboard notification if allowed
|
||||
if (PreferencesUtil.isKeyboardEntrySelectionEnable(this)) {
|
||||
MagikIME.addEntryAndLaunchNotificationIfAllowed(this, entryInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -403,9 +403,10 @@ class GroupActivity : LockingActivity(),
|
||||
EntryActivity.launch(this@GroupActivity, entryVersioned, readOnly)
|
||||
},
|
||||
{
|
||||
// Init Magikeyboard with entry
|
||||
// Populate Magikeyboard with entry
|
||||
mDatabase?.let { database ->
|
||||
MagikIME.initMagikeyboardForEntry(this@GroupActivity, entryVersioned.getEntryInfo(database))
|
||||
MagikIME.addEntryAndLaunchNotificationIfAllowed(this@GroupActivity,
|
||||
entryVersioned.getEntryInfo(database))
|
||||
}
|
||||
// Consume the selection mode
|
||||
EntrySelectionHelper.removeEntrySelectionModeFromIntent(intent)
|
||||
|
||||
@@ -10,12 +10,13 @@ import android.util.Log
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.model.EntryInfo
|
||||
import com.kunzisoft.keepass.notifications.NotificationService
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
import com.kunzisoft.keepass.utils.LOCK_ACTION
|
||||
|
||||
class KeyboardEntryNotificationService : NotificationService() {
|
||||
|
||||
private val notificationId = 2
|
||||
private val notificationId = 486
|
||||
private var cleanNotificationTimer: Thread? = null
|
||||
private var notificationTimeoutMilliSecs: Long = 0
|
||||
|
||||
@@ -157,6 +158,15 @@ class KeyboardEntryNotificationService : NotificationService() {
|
||||
const val ENTRY_INFO_KEY = "ENTRY_INFO_KEY"
|
||||
|
||||
const val ACTION_CLEAN_KEYBOARD_ENTRY = "ACTION_CLEAN_KEYBOARD_ENTRY"
|
||||
|
||||
fun launchNotificationIfAllowed(context: Context, entry: EntryInfo) {
|
||||
// Show the notification if allowed in Preferences
|
||||
if (PreferencesUtil.isKeyboardNotificationEntryEnable(context)) {
|
||||
context.startService(Intent(context, KeyboardEntryNotificationService::class.java).apply {
|
||||
putExtra(ENTRY_INFO_KEY, entry)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ import android.widget.FrameLayout
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.TextView
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.magikeyboard.KeyboardEntryNotificationService.Companion.ENTRY_INFO_KEY
|
||||
import com.kunzisoft.keepass.magikeyboard.adapter.FieldsAdapter
|
||||
import com.kunzisoft.keepass.model.EntryInfo
|
||||
import com.kunzisoft.keepass.model.Field
|
||||
@@ -63,8 +62,12 @@ class MagikIME : InputMethodService(), KeyboardView.OnKeyboardActionListener {
|
||||
// Remove the entry and lock the keyboard when the lock signal is receive
|
||||
lockBroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
removeEntryInfo()
|
||||
assignKeyboardView()
|
||||
when (intent?.action) {
|
||||
REMOVE_ENTRY_MAGIKEYBOARD_ACTION, LOCK_ACTION -> {
|
||||
removeEntryInfo()
|
||||
assignKeyboardView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,8 +141,8 @@ class MagikIME : InputMethodService(), KeyboardView.OnKeyboardActionListener {
|
||||
}
|
||||
|
||||
// Define preferences
|
||||
keyboardView?.isHapticFeedbackEnabled = PreferencesUtil.enableKeyboardVibration(this)
|
||||
playSoundDuringCLick = PreferencesUtil.enableKeyboardSound(this)
|
||||
keyboardView?.isHapticFeedbackEnabled = PreferencesUtil.isKeyboardVibrationEnable(this)
|
||||
playSoundDuringCLick = PreferencesUtil.isKeyboardSoundEnable(this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,14 +304,11 @@ class MagikIME : InputMethodService(), KeyboardView.OnKeyboardActionListener {
|
||||
context.sendBroadcast(Intent(REMOVE_ENTRY_MAGIKEYBOARD_ACTION))
|
||||
}
|
||||
|
||||
fun initMagikeyboardForEntry(context: Context, entry: EntryInfo) {
|
||||
fun addEntryAndLaunchNotificationIfAllowed(context: Context, entry: EntryInfo) {
|
||||
// Add a new entry
|
||||
entryInfoKey = entry
|
||||
// Show the notification if allowed in Preferences
|
||||
if (PreferencesUtil.enableKeyboardNotificationEntry(context)) {
|
||||
context.startService(Intent(context, KeyboardEntryNotificationService::class.java).apply {
|
||||
putExtra(ENTRY_INFO_KEY, entry)
|
||||
})
|
||||
}
|
||||
// Launch notification if allowed
|
||||
KeyboardEntryNotificationService.launchNotificationIfAllowed(context, entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,14 @@ class EntryInfo : Parcelable {
|
||||
parcel.writeArray(customFields.toTypedArray())
|
||||
}
|
||||
|
||||
fun containsCustomFieldsProtected(): Boolean {
|
||||
return customFields.any { it.protectedValue.isProtected }
|
||||
}
|
||||
|
||||
fun containsCustomFieldsNotProtected(): Boolean {
|
||||
return customFields.any { !it.protectedValue.isProtected }
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmField
|
||||
|
||||
@@ -20,18 +20,21 @@
|
||||
package com.kunzisoft.keepass.notifications
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.preference.PreferenceManager
|
||||
import android.util.Log
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.database.exception.SamsungClipboardException
|
||||
import com.kunzisoft.keepass.model.EntryInfo
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.timeout.ClipboardHelper
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper.NEVER
|
||||
import java.util.*
|
||||
|
||||
class CopyingEntryNotificationService : NotificationService() {
|
||||
|
||||
private var notificationId = 1
|
||||
private var notificationId = 485
|
||||
private var cleanNotificationTimer: Thread? = null
|
||||
private var notificationTimeoutMilliSecs: Long = 0
|
||||
|
||||
@@ -219,6 +222,72 @@ class CopyingEntryNotificationService : NotificationService() {
|
||||
const val EXTRA_ENTRY_TITLE = "EXTRA_ENTRY_TITLE"
|
||||
const val EXTRA_FIELDS = "EXTRA_FIELDS"
|
||||
const val ACTION_CLEAN_CLIPBOARD = "ACTION_CLEAN_CLIPBOARD"
|
||||
}
|
||||
|
||||
fun launchNotificationIfAllowed(context: Context, entry: EntryInfo) {
|
||||
|
||||
val containsUsernameToCopy = entry.username.isNotEmpty()
|
||||
val containsPasswordToCopy = entry.password.isNotEmpty()
|
||||
&& PreferencesUtil.allowCopyPasswordAndProtectedFields(context)
|
||||
val containsExtraFieldToCopy = entry.customFields.isNotEmpty()
|
||||
&& (entry.containsCustomFieldsNotProtected()
|
||||
||
|
||||
(entry.containsCustomFieldsProtected() && PreferencesUtil.allowCopyPasswordAndProtectedFields(context))
|
||||
)
|
||||
|
||||
// If notifications enabled in settings
|
||||
// Don't if application timeout
|
||||
if (PreferencesUtil.isClipboardNotificationsEnable(context)) {
|
||||
if (containsUsernameToCopy || containsPasswordToCopy || containsExtraFieldToCopy) {
|
||||
|
||||
// username already copied, waiting for user's action before copy password.
|
||||
val intent = Intent(context, CopyingEntryNotificationService::class.java)
|
||||
intent.action = ACTION_NEW_NOTIFICATION
|
||||
intent.putExtra(EXTRA_ENTRY_TITLE, entry.title)
|
||||
// Construct notification fields
|
||||
val notificationFields = ArrayList<NotificationCopyingField>()
|
||||
// Add username if exists to notifications
|
||||
if (containsUsernameToCopy)
|
||||
notificationFields.add(
|
||||
NotificationCopyingField(
|
||||
NotificationCopyingField.NotificationFieldId.USERNAME,
|
||||
entry.username,
|
||||
context.resources))
|
||||
// Add password to notifications
|
||||
if (containsPasswordToCopy) {
|
||||
notificationFields.add(
|
||||
NotificationCopyingField(
|
||||
NotificationCopyingField.NotificationFieldId.PASSWORD,
|
||||
entry.password,
|
||||
context.resources))
|
||||
}
|
||||
// Add extra fields
|
||||
if (containsExtraFieldToCopy) {
|
||||
try {
|
||||
var anonymousFieldNumber = 0
|
||||
entry.customFields.forEach { field ->
|
||||
//If value is not protected or allowed
|
||||
if (!field.protectedValue.isProtected
|
||||
|| PreferencesUtil.allowCopyPasswordAndProtectedFields(context)) {
|
||||
notificationFields.add(
|
||||
NotificationCopyingField(
|
||||
NotificationCopyingField.NotificationFieldId.anonymousFieldId[anonymousFieldNumber],
|
||||
field.protectedValue.toString(),
|
||||
field.name,
|
||||
context.resources))
|
||||
anonymousFieldNumber++
|
||||
}
|
||||
}
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
Log.w("NotificationEntryCopyMg", "Only " + NotificationCopyingField.NotificationFieldId.anonymousFieldId.size +
|
||||
" anonymous notifications are available")
|
||||
}
|
||||
|
||||
}
|
||||
// Add notifications
|
||||
intent.putParcelableArrayListExtra(EXTRA_FIELDS, notificationFields)
|
||||
context.startService(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
package com.kunzisoft.keepass.notifications
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.element.EntryVersioned
|
||||
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import java.util.*
|
||||
|
||||
|
||||
object NotificationEntryCopyManager {
|
||||
|
||||
fun launchNotificationIfAllowed(context: Context, firstLaunch: Boolean, entry: EntryVersioned) {
|
||||
// Start to manage field reference to copy a value from ref
|
||||
val database = Database.getInstance()
|
||||
database.startManageEntry(entry)
|
||||
|
||||
val containsUsernameToCopy = entry.username.isNotEmpty()
|
||||
val containsPasswordToCopy = entry.password.isNotEmpty()
|
||||
&& PreferencesUtil.allowCopyPasswordAndProtectedFields(context)
|
||||
val containsExtraFieldToCopy = entry.allowExtraFields()
|
||||
&& (entry.containsCustomFields()
|
||||
&& entry.containsCustomFieldsNotProtected()
|
||||
|| (entry.containsCustomFields()
|
||||
&& entry.containsCustomFieldsProtected()
|
||||
&& PreferencesUtil.allowCopyPasswordAndProtectedFields(context))
|
||||
)
|
||||
|
||||
// If notifications enabled in settings
|
||||
// Don't if application timeout
|
||||
if (firstLaunch
|
||||
&& PreferencesUtil.isClipboardNotificationsEnable(context.applicationContext)) {
|
||||
if (containsUsernameToCopy || containsPasswordToCopy || containsExtraFieldToCopy) {
|
||||
|
||||
// username already copied, waiting for user's action before copy password.
|
||||
val intent = Intent(context, CopyingEntryNotificationService::class.java)
|
||||
intent.action = CopyingEntryNotificationService.ACTION_NEW_NOTIFICATION
|
||||
intent.putExtra(CopyingEntryNotificationService.EXTRA_ENTRY_TITLE, entry.title)
|
||||
// Construct notification fields
|
||||
val notificationFields = ArrayList<NotificationCopyingField>()
|
||||
// Add username if exists to notifications
|
||||
if (containsUsernameToCopy)
|
||||
notificationFields.add(
|
||||
NotificationCopyingField(
|
||||
NotificationCopyingField.NotificationFieldId.USERNAME,
|
||||
entry.username,
|
||||
context.resources))
|
||||
// Add password to notifications
|
||||
if (containsPasswordToCopy) {
|
||||
notificationFields.add(
|
||||
NotificationCopyingField(
|
||||
NotificationCopyingField.NotificationFieldId.PASSWORD,
|
||||
entry.password,
|
||||
context.resources))
|
||||
}
|
||||
// Add extra fields
|
||||
if (containsExtraFieldToCopy) {
|
||||
try {
|
||||
entry.fields.doActionToAllCustomProtectedField(object : (String, ProtectedString) -> Unit {
|
||||
private var anonymousFieldNumber = 0
|
||||
override fun invoke(key: String, value: ProtectedString) {
|
||||
//If value is not protected or allowed
|
||||
if (!value.isProtected
|
||||
|| PreferencesUtil.allowCopyPasswordAndProtectedFields(context)) {
|
||||
notificationFields.add(
|
||||
NotificationCopyingField(
|
||||
NotificationCopyingField.NotificationFieldId.anonymousFieldId[anonymousFieldNumber],
|
||||
value.toString(),
|
||||
key,
|
||||
context.resources))
|
||||
anonymousFieldNumber++
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
Log.w("NotificationEntryCopyMg", "Only " + NotificationCopyingField.NotificationFieldId.anonymousFieldId.size +
|
||||
" anonymous notifications are available")
|
||||
}
|
||||
|
||||
}
|
||||
// Add notifications
|
||||
intent.putParcelableArrayListExtra(CopyingEntryNotificationService.EXTRA_FIELDS, notificationFields)
|
||||
context.startService(intent)
|
||||
}
|
||||
}
|
||||
database.stopManageEntry(entry)
|
||||
}
|
||||
}
|
||||
@@ -51,8 +51,9 @@ abstract class NotificationService : Service() {
|
||||
.setVisibility(NotificationCompat.VISIBILITY_SECRET)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const val CHANNEL_ID_KEEPASS = "com.kunzisoft.keepass.notification.channel"
|
||||
const val CHANNEL_NAME_KEEPASS = "KeePass DX notification"
|
||||
const val GROUP_KEEPASS = "GROUP_KEEPASS"
|
||||
companion object {
|
||||
const val CHANNEL_ID_KEEPASS = "com.kunzisoft.keepass.notification.channel"
|
||||
const val CHANNEL_NAME_KEEPASS = "KeePass DX notification"
|
||||
const val GROUP_KEEPASS = "GROUP_KEEPASS"
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@
|
||||
package com.kunzisoft.keepass.settings
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.preference.PreferenceManager
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.database.SortNodeEnum
|
||||
@@ -218,25 +217,25 @@ object PreferencesUtil {
|
||||
context.resources.getBoolean(R.bool.delete_entered_password_default))
|
||||
}
|
||||
|
||||
fun enableKeyboardEntrySelection(context: Context): Boolean {
|
||||
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))
|
||||
}
|
||||
|
||||
fun enableKeyboardNotificationEntry(context: Context): Boolean {
|
||||
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))
|
||||
}
|
||||
|
||||
fun enableKeyboardVibration(context: Context): Boolean {
|
||||
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))
|
||||
}
|
||||
|
||||
fun enableKeyboardSound(context: Context): Boolean {
|
||||
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))
|
||||
|
||||
Reference in New Issue
Block a user