From d1d99a0ab34d26fd5781336e9cb86cef177d5593 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Fri, 20 Feb 2026 19:37:00 +0530 Subject: [PATCH 1/5] fix: empty passcodes autofill response bug #44 --- .../passcodes/autofill/PasswordAutofillService.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt b/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt index c460aa12..372355b9 100644 --- a/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt +++ b/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt @@ -55,6 +55,10 @@ class PasswordAutofillService : AutofillService() { .first() val responseBuilder = FillResponse.Builder() + if (passcodes.isEmpty()) { + callback.onSuccess(null) + } + for (passcode in passcodes) { val presentation = RemoteViews(packageName, R.layout.autofill_list_item).apply { setTextViewText(R.id.autofill_username, passcode.name) From 1f2d310b56b1b4b2bf5e2e76d7c425b8a653332a Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Fri, 20 Feb 2026 19:54:54 +0530 Subject: [PATCH 2/5] feat: make autofill service work with database libs --- autofill/build.gradle.kts | 5 ++++- .../autofill/PasswordAutofillService.kt | 21 +++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/autofill/build.gradle.kts b/autofill/build.gradle.kts index 2832a9c4..ac29b3a4 100644 --- a/autofill/build.gradle.kts +++ b/autofill/build.gradle.kts @@ -46,7 +46,7 @@ android { } dependencies { - // implementation(project(":password_manager")) + implementation(project(":database")) implementation(libs.androidx.core.ktx) implementation(libs.appcompat) @@ -55,4 +55,7 @@ dependencies { // Data/Persistence (Room Bundle) ksp(libs.room.compiler) implementation(libs.room.ktx) + + implementation(libs.coroutines.core) + implementation(libs.koin.compose) } diff --git a/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt b/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt index 372355b9..101b85a9 100644 --- a/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt +++ b/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt @@ -12,10 +12,12 @@ import android.view.autofill.AutofillValue import android.widget.RemoteViews import com.jeeldobariya.passcodes.autofill.data.Passcode import com.jeeldobariya.passcodes.autofill.data.PasscodeDatabase +import com.jeeldobariya.passcodes.database.master.PasswordsDao import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch +import org.koin.android.ext.android.inject // TODO: currently the code here serves as a foundation for autofill features.. class PasswordAutofillService : AutofillService() { @@ -49,24 +51,25 @@ class PasswordAutofillService : AutofillService() { } serviceScope.launch { - // TODO: use the database module instead of separate database - val passcodes = - PasscodeDatabase.getDatabase(applicationContext).passcodeDao().getAllPasscodes() - .first() + val passwordsDao by inject() + val passwords = passwordsDao.getAllPasswords().first() val responseBuilder = FillResponse.Builder() - if (passcodes.isEmpty()) { + if (passwords.isEmpty()) { callback.onSuccess(null) } - for (passcode in passcodes) { + for (password in passwords) { val presentation = RemoteViews(packageName, R.layout.autofill_list_item).apply { - setTextViewText(R.id.autofill_username, passcode.name) + setTextViewText( + R.id.autofill_username, + "${password.domain}(${password.username})" + ) } val dataset = android.service.autofill.Dataset.Builder(presentation) - .setValue(usernameId, AutofillValue.forText(passcode.name)) - .setValue(passwordId, AutofillValue.forText(passcode.value)) + .setValue(usernameId, AutofillValue.forText(password.username)) + .setValue(passwordId, AutofillValue.forText(password.password)) .build() responseBuilder.addDataset(dataset) } From 0da2ac25d1e2ea369b7a90a430b4e5ec15a19c7d Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Fri, 20 Feb 2026 19:56:21 +0530 Subject: [PATCH 3/5] chore(feat): remove auto save feature.. as it could crash app. --- .../autofill/PasswordAutofillService.kt | 52 +++++++++---------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt b/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt index 101b85a9..9c652170 100644 --- a/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt +++ b/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt @@ -6,12 +6,8 @@ import android.service.autofill.AutofillService import android.service.autofill.FillCallback import android.service.autofill.FillRequest import android.service.autofill.FillResponse -import android.service.autofill.SaveCallback -import android.service.autofill.SaveRequest import android.view.autofill.AutofillValue import android.widget.RemoteViews -import com.jeeldobariya.passcodes.autofill.data.Passcode -import com.jeeldobariya.passcodes.autofill.data.PasscodeDatabase import com.jeeldobariya.passcodes.database.master.PasswordsDao import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -78,30 +74,30 @@ class PasswordAutofillService : AutofillService() { } } - override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) { - val context = request.fillContexts - val structure = context.last().structure - - val viewNodes = mutableMapOf() - parseStructure(structure.getWindowNodeAt(0).rootViewNode, viewNodes) - - val usernameNode = viewNodes["username"] ?: viewNodes["emailAddress"] - val passwordNode = viewNodes["password"] - - val username = usernameNode?.text?.toString() - val password = passwordNode?.text?.toString() - - if (!username.isNullOrEmpty() && !password.isNullOrEmpty()) { - serviceScope.launch { - PasscodeDatabase.getDatabase(applicationContext).passcodeDao().insert( - Passcode(name = username, value = password) - ) - } - callback.onSuccess() - } else { - callback.onFailure(getString(R.string.could_not_save_credentials)) - } - } +// override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) { +// val context = request.fillContexts +// val structure = context.last().structure +// +// val viewNodes = mutableMapOf() +// parseStructure(structure.getWindowNodeAt(0).rootViewNode, viewNodes) +// +// val usernameNode = viewNodes["username"] ?: viewNodes["emailAddress"] +// val passwordNode = viewNodes["password"] +// +// val username = usernameNode?.text?.toString() +// val password = passwordNode?.text?.toString() +// +// if (!username.isNullOrEmpty() && !password.isNullOrEmpty()) { +// serviceScope.launch { +// PasscodeDatabase.getDatabase(applicationContext).passcodeDao().insert( +// Passcode(name = username, value = password) +// ) +// } +// callback.onSuccess() +// } else { +// callback.onFailure(getString(R.string.could_not_save_credentials)) +// } +// } private fun parseStructure( node: AssistStructure.ViewNode, From b5d5c5819d39aafb30a697b33ab100e68d4a9d9f Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Fri, 20 Feb 2026 20:03:25 +0530 Subject: [PATCH 4/5] feat: improve save functionality of autofill service. --- .../autofill/PasswordAutofillService.kt | 70 ++++++++++++------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt b/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt index 9c652170..a5d30837 100644 --- a/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt +++ b/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt @@ -6,8 +6,12 @@ import android.service.autofill.AutofillService import android.service.autofill.FillCallback import android.service.autofill.FillRequest import android.service.autofill.FillResponse +import android.service.autofill.SaveCallback +import android.service.autofill.SaveRequest import android.view.autofill.AutofillValue import android.widget.RemoteViews +import android.widget.Toast +import com.jeeldobariya.passcodes.database.master.PasswordEntity import com.jeeldobariya.passcodes.database.master.PasswordsDao import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -47,6 +51,12 @@ class PasswordAutofillService : AutofillService() { } serviceScope.launch { + Toast.makeText( + applicationContext, + "Passcodes autofill is preview feature!!!", + Toast.LENGTH_LONG + ).show() + val passwordsDao by inject() val passwords = passwordsDao.getAllPasswords().first() val responseBuilder = FillResponse.Builder() @@ -74,30 +84,42 @@ class PasswordAutofillService : AutofillService() { } } -// override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) { -// val context = request.fillContexts -// val structure = context.last().structure -// -// val viewNodes = mutableMapOf() -// parseStructure(structure.getWindowNodeAt(0).rootViewNode, viewNodes) -// -// val usernameNode = viewNodes["username"] ?: viewNodes["emailAddress"] -// val passwordNode = viewNodes["password"] -// -// val username = usernameNode?.text?.toString() -// val password = passwordNode?.text?.toString() -// -// if (!username.isNullOrEmpty() && !password.isNullOrEmpty()) { -// serviceScope.launch { -// PasscodeDatabase.getDatabase(applicationContext).passcodeDao().insert( -// Passcode(name = username, value = password) -// ) -// } -// callback.onSuccess() -// } else { -// callback.onFailure(getString(R.string.could_not_save_credentials)) -// } -// } + override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) { + val context = request.fillContexts + val structure = context.last().structure + + val viewNodes = mutableMapOf() + parseStructure(structure.getWindowNodeAt(0).rootViewNode, viewNodes) + + val usernameNode = viewNodes["username"] ?: viewNodes["emailAddress"] + val passwordNode = viewNodes["password"] + + val username = usernameNode?.text?.toString() + val password = passwordNode?.text?.toString() + + if (!username.isNullOrEmpty() && !password.isNullOrEmpty()) { + serviceScope.launch { + val passwordsDao by inject() + passwordsDao.insertPassword( + PasswordEntity( + domain = "Autofill", + username = username, + password = password, + notes = "Save using autofill service..." + ) + ) + Toast.makeText( + applicationContext, + "Open passcodes app and configure the saved password!!!", + Toast.LENGTH_LONG + ).show() + } + + callback.onSuccess() + } else { + callback.onFailure(getString(R.string.could_not_save_credentials)) + } + } private fun parseStructure( node: AssistStructure.ViewNode, From 337d6395bbe2e2a96e6c595c30b253d2a4c3eb29 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Fri, 20 Feb 2026 20:05:03 +0530 Subject: [PATCH 5/5] chore: remove dead codes --- .../passcodes/autofill/data/Passcode.kt | 12 -------- .../passcodes/autofill/data/PasscodeDao.kt | 28 ------------------ .../autofill/data/PasscodeDatabase.kt | 29 ------------------- 3 files changed, 69 deletions(-) delete mode 100644 autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/Passcode.kt delete mode 100644 autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/PasscodeDao.kt delete mode 100644 autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/PasscodeDatabase.kt diff --git a/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/Passcode.kt b/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/Passcode.kt deleted file mode 100644 index 61a37394..00000000 --- a/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/Passcode.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.jeeldobariya.passcodes.autofill.data - -import androidx.room.Entity -import androidx.room.PrimaryKey - -@Entity(tableName = "passcodes") -data class Passcode( - @PrimaryKey(autoGenerate = true) - val id: Int = 0, - val name: String, - val value: String -) diff --git a/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/PasscodeDao.kt b/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/PasscodeDao.kt deleted file mode 100644 index 9519602d..00000000 --- a/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/PasscodeDao.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.jeeldobariya.passcodes.autofill.data - -import androidx.room.Dao -import androidx.room.Delete -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query -import androidx.room.Update -import kotlinx.coroutines.flow.Flow - -@Dao -interface PasscodeDao { - - @Insert(onConflict = OnConflictStrategy.REPLACE) - suspend fun insert(passcode: Passcode) - - @Update - suspend fun update(passcode: Passcode) - - @Delete - suspend fun delete(passcode: Passcode) - - @Query("SELECT * FROM passcodes ORDER BY name ASC") - fun getAllPasscodes(): Flow> - - @Query("SELECT * FROM passcodes WHERE id = :id") - fun getPasscode(id: Int): Flow -} diff --git a/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/PasscodeDatabase.kt b/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/PasscodeDatabase.kt deleted file mode 100644 index e81ca689..00000000 --- a/autofill/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/PasscodeDatabase.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.jeeldobariya.passcodes.autofill.data - -import android.content.Context -import androidx.room.Database -import androidx.room.Room -import androidx.room.RoomDatabase - -@Database(entities = [Passcode::class], version = 1, exportSchema = false) -abstract class PasscodeDatabase : RoomDatabase() { - - abstract fun passcodeDao(): PasscodeDao - - companion object { - @Volatile - private var INSTANCE: PasscodeDatabase? = null - - fun getDatabase(context: Context): PasscodeDatabase { - return INSTANCE ?: synchronized(this) { - val instance = Room.databaseBuilder( - context.applicationContext, - PasscodeDatabase::class.java, - "passcode_database" - ).build() - INSTANCE = instance - instance - } - } - } -}