From 1c4925b05d9f50eb91ddc5b563e64fce385365d5 Mon Sep 17 00:00:00 2001 From: cketti Date: Tue, 2 Apr 2024 15:14:23 +0200 Subject: [PATCH] Add support for background activity start mode See https://developer.android.com/about/versions/14/behavior-changes-14#background-activity-restrictions --- .../com/fsck/k9/activity/MessageCompose.java | 12 +-- .../fsck/k9/activity/MessageLoaderHelper.java | 9 +-- .../k9/ui/crypto/MessageCryptoCallback.java | 4 +- .../k9/ui/crypto/MessageCryptoHelper.java | 2 +- .../endtoend/AutocryptKeyTransferActivity.kt | 5 +- .../messagedetails/MessageDetailsFragment.kt | 9 ++- .../messageview/MessageCryptoPresenter.java | 8 +- .../k9/ui/messageview/MessageViewFragment.kt | 37 ++------- .../openpgp/util/OpenPgpIntentStarter.kt | 75 +++++++++++++++++++ .../openpgp/util/OpenPgpKeyPreference.java | 5 +- 10 files changed, 109 insertions(+), 57 deletions(-) create mode 100644 plugins/openpgp-api-lib/openpgp-api/src/main/java/org/openintents/openpgp/util/OpenPgpIntentStarter.kt diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageCompose.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageCompose.java index 327362df2..18fa6d8e3 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageCompose.java +++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageCompose.java @@ -118,6 +118,7 @@ import com.fsck.k9.ui.helper.SizeFormatter; import com.fsck.k9.ui.messagelist.DefaultFolderProvider; import org.openintents.openpgp.OpenPgpApiManager; import org.openintents.openpgp.util.OpenPgpApi; +import org.openintents.openpgp.util.OpenPgpIntentStarter; import timber.log.Timber; @@ -1622,7 +1623,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, public void onMessageBuildReturnPendingIntent(PendingIntent pendingIntent, int requestCode) { requestCode |= REQUEST_MASK_MESSAGE_BUILDER; try { - startIntentSenderForResult(pendingIntent.getIntentSender(), requestCode, null, 0, 0, 0); + OpenPgpIntentStarter.startIntentSenderForResult(this, pendingIntent.getIntentSender(), requestCode); } catch (SendIntentException e) { Timber.e(e, "Error starting pending intent from builder!"); } @@ -1631,9 +1632,9 @@ public class MessageCompose extends K9Activity implements OnClickListener, public void launchUserInteractionPendingIntent(PendingIntent pendingIntent, int requestCode) { requestCode |= REQUEST_MASK_RECIPIENT_PRESENTER; try { - startIntentSenderForResult(pendingIntent.getIntentSender(), requestCode, null, 0, 0, 0); + OpenPgpIntentStarter.startIntentSenderForResult(this, pendingIntent.getIntentSender(), requestCode); } catch (SendIntentException e) { - e.printStackTrace(); + Timber.e(e, "Error starting pending intent from builder!"); } } @@ -1689,11 +1690,10 @@ public class MessageCompose extends K9Activity implements OnClickListener, } @Override - public boolean startIntentSenderForMessageLoaderHelper(IntentSender si, int requestCode, Intent fillIntent, - int flagsMask, int flagValues, int extraFlags) { + public boolean startIntentSenderForMessageLoaderHelper(IntentSender intentSender, int requestCode) { try { requestCode |= REQUEST_MASK_LOADER_HELPER; - startIntentSenderForResult(si, requestCode, fillIntent, flagsMask, flagValues, extraFlags); + OpenPgpIntentStarter.startIntentSenderForResult(MessageCompose.this, intentSender, requestCode); } catch (SendIntentException e) { Timber.e(e, "Irrecoverable error calling PendingIntent!"); } diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageLoaderHelper.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageLoaderHelper.java index 2c905f0cc..7ee2a340f 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageLoaderHelper.java +++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageLoaderHelper.java @@ -357,14 +357,12 @@ public class MessageLoaderHelper { } @Override - public boolean startPendingIntentForCryptoHelper(IntentSender si, int requestCode, Intent fillIntent, - int flagsMask, int flagValues, int extraFlags) { + public boolean startPendingIntentForCryptoHelper(IntentSender intentSender, int requestCode) { if (callback == null) { throw new IllegalStateException("unexpected call when callback is already detached"); } - return callback.startIntentSenderForMessageLoaderHelper(si, requestCode, fillIntent, - flagsMask, flagValues, extraFlags); + return callback.startIntentSenderForMessageLoaderHelper(intentSender, requestCode); } }; @@ -524,8 +522,7 @@ public class MessageLoaderHelper { void setLoadingProgress(int current, int max); - boolean startIntentSenderForMessageLoaderHelper(IntentSender si, int requestCode, Intent fillIntent, - int flagsMask, int flagValues, int extraFlags); + boolean startIntentSenderForMessageLoaderHelper(IntentSender intentSender, int requestCode); void onDownloadErrorMessageNotFound(); void onDownloadErrorNetworkError(); diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoCallback.java b/app/ui/legacy/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoCallback.java index 3df5d0508..95b5d86de 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoCallback.java +++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoCallback.java @@ -1,7 +1,6 @@ package com.fsck.k9.ui.crypto; -import android.content.Intent; import android.content.IntentSender; import com.fsck.k9.mailstore.MessageCryptoAnnotations; @@ -10,6 +9,5 @@ import com.fsck.k9.mailstore.MessageCryptoAnnotations; public interface MessageCryptoCallback { void onCryptoHelperProgress(int current, int max); void onCryptoOperationsFinished(MessageCryptoAnnotations annotations); - boolean startPendingIntentForCryptoHelper(IntentSender si, int requestCode, Intent fillIntent, - int flagsMask, int flagValues, int extraFlags); + boolean startPendingIntentForCryptoHelper(IntentSender intentSender, int requestCode); } diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoHelper.java b/app/ui/legacy/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoHelper.java index 6a30ce138..522f76681 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoHelper.java +++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoHelper.java @@ -795,7 +795,7 @@ public class MessageCryptoHelper { callback.onCryptoOperationsFinished(queuedResult); } else if (queuedPendingIntent != null) { boolean pendingIntentHandled = callback.startPendingIntentForCryptoHelper( - queuedPendingIntent.getIntentSender(), REQUEST_CODE_USER_INTERACTION, null, 0, 0, 0); + queuedPendingIntent.getIntentSender(), REQUEST_CODE_USER_INTERACTION); if (pendingIntentHandled) { queuedPendingIntent = null; } diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/endtoend/AutocryptKeyTransferActivity.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/endtoend/AutocryptKeyTransferActivity.kt index 0da4afc95..0124e9c1d 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/endtoend/AutocryptKeyTransferActivity.kt +++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/endtoend/AutocryptKeyTransferActivity.kt @@ -19,6 +19,7 @@ import com.fsck.k9.view.StatusIndicator import kotlinx.coroutines.delay import org.koin.android.ext.android.inject import org.koin.core.parameter.parametersOf +import org.openintents.openpgp.util.OpenPgpIntentStarter import timber.log.Timber class AutocryptKeyTransferActivity : K9Activity() { @@ -161,9 +162,9 @@ class AutocryptKeyTransferActivity : K9Activity() { fun launchUserInteractionPendingIntent(pendingIntent: PendingIntent) { try { - startIntentSender(pendingIntent.intentSender, null, 0, 0, 0) + OpenPgpIntentStarter.startIntentSender(this, pendingIntent.intentSender) } catch (e: SendIntentException) { - Timber.e(e) + Timber.e(e, "Error starting PendingIntent") } } diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/messagedetails/MessageDetailsFragment.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/messagedetails/MessageDetailsFragment.kt index 336e67d5d..23dc2fd27 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/messagedetails/MessageDetailsFragment.kt +++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/messagedetails/MessageDetailsFragment.kt @@ -2,6 +2,7 @@ package com.fsck.k9.ui.messagedetails import android.app.PendingIntent import android.content.Intent +import android.content.IntentSender.SendIntentException import android.net.Uri import android.os.Bundle import android.view.LayoutInflater @@ -36,6 +37,8 @@ import com.mikepenz.fastadapter.listeners.ClickEventHook import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.core.parameter.parametersOf +import org.openintents.openpgp.util.OpenPgpIntentStarter +import timber.log.Timber class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() { private val viewModel: MessageDetailsViewModel by viewModel() @@ -333,7 +336,11 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() { } private fun showCryptoKeys(pendingIntent: PendingIntent) { - requireActivity().startIntentSender(pendingIntent.intentSender, null, 0, 0, 0) + try { + OpenPgpIntentStarter.startIntentSender(requireActivity(), pendingIntent.intentSender) + } catch (e: SendIntentException) { + Timber.e(e, "Error starting PendingIntent") + } } private fun searchCryptoKeys() { diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageCryptoPresenter.java b/app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageCryptoPresenter.java index 260ff8b81..7907291a1 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageCryptoPresenter.java +++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageCryptoPresenter.java @@ -120,7 +120,7 @@ public class MessageCryptoPresenter { PendingIntent pendingIntent = cryptoResultAnnotation.getOpenPgpSigningKeyIntentIfAny(); if (pendingIntent != null) { messageCryptoMvpView.startPendingIntentForCryptoPresenter( - pendingIntent.getIntentSender(), REQUEST_CODE_UNKNOWN_KEY, null, 0, 0, 0); + pendingIntent.getIntentSender(), REQUEST_CODE_UNKNOWN_KEY); } } catch (IntentSender.SendIntentException e) { Timber.e(e, "SendIntentException"); @@ -136,7 +136,7 @@ public class MessageCryptoPresenter { PendingIntent pendingIntent = cryptoResultAnnotation.getOpenPgpInsecureWarningPendingIntent(); if (pendingIntent != null) { messageCryptoMvpView.startPendingIntentForCryptoPresenter( - pendingIntent.getIntentSender(), REQUEST_CODE_SECURITY_WARNING, null, 0, 0, 0); + pendingIntent.getIntentSender(), REQUEST_CODE_SECURITY_WARNING); } } catch (IntentSender.SendIntentException e) { Timber.e(e, "SendIntentException"); @@ -171,8 +171,8 @@ public class MessageCryptoPresenter { void redisplayMessage(); void restartMessageCryptoProcessing(); - void startPendingIntentForCryptoPresenter(IntentSender si, Integer requestCode, Intent fillIntent, - int flagsMask, int flagValues, int extraFlags) throws IntentSender.SendIntentException; + void startPendingIntentForCryptoPresenter(IntentSender intentSender, Integer requestCode) + throws IntentSender.SendIntentException; void showCryptoConfigDialog(); } diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.kt index 76b883fa8..f01616905 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.kt +++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.kt @@ -54,6 +54,7 @@ import com.fsck.k9.ui.share.ShareIntentBuilder import com.fsck.k9.ui.withArguments import java.util.Locale import org.koin.android.ext.android.inject +import org.openintents.openpgp.util.OpenPgpIntentStarter import timber.log.Timber class MessageViewFragment : @@ -828,24 +829,9 @@ class MessageViewFragment : } @Throws(SendIntentException::class) - override fun startPendingIntentForCryptoPresenter( - intentSender: IntentSender, - requestCode: Int, - fillIntent: Intent?, - flagsMask: Int, - flagValues: Int, - extraFlags: Int, - ) { + override fun startPendingIntentForCryptoPresenter(intentSender: IntentSender, requestCode: Int) { val maskedRequestCode = requestCode or REQUEST_MASK_CRYPTO_PRESENTER - startIntentSenderForResult( - intentSender, - maskedRequestCode, - fillIntent, - flagsMask, - flagValues, - extraFlags, - null, - ) + OpenPgpIntentStarter.startIntentSenderForResult(this@MessageViewFragment, intentSender, maskedRequestCode) } override fun restartMessageCryptoProcessing() { @@ -921,27 +907,16 @@ class MessageViewFragment : Toast.makeText(requireContext(), R.string.status_network_error, Toast.LENGTH_LONG).show() } - override fun startIntentSenderForMessageLoaderHelper( - intentSender: IntentSender, - requestCode: Int, - fillIntent: Intent?, - flagsMask: Int, - flagValues: Int, - extraFlags: Int, - ): Boolean { + override fun startIntentSenderForMessageLoaderHelper(intentSender: IntentSender, requestCode: Int): Boolean { if (!isActive) return false showProgressThreshold = null try { val maskedRequestCode = requestCode or REQUEST_MASK_LOADER_HELPER - startIntentSenderForResult( + OpenPgpIntentStarter.startIntentSenderForResult( + this@MessageViewFragment, intentSender, maskedRequestCode, - fillIntent, - flagsMask, - flagValues, - extraFlags, - null, ) } catch (e: SendIntentException) { Timber.e(e, "Irrecoverable error calling PendingIntent!") diff --git a/plugins/openpgp-api-lib/openpgp-api/src/main/java/org/openintents/openpgp/util/OpenPgpIntentStarter.kt b/plugins/openpgp-api-lib/openpgp-api/src/main/java/org/openintents/openpgp/util/OpenPgpIntentStarter.kt new file mode 100644 index 000000000..36dd12354 --- /dev/null +++ b/plugins/openpgp-api-lib/openpgp-api/src/main/java/org/openintents/openpgp/util/OpenPgpIntentStarter.kt @@ -0,0 +1,75 @@ +package org.openintents.openpgp.util + +import android.app.Activity +import android.app.ActivityOptions +import android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED +import android.content.IntentSender +import android.os.Build +import android.os.Bundle +import androidx.annotation.RequiresApi +import androidx.fragment.app.Fragment + +/** + * Start OpenPGP crypto provider intents. + * + * On Android 14+ we need to use [MODE_BACKGROUND_ACTIVITY_START_ALLOWED] in order to start those intents. + */ +object OpenPgpIntentStarter { + @Throws(IntentSender.SendIntentException::class) + fun startIntentSender(activity: Activity, intentSender: IntentSender) { + val options = buildOptionsBundle() + + activity.startIntentSender( + intentSender, + /* fillInIntent = */ null, + /* flagsMask = */ 0, + /* flagsValues = */ 0, + /* extraFlags = */ 0, + options, + ) + } + + @JvmStatic + @Throws(IntentSender.SendIntentException::class) + fun startIntentSenderForResult(activity: Activity, intentSender: IntentSender, requestCode: Int) { + val options = buildOptionsBundle() + + activity.startIntentSenderForResult( + intentSender, + requestCode, + /* fillInIntent = */ null, + /* flagsMask = */ 0, + /* flagsValues = */ 0, + /* extraFlags = */ 0, + options, + ) + } + + @JvmStatic + @Throws(IntentSender.SendIntentException::class) + fun startIntentSenderForResult(fragment: Fragment, intentSender: IntentSender, requestCode: Int) { + val options = buildOptionsBundle() + + @Suppress("DEPRECATION") + fragment.startIntentSenderForResult( + intentSender, + requestCode, + /* fillInIntent = */ null, + /* flagsMask = */ 0, + /* flagsValues = */ 0, + /* extraFlags = */ 0, + options, + ) + } + + private fun buildOptionsBundle(): Bundle? { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + ActivityOptions.makeBasic().apply { + setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED) + setShareIdentityEnabled(true) + }.toBundle() + } else { + null + } + } +} diff --git a/plugins/openpgp-api-lib/openpgp-api/src/main/java/org/openintents/openpgp/util/OpenPgpKeyPreference.java b/plugins/openpgp-api-lib/openpgp-api/src/main/java/org/openintents/openpgp/util/OpenPgpKeyPreference.java index b00ba409e..3e6f1eea8 100644 --- a/plugins/openpgp-api-lib/openpgp-api/src/main/java/org/openintents/openpgp/util/OpenPgpKeyPreference.java +++ b/plugins/openpgp-api-lib/openpgp-api/src/main/java/org/openintents/openpgp/util/OpenPgpKeyPreference.java @@ -196,9 +196,8 @@ public class OpenPgpKeyPreference extends Preference implements OpenPgpApiManage } try { - intentSenderFragment - .startIntentSenderForResult(pendingIntentSelectKey.getIntentSender(), REQUEST_CODE_KEY_PREFERENCE, - null, 0, 0, 0, null); + OpenPgpIntentStarter.startIntentSenderForResult(intentSenderFragment, + pendingIntentSelectKey.getIntentSender(), REQUEST_CODE_KEY_PREFERENCE); } catch (IntentSender.SendIntentException e) { Timber.e(e,"Error launching pending intent"); } finally {