So basically I am trying to develop an App Lock application where the user can select which app they want to lock using Biometric stored in the device. I have already fetched the list of apps and store the package name in the shared preference once it is locked.
Now I want to create a foreground service to check when an app is launch is it present in my List of locked apps in the Shared Preference. For this I have created the Foreground service, but the problem is the BiometricPrompt only accepts Fragment/FragmentActivity as the 1st Parameter.
This is my ForegroundAppLockService.kt
class ForegroundAppLockService : Service() {
private lateinit var biometricPrompt: BiometricPrompt
private val notificationId = 12345
private val channelId = "app_lock_channel"
private val channelName = "App Lock Service"
override fun onCreate() {
super.onCreate()
createNotificationChannel()
biometricPrompt = createBiometricPrompt()
startAppLaunchAccessibilityService()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
startForeground(notificationId, createNotification())
return START_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
private fun createBiometricPrompt(): BiometricPrompt {
val executor = ContextCompat.getMainExecutor(applicationContext)
val callback = object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
Toast.makeText(applicationContext, "App unlocked!", Toast.LENGTH_SHORT).show()
}
}
return BiometricPrompt(this, executor, callback)
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
channelId,
channelName,
NotificationManager.IMPORTANCE_DEFAULT
)
val notificationManager = getSystemService(NotificationManager::class.java)
notificationManager.createNotificationChannel(channel)
}
}
private fun createNotification(): Notification {
val pendingIntent: PendingIntent =
PendingIntent.getActivity(this, 0, Intent(), PendingIntent.FLAG_UPDATE_CURRENT)
return NotificationCompat.Builder(this, channelId)
.setContentTitle("App Lock Service")
.setContentText("Monitoring app launches")
.setSmallIcon(R.drawable.icon)
.setContentIntent(pendingIntent)
.build()
}
private fun startAppLaunchAccessibilityService() {
val intent = Intent(this, AppLaunchAccessibilityService::class.java)
startService(intent)
}
companion object {
fun startService(context: Context) {
val intent = Intent(context, ForegroundAppLockService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
} else {
context.startService(intent)
}
}
fun startBiometricAuthentication(context: Context) {
val serviceIntent = Intent(context, ForegroundAppLockService::class.java)
ContextCompat.startForegroundService(context, serviceIntent)
}
fun stopService(context: Context) {
val intent = Intent(context, ForegroundAppLockService::class.java)
context.stopService(intent)
}
}
}
And this is the AppLaunchAccessibilityService.
class AppLaunchAccessibilityService : AccessibilityService() {
private lateinit var sharedPreferences: SharedPreferences
override fun onCreate() {
super.onCreate()
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
}
override fun onAccessibilityEvent(event: AccessibilityEvent?) {
if (event?.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
val packageName = event.packageName?.toString()
packageName?.let {
if (isAppLocked(packageName)) {
showBiometricPrompt()
}
}
}
}
override fun onInterrupt() {
}
private fun isAppLocked(packageName: String): Boolean {
val lockedPackages = getLockedPackages()
return lockedPackages.contains(packageName)
}
private fun getLockedPackages(): Set<String> {
val lockedPackagesKey = "key_locked_packages"
return sharedPreferences.getStringSet(lockedPackagesKey, HashSet()) ?: HashSet()
}
private fun showBiometricPrompt() {
ForegroundAppLockService.startBiometricAuthentication(this)
}
}
I want the Biometric prompt to be shown whenever user clicks on any app that is present in my lockedApps.