package com.fastest.pass.autofill import android.app.assist.AssistStructure import android.service.autofill.AutofillService import android.service.autofill.Dataset import android.service.autofill.FillCallback import android.service.autofill.FillContext import android.service.autofill.FillRequest import android.service.autofill.FillResponse import android.view.autofill.AutofillId import android.view.autofill.AutofillValue import android.widget.RemoteViews import com.fastest.pass.home.domain.model.AddPassword import com.fastest.pass.sharedpref.CredentialManager class FastestPassAutofillService : AutofillService() { override fun onFillRequest( request: FillRequest, cancellationSignal: android.os.CancellationSignal, callback: FillCallback ) { // Extract structure val context: List = request.fillContexts val structure: AssistStructure = context.last().structure val packageName = getRequestingPackageName(structure) if (packageName == null) { callback.onFailure("Unable to determine requesting package") return } // Fetch credentials matching the package name or domain /* val data = getCredentials().filter { it.url.contains(packageName) }*/ val data = getCredentials() if (data.isEmpty()) { callback.onFailure("No matching credentials found") return } val fillResponseBuilder = FillResponse.Builder() for (i in 0 until structure.windowNodeCount) { val windowNode = structure.getWindowNodeAt(i) val viewNode = windowNode.rootViewNode parseViewNode(viewNode, data, fillResponseBuilder) } callback.onSuccess(fillResponseBuilder.build()) } override fun onSaveRequest( request: android.service.autofill.SaveRequest, callback: android.service.autofill.SaveCallback ) { /* val credentialManager = CredentialManager(applicationContext) // Extracting the FillContexts from the SaveRequest val fillContexts = request.fillContexts // For each field in the SaveRequest, extract the autofill values (email and password) val credentials = mutableListOf() for (context in fillContexts) { val structure = context.structure // Loop through the views in the structure and extract the autofill values for (i in 0 until structure.windowNodeCount) { val windowNode = structure.getWindowNodeAt(i) val rootNode = windowNode.rootViewNode // Extract the values from the autofill fields val title = extractAutofillValue(rootNode, "personFirstName") ?: "" val url = extractAutofillValue(rootNode, "personLastName") ?: "" val username = extractAutofillValue(rootNode, "username") ?: "" val password = extractAutofillValue(rootNode, "password") ?: "" val notes = extractAutofillValue(rootNode, "addressStreet") ?: "" // Create a new Credential object and add it to the list val credential = AddPassword(title, url, username, password, notes) credentials.add(credential) } } // Save the credentials in SharedPreferences credentialManager.saveCredentials(credentials)*/ callback.onSuccess() } private fun extractAutofillValue(node: AssistStructure.ViewNode, hint: String): String? { val autofillHints = node.autofillHints // Check if the hint matches the autofill field (e.g., "emailAddress" or "password") if (autofillHints != null && autofillHints.contains(hint)) { val value = node.autofillValue return if (value != null && value.isText) value.textValue.toString() else null } // Recursively check child nodes if no value is found for (i in 0 until node.childCount) { val childNode = node.getChildAt(i) val result = extractAutofillValue(childNode, hint) if (result != null) return result } return null } private fun getCredentials(): List { val credentialManager = CredentialManager(applicationContext) return credentialManager.getCredentials() } private fun parseViewNode( node: AssistStructure.ViewNode, credentials: List, fillResponseBuilder: FillResponse.Builder ) { val autofillHints = node.autofillHints if (autofillHints != null) { // Collect Autofill IDs for username and password fields val emailAddress: AutofillId? = if ("emailAddress" in autofillHints) node.autofillId else null val username: AutofillId? = if ("username" in autofillHints) node.autofillId else null val passwordId: AutofillId? = if ("password" in autofillHints) node.autofillId else null if (username != null || emailAddress != null || passwordId != null) { credentials.forEach { credential -> val presentation = RemoteViews(packageName, android.R.layout.simple_list_item_1).apply { setTextViewText( android.R.id.text1, "${credential.username} @ ${credential.url}" ) } val datasetBuilder = Dataset.Builder() emailAddress?.let { datasetBuilder.setValue( it, AutofillValue.forText(credential.username), presentation ) } passwordId?.let { datasetBuilder.setValue( it, AutofillValue.forText(credential.password), presentation ) } username?.let { datasetBuilder.setValue( it, AutofillValue.forText(credential.username), presentation ) } fillResponseBuilder.addDataset(datasetBuilder.build()) } } } // Recursively parse child nodes for (i in 0 until node.childCount) { parseViewNode(node.getChildAt(i), credentials, fillResponseBuilder) } } private fun getRequestingPackageName(structure: AssistStructure): String? { return structure.activityComponent?.packageName } }