PeachAutofillService.kt

3.8 KB · raw

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}