123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- 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<FillContext> = 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<AddPassword>()
- 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<AddPassword> {
- val credentialManager = CredentialManager(applicationContext)
- return credentialManager.getCredentials()
- }
- private fun parseViewNode(
- node: AssistStructure.ViewNode,
- credentials: List<AddPassword>,
- 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
- }
- }
|