AutofillIntents.kt

4.4 KB · raw

1package com.peachpasswords.autofill23import android.app.PendingIntent4import android.content.Context5import android.content.Intent6import android.content.IntentSender7import android.os.Build89/**10 * PendingIntents the autofill surfaces hand to the framework: a no-op11 * attribution target the inline chip requires, the authentication12 * IntentSender that opens the branded [AutofillEntryPickerActivity], and the13 * "open new entry" launcher that the picker fires when the user taps the14 * "+ Create new entry" affordance.15 */16object AutofillIntents {17    const val EXTRA_IDENTITY_ID = "peach.autofill.identityId"18    const val EXTRA_PASSWORD_ID = "peach.autofill.passwordId"19    const val EXTRA_OTP_ID = "peach.autofill.otpId"20    const val EXTRA_ORIGIN = "peach.autofill.origin"21    const val EXTRA_IS_WEB_ORIGIN = "peach.autofill.isWebOrigin"22    const val EXTRA_VERIFIED_DOMAINS = "peach.autofill.verifiedDomains"23    /** Authenticated caller package for web-origin re-verification in the picker. */24    const val EXTRA_CALLER_PACKAGE = "peach.autofill.callerPackage"2526    /** Host-typed username captured by the autofill framework — used to prefill the new-entry editor. */27    const val EXTRA_TYPED_USERNAME = "peach.autofill.typedUsername"28    /** Host-typed email captured by the autofill framework — used to prefill the new-entry editor. */29    const val EXTRA_TYPED_EMAIL = "peach.autofill.typedEmail"3031    /**32     * Sent by [AutofillEntryPickerActivity] to launch MainActivity on the "+ Create33     * new entry" path. The picker cancels itself and starts MainActivity with the34     * origin + typed identity so the user can save a brand-new entry pre-filled with35     * what they had typed on the host page. Carries the same key/value shape as the36     * update notification's [com.peachpasswords.updates.EXTRA_OPEN_UPDATE].37     */38    const val EXTRA_OPEN_NEW_ENTRY = "peach.autofill.openNewEntry"39    const val EXTRA_NEW_ENTRY_URL = "peach.autofill.newEntryUrl"40    const val EXTRA_NEW_ENTRY_USERNAME = "peach.autofill.newEntryUsername"41    const val EXTRA_NEW_ENTRY_EMAIL = "peach.autofill.newEntryEmail"4243    private const val REQ_CHIP = 0xC0DE44    private const val REQ_PICKER = 0xBEEF4546    /** Required attribution for an inline suggestion; tapping it is a no-op. */47    fun noopChipIntent(context: Context): PendingIntent {48        val intent = Intent(context, AutofillEntryPickerActivity::class.java)49        return PendingIntent.getActivity(context, REQ_CHIP, intent, immutableFlags())50    }5152    /** Authentication target for the "Search Peach…" dataset. */53    fun pickerIntentSender(context: Context, parsed: ParsedStructure): IntentSender {54        val intent = Intent(context, AutofillEntryPickerActivity::class.java).apply {55            putExtra(EXTRA_IDENTITY_ID, parsed.identityId)56            putExtra(EXTRA_PASSWORD_ID, parsed.passwordId)57            putExtra(EXTRA_OTP_ID, parsed.otpId)58            putExtra(EXTRA_ORIGIN, parsed.origin)59            putExtra(EXTRA_IS_WEB_ORIGIN, parsed.webDomain != null)60            // Origin trust is re-derived in the picker from raw inputs;61            // carry the authenticated caller package for web-origin re-verification.62            putExtra(EXTRA_CALLER_PACKAGE, parsed.packageName)63            putStringArrayListExtra(EXTRA_VERIFIED_DOMAINS, ArrayList(parsed.verifiedDomains))64            // Mirror the browser's preUsername/preEmail capture so the "+ Create65            // new entry" path can hand the typed identity to the new-entry editor.66            // Empty/blank values are dropped — the picker reads the typed username67            // from the identity field the host anchored on.68            parsed.usernameValue?.trim()?.takeIf { it.isNotBlank() }?.let {69                putExtra(EXTRA_TYPED_USERNAME, it)70            }71            parsed.emailValue?.trim()?.takeIf { it.isNotBlank() }?.let {72                putExtra(EXTRA_TYPED_EMAIL, it)73            }74        }75        // Freezing the sender prevents the host app from rewriting origin76        // extras before the private picker receives them. The picker re-derives77        // origin trust from raw authenticated inputs in-process.78        return PendingIntent.getActivity(context, REQ_PICKER, intent, immutableFlags()).intentSender79    }8081    private fun immutableFlags(): Int =82        PendingIntent.FLAG_UPDATE_CURRENT or83            if (Build.VERSION.SDK_INT >= 23) PendingIntent.FLAG_IMMUTABLE else 08485}