1package com.peachpasswords.app23import android.app.assist.AssistStructure4import android.os.CancellationSignal5import android.service.autofill.*6import android.view.autofill.AutofillValue7import android.widget.RemoteViews8import android.app.PendingIntent9import android.content.Intent1011class PeachAutofillService : AutofillService() {1213 override fun onFillRequest(14 request: FillRequest,15 cancellationSignal: CancellationSignal,16 callback: FillCallback17 ) {18 val structure = request.fillContexts.lastOrNull()?.structure ?: run {19 callback.onSuccess(null)20 return21 }22 val parser = AssistStructureParser(structure)2324 val domain = parser.webDomain25 val packageName = parser.packageName2627 if (!VaultBridge.isUnlocked()) {28 val authIntent = Intent(this, MainActivity::class.java).apply {29 putExtra("autofill_domain", domain)30 putExtra("autofill_package", packageName)31 addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)32 }33 val pendingIntent = PendingIntent.getActivity(34 this, 0, authIntent,35 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE36 )37 val presentation = RemoteViews(packageName, R.layout.autofill_item).apply {38 setTextViewText(R.id.autofill_label, "Unlock Peach to autofill")39 }40 val usernameId = parser.usernameId41 if (usernameId == null) {42 callback.onSuccess(null)43 return44 }45 val authDataset = Dataset.Builder()46 .setAuthentication(pendingIntent.intentSender)47 .setValue(usernameId, null, presentation)48 .build()49 callback.onSuccess(50 FillResponse.Builder().addDataset(authDataset).build()51 )52 return53 }5455 val entries = VaultBridge.findEntries(domain ?: packageName ?: "")5657 if (entries.isEmpty()) {58 callback.onSuccess(null)59 return60 }6162 val response = FillResponse.Builder()6364 for (entry in entries.take(3)) {65 val presentation = RemoteViews(packageName, R.layout.autofill_item).apply {66 setTextViewText(R.id.autofill_label, entry.title)67 setTextViewText(R.id.autofill_subtitle, entry.username)68 }6970 val datasetBuilder = Dataset.Builder()7172 parser.usernameId?.let { id ->73 datasetBuilder.setValue(74 id,75 AutofillValue.forText(entry.username),76 presentation77 )78 }7980 parser.passwordId?.let { id ->81 datasetBuilder.setValue(82 id,83 AutofillValue.forText(entry.password),84 RemoteViews(packageName, R.layout.autofill_item).apply {85 setTextViewText(R.id.autofill_label, entry.title)86 setTextViewText(R.id.autofill_subtitle, "••••••••")87 }88 )89 }9091 response.addDataset(datasetBuilder.build())92 }9394 callback.onSuccess(response.build())95 }9697 override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) {98 val structure = request.fillContexts.lastOrNull()?.structure ?: run {99 callback.onSuccess()100 return101 }102 val parser = AssistStructureParser(structure)103104 val username = parser.extractUsername()105 val password = parser.extractPassword()106 val domain = parser.webDomain107108 if (username != null && password != null) {109 VaultBridge.offerSave(domain ?: "", username, password)110 }111112 callback.onSuccess()113 }114}