/* * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved. * SPDX-License-Identifier: GPL-3.0-only */ package dev.msfjarvis.aps.ui.autofill import android.annotation.TargetApi import android.app.PendingIntent import android.content.Context import android.content.Intent import android.content.IntentSender import android.content.pm.PackageManager import android.os.Build import android.os.Bundle import android.service.autofill.FillResponse import android.text.format.DateUtils import android.view.View import android.view.autofill.AutofillManager import androidx.appcompat.app.AppCompatActivity import com.github.androidpasswordstore.autofillparser.FormOrigin import com.github.androidpasswordstore.autofillparser.computeCertificatesHash import com.github.michaelbull.result.onFailure import com.github.michaelbull.result.runCatching import dev.msfjarvis.aps.R import dev.msfjarvis.aps.databinding.ActivityOreoAutofillPublisherChangedBinding import dev.msfjarvis.aps.util.autofill.AutofillMatcher import dev.msfjarvis.aps.util.autofill.AutofillPublisherChangedException import dev.msfjarvis.aps.util.extensions.asLog import dev.msfjarvis.aps.util.extensions.viewBinding import logcat.LogPriority.ERROR import logcat.logcat @TargetApi(Build.VERSION_CODES.O) class AutofillPublisherChangedActivity : AppCompatActivity() { companion object { private const val EXTRA_APP_PACKAGE = "dev.msfjarvis.aps.autofill.oreo.ui.EXTRA_APP_PACKAGE" private const val EXTRA_FILL_RESPONSE_AFTER_RESET = "dev.msfjarvis.aps.autofill.oreo.ui.EXTRA_FILL_RESPONSE_AFTER_RESET" private var publisherChangedRequestCode = 1 fun makePublisherChangedIntentSender( context: Context, publisherChangedException: AutofillPublisherChangedException, fillResponseAfterReset: FillResponse?, ): IntentSender { val intent = Intent(context, AutofillPublisherChangedActivity::class.java).apply { putExtra(EXTRA_APP_PACKAGE, publisherChangedException.formOrigin.identifier) putExtra(EXTRA_FILL_RESPONSE_AFTER_RESET, fillResponseAfterReset) } return PendingIntent.getActivity( context, publisherChangedRequestCode++, intent, if (Build.VERSION.SDK_INT >= 31) { PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE } else { PendingIntent.FLAG_CANCEL_CURRENT }, ) .intentSender } } private lateinit var appPackage: String private val binding by viewBinding(ActivityOreoAutofillPublisherChangedBinding::inflate) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(binding.root) setFinishOnTouchOutside(true) appPackage = intent.getStringExtra(EXTRA_APP_PACKAGE) ?: run { logcat(ERROR) { "AutofillPublisherChangedActivity started without EXTRA_PACKAGE_NAME" } finish() return } supportActionBar?.hide() showPackageInfo() with(binding) { okButton.setOnClickListener { finish() } advancedButton.setOnClickListener { advancedButton.visibility = View.GONE warningAppAdvancedInfo.visibility = View.VISIBLE resetButton.visibility = View.VISIBLE } resetButton.setOnClickListener { AutofillMatcher.clearMatchesFor( this@AutofillPublisherChangedActivity, FormOrigin.App(appPackage) ) val fillResponse = intent.getParcelableExtra(EXTRA_FILL_RESPONSE_AFTER_RESET) setResult( RESULT_OK, Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillResponse) } ) finish() } } } private fun showPackageInfo() { runCatching { with(binding) { val packageInfo = packageManager.getPackageInfo(appPackage, PackageManager.GET_META_DATA) val installTime = DateUtils.getRelativeTimeSpanString(packageInfo.firstInstallTime) warningAppInstallDate.text = getString(R.string.oreo_autofill_warning_publisher_install_time, installTime) val appInfo = packageManager.getApplicationInfo(appPackage, PackageManager.GET_META_DATA) warningAppName.text = getString( R.string.oreo_autofill_warning_publisher_app_name, packageManager.getApplicationLabel(appInfo) ) val currentHash = computeCertificatesHash(this@AutofillPublisherChangedActivity, appPackage) warningAppAdvancedInfo.text = getString( R.string.oreo_autofill_warning_publisher_advanced_info_template, appPackage, currentHash ) } } .onFailure { e -> logcat(ERROR) { e.asLog("Failed to retrieve package info for $appPackage") } finish() } } }