From 5288c980d004fb8f0a0658996701a90c05f2179d Mon Sep 17 00:00:00 2001 From: Jonas Haugesen Date: Wed, 19 Aug 2026 10:53:39 +0200 Subject: [PATCH] feat: notification dots on app icons New NotificationBadgeService (NotificationListenerService) tracks pending, dismissible notifications per app. Home, favorite, and drawer icons get a red dot in the top-right corner when the app has active notifications. Settings: 'Notification Dots' toggle under Display features; enabling it opens the system notification-access screen when permission is missing. Dots update live via a StateFlow observed by the fragments. --- app/src/main/AndroidManifest.xml | 9 +++ .../launcher/helper/PreferenceHelper.kt | 4 + .../service/NotificationBadgeService.kt | 76 +++++++++++++++++++ .../launcher/ui/drawer/DrawFragment.kt | 21 +++++ .../launcher/ui/drawer/DrawViewHolder.kt | 17 ++++- .../launcher/ui/favorite/FavoriteFragment.kt | 24 ++++++ .../ui/favorite/FavoriteViewHolder.kt | 15 +++- .../launcher/ui/home/HomeFragment.kt | 23 ++++++ .../launcher/ui/home/HomeViewHolder.kt | 17 ++++- .../ui/settings/SettingsFeaturesFragment.kt | 33 ++++++++ .../launcher/utils/Constants.kt | 1 + .../launcher/utils/NotificationDotHelper.kt | 51 +++++++++++++ .../launcher/viewmodel/PreferenceViewModel.kt | 6 ++ .../res/layout/fragment_settings_features.xml | 31 ++++++++ app/src/main/res/values/strings.xml | 3 + 15 files changed, 328 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/com/github/droidworksstudio/launcher/service/NotificationBadgeService.kt create mode 100644 app/src/main/java/com/github/droidworksstudio/launcher/utils/NotificationDotHelper.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d46636d..77ee81f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -103,6 +103,15 @@ + + + + + "userId/packageName". Keyed to dedupe updates. */ + private val keyToPackage = HashMap() + + override fun onListenerConnected() { + super.onListenerConnected() + synchronized(keyToPackage) { + keyToPackage.clear() + activeNotifications.forEach { sbn -> + if (isCounted(sbn)) keyToPackage[sbn.key] = userIdKey(sbn) + } + publish() + } + } + + override fun onNotificationPosted(sbn: StatusBarNotification) { + if (!isCounted(sbn)) return + synchronized(keyToPackage) { + // A posted notification with an existing key is just an update. + if (keyToPackage.containsKey(sbn.key)) return + keyToPackage[sbn.key] = userIdKey(sbn) + publish() + } + } + + override fun onNotificationRemoved(sbn: StatusBarNotification) { + synchronized(keyToPackage) { + if (keyToPackage.remove(sbn.key) != null) publish() + } + } + + /** Only swipe-away, non-ongoing notifications get a dot. */ + private fun isCounted(sbn: StatusBarNotification): Boolean { + val notification = sbn.notification + if (!sbn.isClearable) return false + if (notification.flags and Notification.FLAG_ONGOING_EVENT != 0) return false + return true + } + + private fun userIdKey(sbn: StatusBarNotification) = + "${sbn.userId}/" + sbn.packageName + + private fun publish() { + val counts = HashMap() + keyToPackage.values.forEach { key -> + counts[key] = (counts[key] ?: 0) + 1 + } + notificationCounts.value = counts + } + + companion object { + /** Active notification count per app, keyed by "userId/packageName". */ + val notificationCounts: MutableStateFlow> = + MutableStateFlow(emptyMap()) + + fun hasNotifications(userId: Int, packageName: String): Boolean = + notificationCounts.value["$userId/$packageName"]?.let { it > 0 } ?: false + } +} diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawFragment.kt b/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawFragment.kt index aec1728..7771d73 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawFragment.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawFragment.kt @@ -40,6 +40,7 @@ import com.github.droidworksstudio.launcher.helper.PreferenceHelper import com.github.droidworksstudio.launcher.listener.OnItemClickedListener import com.github.droidworksstudio.launcher.listener.OnSwipeTouchListener import com.github.droidworksstudio.launcher.listener.ScrollEventListener +import com.github.droidworksstudio.launcher.service.NotificationBadgeService import kotlin.math.roundToInt import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.AppInfoBottomSheetFragment import com.github.droidworksstudio.launcher.utils.Constants @@ -111,6 +112,7 @@ class DrawFragment : Fragment(), observeClickListener() observeSwipeTouchListener() observeScrollTouchListener() + observeNotificationBadges() // Initialize observation of drawer apps observeDrawerApps() @@ -166,6 +168,25 @@ class DrawFragment : Fragment(), } } + private fun observeNotificationBadges() { + viewLifecycleOwner.lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.CREATED) { + NotificationBadgeService.notificationCounts.collect { + val recyclerView = binding.drawAdapter + for (i in 0 until recyclerView.childCount) { + val holder = recyclerView.getChildViewHolder(recyclerView.getChildAt(i)) + if (holder is DrawViewHolder) { + val position = holder.bindingAdapterPosition + if (position != RecyclerView.NO_POSITION) { + holder.bind(drawAdapter.currentList[position]) + } + } + } + } + } + } + } + @RequiresApi(Build.VERSION_CODES.R) private fun observeDrawerApps() { // Start comparing installed app information diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawViewHolder.kt b/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawViewHolder.kt index 1706f3e..2db5e4e 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawViewHolder.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawViewHolder.kt @@ -14,7 +14,9 @@ import com.github.droidworksstudio.launcher.data.entities.AppInfo import com.github.droidworksstudio.launcher.databinding.ItemDrawBinding import com.github.droidworksstudio.launcher.helper.PreferenceHelper import com.github.droidworksstudio.launcher.listener.OnItemClickedListener +import com.github.droidworksstudio.launcher.service.NotificationBadgeService import com.github.droidworksstudio.launcher.utils.Constants +import com.github.droidworksstudio.launcher.utils.NotificationDotHelper class DrawViewHolder( private val binding: ItemDrawBinding, @@ -70,7 +72,20 @@ class DrawViewHolder( } appDrawIcon.layoutParams = layoutParams - appDrawIcon.setImageDrawable(appNewIcon ?: nonNullDrawable) + + val baseIcon: Drawable = appNewIcon ?: nonNullDrawable + appDrawIcon.setImageDrawable( + if (preferenceHelper.showNotificationDots && + NotificationBadgeService.hasNotifications( + appInfo.userHandle, + appInfo.packageName + ) + ) { + NotificationDotHelper.withDot(itemView.context, baseIcon) + } else { + baseIcon + } + ) appDrawIcon.visibility = View.VISIBLE val parentLayout = appDrawName.parent as LinearLayoutCompat diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/ui/favorite/FavoriteFragment.kt b/app/src/main/java/com/github/droidworksstudio/launcher/ui/favorite/FavoriteFragment.kt index e093aea..7336564 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/ui/favorite/FavoriteFragment.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/ui/favorite/FavoriteFragment.kt @@ -11,7 +11,9 @@ import android.view.ViewGroup import androidx.annotation.RequiresApi import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView @@ -28,6 +30,8 @@ import com.github.droidworksstudio.launcher.helper.PreferenceHelper import com.github.droidworksstudio.launcher.listener.OnItemClickedListener import com.github.droidworksstudio.launcher.listener.OnItemMoveListener import com.github.droidworksstudio.launcher.listener.OnSwipeTouchListener +import com.github.droidworksstudio.launcher.service.NotificationBadgeService +import com.github.droidworksstudio.launcher.ui.favorite.FavoriteViewHolder import com.github.droidworksstudio.launcher.viewmodel.AppViewModel import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch @@ -82,6 +86,7 @@ class FavoriteFragment : Fragment(), setupRecyclerView() observeFavorite() observeHomeAppOrder() + observeNotificationBadges() observeSwipeTouchListener() } @@ -128,6 +133,25 @@ class FavoriteFragment : Fragment(), } } + private fun observeNotificationBadges() { + viewLifecycleOwner.lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.CREATED) { + NotificationBadgeService.notificationCounts.collect { + val recyclerView = binding.favoriteAdapter + for (i in 0 until recyclerView.childCount) { + val holder = recyclerView.getChildViewHolder(recyclerView.getChildAt(i)) + if (holder is FavoriteViewHolder) { + val position = holder.bindingAdapterPosition + if (position != RecyclerView.NO_POSITION) { + holder.bind(favoriteAdapter.currentList[position]) + } + } + } + } + } + } + } + private fun observeHomeAppOrder() { binding.favoriteAdapter.adapter = favoriteAdapter val listener: OnItemMoveListener.OnItemActionListener = favoriteAdapter diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/ui/favorite/FavoriteViewHolder.kt b/app/src/main/java/com/github/droidworksstudio/launcher/ui/favorite/FavoriteViewHolder.kt index e508a66..23004a8 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/ui/favorite/FavoriteViewHolder.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/ui/favorite/FavoriteViewHolder.kt @@ -11,6 +11,8 @@ import com.github.droidworksstudio.launcher.data.entities.AppInfo import com.github.droidworksstudio.launcher.databinding.ItemFavoriteBinding import com.github.droidworksstudio.launcher.helper.PreferenceHelper import com.github.droidworksstudio.launcher.listener.OnItemClickedListener +import com.github.droidworksstudio.launcher.service.NotificationBadgeService +import com.github.droidworksstudio.launcher.utils.NotificationDotHelper @SuppressLint("ClickableViewAccessibility") class FavoriteViewHolder( @@ -48,7 +50,18 @@ class FavoriteViewHolder( if (preferenceHelper.showAppIcon) { val appIcon = binding.root.context.packageManager.getApplicationIcon(appInfo.packageName) - appFavoriteLeftIcon.setImageDrawable(appIcon) + val baseIcon: android.graphics.drawable.Drawable = + if (preferenceHelper.showNotificationDots && + NotificationBadgeService.hasNotifications( + appInfo.userHandle, + appInfo.packageName + ) + ) { + NotificationDotHelper.withDot(binding.root.context, appIcon) + } else { + appIcon + } + appFavoriteLeftIcon.setImageDrawable(baseIcon) appFavoriteLeftIcon.layoutParams.width = preferenceHelper.appTextSize.toInt() * 3 appFavoriteLeftIcon.layoutParams.height = diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/ui/home/HomeFragment.kt b/app/src/main/java/com/github/droidworksstudio/launcher/ui/home/HomeFragment.kt index 6626b33..96dfe36 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/ui/home/HomeFragment.kt @@ -24,7 +24,9 @@ import androidx.biometric.BiometricPrompt import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.NavOptions import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.StaggeredGridLayoutManager @@ -46,6 +48,7 @@ import com.github.droidworksstudio.launcher.helper.PreferenceHelper import com.github.droidworksstudio.launcher.listener.OnItemClickedListener import com.github.droidworksstudio.launcher.listener.OnSwipeTouchListener import com.github.droidworksstudio.launcher.listener.ScrollEventListener +import com.github.droidworksstudio.launcher.service.NotificationBadgeService import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.AppInfoBottomSheetFragment import com.github.droidworksstudio.launcher.utils.Constants import com.github.droidworksstudio.launcher.viewmodel.AppViewModel @@ -232,6 +235,25 @@ class HomeFragment : Fragment(), } } + private fun observeNotificationBadges() { + viewLifecycleOwner.lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.CREATED) { + NotificationBadgeService.notificationCounts.collect { + val recyclerView = binding.appListAdapter + for (i in 0 until recyclerView.childCount) { + val holder = recyclerView.getChildViewHolder(recyclerView.getChildAt(i)) + if (holder is HomeViewHolder) { + val position = holder.bindingAdapterPosition + if (position != androidx.recyclerview.widget.RecyclerView.NO_POSITION) { + holder.bind(homeAdapter.currentList[position]) + } + } + } + } + } + } + } + @SuppressLint("ClickableViewAccessibility", "InflateParams") private fun observeSwipeTouchListener() { binding.apply { @@ -584,6 +606,7 @@ class HomeFragment : Fragment(), binding.mainView.hideKeyboard() observeUserInterfaceSettings() observeFavoriteAppList() + observeNotificationBadges() } override fun onAppClicked(appInfo: AppInfo) { diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/ui/home/HomeViewHolder.kt b/app/src/main/java/com/github/droidworksstudio/launcher/ui/home/HomeViewHolder.kt index 0c1303b..947ce1e 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/ui/home/HomeViewHolder.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/ui/home/HomeViewHolder.kt @@ -15,7 +15,9 @@ import com.github.droidworksstudio.launcher.data.entities.AppInfo import com.github.droidworksstudio.launcher.databinding.ItemHomeBinding import com.github.droidworksstudio.launcher.helper.PreferenceHelper import com.github.droidworksstudio.launcher.listener.OnItemClickedListener +import com.github.droidworksstudio.launcher.service.NotificationBadgeService import com.github.droidworksstudio.launcher.utils.Constants +import com.github.droidworksstudio.launcher.utils.NotificationDotHelper import javax.inject.Inject class HomeViewHolder @Inject constructor( @@ -70,7 +72,20 @@ class HomeViewHolder @Inject constructor( } appHomeIcon.layoutParams = layoutParams - appHomeIcon.setImageDrawable(appNewIcon ?: nonNullDrawable) + + val baseIcon: Drawable = appNewIcon ?: nonNullDrawable + appHomeIcon.setImageDrawable( + if (preferenceHelper.showNotificationDots && + NotificationBadgeService.hasNotifications( + appInfo.userHandle, + appInfo.packageName + ) + ) { + NotificationDotHelper.withDot(itemView.context, baseIcon) + } else { + baseIcon + } + ) appHomeIcon.visibility = View.VISIBLE val parentLayout = appHomeName.parent as LinearLayoutCompat diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/ui/settings/SettingsFeaturesFragment.kt b/app/src/main/java/com/github/droidworksstudio/launcher/ui/settings/SettingsFeaturesFragment.kt index 1a12eab..1e11161 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/ui/settings/SettingsFeaturesFragment.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/ui/settings/SettingsFeaturesFragment.kt @@ -1,8 +1,11 @@ package com.github.droidworksstudio.launcher.ui.settings import android.content.Context +import android.content.ComponentName +import android.content.Intent import android.os.Build import android.os.Bundle +import android.provider.Settings import android.view.Gravity import android.view.LayoutInflater import android.view.View @@ -18,6 +21,7 @@ import androidx.lifecycle.lifecycleScope import androidx.navigation.NavController import androidx.navigation.fragment.findNavController import com.github.droidworksstudio.common.getAppNameFromPackageName +import com.github.droidworksstudio.common.showLongToast import com.github.droidworksstudio.launcher.R import com.github.droidworksstudio.launcher.databinding.FragmentSettingsFeaturesBinding import com.github.droidworksstudio.launcher.helper.AppHelper @@ -25,6 +29,7 @@ import com.github.droidworksstudio.launcher.helper.AppReloader import com.github.droidworksstudio.launcher.helper.PreferenceHelper import com.github.droidworksstudio.launcher.listener.ScrollEventListener import com.github.droidworksstudio.launcher.repository.AppInfoRepository +import com.github.droidworksstudio.launcher.service.NotificationBadgeService import com.github.droidworksstudio.launcher.utils.Constants import com.github.droidworksstudio.launcher.viewmodel.PreferenceViewModel import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -129,6 +134,7 @@ class SettingsFeaturesFragment : Fragment(), homeAlignmentBottomSwitchCompat.isChecked = preferenceHelper.homeAlignmentBottom lockSettingsSwitchCompat.isChecked = preferenceHelper.settingsLock disableAnimationsSwitchCompat.isChecked = preferenceHelper.disableAnimations + showNotificationDotsSwitchCompat.isChecked = preferenceHelper.showNotificationDots } } @@ -450,10 +456,37 @@ class SettingsFeaturesFragment : Fragment(), val feedbackType = if (isChecked) "on" else "off" appHelper.triggerHapticFeedback(context, feedbackType) } + + showNotificationDotsSwitchCompat.setOnCheckedChangeListener { _, isChecked -> + preferenceViewModel.setShowNotificationDots(isChecked) + val feedbackType = if (isChecked) "on" else "off" + appHelper.triggerHapticFeedback(context, feedbackType) + + if (isChecked && !isNotificationAccessGranted()) { + openNotificationAccessSettings() + } + } } } + private fun isNotificationAccessGranted(): Boolean { + val componentName = ComponentName(requireContext(), NotificationBadgeService::class.java) + val notificationManager = + requireContext().getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager + return notificationManager.isNotificationListenerAccessGranted(componentName) + } + + private fun openNotificationAccessSettings() { + try { + startActivity(Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS)) + } catch (_: Exception) { + requireContext().showLongToast( + getString(R.string.toast_cannot_open_notification_access_settings) + ) + } + } + private var swipeActionDialog: AlertDialog? = null @RequiresApi(Build.VERSION_CODES.Q) diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/utils/Constants.kt b/app/src/main/java/com/github/droidworksstudio/launcher/utils/Constants.kt index b7ed69e..81d8a44 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/utils/Constants.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/utils/Constants.kt @@ -70,6 +70,7 @@ object Constants { const val HOME_ALLIGNMENT_BOTTOM = "HOME_ALLIGNMENT_BOTTOM" const val TOGGLE_SETTING_LOCK = "TOGGLE_SETTING_LOCK" const val DISABLE_ANIMATIONS = "DISABLE_ANIMATIONS" + const val SHOW_NOTIFICATION_DOTS = "SHOW_NOTIFICATION_DOTS" const val HOME_DATE_ALIGNMENT = "HOME_DATE_ALIGNMENT" const val HOME_TIME_ALIGNMENT = "HOME_TIME_ALIGNMENT" diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/utils/NotificationDotHelper.kt b/app/src/main/java/com/github/droidworksstudio/launcher/utils/NotificationDotHelper.kt new file mode 100644 index 0000000..34b71ef --- /dev/null +++ b/app/src/main/java/com/github/droidworksstudio/launcher/utils/NotificationDotHelper.kt @@ -0,0 +1,51 @@ +package com.github.droidworksstudio.launcher.utils + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable +import com.github.droidworksstudio.common.ColorIconsExtensions + +object NotificationDotHelper { + + /** + * Returns a copy of [icon] with a red dot drawn in its top-right corner, + * surrounded by a thin white border so it stays visible on busy icons. + */ + fun withDot(context: Context, icon: Drawable): Drawable { + val source = ColorIconsExtensions.drawableToBitmap(icon) + val width = source.width + val height = source.height + if (width <= 0 || height <= 0) return icon + + val dotRadius = (minOf(width, height) * 0.22f).coerceAtLeast(4f) + val centerX = width - dotRadius * 0.75f + val centerY = dotRadius * 0.75f + + val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + canvas.drawBitmap(source, 0f, 0f, null) + + val dotPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + color = Color.RED + } + canvas.drawCircle(centerX, centerY, dotRadius, dotPaint) + + val borderPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + color = Color.WHITE + style = Paint.Style.STROKE + strokeWidth = (dotRadius * 0.28f).coerceAtLeast(1.5f) + } + canvas.drawCircle( + centerX, + centerY, + dotRadius - borderPaint.strokeWidth / 2f, + borderPaint + ) + + return BitmapDrawable(context.resources, bitmap) + } +} diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/viewmodel/PreferenceViewModel.kt b/app/src/main/java/com/github/droidworksstudio/launcher/viewmodel/PreferenceViewModel.kt index 62f767d..630d26e 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/viewmodel/PreferenceViewModel.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/viewmodel/PreferenceViewModel.kt @@ -49,6 +49,7 @@ class PreferenceViewModel @Inject constructor( private val autoKeyboardLiveData: MutableLiveData = MutableLiveData() private val lockSettingsLiveData: MutableLiveData = MutableLiveData() private val disableAnimationsLiveData: MutableLiveData = MutableLiveData() + private val showNotificationDotsLiveData: MutableLiveData = MutableLiveData() private val appGroupPaddingSizeLiveData: MutableLiveData = MutableLiveData() private val appPaddingSizeLiveData: MutableLiveData = MutableLiveData() @@ -297,6 +298,11 @@ class PreferenceViewModel @Inject constructor( disableAnimationsLiveData.postValue((preferenceHelper.disableAnimations)) } + fun setShowNotificationDots(showNotificationDots: Boolean) { + preferenceHelper.showNotificationDots = showNotificationDots + showNotificationDotsLiveData.postValue((preferenceHelper.showNotificationDots)) + } + fun setAppLanguage(appLanguage: Constants.Language) { preferenceHelper.appLanguage = appLanguage appLanguageLiveData.postValue((preferenceHelper.appLanguage)) diff --git a/app/src/main/res/layout/fragment_settings_features.xml b/app/src/main/res/layout/fragment_settings_features.xml index 6331850..920d0fe 100644 --- a/app/src/main/res/layout/fragment_settings_features.xml +++ b/app/src/main/res/layout/fragment_settings_features.xml @@ -238,6 +238,37 @@ tools:ignore="TouchTargetSizeCheck" /> + + + + + + + + Search From Start Lock Settings Disable Animations + Notification Dots + Cannot open notification access settings. Size Color @@ -200,6 +202,7 @@ Disable Easy Launcher Actions Service + Easy Launcher - notification dots Please turn on accessibility service to use double tap to lock feature in Easy Launcher.\n\nThis permission is used only to turn off your screen. Our accessibility service does not collect or share any data.