fix: Upgrade Foreground service and version to 4.1.0

This commit is contained in:
J-Jamet
2024-06-24 12:32:05 +02:00
parent f9db4325d8
commit 4032e52317
12 changed files with 158 additions and 65 deletions

View File

@@ -1,3 +1,6 @@
KeePassDX(4.1.0)
* Upgrade to API 34 (Android 14)
KeePassDX(4.0.8) KeePassDX(4.0.8)
* Fix graphical bug that prevented databases from being opened on some versions of Android #1848 #1850 * Fix graphical bug that prevented databases from being opened on some versions of Android #1848 #1850

View File

@@ -5,15 +5,15 @@ apply plugin: 'kotlin-kapt'
android { android {
namespace 'com.kunzisoft.keepass' namespace 'com.kunzisoft.keepass'
compileSdkVersion 33 compileSdkVersion 34
buildToolsVersion "33.0.2" buildToolsVersion "33.0.2"
defaultConfig { defaultConfig {
applicationId "com.kunzisoft.keepass" applicationId "com.kunzisoft.keepass"
minSdkVersion 15 minSdkVersion 15
targetSdkVersion 33 targetSdkVersion 34
versionCode = 131 versionCode = 132
versionName = "4.0.8" versionName = "4.1.0"
multiDexEnabled true multiDexEnabled true
testApplicationId = "com.kunzisoft.keepass.tests" testApplicationId = "com.kunzisoft.keepass.tests"

View File

@@ -9,6 +9,10 @@
android:anyDensity="true" /> android:anyDensity="true" />
<uses-permission <uses-permission
android:name="android.permission.FOREGROUND_SERVICE" /> android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission
android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission
android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>
<uses-permission <uses-permission
android:name="android.permission.POST_NOTIFICATIONS" /> android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission <uses-permission
@@ -197,18 +201,27 @@
<service <service
android:name="com.kunzisoft.keepass.services.DatabaseTaskNotificationService" android:name="com.kunzisoft.keepass.services.DatabaseTaskNotificationService"
android:foregroundServiceType="dataSync"
android:enabled="true" android:enabled="true"
android:exported="false" /> android:exported="false" />
<service <service
android:name="com.kunzisoft.keepass.services.AttachmentFileNotificationService" android:name="com.kunzisoft.keepass.services.AttachmentFileNotificationService"
android:foregroundServiceType="dataSync"
android:enabled="true" android:enabled="true"
android:exported="false" /> android:exported="false" />
<service <service
android:name="com.kunzisoft.keepass.services.ClipboardEntryNotificationService" android:name="com.kunzisoft.keepass.services.ClipboardEntryNotificationService"
android:foregroundServiceType="specialUse"
android:enabled="true"
android:exported="false" />
<service
android:name="com.kunzisoft.keepass.services.KeyboardEntryNotificationService"
android:foregroundServiceType="specialUse"
android:enabled="true" android:enabled="true"
android:exported="false" /> android:exported="false" />
<service <service
android:name="com.kunzisoft.keepass.services.AdvancedUnlockNotificationService" android:name="com.kunzisoft.keepass.services.AdvancedUnlockNotificationService"
android:foregroundServiceType="specialUse"
android:enabled="true" android:enabled="true"
android:exported="false" /> android:exported="false" />
<!-- Receiver for Autofill --> <!-- Receiver for Autofill -->
@@ -235,10 +248,6 @@
<action android:name="android.view.InputMethod" /> <action android:name="android.view.InputMethod" />
</intent-filter> </intent-filter>
</service> </service>
<service
android:name="com.kunzisoft.keepass.services.KeyboardEntryNotificationService"
android:enabled="true"
android:exported="false" />
<receiver <receiver
android:name="com.kunzisoft.keepass.receivers.DexModeReceiver" android:name="com.kunzisoft.keepass.receivers.DexModeReceiver"
android:exported="true"> android:exported="true">

View File

@@ -86,11 +86,19 @@ class AdvancedUnlockNotificationService : NotificationService() {
val notificationTimeoutMilliSecs = PreferencesUtil.getAdvancedUnlockTimeout(this) val notificationTimeoutMilliSecs = PreferencesUtil.getAdvancedUnlockTimeout(this)
// Not necessarily a foreground service // Not necessarily a foreground service
if (mTimerJob == null && notificationTimeoutMilliSecs != TimeoutHelper.NEVER) { if (mTimerJob == null && notificationTimeoutMilliSecs != TimeoutHelper.NEVER) {
defineTimerJob(notificationBuilder, notificationTimeoutMilliSecs) { defineTimerJob(
notificationBuilder,
NotificationServiceType.ADVANCED_UNLOCK,
notificationTimeoutMilliSecs
) {
sendBroadcast(Intent(REMOVE_ADVANCED_UNLOCK_KEY_ACTION)) sendBroadcast(Intent(REMOVE_ADVANCED_UNLOCK_KEY_ACTION))
} }
} else { } else {
startForeground(notificationId, notificationBuilder.build()) startForegroundCompat(
notificationId,
notificationBuilder,
NotificationServiceType.ADVANCED_UNLOCK
)
} }
return mActionTaskBinder return mActionTaskBinder

View File

@@ -36,13 +36,13 @@ import com.kunzisoft.keepass.model.AttachmentState
import com.kunzisoft.keepass.model.EntryAttachmentState import com.kunzisoft.keepass.model.EntryAttachmentState
import com.kunzisoft.keepass.model.StreamDirection import com.kunzisoft.keepass.model.StreamDirection
import com.kunzisoft.keepass.tasks.BinaryDatabaseManager import com.kunzisoft.keepass.tasks.BinaryDatabaseManager
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.util.* import java.util.LinkedList
import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.CopyOnWriteArrayList
@@ -282,15 +282,21 @@ class AttachmentFileNotificationService: LockNotificationService() {
AttachmentState.ERROR -> { AttachmentState.ERROR -> {
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_DETACH) ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_DETACH)
try { try {
notificationManager?.notify( checkNotificationsPermission(this) {
attachmentNotification.notificationId, notificationManager?.notify(
builder.build() attachmentNotification.notificationId,
) builder.build()
)
}
} catch (e: SecurityException) { } catch (e: SecurityException) {
Log.e(TAG, "Unable to notify the attachment state", e) Log.e(TAG, "Unable to notify the attachment state", e)
} }
} else -> { } else -> {
startForeground(attachmentNotification.notificationId, builder.build()) startForegroundCompat(
attachmentNotification.notificationId,
builder,
NotificationServiceType.ATTACHMENT
)
} }
} }
} }

View File

@@ -19,16 +19,12 @@
*/ */
package com.kunzisoft.keepass.services package com.kunzisoft.keepass.services
import android.Manifest
import android.app.Activity import android.app.Activity
import android.app.PendingIntent import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import android.widget.Toast
import androidx.core.content.ContextCompat
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.model.EntryInfo import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.otp.OtpEntryFields.OTP_TOKEN_FIELD import com.kunzisoft.keepass.otp.OtpEntryFields.OTP_TOKEN_FIELD
@@ -196,23 +192,29 @@ class ClipboardEntryNotificationService : LockNotificationService() {
//Get settings //Get settings
val notificationTimeoutMilliSecs = PreferencesUtil.getClipboardTimeout(this) val notificationTimeoutMilliSecs = PreferencesUtil.getClipboardTimeout(this)
if (notificationTimeoutMilliSecs != NEVER) { if (notificationTimeoutMilliSecs != NEVER) {
defineTimerJob(builder, notificationTimeoutMilliSecs, { defineTimerJob(
val newGeneratedValue = fieldToCopy.getGeneratedValue(mEntryInfo) builder,
// New auto generated value NotificationServiceType.CLIPBOARD,
if (generatedValue != newGeneratedValue) { notificationTimeoutMilliSecs,
generatedValue = newGeneratedValue {
clipboardHelper?.copyToClipboard( val newGeneratedValue = fieldToCopy.getGeneratedValue(mEntryInfo)
fieldToCopy.label, // New auto generated value
generatedValue, if (generatedValue != newGeneratedValue) {
fieldToCopy.isSensitive generatedValue = newGeneratedValue
) clipboardHelper?.copyToClipboard(
fieldToCopy.label,
generatedValue,
fieldToCopy.isSensitive
)
}
},
{
stopNotificationAndSendLockIfNeeded()
// Clean password only if no next field
if (nextFields.size <= 0)
clipboardHelper?.cleanClipboard()
} }
}) { )
stopNotificationAndSendLockIfNeeded()
// Clean password only if no next field
if (nextFields.size <= 0)
clipboardHelper?.cleanClipboard()
}
} else { } else {
// No timer // No timer
checkNotificationsPermission { checkNotificationsPermission {
@@ -226,12 +228,11 @@ class ClipboardEntryNotificationService : LockNotificationService() {
} }
private fun checkNotificationsPermission(action: () -> Unit) { private fun checkNotificationsPermission(action: () -> Unit) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) checkNotificationsPermission(
== PackageManager.PERMISSION_GRANTED) { this,
action.invoke() PreferencesUtil.isClipboardNotificationsEnable(this),
} else { action
showPermissionErrorIfNeeded(this) )
}
} }
override fun onTaskRemoved(rootIntent: Intent?) { override fun onTaskRemoved(rootIntent: Intent?) {
@@ -255,26 +256,14 @@ class ClipboardEntryNotificationService : LockNotificationService() {
const val EXTRA_CLIPBOARD_FIELDS = "EXTRA_CLIPBOARD_FIELDS" const val EXTRA_CLIPBOARD_FIELDS = "EXTRA_CLIPBOARD_FIELDS"
const val ACTION_CLEAN_CLIPBOARD = "ACTION_CLEAN_CLIPBOARD" const val ACTION_CLEAN_CLIPBOARD = "ACTION_CLEAN_CLIPBOARD"
private fun showPermissionErrorIfNeeded(context: Context) {
if (PreferencesUtil.isClipboardNotificationsEnable(context)) {
Toast.makeText(context, R.string.warning_copy_permission, Toast.LENGTH_LONG).show()
}
}
fun checkAndLaunchNotification( fun checkAndLaunchNotification(
activity: Activity, activity: Activity,
entry: EntryInfo entry: EntryInfo
) { ) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { checkNotificationsPermission(
if (ContextCompat.checkSelfPermission( activity,
activity, PreferencesUtil.isClipboardNotificationsEnable(activity)
Manifest.permission.POST_NOTIFICATIONS ) {
) == PackageManager.PERMISSION_GRANTED) {
launchNotificationIfAllowed(activity, entry)
} else {
showPermissionErrorIfNeeded(activity)
}
} else {
launchNotificationIfAllowed(activity, entry) launchNotificationIfAllowed(activity, entry)
} }
} }

View File

@@ -591,7 +591,11 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
} }
// Create the notification // Create the notification
startForeground(notificationId, notificationBuilder.build()) startForegroundCompat(
notificationId,
notificationBuilder,
NotificationServiceType.DATABASE_TASK
)
} }
private fun removeIntentData(intent: Intent?) { private fun removeIntentData(intent: Intent?) {

View File

@@ -111,13 +111,18 @@ class KeyboardEntryNotificationService : LockNotificationService() {
.setContentIntent(null) .setContentIntent(null)
.setDeleteIntent(pendingDeleteIntent) .setDeleteIntent(pendingDeleteIntent)
notificationManager?.cancel(notificationId) checkNotificationsPermission(this, PreferencesUtil.isKeyboardNotificationEntryEnable(this)) {
notificationManager?.notify(notificationId, builder.build()) notificationManager?.notify(notificationId, builder.build())
}
// Timeout only if notification clear is available // Timeout only if notification clear is available
if (PreferencesUtil.isClearKeyboardNotificationEnable(this)) { if (PreferencesUtil.isClearKeyboardNotificationEnable(this)) {
if (mNotificationTimeoutMilliSecs != TimeoutHelper.NEVER) { if (mNotificationTimeoutMilliSecs != TimeoutHelper.NEVER) {
defineTimerJob(builder, mNotificationTimeoutMilliSecs) { defineTimerJob(
builder,
NotificationServiceType.KEYBOARD,
mNotificationTimeoutMilliSecs
) {
stopNotificationAndSendLockIfNeeded() stopNotificationAndSendLockIfNeeded()
} }
} }

View File

@@ -1,17 +1,30 @@
package com.kunzisoft.keepass.services package com.kunzisoft.keepass.services
import android.Manifest
import android.app.NotificationChannel import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.app.Service import android.app.Service
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
import android.os.Build import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.util.TypedValue import android.util.TypedValue
import android.widget.Toast
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.stylish.Stylish import com.kunzisoft.keepass.activities.stylish.Stylish
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
abstract class NotificationService : Service() { abstract class NotificationService : Service() {
@@ -74,7 +87,32 @@ abstract class NotificationService : Service() {
} }
} }
protected fun startForegroundCompat(notificationId: Int,
builder: NotificationCompat.Builder,
type: NotificationServiceType
) {
@Suppress("DEPRECATION")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val foregroundServiceTimer = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
FOREGROUND_SERVICE_TYPE_SPECIAL_USE
} else {
FOREGROUND_SERVICE_TYPE_NONE
}
val foregroundType = when (type) {
NotificationServiceType.DATABASE_TASK -> FOREGROUND_SERVICE_TYPE_DATA_SYNC
NotificationServiceType.ATTACHMENT -> FOREGROUND_SERVICE_TYPE_DATA_SYNC
NotificationServiceType.CLIPBOARD -> foregroundServiceTimer
NotificationServiceType.KEYBOARD -> foregroundServiceTimer
NotificationServiceType.ADVANCED_UNLOCK -> foregroundServiceTimer
}
startForeground(notificationId, builder.build(), foregroundType)
} else {
startForeground(notificationId, builder.build())
}
}
protected fun defineTimerJob(builder: NotificationCompat.Builder, protected fun defineTimerJob(builder: NotificationCompat.Builder,
type: NotificationServiceType,
timeoutMilliseconds: Long, timeoutMilliseconds: Long,
actionAfterASecond: (() -> Unit)? = null, actionAfterASecond: (() -> Unit)? = null,
actionEnd: () -> Unit) { actionEnd: () -> Unit) {
@@ -87,7 +125,7 @@ abstract class NotificationService : Service() {
builder.setProgress(100, builder.setProgress(100,
(currentTime * 100 / timeoutInSeconds).toInt(), (currentTime * 100 / timeoutInSeconds).toInt(),
false) false)
startForeground(notificationId, builder.build()) startForegroundCompat(notificationId, builder, type)
delay(1000) delay(1000)
if (currentTime <= 0) { if (currentTime <= 0) {
actionEnd() actionEnd()
@@ -114,5 +152,25 @@ abstract class NotificationService : Service() {
companion object { companion object {
private const val CHANNEL_ID = "com.kunzisoft.keepass.notification.channel" private const val CHANNEL_ID = "com.kunzisoft.keepass.notification.channel"
private const val CHANNEL_NAME = "KeePassDX notification" private const val CHANNEL_NAME = "KeePassDX notification"
fun checkNotificationsPermission(
context: Context,
showError: Boolean = true,
action: () -> Unit
) {
if (ContextCompat.checkSelfPermission(context,
Manifest.permission.POST_NOTIFICATIONS)
== PackageManager.PERMISSION_GRANTED) {
action.invoke()
} else {
if (showError) {
Toast.makeText(
context,
R.string.warning_copy_permission,
Toast.LENGTH_LONG
).show()
}
}
}
} }
} }

View File

@@ -0,0 +1,9 @@
package com.kunzisoft.keepass.services
enum class NotificationServiceType {
DATABASE_TASK,
ATTACHMENT,
CLIPBOARD,
KEYBOARD,
ADVANCED_UNLOCK
}

View File

@@ -0,0 +1 @@
* Upgrade to API 34 (Android 14)

View File

@@ -0,0 +1 @@
* Mise à jour vers API 34 (Android 14)