Better notification implementation

This commit is contained in:
J-Jamet
2019-08-13 11:33:42 +02:00
parent 5ffbe0e9ee
commit 17eadcee2b
11 changed files with 116 additions and 119 deletions

View File

@@ -146,7 +146,7 @@
android:enabled="true"
android:exported="false" />
<service
android:name="com.kunzisoft.keepass.notifications.NotificationCopyingService"
android:name="com.kunzisoft.keepass.notifications.CopyingEntryNotificationService"
android:enabled="true"
android:exported="false" />
<!-- Receiver for Autofill -->

View File

@@ -197,7 +197,7 @@ abstract class LockingActivity : StylishActivity() {
fun Activity.lock() {
// Stop the Magikeyboard service
stopService(Intent(this, KeyboardEntryNotificationService::class.java))
MagikIME.removeEntryInfo()
MagikIME.removeEntry(this)
Log.i(Activity::class.java.name, "Shutdown " + localClassName +
" after inactivity or manual lock")

View File

@@ -1,52 +1,29 @@
package com.kunzisoft.keepass.magikeyboard
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.IBinder
import android.support.v4.app.NotificationCompat
import android.support.v7.preference.PreferenceManager
import android.util.Log
import android.util.TypedValue
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.stylish.Stylish
import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.notifications.NotificationService
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.utils.LOCK_ACTION
class KeyboardEntryNotificationService : Service() {
class KeyboardEntryNotificationService : NotificationService() {
private var notificationManager: NotificationManager? = null
private val notificationId = 2
private var cleanNotificationTimer: Thread? = null
private val notificationId = 582
private var notificationTimeoutMilliSecs: Long = 0
private var colorNotificationAccent: Int = 0
private var lockBroadcastReceiver: BroadcastReceiver? = null
private var pendingDeleteIntent: PendingIntent? = null
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Create notification channel for Oreo+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(CHANNEL_ID_KEYBOARD,
CHANNEL_NAME_KEYBOARD,
NotificationManager.IMPORTANCE_DEFAULT)
notificationManager?.createNotificationChannel(channel)
}
// Register a lock receiver to stop notification service when lock on keyboard is performed
lockBroadcastReceiver = object : BroadcastReceiver() {
@@ -60,23 +37,19 @@ class KeyboardEntryNotificationService : Service() {
addAction(LOCK_ACTION)
}
)
// Get the color
setTheme(Stylish.getThemeId(this))
val typedValue = TypedValue()
val theme = theme
theme.resolveAttribute(R.attr.colorPrimary, typedValue, true)
colorNotificationAccent = typedValue.data
}
private fun stopNotificationAndSendLockIfNeeded() {
stopSelf()
// Remove the entry from the keyboard
MagikIME.removeEntry(this)
// Clear the entry if define in preferences
val sharedPreferences = android.preference.PreferenceManager.getDefaultSharedPreferences(this)
if (sharedPreferences.getBoolean(getString(R.string.keyboard_notification_entry_clear_close_key),
resources.getBoolean(R.bool.keyboard_notification_entry_clear_close_default))) {
sendBroadcast(Intent(LOCK_ACTION))
}
// Stop the notification
stopSelf()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
@@ -109,12 +82,9 @@ class KeyboardEntryNotificationService : Service() {
}
pendingDeleteIntent = PendingIntent.getService(this, 0, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val builder = NotificationCompat.Builder(this, CHANNEL_ID_KEYBOARD)
val builder = buildNewNotification()
.setSmallIcon(R.drawable.ic_vpn_key_white_24dp)
.setColor(colorNotificationAccent)
.setContentTitle(getString(R.string.keyboard_notification_entry_content_title, entryTitle))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setVisibility(NotificationCompat.VISIBILITY_SECRET)
.setContentText(getString(R.string.keyboard_notification_entry_content_text, entryUsername))
.setAutoCancel(false)
.setContentIntent(null)
@@ -184,9 +154,6 @@ class KeyboardEntryNotificationService : Service() {
private const val TAG = "KeyboardEntryNotifSrv"
private const val CHANNEL_ID_KEYBOARD = "com.kunzisoft.keyboard.notification.entry.channel"
private const val CHANNEL_NAME_KEYBOARD = "Magikeyboard notification"
const val ENTRY_INFO_KEY = "ENTRY_INFO_KEY"
const val ACTION_CLEAN_KEYBOARD_ENTRY = "ACTION_CLEAN_KEYBOARD_ENTRY"

View File

@@ -43,6 +43,7 @@ import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.model.Field
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.LOCK_ACTION
import com.kunzisoft.keepass.utils.REMOVE_ENTRY_MAGIKEYBOARD_ACTION
class MagikIME : InputMethodService(), KeyboardView.OnKeyboardActionListener {
@@ -70,6 +71,7 @@ class MagikIME : InputMethodService(), KeyboardView.OnKeyboardActionListener {
registerReceiver(lockBroadcastReceiver,
IntentFilter().apply {
addAction(LOCK_ACTION)
addAction(REMOVE_ENTRY_MAGIKEYBOARD_ACTION)
}
)
}
@@ -291,10 +293,14 @@ class MagikIME : InputMethodService(), KeyboardView.OnKeyboardActionListener {
private var entryInfoKey: EntryInfo? = null
fun removeEntryInfo() {
private fun removeEntryInfo() {
entryInfoKey = null
}
fun removeEntry(context: Context) {
context.sendBroadcast(Intent(REMOVE_ENTRY_MAGIKEYBOARD_ACTION))
}
fun initMagikeyboardForEntry(context: Context, entry: EntryInfo) {
entryInfoKey = entry
// Show the notification if allowed in Preferences

View File

@@ -19,56 +19,29 @@
*/
package com.kunzisoft.keepass.notifications
import android.app.*
import android.content.Context
import android.app.PendingIntent
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.preference.PreferenceManager
import android.support.v4.app.NotificationCompat
import android.util.Log
import android.util.TypedValue
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.stylish.Stylish
import com.kunzisoft.keepass.database.exception.SamsungClipboardException
import com.kunzisoft.keepass.timeout.ClipboardHelper
import com.kunzisoft.keepass.timeout.TimeoutHelper.NEVER
import java.util.*
class NotificationCopyingService : Service() {
class CopyingEntryNotificationService : NotificationService() {
private var notificationManager: NotificationManager? = null
private var clipboardHelper: ClipboardHelper? = null
private var cleanNotificationTimer: Thread? = null
private var countingDownTask: Thread? = null
private var notificationId = 1
private var cleanNotificationTimer: Thread? = null
private var notificationTimeoutMilliSecs: Long = 0
private var colorNotificationAccent: Int = 0
override fun onBind(intent: Intent): IBinder? {
return null
}
private var clipboardHelper: ClipboardHelper? = null
private var countingDownTask: Thread? = null
override fun onCreate() {
super.onCreate()
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
clipboardHelper = ClipboardHelper(this)
// Create notification channel for Oreo+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(CHANNEL_ID_COPYING,
CHANNEL_NAME_COPYING,
NotificationManager.IMPORTANCE_DEFAULT)
notificationManager?.createNotificationChannel(channel)
}
// Get the color
setTheme(Stylish.getThemeId(this))
val typedValue = TypedValue()
val theme = theme
theme.resolveAttribute(R.attr.colorPrimary, typedValue, true)
colorNotificationAccent = typedValue.data
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
@@ -92,10 +65,10 @@ class NotificationCopyingService : Service() {
Log.e(TAG, "Clipboard can't be cleaned", e)
}
}
else -> for (actionKey in NotificationField.allActionKeys) {
else -> for (actionKey in NotificationCopyingField.allActionKeys) {
if (actionKey == intent.action) {
val fieldToCopy = intent.getParcelableExtra<NotificationField>(
NotificationField.getExtraKeyLinkToActionKey(actionKey))
val fieldToCopy = intent.getParcelableExtra<NotificationCopyingField>(
NotificationCopyingField.getExtraKeyLinkToActionKey(actionKey))
val nextFields = constructListOfField(intent)
// Remove the current field from the next fields
nextFields.remove(fieldToCopy)
@@ -106,8 +79,8 @@ class NotificationCopyingService : Service() {
return START_NOT_STICKY
}
private fun constructListOfField(intent: Intent?): ArrayList<NotificationField> {
var fieldList = ArrayList<NotificationField>()
private fun constructListOfField(intent: Intent?): ArrayList<NotificationCopyingField> {
var fieldList = ArrayList<NotificationCopyingField>()
if (intent != null && intent.extras != null) {
if (intent.extras!!.containsKey(EXTRA_FIELDS))
fieldList = intent.getParcelableArrayListExtra(EXTRA_FIELDS)
@@ -115,8 +88,8 @@ class NotificationCopyingService : Service() {
return fieldList
}
private fun getCopyPendingIntent(fieldToCopy: NotificationField, fieldsToAdd: ArrayList<NotificationField>): PendingIntent {
val copyIntent = Intent(this, NotificationCopyingService::class.java)
private fun getCopyPendingIntent(fieldToCopy: NotificationCopyingField, fieldsToAdd: ArrayList<NotificationCopyingField>): PendingIntent {
val copyIntent = Intent(this, CopyingEntryNotificationService::class.java)
copyIntent.action = fieldToCopy.actionKey
copyIntent.putExtra(fieldToCopy.extraKey, fieldToCopy)
copyIntent.putParcelableArrayListExtra(EXTRA_FIELDS, fieldsToAdd)
@@ -125,14 +98,11 @@ class NotificationCopyingService : Service() {
this, 0, copyIntent, PendingIntent.FLAG_UPDATE_CURRENT)
}
private fun newNotification(title: String?, fieldsToAdd: ArrayList<NotificationField>) {
private fun newNotification(title: String?, fieldsToAdd: ArrayList<NotificationCopyingField>) {
stopTask(countingDownTask)
val builder = NotificationCompat.Builder(this, CHANNEL_ID_COPYING)
val builder = buildNewNotification()
.setSmallIcon(R.drawable.ic_key_white_24dp)
.setColor(colorNotificationAccent)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setVisibility(NotificationCompat.VISIBILITY_SECRET)
if (title != null)
builder.setContentTitle(title)
@@ -171,19 +141,16 @@ class NotificationCopyingService : Service() {
}
}
private fun copyField(fieldToCopy: NotificationField, nextFields: ArrayList<NotificationField>) {
private fun copyField(fieldToCopy: NotificationCopyingField, nextFields: ArrayList<NotificationCopyingField>) {
stopTask(countingDownTask)
stopTask(cleanNotificationTimer)
try {
clipboardHelper?.copyToClipboard(fieldToCopy.label, fieldToCopy.value)
val builder = NotificationCompat.Builder(this, CHANNEL_ID_COPYING)
val builder = buildNewNotification()
.setSmallIcon(R.drawable.ic_key_white_24dp)
.setColor(colorNotificationAccent)
.setContentTitle(fieldToCopy.label)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setVisibility(NotificationCompat.VISIBILITY_SECRET)
// New action with next field if click
if (nextFields.size > 0) {
@@ -195,7 +162,7 @@ class NotificationCopyingService : Service() {
builder.setContentText(getString(R.string.clipboard_swipe_clean))
}
val cleanIntent = Intent(this, NotificationCopyingService::class.java)
val cleanIntent = Intent(this, CopyingEntryNotificationService::class.java)
cleanIntent.action = ACTION_CLEAN_CLIPBOARD
val cleanPendingIntent = PendingIntent.getService(
this, 0, cleanIntent, PendingIntent.FLAG_UPDATE_CURRENT)
@@ -246,9 +213,7 @@ class NotificationCopyingService : Service() {
companion object {
private val TAG = NotificationCopyingService::class.java.name
private const val CHANNEL_ID_COPYING = "CHANNEL_ID_COPYING"
private const val CHANNEL_NAME_COPYING = "Copy fields"
private val TAG = CopyingEntryNotificationService::class.java.name
const val ACTION_NEW_NOTIFICATION = "ACTION_NEW_NOTIFICATION"
const val EXTRA_ENTRY_TITLE = "EXTRA_ENTRY_TITLE"

View File

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

View File

@@ -35,23 +35,23 @@ object NotificationEntryCopyManager {
if (containsUsernameToCopy || containsPasswordToCopy || containsExtraFieldToCopy) {
// username already copied, waiting for user's action before copy password.
val intent = Intent(context, NotificationCopyingService::class.java)
intent.action = NotificationCopyingService.ACTION_NEW_NOTIFICATION
intent.putExtra(NotificationCopyingService.EXTRA_ENTRY_TITLE, entry.title)
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<NotificationField>()
val notificationFields = ArrayList<NotificationCopyingField>()
// Add username if exists to notifications
if (containsUsernameToCopy)
notificationFields.add(
NotificationField(
NotificationField.NotificationFieldId.USERNAME,
NotificationCopyingField(
NotificationCopyingField.NotificationFieldId.USERNAME,
entry.username,
context.resources))
// Add password to notifications
if (containsPasswordToCopy) {
notificationFields.add(
NotificationField(
NotificationField.NotificationFieldId.PASSWORD,
NotificationCopyingField(
NotificationCopyingField.NotificationFieldId.PASSWORD,
entry.password,
context.resources))
}
@@ -65,8 +65,8 @@ object NotificationEntryCopyManager {
if (!value.isProtected
|| PreferencesUtil.allowCopyPasswordAndProtectedFields(context)) {
notificationFields.add(
NotificationField(
NotificationField.NotificationFieldId.anonymousFieldId[anonymousFieldNumber],
NotificationCopyingField(
NotificationCopyingField.NotificationFieldId.anonymousFieldId[anonymousFieldNumber],
value.toString(),
key,
context.resources))
@@ -75,13 +75,13 @@ object NotificationEntryCopyManager {
}
})
} catch (e: ArrayIndexOutOfBoundsException) {
Log.w("NotificationEntryCopyMg", "Only " + NotificationField.NotificationFieldId.anonymousFieldId.size +
Log.w("NotificationEntryCopyMg", "Only " + NotificationCopyingField.NotificationFieldId.anonymousFieldId.size +
" anonymous notifications are available")
}
}
// Add notifications
intent.putParcelableArrayListExtra(NotificationCopyingService.EXTRA_FIELDS, notificationFields)
intent.putParcelableArrayListExtra(CopyingEntryNotificationService.EXTRA_FIELDS, notificationFields)
context.startService(intent)
}
}

View File

@@ -0,0 +1,58 @@
package com.kunzisoft.keepass.notifications
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.support.v4.app.NotificationCompat
import android.util.TypedValue
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.stylish.Stylish
abstract class NotificationService : Service() {
protected var notificationManager: NotificationManager? = null
private var colorNotificationAccent: Int = 0
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Create notification channel for Oreo+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(CHANNEL_ID_KEEPASS,
CHANNEL_NAME_KEEPASS,
NotificationManager.IMPORTANCE_DEFAULT)
notificationManager?.createNotificationChannel(channel)
}
// Get the color
setTheme(Stylish.getThemeId(this))
val typedValue = TypedValue()
val theme = theme
theme.resolveAttribute(R.attr.colorPrimary, typedValue, true)
colorNotificationAccent = typedValue.data
}
protected fun buildNewNotification(): NotificationCompat.Builder {
return NotificationCompat.Builder(this, CHANNEL_ID_KEEPASS)
.setColor(colorNotificationAccent)
.setGroup(GROUP_KEEPASS)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.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"

View File

@@ -1,4 +1,5 @@
package com.kunzisoft.keepass.utils
const val LOCK_ACTION = "com.kunzisoft.keepass.LOCK"
const val REMOVE_ENTRY_MAGIKEYBOARD_ACTION = "com.kunzisoft.keepass.REMOVE_ENTRY_MAGIKEYBOARD"

View File

@@ -115,7 +115,7 @@
<string name="keyboard_notification_entry_key" translatable="false">keyboard_notification_entry_key</string>
<bool name="keyboard_notification_entry_default" translatable="false">true</bool>
<string name="keyboard_notification_entry_clear_close_key" translatable="false">keyboard_notification_entry_clear_close_key</string>
<bool name="keyboard_notification_entry_clear_close_default" translatable="false">true</bool>
<bool name="keyboard_notification_entry_clear_close_default" translatable="false">false</bool>
<string name="keyboard_entry_timeout_key" translatable="false">keyboard_entry_timeout_key</string>
<string name="keyboard_theme_key" translatable="false">keyboard_theme_key</string>
<string name="keyboard_key_vibrate_key" translatable="false">keyboard_key_vibrate_key</string>

View File

@@ -309,7 +309,7 @@
<string name="keyboard_notification_entry_summary">Show a notification when an entry is available</string>
<string name="keyboard_notification_entry_clear_close_title">Clear at closing</string>
<string name="keyboard_notification_entry_clear_close_summary">Clear the keyboard entry when closing the notification</string>
<string name="keyboard_notification_entry_clear_close_summary">Close the database when closing the notification</string>
<string name="keyboard_entry_timeout_title">Timeout</string>
<string name="keyboard_entry_timeout_summary">Timeout to clear the keyboard entry</string>