/*
* 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 .
*
*/
package com.kunzisoft.keepass.services
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import android.util.Log
import android.widget.Toast
import androidx.preference.PreferenceManager
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.credentialprovider.magikeyboard.MagikeyboardService
import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.utils.LOCK_ACTION
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
class KeyboardEntryNotificationService : LockNotificationService() {
override val notificationId = 486
private var mNotificationTimeoutMilliSecs: Long = 0
private var pendingDeleteIntent: PendingIntent? = null
override fun retrieveChannelId(): String {
return CHANNEL_MAGIKEYBOARD_ID
}
override fun retrieveChannelName(): String {
return getString(R.string.magic_keyboard_title)
}
private fun stopNotificationAndSendLockIfNeeded() {
// Clear the entry if define in preferences
if (PreferencesUtil.isClearKeyboardNotificationEnable(this)) {
sendBroadcast(Intent(LOCK_ACTION))
}
// Stop the service
stopSelf()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
//Get settings
mNotificationTimeoutMilliSecs = PreferenceManager.getDefaultSharedPreferences(this)
.getString(getString(R.string.keyboard_entry_timeout_key),
getString(R.string.timeout_default))?.toLong() ?: TimeoutHelper.DEFAULT_TIMEOUT
when {
intent == null -> Log.w(TAG, "null intent")
ACTION_CLEAN_KEYBOARD_ENTRY == intent.action -> {
stopNotificationAndSendLockIfNeeded()
}
else -> {
notificationManager?.cancel(notificationId)
if (intent.hasExtra(ENTRY_INFO_KEY)) {
intent.getParcelableExtraCompat(ENTRY_INFO_KEY)?.let {
newNotification(it)
}
}
}
}
return START_NOT_STICKY
}
private fun newNotification(entryInfo: EntryInfo) {
var entryTitle = getString(R.string.keyboard_notification_entry_content_title_text)
var entryUsername = ""
if (entryInfo.title.isNotEmpty())
entryTitle = entryInfo.title
if (entryInfo.username.isNotEmpty())
entryUsername = entryInfo.username
val deleteIntent = Intent(this, KeyboardEntryNotificationService::class.java).apply {
action = ACTION_CLEAN_KEYBOARD_ENTRY
}
pendingDeleteIntent = PendingIntent.getService(this, 0, deleteIntent,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
)
val builder = buildNewNotification()
.setSmallIcon(R.drawable.notification_ic_keyboard_key_24dp)
.setContentTitle(getString(R.string.keyboard_notification_entry_content_title, entryTitle))
.setContentText(getString(R.string.keyboard_notification_entry_content_text, entryUsername))
.setAutoCancel(false)
.setContentIntent(null)
.setDeleteIntent(pendingDeleteIntent)
checkNotificationsPermission(this, PreferencesUtil.isKeyboardNotificationEntryEnable(this)) {
notificationManager?.notify(notificationId, builder.build())
}
// Timeout only if notification clear is available
if (PreferencesUtil.isClearKeyboardNotificationEnable(this)) {
if (mNotificationTimeoutMilliSecs != TimeoutHelper.NEVER) {
defineTimerJob(
builder,
NotificationServiceType.KEYBOARD,
mNotificationTimeoutMilliSecs
) {
stopNotificationAndSendLockIfNeeded()
}
}
}
}
override fun onTaskRemoved(rootIntent: Intent?) {
MagikeyboardService.removeEntry(this)
super.onTaskRemoved(rootIntent)
}
override fun onDestroy() {
// Remove the entry from the keyboard
MagikeyboardService.removeEntry(this)
pendingDeleteIntent?.cancel()
super.onDestroy()
}
companion object {
private const val TAG = "KeyboardEntryNotifSrv"
private const val CHANNEL_MAGIKEYBOARD_ID = "com.kunzisoft.keepass.notification.channel.magikeyboard"
const val ENTRY_INFO_KEY = "ENTRY_INFO_KEY"
const val ACTION_CLEAN_KEYBOARD_ENTRY = "ACTION_CLEAN_KEYBOARD_ENTRY"
fun launchNotificationIfAllowed(context: Context, entry: EntryInfo, toast: Boolean) {
var startService = false
val intent = Intent(context, KeyboardEntryNotificationService::class.java)
if (toast) {
Toast.makeText(context,
context.getString(R.string.keyboard_notification_entry_content_title,
entry.getVisualTitle()
),
Toast.LENGTH_SHORT).show()
}
// Show the notification if allowed in Preferences
if (PreferencesUtil.isKeyboardNotificationEntryEnable(context)) {
startService = true
context.startService(intent.apply {
putExtra(ENTRY_INFO_KEY, entry)
})
}
if (!startService)
context.stopService(intent)
}
}
}