Add clear database option when close clipboard notification

This commit is contained in:
J-Jamet
2019-08-13 16:06:30 +02:00
parent c7a8322c5d
commit 2b33d785ac
11 changed files with 86 additions and 56 deletions

View File

@@ -146,7 +146,7 @@
android:enabled="true"
android:exported="false" />
<service
android:name="com.kunzisoft.keepass.notifications.CopyingEntryNotificationService"
android:name="com.kunzisoft.keepass.notifications.ClipboardEntryNotificationService"
android:enabled="true"
android:exported="false" />
<!-- Receiver for Autofill -->
@@ -171,7 +171,10 @@
<action android:name="android.view.InputMethod" />
</intent-filter>
</service>
<service android:name="com.kunzisoft.keepass.magikeyboard.KeyboardEntryNotificationService" />
<service
android:name="com.kunzisoft.keepass.notifications.KeyboardEntryNotificationService"
android:enabled="true"
android:exported="false" />
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
</application>

View File

@@ -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.CopyingEntryNotificationService
import com.kunzisoft.keepass.notifications.ClipboardEntryNotificationService
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.settings.PreferencesUtil.isFirstTimeAskAllowCopyPasswordAndProtectedFields
import com.kunzisoft.keepass.settings.SettingsAutofillActivity
@@ -133,7 +133,7 @@ class EntryActivity : LockingHideActivity() {
// Manage entry copy to start notification if allowed
if (firstLaunchOfActivity) {
// Manage entry to launch copying notification if allowed
CopyingEntryNotificationService.launchNotificationIfAllowed(this, entryInfo)
ClipboardEntryNotificationService.launchNotificationIfAllowed(this, entryInfo)
// Manage entry to populate Magikeyboard and launch keyboard notification if allowed
if (PreferencesUtil.isKeyboardEntrySelectionEnable(this)) {
MagikIME.addEntryAndLaunchNotificationIfAllowed(this, entryInfo)

View File

@@ -33,7 +33,7 @@ import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
import com.kunzisoft.keepass.activities.stylish.StylishActivity
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.magikeyboard.KeyboardEntryNotificationService
import com.kunzisoft.keepass.notifications.KeyboardEntryNotificationService
import com.kunzisoft.keepass.magikeyboard.MagikIME
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.timeout.TimeoutHelper

View File

@@ -40,6 +40,7 @@ import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.magikeyboard.adapter.FieldsAdapter
import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.model.Field
import com.kunzisoft.keepass.notifications.KeyboardEntryNotificationService
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.LOCK_ACTION
import com.kunzisoft.keepass.utils.REMOVE_ENTRY_MAGIKEYBOARD_ACTION

View File

@@ -31,7 +31,7 @@ import java.util.ArrayList
/**
* Utility class to manage fields in Notifications
*/
open class NotificationCopyingField : Parcelable {
open class ClipboardEntryNotificationField : Parcelable {
private var id: NotificationFieldId = NotificationFieldId.UNKNOWN
var value: String
@@ -79,7 +79,7 @@ open class NotificationCopyingField : Parcelable {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || javaClass != other.javaClass) return false
val field = other as NotificationCopyingField
val field = other as ClipboardEntryNotificationField
return id == field.id
}
@@ -111,15 +111,15 @@ open class NotificationCopyingField : Parcelable {
companion object {
private val TAG = NotificationCopyingField::class.java.name
private val TAG = ClipboardEntryNotificationField::class.java.name
@JvmField
val CREATOR: Parcelable.Creator<NotificationCopyingField> = object : Parcelable.Creator<NotificationCopyingField> {
override fun createFromParcel(`in`: Parcel): NotificationCopyingField {
return NotificationCopyingField(`in`)
val CREATOR: Parcelable.Creator<ClipboardEntryNotificationField> = object : Parcelable.Creator<ClipboardEntryNotificationField> {
override fun createFromParcel(`in`: Parcel): ClipboardEntryNotificationField {
return ClipboardEntryNotificationField(`in`)
}
override fun newArray(size: Int): Array<NotificationCopyingField?> {
override fun newArray(size: Int): Array<ClipboardEntryNotificationField?> {
return arrayOfNulls(size)
}
}

View File

@@ -30,16 +30,17 @@ 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 com.kunzisoft.keepass.utils.LOCK_ACTION
import java.util.*
class CopyingEntryNotificationService : NotificationService() {
class ClipboardEntryNotificationService : NotificationService() {
private var notificationId = 485
private var cleanNotificationTimer: Thread? = null
private var cleanNotificationTimerTask: Thread? = null
private var notificationTimeoutMilliSecs: Long = 0
private var clipboardHelper: ClipboardHelper? = null
private var countingDownTask: Thread? = null
private var cleanCopyNotificationTimerTask: Thread? = null
override fun onCreate() {
super.onCreate()
@@ -47,6 +48,13 @@ class CopyingEntryNotificationService : NotificationService() {
clipboardHelper = ClipboardHelper(this)
}
private fun stopNotificationAndSendLockIfNeeded() {
// Clear the entry if define in preferences
if (PreferencesUtil.isClearClipboardNotificationEnable(this)) {
sendBroadcast(Intent(LOCK_ACTION))
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
//Get settings
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
@@ -61,17 +69,18 @@ class CopyingEntryNotificationService : NotificationService() {
newNotification(title, constructListOfField(intent))
}
ACTION_CLEAN_CLIPBOARD == intent.action -> {
stopTask(countingDownTask)
stopTask(cleanCopyNotificationTimerTask)
try {
clipboardHelper?.cleanClipboard()
} catch (e: SamsungClipboardException) {
Log.e(TAG, "Clipboard can't be cleaned", e)
}
stopNotificationAndSendLockIfNeeded()
}
else -> for (actionKey in NotificationCopyingField.allActionKeys) {
else -> for (actionKey in ClipboardEntryNotificationField.allActionKeys) {
if (actionKey == intent.action) {
val fieldToCopy = intent.getParcelableExtra<NotificationCopyingField>(
NotificationCopyingField.getExtraKeyLinkToActionKey(actionKey))
val fieldToCopy = intent.getParcelableExtra<ClipboardEntryNotificationField>(
ClipboardEntryNotificationField.getExtraKeyLinkToActionKey(actionKey))
val nextFields = constructListOfField(intent)
// Remove the current field from the next fields
nextFields.remove(fieldToCopy)
@@ -82,8 +91,8 @@ class CopyingEntryNotificationService : NotificationService() {
return START_NOT_STICKY
}
private fun constructListOfField(intent: Intent?): ArrayList<NotificationCopyingField> {
var fieldList = ArrayList<NotificationCopyingField>()
private fun constructListOfField(intent: Intent?): ArrayList<ClipboardEntryNotificationField> {
var fieldList = ArrayList<ClipboardEntryNotificationField>()
if (intent != null && intent.extras != null) {
if (intent.extras!!.containsKey(EXTRA_FIELDS))
fieldList = intent.getParcelableArrayListExtra(EXTRA_FIELDS)
@@ -91,8 +100,8 @@ class CopyingEntryNotificationService : NotificationService() {
return fieldList
}
private fun getCopyPendingIntent(fieldToCopy: NotificationCopyingField, fieldsToAdd: ArrayList<NotificationCopyingField>): PendingIntent {
val copyIntent = Intent(this, CopyingEntryNotificationService::class.java)
private fun getCopyPendingIntent(fieldToCopy: ClipboardEntryNotificationField, fieldsToAdd: ArrayList<ClipboardEntryNotificationField>): PendingIntent {
val copyIntent = Intent(this, ClipboardEntryNotificationService::class.java)
copyIntent.action = fieldToCopy.actionKey
copyIntent.putExtra(fieldToCopy.extraKey, fieldToCopy)
copyIntent.putParcelableArrayListExtra(EXTRA_FIELDS, fieldsToAdd)
@@ -101,8 +110,8 @@ class CopyingEntryNotificationService : NotificationService() {
this, 0, copyIntent, PendingIntent.FLAG_UPDATE_CURRENT)
}
private fun newNotification(title: String?, fieldsToAdd: ArrayList<NotificationCopyingField>) {
stopTask(countingDownTask)
private fun newNotification(title: String?, fieldsToAdd: ArrayList<ClipboardEntryNotificationField>) {
stopTask(cleanCopyNotificationTimerTask)
val builder = buildNewNotification()
.setSmallIcon(R.drawable.ic_key_white_24dp)
@@ -129,24 +138,24 @@ class CopyingEntryNotificationService : NotificationService() {
notificationManager?.notify(++notificationId, builder.build())
val myNotificationId = notificationId
stopTask(cleanNotificationTimer)
stopTask(cleanNotificationTimerTask)
// If timer
if (notificationTimeoutMilliSecs != NEVER) {
cleanNotificationTimer = Thread {
cleanNotificationTimerTask = Thread {
try {
Thread.sleep(notificationTimeoutMilliSecs)
} catch (e: InterruptedException) {
cleanNotificationTimer = null
cleanNotificationTimerTask = null
}
notificationManager?.cancel(myNotificationId)
}
cleanNotificationTimer?.start()
cleanNotificationTimerTask?.start()
}
}
private fun copyField(fieldToCopy: NotificationCopyingField, nextFields: ArrayList<NotificationCopyingField>) {
stopTask(countingDownTask)
stopTask(cleanNotificationTimer)
private fun copyField(fieldToCopy: ClipboardEntryNotificationField, nextFields: ArrayList<ClipboardEntryNotificationField>) {
stopTask(cleanCopyNotificationTimerTask)
stopTask(cleanNotificationTimerTask)
try {
clipboardHelper?.copyToClipboard(fieldToCopy.label, fieldToCopy.value)
@@ -165,7 +174,7 @@ class CopyingEntryNotificationService : NotificationService() {
builder.setContentText(getString(R.string.clipboard_swipe_clean))
}
val cleanIntent = Intent(this, CopyingEntryNotificationService::class.java)
val cleanIntent = Intent(this, ClipboardEntryNotificationService::class.java)
cleanIntent.action = ACTION_CLEAN_CLIPBOARD
val cleanPendingIntent = PendingIntent.getService(
this, 0, cleanIntent, PendingIntent.FLAG_UPDATE_CURRENT)
@@ -174,10 +183,10 @@ class CopyingEntryNotificationService : NotificationService() {
val myNotificationId = notificationId
if (notificationTimeoutMilliSecs != NEVER) {
countingDownTask = Thread {
cleanCopyNotificationTimerTask = Thread {
val maxPos = 100
val posDurationMills = notificationTimeoutMilliSecs / maxPos
for (pos in maxPos downTo 1) {
for (pos in maxPos downTo 0) {
builder.setProgress(maxPos, pos, false)
notificationManager?.notify(myNotificationId, builder.build())
try {
@@ -185,9 +194,11 @@ class CopyingEntryNotificationService : NotificationService() {
} catch (e: InterruptedException) {
break
}
if (pos <= 0) {
stopNotificationAndSendLockIfNeeded()
}
}
countingDownTask = null
stopTask(cleanCopyNotificationTimerTask)
notificationManager?.cancel(myNotificationId)
// Clean password only if no next field
if (nextFields.size <= 0)
@@ -197,7 +208,7 @@ class CopyingEntryNotificationService : NotificationService() {
Log.e(TAG, "Clipboard can't be cleaned", e)
}
}
countingDownTask?.start()
cleanCopyNotificationTimerTask?.start()
} else {
// No timer
notificationManager?.notify(myNotificationId, builder.build())
@@ -216,7 +227,7 @@ class CopyingEntryNotificationService : NotificationService() {
companion object {
private val TAG = CopyingEntryNotificationService::class.java.name
private val TAG = ClipboardEntryNotificationService::class.java.name
const val ACTION_NEW_NOTIFICATION = "ACTION_NEW_NOTIFICATION"
const val EXTRA_ENTRY_TITLE = "EXTRA_ENTRY_TITLE"
@@ -240,23 +251,23 @@ class CopyingEntryNotificationService : NotificationService() {
if (containsUsernameToCopy || containsPasswordToCopy || containsExtraFieldToCopy) {
// username already copied, waiting for user's action before copy password.
val intent = Intent(context, CopyingEntryNotificationService::class.java)
val intent = Intent(context, ClipboardEntryNotificationService::class.java)
intent.action = ACTION_NEW_NOTIFICATION
intent.putExtra(EXTRA_ENTRY_TITLE, entry.title)
// Construct notification fields
val notificationFields = ArrayList<NotificationCopyingField>()
val notificationFields = ArrayList<ClipboardEntryNotificationField>()
// Add username if exists to notifications
if (containsUsernameToCopy)
notificationFields.add(
NotificationCopyingField(
NotificationCopyingField.NotificationFieldId.USERNAME,
ClipboardEntryNotificationField(
ClipboardEntryNotificationField.NotificationFieldId.USERNAME,
entry.username,
context.resources))
// Add password to notifications
if (containsPasswordToCopy) {
notificationFields.add(
NotificationCopyingField(
NotificationCopyingField.NotificationFieldId.PASSWORD,
ClipboardEntryNotificationField(
ClipboardEntryNotificationField.NotificationFieldId.PASSWORD,
entry.password,
context.resources))
}
@@ -269,8 +280,8 @@ class CopyingEntryNotificationService : NotificationService() {
if (!field.protectedValue.isProtected
|| PreferencesUtil.allowCopyPasswordAndProtectedFields(context)) {
notificationFields.add(
NotificationCopyingField(
NotificationCopyingField.NotificationFieldId.anonymousFieldId[anonymousFieldNumber],
ClipboardEntryNotificationField(
ClipboardEntryNotificationField.NotificationFieldId.anonymousFieldId[anonymousFieldNumber],
field.protectedValue.toString(),
field.name,
context.resources))
@@ -278,7 +289,7 @@ class CopyingEntryNotificationService : NotificationService() {
}
}
} catch (e: ArrayIndexOutOfBoundsException) {
Log.w("NotificationEntryCopyMg", "Only " + NotificationCopyingField.NotificationFieldId.anonymousFieldId.size +
Log.w("NotificationEntryCopyMg", "Only " + ClipboardEntryNotificationField.NotificationFieldId.anonymousFieldId.size +
" anonymous notifications are available")
}

View File

@@ -1,4 +1,4 @@
package com.kunzisoft.keepass.magikeyboard
package com.kunzisoft.keepass.notifications
import android.app.PendingIntent
import android.content.BroadcastReceiver
@@ -8,8 +8,8 @@ import android.content.IntentFilter
import android.support.v7.preference.PreferenceManager
import android.util.Log
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.magikeyboard.MagikIME
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
@@ -17,7 +17,7 @@ import com.kunzisoft.keepass.utils.LOCK_ACTION
class KeyboardEntryNotificationService : NotificationService() {
private val notificationId = 486
private var cleanNotificationTimer: Thread? = null
private var cleanNotificationTimerTask: Thread? = null
private var notificationTimeoutMilliSecs: Long = 0
private var lockBroadcastReceiver: BroadcastReceiver? = null
@@ -95,7 +95,7 @@ class KeyboardEntryNotificationService : NotificationService() {
notificationManager?.notify(notificationId, builder.build())
stopTask(cleanNotificationTimer)
stopTask(cleanNotificationTimerTask)
// Timeout only if notification clear is available
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
if (sharedPreferences.getBoolean(getString(R.string.keyboard_notification_entry_clear_close_key),
@@ -109,7 +109,7 @@ class KeyboardEntryNotificationService : NotificationService() {
}
if (notificationTimeoutMilliSecs != TimeoutHelper.NEVER) {
cleanNotificationTimer = Thread {
cleanNotificationTimerTask = Thread {
val maxPos = 100
val posDurationMills = notificationTimeoutMilliSecs / maxPos
for (pos in maxPos downTo 0) {
@@ -125,7 +125,7 @@ class KeyboardEntryNotificationService : NotificationService() {
}
}
}
cleanNotificationTimer?.start()
cleanNotificationTimerTask?.start()
}
}
}
@@ -136,8 +136,8 @@ class KeyboardEntryNotificationService : NotificationService() {
}
private fun destroyKeyboardNotification() {
stopTask(cleanNotificationTimer)
cleanNotificationTimer = null
stopTask(cleanNotificationTimerTask)
cleanNotificationTimerTask = null
unregisterReceiver(lockBroadcastReceiver)
pendingDeleteIntent?.cancel()

View File

@@ -184,6 +184,12 @@ object PreferencesUtil {
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))
}
fun setAllowCopyPasswordAndProtectedFields(context: Context, allowCopy: Boolean) {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
prefs.edit()

View File

@@ -86,6 +86,8 @@
<bool name="maskpass_default" translatable="false">true</bool>
<string name="allow_copy_password_key" translatable="false">allow_copy_password_key</string>
<bool name="allow_copy_password_default" translatable="false">false</bool>
<string name="clear_clipboard_notification_key" translatable="false">clear_clipboard_notification_key</string>
<bool name="clear_clipboard_notification_default" translatable="false">false</bool>
<string name="recentfile_key" translatable="false">recentfile</string>
<bool name="recentfile_default" translatable="false">true</bool>
<string name="keyfile_key" translatable="false">keyfile</string>

View File

@@ -270,6 +270,8 @@
<string name="allow_copy_password_title">Clipboard trust</string>
<string name="allow_copy_password_summary">Allow the entry password and protected fields to enter the clipboard</string>
<string name="allow_copy_password_warning">WARNING: The clipboard is shared by all apps. If sensitive data is copied, other software may recover it.</string>
<string name="clear_clipboard_notification_title">Clear at closing</string>
<string name="clear_clipboard_notification_summary">Close the database when closing the notification</string>
<string name="warning_disabling_storage_access_framework">WARNING: Turning off this feature may prevent opening or saving databases.</string>
<string name="open_link_database">Link of database file to open</string>
<string name="database_name_title">Database name</string>

View File

@@ -42,6 +42,11 @@
android:title="@string/allow_copy_password_title"
android:summary="@string/allow_copy_password_summary"
android:defaultValue="@bool/allow_copy_password_default"/>
<SwitchPreference
android:key="@string/clear_clipboard_notification_key"
android:title="@string/clear_clipboard_notification_title"
android:summary="@string/clear_clipboard_notification_summary"
android:defaultValue="@bool/clear_clipboard_notification_default"/>
<ListPreference
android:key="@string/clipboard_timeout_key"
android:title="@string/clipboard_timeout"