diff options
Diffstat (limited to 'app/src/main/java')
16 files changed, 141 insertions, 42 deletions
diff --git a/app/src/main/java/app/passwordstore/ui/autofill/AutofillPublisherChangedActivity.kt b/app/src/main/java/app/passwordstore/ui/autofill/AutofillPublisherChangedActivity.kt index dd54b8eb..ac85a92a 100644 --- a/app/src/main/java/app/passwordstore/ui/autofill/AutofillPublisherChangedActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/autofill/AutofillPublisherChangedActivity.kt @@ -22,6 +22,9 @@ import app.passwordstore.databinding.ActivityOreoAutofillPublisherChangedBinding import app.passwordstore.util.autofill.AutofillMatcher import app.passwordstore.util.autofill.AutofillPublisherChangedException import app.passwordstore.util.extensions.asLog +import app.passwordstore.util.extensions.getApplicationInfoCompat +import app.passwordstore.util.extensions.getPackageInfoCompat +import app.passwordstore.util.extensions.getParcelableExtraCompat import app.passwordstore.util.extensions.viewBinding import com.github.androidpasswordstore.autofillparser.FormOrigin import com.github.androidpasswordstore.autofillparser.computeCertificatesHash @@ -93,7 +96,8 @@ class AutofillPublisherChangedActivity : AppCompatActivity() { this@AutofillPublisherChangedActivity, FormOrigin.App(appPackage) ) - val fillResponse = intent.getParcelableExtra<FillResponse>(EXTRA_FILL_RESPONSE_AFTER_RESET) + val fillResponse = + intent.getParcelableExtraCompat<FillResponse>(EXTRA_FILL_RESPONSE_AFTER_RESET) setResult( RESULT_OK, Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillResponse) } @@ -106,11 +110,13 @@ class AutofillPublisherChangedActivity : AppCompatActivity() { private fun showPackageInfo() { runCatching { with(binding) { - val packageInfo = packageManager.getPackageInfo(appPackage, PackageManager.GET_META_DATA) + val packageInfo = + packageManager.getPackageInfoCompat(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) + val appInfo = + packageManager.getApplicationInfoCompat(appPackage, PackageManager.GET_META_DATA) warningAppName.text = getString( R.string.oreo_autofill_warning_publisher_app_name, diff --git a/app/src/main/java/app/passwordstore/ui/crypto/BasePgpActivity.kt b/app/src/main/java/app/passwordstore/ui/crypto/BasePgpActivity.kt index b6bb481f..fa85ffdd 100644 --- a/app/src/main/java/app/passwordstore/ui/crypto/BasePgpActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/crypto/BasePgpActivity.kt @@ -10,6 +10,7 @@ import android.content.Intent import android.content.SharedPreferences import android.os.Build import android.os.Bundle +import android.os.PersistableBundle import android.view.WindowManager import androidx.annotation.CallSuper import androidx.annotation.StringRes @@ -68,8 +69,12 @@ open class BasePgpActivity : AppCompatActivity() { ) { val clipboard = clipboard ?: return val clip = ClipData.newPlainText("pgp_handler_result_pm", text) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + clip.description.extras = + PersistableBundle().apply { putBoolean("android.content.extra.IS_SENSITIVE", true) } + } clipboard.setPrimaryClip(clip) - if (showSnackbar) { + if (showSnackbar && Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { snackbar(message = resources.getString(snackbarTextRes)) } } @@ -80,7 +85,7 @@ open class BasePgpActivity : AppCompatActivity() { * clearing the clipboard. */ fun copyPasswordToClipboard(password: String?) { - copyTextToClipboard(password, showSnackbar = false) + copyTextToClipboard(password) val clearAfter = settings.getString(PreferenceKeys.GENERAL_SHOW_TIME)?.toIntOrNull() ?: 45 @@ -95,9 +100,6 @@ open class BasePgpActivity : AppCompatActivity() { } else { startService(service) } - snackbar(message = resources.getString(R.string.clipboard_password_toast_text, clearAfter)) - } else { - snackbar(message = resources.getString(R.string.clipboard_password_no_clear_toast_text)) } } diff --git a/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt b/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt index 7b288ca6..3fb0d52f 100644 --- a/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt @@ -78,7 +78,7 @@ class DecryptActivity : BasePgpActivity() { override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - android.R.id.home -> onBackPressed() + android.R.id.home -> onBackPressedDispatcher.onBackPressed() R.id.edit_password -> editPassword() R.id.share_password_as_plaintext -> shareAsPlaintext() R.id.copy_password -> copyPasswordToClipboard(passwordEntry?.password) diff --git a/app/src/main/java/app/passwordstore/ui/crypto/PasswordCreationActivity.kt b/app/src/main/java/app/passwordstore/ui/crypto/PasswordCreationActivity.kt index b8221a46..8fee21b4 100644 --- a/app/src/main/java/app/passwordstore/ui/crypto/PasswordCreationActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/crypto/PasswordCreationActivity.kt @@ -262,7 +262,7 @@ class PasswordCreationActivity : BasePgpActivity() { when (item.itemId) { android.R.id.home -> { setResult(RESULT_CANCELED) - onBackPressed() + onBackPressedDispatcher.onBackPressed() } R.id.save_password -> { copy = false diff --git a/app/src/main/java/app/passwordstore/ui/folderselect/SelectFolderActivity.kt b/app/src/main/java/app/passwordstore/ui/folderselect/SelectFolderActivity.kt index 009267e2..9ab146fe 100644 --- a/app/src/main/java/app/passwordstore/ui/folderselect/SelectFolderActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/folderselect/SelectFolderActivity.kt @@ -49,7 +49,7 @@ class SelectFolderActivity : AppCompatActivity(R.layout.select_folder_layout) { when (item.itemId) { android.R.id.home -> { setResult(RESULT_CANCELED) - onBackPressed() + onBackPressedDispatcher.onBackPressed() } R.id.crypto_select -> selectFolder() else -> return super.onOptionsItemSelected(item) diff --git a/app/src/main/java/app/passwordstore/ui/git/config/GitConfigActivity.kt b/app/src/main/java/app/passwordstore/ui/git/config/GitConfigActivity.kt index 2b5ecae5..5b9a04be 100644 --- a/app/src/main/java/app/passwordstore/ui/git/config/GitConfigActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/git/config/GitConfigActivity.kt @@ -69,7 +69,7 @@ class GitConfigActivity : BaseGitActivity() { override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { android.R.id.home -> { - onBackPressed() + onBackPressedDispatcher.onBackPressed() true } else -> super.onOptionsItemSelected(item) diff --git a/app/src/main/java/app/passwordstore/ui/git/config/GitServerConfigActivity.kt b/app/src/main/java/app/passwordstore/ui/git/config/GitServerConfigActivity.kt index a7ecd697..a07b409f 100644 --- a/app/src/main/java/app/passwordstore/ui/git/config/GitServerConfigActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/git/config/GitServerConfigActivity.kt @@ -202,7 +202,7 @@ class GitServerConfigActivity : BaseGitActivity() { override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { android.R.id.home -> { - onBackPressed() + onBackPressedDispatcher.onBackPressed() true } else -> super.onOptionsItemSelected(item) diff --git a/app/src/main/java/app/passwordstore/ui/onboarding/activity/OnboardingActivity.kt b/app/src/main/java/app/passwordstore/ui/onboarding/activity/OnboardingActivity.kt index 2fe92098..f5257530 100644 --- a/app/src/main/java/app/passwordstore/ui/onboarding/activity/OnboardingActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/onboarding/activity/OnboardingActivity.kt @@ -6,6 +6,7 @@ package app.passwordstore.ui.onboarding.activity import android.os.Bundle +import androidx.activity.addCallback import androidx.appcompat.app.AppCompatActivity import app.passwordstore.R @@ -14,13 +15,11 @@ class OnboardingActivity : AppCompatActivity(R.layout.activity_onboarding) { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) supportActionBar?.hide() - } - - override fun onBackPressed() { - if (supportFragmentManager.backStackEntryCount == 0) { - finishAffinity() - } else { - super.onBackPressed() + val callback = onBackPressedDispatcher.addCallback(enabled = false) { finishAffinity() } + supportFragmentManager.addOnBackStackChangedListener { + if (supportFragmentManager.backStackEntryCount == 0) { + callback.isEnabled = true + } } } } diff --git a/app/src/main/java/app/passwordstore/ui/passwords/PasswordStore.kt b/app/src/main/java/app/passwordstore/ui/passwords/PasswordStore.kt index 0078f08e..c97782b0 100644 --- a/app/src/main/java/app/passwordstore/ui/passwords/PasswordStore.kt +++ b/app/src/main/java/app/passwordstore/ui/passwords/PasswordStore.kt @@ -4,7 +4,6 @@ */ package app.passwordstore.ui.passwords -import android.annotation.SuppressLint import android.content.ComponentName import android.content.Context import android.content.Intent @@ -14,7 +13,6 @@ import android.view.Menu import android.view.MenuItem import android.view.MenuItem.OnActionExpandListener import android.view.WindowManager -import androidx.activity.result.contract.ActivityResultContracts.RequestPermission import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult import androidx.activity.viewModels import androidx.appcompat.widget.SearchView @@ -77,18 +75,6 @@ class PasswordStore : BaseGitActivity() { ViewModelProvider.AndroidViewModelFactory(application) } - private val storagePermissionRequest = - registerForActivityResult(RequestPermission()) { granted -> - if (granted) checkLocalRepository() - } - - private val directorySelectAction = - registerForActivityResult(StartActivityForResult()) { result -> - if (result.resultCode == RESULT_OK) { - checkLocalRepository() - } - } - private val listRefreshAction = registerForActivityResult(StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { @@ -196,7 +182,6 @@ class PasswordStore : BaseGitActivity() { return super.onKeyDown(keyCode, event) } - @SuppressLint("NewApi") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_pwdstore) @@ -313,12 +298,14 @@ class PasswordStore : BaseGitActivity() { } } R.id.refresh -> refreshPasswordList() - android.R.id.home -> onBackPressed() + android.R.id.home -> onBackPressedDispatcher.onBackPressed() else -> return super.onOptionsItemSelected(item) } return true } + @Deprecated("Deprecated in Java") + @Suppress("DEPRECATION") override fun onBackPressed() { if (getPasswordFragment()?.onBackPressedInActivity() != true) super.onBackPressed() } diff --git a/app/src/main/java/app/passwordstore/ui/settings/SettingsActivity.kt b/app/src/main/java/app/passwordstore/ui/settings/SettingsActivity.kt index 7fc20d5d..e4a9de8c 100644 --- a/app/src/main/java/app/passwordstore/ui/settings/SettingsActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/settings/SettingsActivity.kt @@ -10,6 +10,7 @@ import android.view.MenuItem import androidx.appcompat.app.AppCompatActivity import app.passwordstore.R import app.passwordstore.databinding.ActivityPreferenceRecyclerviewBinding +import app.passwordstore.util.extensions.getParcelableCompat import app.passwordstore.util.extensions.viewBinding import com.google.android.material.dialog.MaterialAlertDialogBuilder import de.Maxr1998.modernpreferences.Preference @@ -84,7 +85,7 @@ class SettingsActivity : AppCompatActivity() { } } savedInstanceState - ?.getParcelable<PreferencesAdapter.SavedState>("adapter") + ?.getParcelableCompat<PreferencesAdapter.SavedState>("adapter") ?.let(adapter::loadSavedState) binding.preferenceRecyclerView.adapter = adapter } @@ -106,6 +107,8 @@ class SettingsActivity : AppCompatActivity() { } } + @Deprecated("Deprecated in Java") + @Suppress("DEPRECATION") override fun onBackPressed() { if (!preferencesAdapter.goBack()) super.onBackPressed() } diff --git a/app/src/main/java/app/passwordstore/ui/sshkeygen/SshKeyGenActivity.kt b/app/src/main/java/app/passwordstore/ui/sshkeygen/SshKeyGenActivity.kt index 8a3d3edf..67528d24 100644 --- a/app/src/main/java/app/passwordstore/ui/sshkeygen/SshKeyGenActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/sshkeygen/SshKeyGenActivity.kt @@ -103,7 +103,7 @@ class SshKeyGenActivity : AppCompatActivity() { override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { android.R.id.home -> { - onBackPressed() + onBackPressedDispatcher.onBackPressed() true } else -> super.onOptionsItemSelected(item) diff --git a/app/src/main/java/app/passwordstore/util/autofill/Api30AutofillResponseBuilder.kt b/app/src/main/java/app/passwordstore/util/autofill/Api30AutofillResponseBuilder.kt index f46d3c1a..997e27b4 100644 --- a/app/src/main/java/app/passwordstore/util/autofill/Api30AutofillResponseBuilder.kt +++ b/app/src/main/java/app/passwordstore/util/autofill/Api30AutofillResponseBuilder.kt @@ -7,9 +7,11 @@ package app.passwordstore.util.autofill import android.content.Context import android.content.IntentSender +import android.os.Build import android.service.autofill.Dataset import android.service.autofill.FillCallback import android.service.autofill.FillResponse +import android.service.autofill.Presentations import android.service.autofill.SaveInfo import android.view.inputmethod.InlineSuggestionsRequest import android.widget.inline.InlinePresentationSpec @@ -61,6 +63,23 @@ constructor( metadata: DatasetMetadata, imeSpec: InlinePresentationSpec?, ): Dataset { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + makeIntentDataSetTiramisu(context, action, intentSender, metadata, imeSpec) + } else { + makeIntentDataSetR(context, action, intentSender, metadata, imeSpec) + } + } + + /** Helper for creating an Autofill [Dataset]s for Android R and above. */ + @RequiresApi(Build.VERSION_CODES.R) + @Suppress("DEPRECATION") + private fun makeIntentDataSetR( + context: Context, + action: AutofillAction, + intentSender: IntentSender, + metadata: DatasetMetadata, + imeSpec: InlinePresentationSpec?, + ): Dataset { return Dataset.Builder(makeRemoteView(context, metadata)).run { fillWith(scenario, action, credentials = null) setAuthentication(intentSender) @@ -74,6 +93,30 @@ constructor( } } + /** Helper for creating Autofill [Dataset]s for Android Tiramisu and above. */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + private fun makeIntentDataSetTiramisu( + context: Context, + action: AutofillAction, + intentSender: IntentSender, + metadata: DatasetMetadata, + imeSpec: InlinePresentationSpec?, + ): Dataset { + val presentationsBuilder = Presentations.Builder() + if (imeSpec != null) { + val inlinePresentation = makeInlinePresentation(context, imeSpec, metadata) + if (inlinePresentation != null) { + presentationsBuilder.setInlinePresentation(inlinePresentation) + } + } + val presentations = presentationsBuilder.build() + return Dataset.Builder(presentations).run { + fillWith(scenario, action, credentials = null) + setAuthentication(intentSender) + build() + } + } + private fun makeMatchDataset( context: Context, file: File, diff --git a/app/src/main/java/app/passwordstore/util/autofill/AutofillResponseBuilder.kt b/app/src/main/java/app/passwordstore/util/autofill/AutofillResponseBuilder.kt index 94a4a564..a198297c 100644 --- a/app/src/main/java/app/passwordstore/util/autofill/AutofillResponseBuilder.kt +++ b/app/src/main/java/app/passwordstore/util/autofill/AutofillResponseBuilder.kt @@ -54,6 +54,7 @@ constructor( private val scenarioSupportsSave = scenario.hasPasswordFieldsToSave private val canBeSaved = saveFlags != null && scenarioSupportsSave + @Suppress("DEPRECATION") private fun makeIntentDataset( context: Context, action: AutofillAction, @@ -212,7 +213,7 @@ constructor( if (Build.VERSION.SDK_INT >= 28) { Dataset.Builder() } else { - Dataset.Builder(makeRemoteView(context, makeEmptyMetadata())) + @Suppress("DEPRECATION") Dataset.Builder(makeRemoteView(context, makeEmptyMetadata())) } return builder.run { if (scenario != null) fillWith(scenario, action, credentials) diff --git a/app/src/main/java/app/passwordstore/util/extensions/AndroidExtensions.kt b/app/src/main/java/app/passwordstore/util/extensions/AndroidExtensions.kt index ebb24a78..948d3827 100644 --- a/app/src/main/java/app/passwordstore/util/extensions/AndroidExtensions.kt +++ b/app/src/main/java/app/passwordstore/util/extensions/AndroidExtensions.kt @@ -10,7 +10,14 @@ import android.content.ClipboardManager import android.content.Context import android.content.Intent import android.content.SharedPreferences +import android.content.pm.ApplicationInfo +import android.content.pm.PackageInfo import android.content.pm.PackageManager +import android.content.pm.PackageManager.ApplicationInfoFlags +import android.content.pm.PackageManager.PackageInfoFlags +import android.os.Build +import android.os.Bundle +import android.os.Parcelable import android.util.Base64 import android.util.TypedValue import android.view.View @@ -132,3 +139,45 @@ fun SharedPreferences.getString(key: String): String? = getString(key, null) fun String.base64(): String { return Base64.encodeToString(encodeToByteArray(), Base64.NO_WRAP) } + +inline fun <reified T> Bundle.getParcelableCompat(key: String): T? { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + getParcelable(key, T::class.java) + } else { + @Suppress("DEPRECATION") getParcelable(key) + } +} + +inline fun <reified T : Parcelable> Bundle.getParcelableArrayListCompat( + key: String +): ArrayList<T>? { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + getParcelableArrayList(key, T::class.java) + } else { + @Suppress("DEPRECATION") getParcelableArrayList(key) + } +} + +inline fun <reified T : Parcelable> Intent.getParcelableExtraCompat(key: String): T? { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + getParcelableExtra(key, T::class.java) + } else { + @Suppress("DEPRECATION") getParcelableExtra(key) + } +} + +fun PackageManager.getPackageInfoCompat(packageName: String, flags: Int): PackageInfo { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + getPackageInfo(packageName, PackageInfoFlags.of(flags.toLong())) + } else { + @Suppress("DEPRECATION") getPackageInfo(packageName, flags) + } +} + +fun PackageManager.getApplicationInfoCompat(packageName: String, flags: Int): ApplicationInfo { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + getApplicationInfo(packageName, ApplicationInfoFlags.of(flags.toLong())) + } else { + @Suppress("DEPRECATION") getApplicationInfo(packageName, flags) + } +} diff --git a/app/src/main/java/app/passwordstore/util/services/ClipboardService.kt b/app/src/main/java/app/passwordstore/util/services/ClipboardService.kt index 3d57e29b..c56c319b 100644 --- a/app/src/main/java/app/passwordstore/util/services/ClipboardService.kt +++ b/app/src/main/java/app/passwordstore/util/services/ClipboardService.kt @@ -39,7 +39,11 @@ class ClipboardService : Service() { when (intent.action) { ACTION_CLEAR -> { clearClipboard() - stopForeground(true) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + stopForeground(STOP_FOREGROUND_REMOVE) + } else { + @Suppress("DEPRECATION") stopForeground(true) + } stopSelf() return super.onStartCommand(intent, flags, startId) } @@ -55,7 +59,11 @@ class ClipboardService : Service() { withContext(Dispatchers.IO) { startTimer(time) } withContext(Dispatchers.Main) { clearClipboard() - stopForeground(true) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + stopForeground(STOP_FOREGROUND_REMOVE) + } else { + @Suppress("DEPRECATION") stopForeground(true) + } stopSelf() } } diff --git a/app/src/main/java/app/passwordstore/util/services/PasswordExportService.kt b/app/src/main/java/app/passwordstore/util/services/PasswordExportService.kt index 536006f6..4d587621 100644 --- a/app/src/main/java/app/passwordstore/util/services/PasswordExportService.kt +++ b/app/src/main/java/app/passwordstore/util/services/PasswordExportService.kt @@ -17,6 +17,7 @@ import androidx.core.content.getSystemService import androidx.documentfile.provider.DocumentFile import app.passwordstore.R import app.passwordstore.data.repo.PasswordRepository +import app.passwordstore.util.extensions.getParcelableExtraCompat import java.time.LocalDateTime import java.time.format.DateTimeFormatter import java.util.Calendar @@ -29,7 +30,7 @@ class PasswordExportService : Service() { if (intent != null) { when (intent.action) { ACTION_EXPORT_PASSWORD -> { - val uri = intent.getParcelableExtra<Uri>("uri") + val uri = intent.getParcelableExtraCompat<Uri>("uri") if (uri != null) { val targetDirectory = DocumentFile.fromTreeUri(applicationContext, uri) |