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 32 33 parser.usernameId?.let { putExtra("autofill_username_id", it) }34 parser.passwordId?.let { putExtra("autofill_password_id", it) }35 addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)36 }37 val pendingIntent = PendingIntent.getActivity(38 this, 0, authIntent,39 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE40 )41 val presentation = RemoteViews(packageName, R.layout.autofill_item).apply {42 setTextViewText(R.id.autofill_label, "Unlock Peach to autofill")43 }44 val usernameId = parser.usernameId45 if (usernameId == null) {46 callback.onSuccess(null)47 return48 }49 val authDataset = Dataset.Builder()50 .setAuthentication(pendingIntent.intentSender)51 .setValue(usernameId, null, presentation)52 .build()53 callback.onSuccess(54 FillResponse.Builder().addDataset(authDataset).build()55 )56 return57 }5859 val entries = VaultBridge.findEntries(domain ?: packageName ?: "")6061 if (entries.isEmpty()) {62 callback.onSuccess(null)63 return64 }6566 val response = FillResponse.Builder()6768 for (entry in entries.take(3)) {69 val presentation = RemoteViews(packageName, R.layout.autofill_item).apply {70 setTextViewText(R.id.autofill_label, entry.title)71 setTextViewText(R.id.autofill_subtitle, entry.username)72 }7374 val datasetBuilder = Dataset.Builder()7576 parser.usernameId?.let { id ->77 datasetBuilder.setValue(78 id,79 AutofillValue.forText(entry.username),80 presentation81 )82 }8384 parser.passwordId?.let { id ->85 datasetBuilder.setValue(86 id,87 AutofillValue.forText(entry.password),88 RemoteViews(packageName, R.layout.autofill_item).apply {89 setTextViewText(R.id.autofill_label, entry.title)90 setTextViewText(R.id.autofill_subtitle, "••••••••")91 }92 )93 }9495 response.addDataset(datasetBuilder.build())96 }9798 callback.onSuccess(response.build())99 }100101 override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) {102 val structure = request.fillContexts.lastOrNull()?.structure ?: run {103 callback.onSuccess()104 return105 }106 val parser = AssistStructureParser(structure)107108 val username = parser.extractUsername()109 val password = parser.extractPassword()110 val domain = parser.webDomain111112 if (username != null && password != null) {113 VaultBridge.offerSave(domain ?: "", username, password)114 }115116 callback.onSuccess()117 }118}