From 65034d105e704cb46097a3f2b07f6e425106b7df Mon Sep 17 00:00:00 2001 From: oakkitten Date: Mon, 25 Sep 2023 15:25:36 +0100 Subject: [PATCH 1/8] Specify foreground service type in manifest Needed to target API 34 This type seems to be the most suitable for what we do. Note, however, that the documentation says: In a future version of Android, this foreground service type will be deprecated. It's recommended that you migrate to use either WorkManager or user-initiated data transfer jobs. See https://developer.android.com/about/versions/14/changes/fgs-types-required --- app/src/main/AndroidManifest.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 543ba335..b9d08dc7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ + @@ -33,7 +34,9 @@ android:requestLegacyExternalStorage="true" android:windowSoftInputMode="adjustResize"> - + Date: Mon, 25 Sep 2023 13:39:24 +0100 Subject: [PATCH 2/8] Request permission to schedule exact alarms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Android 12 (API 31) introduced a new permission to schedule exact alarms. It wasn't a big deal then as it was granted by default for new apps. Still, it could be removed by the user. More importantly, since Android 14 (34) apps targeting Android ≥ 13 no longer get this permission by default. So now when user is trying to connect and we lack this permission, we explain the rationale for the permission to the user, and request it, also informing the user that they may forgo the permission by disable pinging. See https://developer.android.com/about/versions/14/changes/schedule-exact-alarms --- .../WeechatAndroid/WeechatActivity.kt | 23 +++-- .../dialogs/ScrollableDialog.kt | 89 +++++++++++++++++++ .../WeechatAndroid/service/PingingPenguin.kt | 45 +++++++++- app/src/main/res/values/strings.xml | 7 ++ 4 files changed, 153 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/com/ubergeek42/WeechatAndroid/dialogs/ScrollableDialog.kt diff --git a/app/src/main/java/com/ubergeek42/WeechatAndroid/WeechatActivity.kt b/app/src/main/java/com/ubergeek42/WeechatAndroid/WeechatActivity.kt index c8c67a64..3a0431c6 100644 --- a/app/src/main/java/com/ubergeek42/WeechatAndroid/WeechatActivity.kt +++ b/app/src/main/java/com/ubergeek42/WeechatAndroid/WeechatActivity.kt @@ -61,6 +61,8 @@ import com.ubergeek42.WeechatAndroid.service.Events.StateChangedEvent import com.ubergeek42.WeechatAndroid.service.P import com.ubergeek42.WeechatAndroid.service.RelayService import com.ubergeek42.WeechatAndroid.service.getSystemTrustedCertificateChain +import com.ubergeek42.WeechatAndroid.service.showAlarmPermissionRationaleDialog +import com.ubergeek42.WeechatAndroid.service.shouldRequestExactAlarmPermission import com.ubergeek42.WeechatAndroid.upload.Config import com.ubergeek42.WeechatAndroid.upload.InsertAt import com.ubergeek42.WeechatAndroid.upload.ShareObject @@ -199,7 +201,7 @@ class WeechatActivity : AppCompatActivity(), CutePageChangeListener, menuBackgroundDrawable = ContextCompat.getDrawable(this, R.drawable.bg_popup_menu)!! - if (P.isServiceAlive()) connect() + if (savedInstanceState == null && P.isServiceAlive()) connect() // restore buffers if we have data in the static // if no data and not going to connect, clear stuff @@ -213,13 +215,20 @@ class WeechatActivity : AppCompatActivity(), CutePageChangeListener, @MainThread @CatD(linger = true) fun connect() { P.loadConnectionPreferences() - val error = P.validateConnectionPreferences() - if (error != 0) { - Toaster.ErrorToast.show(error) - } else { - kitty.debug("proceeding!") - RelayService.startWithAction(this, RelayService.ACTION_START) + + val errorStringId = P.validateConnectionPreferences() + if (errorStringId != 0) { + Toaster.ErrorToast.show(errorStringId) + return } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && shouldRequestExactAlarmPermission()) { + showAlarmPermissionRationaleDialog() + return + } + + kitty.debug("proceeding!") + RelayService.startWithAction(this, RelayService.ACTION_START) } @MainThread @CatD fun disconnect() { diff --git a/app/src/main/java/com/ubergeek42/WeechatAndroid/dialogs/ScrollableDialog.kt b/app/src/main/java/com/ubergeek42/WeechatAndroid/dialogs/ScrollableDialog.kt new file mode 100644 index 00000000..03409ccf --- /dev/null +++ b/app/src/main/java/com/ubergeek42/WeechatAndroid/dialogs/ScrollableDialog.kt @@ -0,0 +1,89 @@ +package com.ubergeek42.WeechatAndroid.dialogs + +import android.app.Dialog +import android.content.Context +import android.widget.ScrollView +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.widget.AppCompatTextView +import com.ubergeek42.WeechatAndroid.R + +private class ButtonInfo( + val title: CharSequence, + val onClickListener: () -> Unit +) + +private class ScrollableDialogInfo( + var text: CharSequence? = null, + var title: CharSequence? = null, + var positiveButton: ButtonInfo? = null, + var negativeButton: ButtonInfo? = null, +) + +interface ScrollableDialogBuilder { + fun setTitle(title: CharSequence) + fun setTitle(titleResourceId: Int) + fun setText(text: CharSequence) + fun setText(textResourceId: Int) + fun setPositiveButton(title: CharSequence, onClickListener: () -> Unit) + fun setPositiveButton(titleResourceId: Int, onClickListener: () -> Unit) + fun setNegativeButton(title: CharSequence, onClickListener: () -> Unit) + fun setNegativeButton(titleResourceId: Int, onClickListener: () -> Unit) +} + +private class ScrollableDialogBuilderImpl(val context: Context) : ScrollableDialogBuilder { + val info = ScrollableDialogInfo() + override fun setTitle(title: CharSequence) { + info.title = title + } + + override fun setTitle(titleResourceId: Int) { + info.title = context.getString(titleResourceId) + } + + override fun setText(text: CharSequence) { + info.text = text + } + + override fun setText(textResourceId: Int) { + info.text = context.getString(textResourceId) + } + + override fun setPositiveButton(title: CharSequence, onClickListener: () -> Unit) { + info.positiveButton = ButtonInfo(title, onClickListener) + } + + override fun setPositiveButton(titleResourceId: Int, onClickListener: () -> Unit) { + info.positiveButton = ButtonInfo(context.getString(titleResourceId), onClickListener) + } + + override fun setNegativeButton(title: CharSequence, onClickListener: () -> Unit) { + info.negativeButton = ButtonInfo(title, onClickListener) + } + + override fun setNegativeButton(titleResourceId: Int, onClickListener: () -> Unit) { + info.negativeButton = ButtonInfo(context.getString(titleResourceId), onClickListener) + } +} + +fun Context.createScrollableDialog(builderBlock: ScrollableDialogBuilder.() -> Unit): Dialog { + val info = ScrollableDialogBuilderImpl(this).apply(builderBlock).info + + val padding = resources.getDimension(R.dimen.dialog_padding_full).toInt() + val scrollView = ScrollView(this) + scrollView.addView(AppCompatTextView(this).apply { text = info.text }) + scrollView.setPadding(padding, padding / 2, padding, 0) + + val builder: AlertDialog.Builder = FancyAlertDialogBuilder(this) + .setTitle(info.title) + .setView(scrollView) + + info.positiveButton?.let { + builder.setPositiveButton(it.title) { _, _ -> it.onClickListener() } + } + + info.negativeButton?.let { + builder.setNegativeButton(it.title) { _, _ -> it.onClickListener() } + } + + return builder.create() +} diff --git a/app/src/main/java/com/ubergeek42/WeechatAndroid/service/PingingPenguin.kt b/app/src/main/java/com/ubergeek42/WeechatAndroid/service/PingingPenguin.kt index ea19f312..b0c5f427 100644 --- a/app/src/main/java/com/ubergeek42/WeechatAndroid/service/PingingPenguin.kt +++ b/app/src/main/java/com/ubergeek42/WeechatAndroid/service/PingingPenguin.kt @@ -19,11 +19,22 @@ import android.app.PendingIntent import android.content.BroadcastReceiver import android.content.Context import android.content.Intent +import android.os.Build +import android.os.Bundle import android.os.SystemClock +import android.provider.Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM import androidx.annotation.AnyThread import androidx.annotation.MainThread +import androidx.annotation.RequiresApi import androidx.annotation.WorkerThread +import androidx.core.content.getSystemService +import androidx.core.net.toUri +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.FragmentActivity +import com.ubergeek42.WeechatAndroid.R +import com.ubergeek42.WeechatAndroid.dialogs.createScrollableDialog import com.ubergeek42.WeechatAndroid.upload.applicationContext +import com.ubergeek42.cats.Cat import com.ubergeek42.cats.Kitty import com.ubergeek42.cats.Root @@ -69,7 +80,12 @@ class PingingPenguin(val relayService: RelayService) { private fun scheduleTick(tick: Tick, at: Long) { lastTick = tick - alarmManager?.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, at, pendingPingIntent) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !alarmManager.canScheduleExactAlarms()) { + kitty.error("Can't schedule exact alarms, so pinging mechanism won't work") + } else { + alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, at, pendingPingIntent) + } } } @@ -92,7 +108,7 @@ class PingBroadcastReceiver : BroadcastReceiver() { private fun unschedulePings() { PendingIntent.getBroadcast(applicationContext, 0, pingIntent, PendingIntent.FLAG_NO_CREATE or PendingIntent.FLAG_IMMUTABLE) - ?.let { alarmManager?.cancel(it) } + ?.let { alarmManager.cancel(it) } } @@ -103,5 +119,26 @@ private val pingIntent = Intent(applicationContext, PingBroadcastReceiver::class private val pendingPingIntent = PendingIntent.getBroadcast(applicationContext, 0, pingIntent, PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE) -private val alarmManager = applicationContext - .getSystemService(Context.ALARM_SERVICE) as AlarmManager? +private val alarmManager = applicationContext.getSystemService()!! + +@RequiresApi(Build.VERSION_CODES.S) +class ExactAlarmPermissionRationaleDialogFragment : DialogFragment() { + override fun onCreateDialog(savedInstanceState: Bundle?) = requireActivity().run { + createScrollableDialog { + setTitle(R.string.dialog__alarm_permission_for_ping__title) + setText(R.string.dialog__alarm_permission_for_ping__text) + setPositiveButton(R.string.dialog__notification_permission__positive_button) { + startActivity(Intent(ACTION_REQUEST_SCHEDULE_EXACT_ALARM, "package:$packageName".toUri())) + } + } + } +} + +@RequiresApi(Build.VERSION_CODES.S) +fun shouldRequestExactAlarmPermission() = P.pingEnabled && !alarmManager.canScheduleExactAlarms() + +@RequiresApi(Build.VERSION_CODES.S) +@Cat fun FragmentActivity.showAlarmPermissionRationaleDialog() { + ExactAlarmPermissionRationaleDialogFragment() + .show(supportFragmentManager, "alarm-permission-for-ping-dialog") +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5c929faf..3ef73e25 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -182,6 +182,13 @@ To take photos, app needs write access to public storage OK + + Permission required + + Pinging machinery needs the permission to set exact alarms. + Alternatively, you can disable pinging in connection settings. + Grant permission + From 9d2eab8e464ec6227b1aca9fef3ba35eea0b965e Mon Sep 17 00:00:00 2001 From: oakkitten Date: Mon, 25 Sep 2023 17:43:57 +0100 Subject: [PATCH 3/8] Request permission to show notifications --- app/src/main/AndroidManifest.xml | 1 + .../WeechatAndroid/WeechatActivity.kt | 15 +++ .../notifications/Notificator.kt | 105 +++++++++++++++++- app/src/main/res/values/strings.xml | 20 +++- 4 files changed, 138 insertions(+), 3 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b9d08dc7..0dd40523 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,6 +13,7 @@ android:maxSdkVersion="28" /> + diff --git a/app/src/main/java/com/ubergeek42/WeechatAndroid/WeechatActivity.kt b/app/src/main/java/com/ubergeek42/WeechatAndroid/WeechatActivity.kt index 3a0431c6..c6c7b416 100644 --- a/app/src/main/java/com/ubergeek42/WeechatAndroid/WeechatActivity.kt +++ b/app/src/main/java/com/ubergeek42/WeechatAndroid/WeechatActivity.kt @@ -13,6 +13,7 @@ // limitations under the License. package com.ubergeek42.WeechatAndroid +import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.content.res.Configuration @@ -53,7 +54,10 @@ import com.ubergeek42.WeechatAndroid.dialogs.ScrollableDialog import com.ubergeek42.WeechatAndroid.fragments.BufferFragment import com.ubergeek42.WeechatAndroid.fragments.BufferFragmentContainer import com.ubergeek42.WeechatAndroid.media.CachePersist +import com.ubergeek42.WeechatAndroid.notifications.NotificationPermissionChecker import com.ubergeek42.WeechatAndroid.notifications.shortcuts +import com.ubergeek42.WeechatAndroid.notifications.shouldRequestNotificationPermission +import com.ubergeek42.WeechatAndroid.notifications.showNotificationPermissionRationaleDialog import com.ubergeek42.WeechatAndroid.notifications.statistics import com.ubergeek42.WeechatAndroid.relay.BufferList import com.ubergeek42.WeechatAndroid.service.Events.ExceptionEvent @@ -129,6 +133,11 @@ class WeechatActivity : AppCompatActivity(), CutePageChangeListener, private val toolbarController = ToolbarController(this).apply { observeLifecycle() } + val notificationPermissionChecker = when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> NotificationPermissionChecker(this) + else -> null + } + init { WeechatActivityFullScreenController(this).observeLifecycle() } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -227,6 +236,12 @@ class WeechatActivity : AppCompatActivity(), CutePageChangeListener, return } + @SuppressLint("NewApi") // notificationPermissionChecker is null on incompatible APIs + if (shouldRequestNotificationPermission()) { + showNotificationPermissionRationaleDialog() + return + } + kitty.debug("proceeding!") RelayService.startWithAction(this, RelayService.ACTION_START) } diff --git a/app/src/main/java/com/ubergeek42/WeechatAndroid/notifications/Notificator.kt b/app/src/main/java/com/ubergeek42/WeechatAndroid/notifications/Notificator.kt index 8e2c8c9b..2c7848bb 100644 --- a/app/src/main/java/com/ubergeek42/WeechatAndroid/notifications/Notificator.kt +++ b/app/src/main/java/com/ubergeek42/WeechatAndroid/notifications/Notificator.kt @@ -2,7 +2,9 @@ // you may not use this file except in compliance with the License. package com.ubergeek42.WeechatAndroid.notifications +import android.Manifest.permission.POST_NOTIFICATIONS import android.app.Activity +import android.app.Dialog import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager @@ -12,10 +14,13 @@ import android.app.PendingIntent import android.content.BroadcastReceiver import android.content.Context import android.content.Intent +import android.content.pm.PackageManager.PERMISSION_GRANTED import android.net.Uri import android.os.Build +import android.os.Bundle import android.os.Handler import android.os.HandlerThread +import androidx.activity.result.contract.ActivityResultContracts.RequestPermission import androidx.annotation.AnyThread import androidx.annotation.MainThread import androidx.annotation.RequiresApi @@ -23,9 +28,15 @@ import androidx.core.app.NotificationCompat import androidx.core.app.Person import androidx.core.app.RemoteInput import androidx.core.content.LocusIdCompat +import androidx.core.content.edit +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.FragmentActivity +import androidx.preference.PreferenceManager import com.ubergeek42.WeechatAndroid.BubbleActivity import com.ubergeek42.WeechatAndroid.R +import com.ubergeek42.WeechatAndroid.Weechat import com.ubergeek42.WeechatAndroid.WeechatActivity +import com.ubergeek42.WeechatAndroid.dialogs.createScrollableDialog import com.ubergeek42.WeechatAndroid.relay.BufferList import com.ubergeek42.WeechatAndroid.relay.as0x import com.ubergeek42.WeechatAndroid.relay.from0xOrNull @@ -38,7 +49,6 @@ import com.ubergeek42.WeechatAndroid.utils.Toaster import com.ubergeek42.cats.Cat import com.ubergeek42.cats.Kitty import com.ubergeek42.cats.Root - import kotlin.apply import kotlin.apply as apply2 @@ -810,4 +820,95 @@ private fun willBubble(fullName: String): Boolean { // We can only detect this on Android S+ PackageBubblingSetting.NothingCanBubble -> false } -} \ No newline at end of file +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// Permission +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// We show the rationale for the notification permission before requesting it. +// If the user approves, or denies it, we proceed, and never ask again. +// If they dismiss the system permission dialog, we ask again. + +// Regarding the behavior of `shouldShowRequestPermissionRationale` in practice: +// +// When the permission is requested and *denied* repeatedly, on API 34 we can observe: +// * Before the first permission request, should-show-rationale is false; +// * The first time permission is requested, permission dialog is shown, +// and after should-show-rationale is true; +// * The second time, permission dialog is shown, and after should-show-rationale is false; +// * The third time, permission dialog is not shown, and after should-show-rationale is false. +// +// However, when the user dismisses the dialog without pressing any buttons, +// `granted` is false and also should-show-rationale is false. +// Dismissals also don't seem to count towards any limits. +// +// Also note that if the user approves and denies the permission *in app settings*, +// it will count as a single denied permission request, that is: +// * Before the first permission request, should-show-rationale is true; +// * The first time permission is requested, permission dialog is shown, +// and after it is denied, should-show-rationale is false. +// However, just like above, if the dialog is dismissed, should-show-rationale remains true. +// +// Therefore, to catch the *first* time user denies the permission *in the dialog*, +// we should check whether `granted` is false, +// and also that should-show-rationale flips in the process. +// +// I wonder if this covers all workflows... This is exhausting + +private var oldShouldShowRequestPermissionRationale = false + +// Recreated with activity, so must be largely stateless +@RequiresApi(Build.VERSION_CODES.TIRAMISU) +class NotificationPermissionChecker(private val activity: WeechatActivity) { + private val shouldShowRequestPermissionRationale get() = + activity.shouldShowRequestPermissionRationale(POST_NOTIFICATIONS) + + private val requestLauncher = activity.registerForActivityResult(RequestPermission()) { granted -> + if (!granted && shouldShowRequestPermissionRationale != oldShouldShowRequestPermissionRationale) { + permissionWasDeniedOnce = true + } + activity.connect() + } + + fun requestNotificationPermission() { + oldShouldShowRequestPermissionRationale = shouldShowRequestPermissionRationale + requestLauncher.launch(POST_NOTIFICATIONS) + } +} + +private val preferences by lazy { PreferenceManager.getDefaultSharedPreferences(Weechat.applicationContext) } + +private var permissionWasDeniedOnce: Boolean + get() = preferences.getBoolean("notificationPermissionWasDeniedOnce", false) + set(value) { preferences.edit { putBoolean("notificationPermissionWasDeniedOnce", value) } } + +@RequiresApi(Build.VERSION_CODES.TIRAMISU) +class NotificationPermissionRationaleDialogFragment : DialogFragment() { + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return requireContext().createScrollableDialog { + setTitle(R.string.dialog__notification_permission__title) + setText(R.string.dialog__notification_permission__text) + setPositiveButton(R.string.dialog__notification_permission__positive_button) { + (requireActivity() as WeechatActivity) + .notificationPermissionChecker!! + .requestNotificationPermission() + + } + setNegativeButton(R.string.dialog__notification_permission__negative_button) { + permissionWasDeniedOnce = true + (requireActivity() as WeechatActivity).connect() + } + } + } +} + +@RequiresApi(Build.VERSION_CODES.TIRAMISU) +fun Activity.shouldRequestNotificationPermission() = + checkSelfPermission(POST_NOTIFICATIONS) != PERMISSION_GRANTED && !permissionWasDeniedOnce + +@RequiresApi(Build.VERSION_CODES.TIRAMISU) +fun FragmentActivity.showNotificationPermissionRationaleDialog() { + NotificationPermissionRationaleDialogFragment() + .show(supportFragmentManager, "notification-permission-dialog") +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3ef73e25..c36d841a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -117,7 +117,7 @@ - Connection Status + Connection status Hotlist Waiting for network @@ -189,6 +189,24 @@ Alternatively, you can disable pinging in connection settings. Grant permission + Permission wanted + + To show notifications, we need a permission. + This is optional. + If you don’t enable notifications now, you can always enable them later in the settings. + \n + \nWhen connected, a persistent notification is shown. + To hide it from the status bar, + we suggest that you enable notification minimization for the category “Connection status”. + \n + \nYou can also customize notifications for individual buffers, changing sound, vibration, etc. + To do this, when you have received a notification for the corresponding buffer, + long tap it and go to settings. + + Grant permission + + Continue without granting permission + From a0a2f6086f141ec211b9dae9b64737b364d29e77 Mon Sep 17 00:00:00 2001 From: oakkitten Date: Mon, 25 Sep 2023 15:50:16 +0100 Subject: [PATCH 4/8] Bump SDK version to 34 & update libraries Note that AspectJ is not updated. Updating it to 1.9.21, the latest version at the moment, leads to a debug build-only compilation error, traceback given below. I do not want to investigate this further, as we should be moving away from AspectJ. While it is neat, the next iteration of AGP removes the Transform API, which we are using for weaving, and I don't think there's a suitable replacement. With most error-prone parts of the app taken care of, we should just move onto something less sophisticated, and less home-brewed. > Task :app:dexBuilderDebug FAILED AGPBI: {"kind":"error","text":"java.lang.NullPointerException: Cannot invoke \"String.length()\" because \"\" is null","sources":[{"file":"~\\.gradle\\caches\\transforms-3\\4082e14c9c25a7a4e013c136023ccb8e\\transformed\\jetified-aspectjrt-1.9.21.jar"}],"tool":"D8"} FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':app:dexBuilderDebug'. > Could not resolve all files for configuration ':app:detachedConfiguration24'. > Failed to transform jetified-aspectjrt-1.9.21.jar to match attributes {artifactType=ext-dex-dexBuilderDebug, org.gradle.libraryelements=jar, org.gradle.usage=java-runtime}. > Execution failed for DexingExternalLibArtifactTransform: ~\.gradle\caches\transforms-3\4082e14c9c25a7a4e013c136023ccb8e\transformed\jetified-aspectjrt-1.9.21.jar. > Error while dexing. * Try: > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. * Exception is: org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:dexBuilderDebug'. at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:38) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52) at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:69) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:327) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:314) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:307) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:293) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:417) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:339) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48) Caused by: org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$ArtifactResolveException: Could not resolve all files for configuration ':app:detachedConfiguration24'. at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.rethrowFailure(DefaultConfiguration.java:1524) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.access$3700(DefaultConfiguration.java:159) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$DefaultResolutionHost.rethrowFailure(DefaultConfiguration.java:2174) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationFileCollection.visitContents(DefaultConfiguration.java:1496) at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:375) at org.gradle.api.internal.file.collections.DefaultConfigurableFileCollection.lambda$calculateFinalizedValue$0(DefaultConfigurableFileCollection.java:241) at org.gradle.api.internal.file.collections.UnpackingVisitor.add(UnpackingVisitor.java:64) at org.gradle.api.internal.file.collections.DefaultConfigurableFileCollection$UnresolvedItemsCollector.visitContents(DefaultConfigurableFileCollection.java:372) at org.gradle.api.internal.file.collections.DefaultConfigurableFileCollection.calculateFinalizedValue(DefaultConfigurableFileCollection.java:241) at org.gradle.api.internal.file.collections.DefaultConfigurableFileCollection.visitChildren(DefaultConfigurableFileCollection.java:277) at org.gradle.api.internal.file.CompositeFileCollection.visitContents(CompositeFileCollection.java:119) at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:375) at org.gradle.api.internal.file.CompositeFileCollection.lambda$visitContents$0(CompositeFileCollection.java:119) at org.gradle.api.internal.file.collections.UnpackingVisitor.add(UnpackingVisitor.java:64) at org.gradle.api.internal.file.collections.UnpackingVisitor.add(UnpackingVisitor.java:89) at org.gradle.api.internal.file.DefaultFileCollectionFactory$ResolvingFileCollection.visitChildren(DefaultFileCollectionFactory.java:333) at org.gradle.api.internal.file.CompositeFileCollection.visitContents(CompositeFileCollection.java:119) at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:375) at org.gradle.api.internal.file.CompositeFileCollection.lambda$visitContents$0(CompositeFileCollection.java:119) at org.gradle.api.internal.tasks.PropertyFileCollection.visitChildren(PropertyFileCollection.java:48) at org.gradle.api.internal.file.CompositeFileCollection.visitContents(CompositeFileCollection.java:119) at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:375) at org.gradle.internal.fingerprint.impl.DefaultFileCollectionSnapshotter.snapshot(DefaultFileCollectionSnapshotter.java:51) at org.gradle.internal.execution.fingerprint.impl.DefaultInputFingerprinter$InputCollectingVisitor.visitInputFileProperty(DefaultInputFingerprinter.java:131) at org.gradle.api.internal.tasks.execution.TaskExecution.visitRegularInputs(TaskExecution.java:322) at org.gradle.internal.execution.fingerprint.impl.DefaultInputFingerprinter.fingerprintInputProperties(DefaultInputFingerprinter.java:61) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.captureExecutionStateWithOutputs(CaptureStateBeforeExecutionStep.java:193) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.lambda$captureExecutionState$1(CaptureStateBeforeExecutionStep.java:141) at org.gradle.internal.execution.steps.BuildOperationStep$1.call(BuildOperationStep.java:37) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73) at org.gradle.internal.execution.steps.BuildOperationStep.operation(BuildOperationStep.java:34) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.captureExecutionState(CaptureStateBeforeExecutionStep.java:130) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.lambda$execute$0(CaptureStateBeforeExecutionStep.java:75) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:75) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:50) at org.gradle.internal.execution.steps.SkipEmptyWorkStep.executeWithNoEmptySources(SkipEmptyWorkStep.java:254) at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:91) at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:56) at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:32) at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:21) at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38) at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:43) at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:31) at org.gradle.internal.execution.steps.AssignWorkspaceStep.lambda$execute$0(AssignWorkspaceStep.java:40) at org.gradle.api.internal.tasks.execution.TaskExecution$4.withWorkspace(TaskExecution.java:281) at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:40) at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:30) at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:37) at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:27) at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:44) at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:33) at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:76) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:139) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:128) at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:77) at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46) at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51) at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57) at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56) at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52) at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:69) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:327) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:314) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:307) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:293) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:417) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:339) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48) Caused by: org.gradle.api.internal.artifacts.transform.TransformException: Failed to transform jetified-aspectjrt-1.9.21.jar to match attributes {artifactType=ext-dex-dexBuilderDebug, org.gradle.libraryelements=jar, org.gradle.usage=java-runtime}. at org.gradle.api.internal.artifacts.transform.TransformingAsyncArtifactListener$TransformedArtifact.lambda$visit$2(TransformingAsyncArtifactListener.java:232) at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:282) at org.gradle.api.internal.artifacts.transform.TransformingAsyncArtifactListener$TransformedArtifact.visit(TransformingAsyncArtifactListener.java:224) at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ParallelResolveArtifactSet$VisitingSet$StartVisitAction.visitResults(ParallelResolveArtifactSet.java:100) at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ParallelResolveArtifactSet$VisitingSet.visit(ParallelResolveArtifactSet.java:69) at org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration.visitArtifacts(DefaultLenientConfiguration.java:301) at org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration.access$600(DefaultLenientConfiguration.java:75) at org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$3.run(DefaultLenientConfiguration.java:249) at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29) at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68) at org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration.visitArtifactsWithBuildOperation(DefaultLenientConfiguration.java:246) at org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration.access$300(DefaultLenientConfiguration.java:75) at org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$2.lambda$visitArtifacts$0(DefaultLenientConfiguration.java:149) at org.gradle.internal.work.DefaultWorkerLeaseService.runAsUnmanagedWorkerThread(DefaultWorkerLeaseService.java:121) at org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$2.visitArtifacts(DefaultLenientConfiguration.java:149) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationFileCollection.visitContents(DefaultConfiguration.java:1494) at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:375) at org.gradle.api.internal.file.collections.DefaultConfigurableFileCollection.lambda$calculateFinalizedValue$0(DefaultConfigurableFileCollection.java:241) at org.gradle.api.internal.file.collections.UnpackingVisitor.add(UnpackingVisitor.java:64) at org.gradle.api.internal.file.collections.DefaultConfigurableFileCollection$UnresolvedItemsCollector.visitContents(DefaultConfigurableFileCollection.java:372) at org.gradle.api.internal.file.collections.DefaultConfigurableFileCollection.calculateFinalizedValue(DefaultConfigurableFileCollection.java:241) at org.gradle.api.internal.file.collections.DefaultConfigurableFileCollection.visitChildren(DefaultConfigurableFileCollection.java:277) at org.gradle.api.internal.file.CompositeFileCollection.visitContents(CompositeFileCollection.java:119) at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:375) at org.gradle.api.internal.file.CompositeFileCollection.lambda$visitContents$0(CompositeFileCollection.java:119) at org.gradle.api.internal.file.collections.UnpackingVisitor.add(UnpackingVisitor.java:64) at org.gradle.api.internal.file.collections.UnpackingVisitor.add(UnpackingVisitor.java:89) at org.gradle.api.internal.file.DefaultFileCollectionFactory$ResolvingFileCollection.visitChildren(DefaultFileCollectionFactory.java:333) at org.gradle.api.internal.file.CompositeFileCollection.visitContents(CompositeFileCollection.java:119) at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:375) at org.gradle.api.internal.file.CompositeFileCollection.lambda$visitContents$0(CompositeFileCollection.java:119) at org.gradle.api.internal.tasks.PropertyFileCollection.visitChildren(PropertyFileCollection.java:48) at org.gradle.api.internal.file.CompositeFileCollection.visitContents(CompositeFileCollection.java:119) at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:375) at org.gradle.internal.fingerprint.impl.DefaultFileCollectionSnapshotter.snapshot(DefaultFileCollectionSnapshotter.java:51) at org.gradle.internal.execution.fingerprint.impl.DefaultInputFingerprinter$InputCollectingVisitor.visitInputFileProperty(DefaultInputFingerprinter.java:131) at org.gradle.api.internal.tasks.execution.TaskExecution.visitRegularInputs(TaskExecution.java:322) at org.gradle.internal.execution.fingerprint.impl.DefaultInputFingerprinter.fingerprintInputProperties(DefaultInputFingerprinter.java:61) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.captureExecutionStateWithOutputs(CaptureStateBeforeExecutionStep.java:193) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.lambda$captureExecutionState$1(CaptureStateBeforeExecutionStep.java:141) at org.gradle.internal.execution.steps.BuildOperationStep$1.call(BuildOperationStep.java:37) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73) at org.gradle.internal.execution.steps.BuildOperationStep.operation(BuildOperationStep.java:34) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.captureExecutionState(CaptureStateBeforeExecutionStep.java:130) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.lambda$execute$0(CaptureStateBeforeExecutionStep.java:75) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:75) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:50) at org.gradle.internal.execution.steps.SkipEmptyWorkStep.executeWithNoEmptySources(SkipEmptyWorkStep.java:254) at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:91) at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:56) at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:32) at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:21) at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38) at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:43) at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:31) at org.gradle.internal.execution.steps.AssignWorkspaceStep.lambda$execute$0(AssignWorkspaceStep.java:40) at org.gradle.api.internal.tasks.execution.TaskExecution$4.withWorkspace(TaskExecution.java:281) at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:40) at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:30) at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:37) at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:27) at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:44) at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:33) at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:76) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:139) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:128) at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:77) at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46) at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51) at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57) at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56) at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52) at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:69) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:327) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:314) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:307) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:293) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:417) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:339) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48) Caused by: org.gradle.api.internal.artifacts.transform.TransformException: Execution failed for DexingExternalLibArtifactTransform: ~\.gradle\caches\transforms-3\4082e14c9c25a7a4e013c136023ccb8e\transformed\jetified-aspectjrt-1.9.21.jar. at org.gradle.api.internal.artifacts.transform.DefaultTransformerInvocationFactory$1.lambda$mapResult$3(DefaultTransformerInvocationFactory.java:159) at org.gradle.internal.Try$Failure.mapFailure(Try.java:273) at org.gradle.api.internal.artifacts.transform.DefaultTransformerInvocationFactory$1.mapResult(DefaultTransformerInvocationFactory.java:159) at org.gradle.api.internal.artifacts.transform.DefaultTransformerInvocationFactory$1.lambda$processDeferredOutput$0(DefaultTransformerInvocationFactory.java:152) at org.gradle.api.internal.artifacts.transform.DefaultTransformerInvocationFactory.fireTransformListeners(DefaultTransformerInvocationFactory.java:184) at org.gradle.api.internal.artifacts.transform.DefaultTransformerInvocationFactory.access$000(DefaultTransformerInvocationFactory.java:69) at org.gradle.api.internal.artifacts.transform.DefaultTransformerInvocationFactory$1.lambda$processDeferredOutput$1(DefaultTransformerInvocationFactory.java:151) at org.gradle.api.internal.artifacts.transform.CacheableInvocation$3.invoke(CacheableInvocation.java:110) at org.gradle.api.internal.artifacts.transform.CacheableInvocation$1.invoke(CacheableInvocation.java:58) at org.gradle.api.internal.artifacts.transform.TransformingAsyncArtifactListener$TransformedArtifact.finalizeValue(TransformingAsyncArtifactListener.java:203) at org.gradle.api.internal.artifacts.transform.TransformingAsyncArtifactListener$TransformedArtifact.run(TransformingAsyncArtifactListener.java:136) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationExecutor$QueueWorker.execute(DefaultBuildOperationExecutor.java:238) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runOperation(DefaultBuildOperationQueue.java:266) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.doRunBatch(DefaultBuildOperationQueue.java:247) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.lambda$runBatch$0(DefaultBuildOperationQueue.java:237) at org.gradle.internal.resources.AbstractResourceLockRegistry.whileDisallowingLockChanges(AbstractResourceLockRegistry.java:50) at org.gradle.internal.work.DefaultWorkerLeaseService.whileDisallowingProjectLockChanges(DefaultWorkerLeaseService.java:221) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.lambda$runBatch$1(DefaultBuildOperationQueue.java:237) at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:249) at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:109) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runBatch(DefaultBuildOperationQueue.java:223) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.run(DefaultBuildOperationQueue.java:191) ... 2 more Caused by: com.android.builder.dexing.DexArchiveBuilderException: Error while dexing. at com.android.builder.dexing.D8DexArchiveBuilder.getExceptionToRethrow(D8DexArchiveBuilder.java:183) at com.android.builder.dexing.D8DexArchiveBuilder.convert(D8DexArchiveBuilder.java:122) at com.android.build.gradle.internal.dependency.BaseDexingTransform.process(DexingTransform.kt:294) at com.android.build.gradle.internal.dependency.BaseDexingTransform.processNonIncrementally(DexingTransform.kt:241) at com.android.build.gradle.internal.dependency.BaseDexingTransform.doTransform(DexingTransform.kt:151) at com.android.build.gradle.internal.dependency.BaseDexingTransform.transform(DexingTransform.kt:109) at org.gradle.api.internal.artifacts.transform.DefaultTransformer.transform(DefaultTransformer.java:264) at org.gradle.api.internal.artifacts.transform.DefaultTransformerInvocationFactory$AbstractTransformerExecution$1.call(DefaultTransformerInvocationFactory.java:290) at org.gradle.api.internal.artifacts.transform.DefaultTransformerInvocationFactory$AbstractTransformerExecution$1.call(DefaultTransformerInvocationFactory.java:285) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73) at org.gradle.api.internal.artifacts.transform.DefaultTransformerInvocationFactory$AbstractTransformerExecution.execute(DefaultTransformerInvocationFactory.java:285) at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:89) at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:40) at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:53) at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:50) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73) at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:50) at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:40) at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:68) at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:38) at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:41) at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:74) at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55) at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:51) at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:29) at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.executeDelegateBroadcastingChanges(CaptureStateAfterExecutionStep.java:124) at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:80) at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:58) at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:48) at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:36) at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:181) at org.gradle.internal.execution.steps.BuildCacheStep.lambda$execute$1(BuildCacheStep.java:71) at org.gradle.internal.Either$Right.fold(Either.java:175) at org.gradle.internal.execution.caching.CachingState.fold(CachingState.java:59) at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:69) at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:47) at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:36) at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:25) at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:36) at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:22) at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:110) at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$2(SkipUpToDateStep.java:56) at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:56) at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:38) at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:73) at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:44) at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37) at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27) at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:89) at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:50) at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:114) at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:57) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:76) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:50) at org.gradle.internal.execution.steps.SkipEmptyWorkStep.executeWithNoEmptySources(SkipEmptyWorkStep.java:254) at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:91) at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:56) at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:32) at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:21) at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38) at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:43) at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:31) at org.gradle.internal.execution.steps.AssignWorkspaceStep.lambda$execute$0(AssignWorkspaceStep.java:40) at org.gradle.internal.execution.workspace.impl.DefaultImmutableWorkspaceProvider.lambda$withWorkspace$3(DefaultImmutableWorkspaceProvider.java:124) at org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess.withFileLock(LockOnDemandCrossProcessCacheAccess.java:90) at org.gradle.cache.internal.DefaultCacheAccess.withFileLock(DefaultCacheAccess.java:191) at org.gradle.cache.internal.DefaultPersistentDirectoryStore.withFileLock(DefaultPersistentDirectoryStore.java:188) at org.gradle.cache.internal.DefaultCacheFactory$ReferenceTrackingCache.withFileLock(DefaultCacheFactory.java:209) at org.gradle.internal.execution.workspace.impl.DefaultImmutableWorkspaceProvider.withWorkspace(DefaultImmutableWorkspaceProvider.java:121) at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:40) at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:30) at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:37) at org.gradle.internal.execution.steps.IdentityCacheStep.lambda$executeDeferred$0(IdentityCacheStep.java:49) at org.gradle.cache.Cache.lambda$get$0(Cache.java:31) at org.gradle.cache.ManualEvictionInMemoryCache.get(ManualEvictionInMemoryCache.java:30) at org.gradle.cache.internal.DefaultCrossBuildInMemoryCacheFactory$CrossBuildCacheRetainingDataFromPreviousBuild.get(DefaultCrossBuildInMemoryCacheFactory.java:255) at org.gradle.cache.Cache.get(Cache.java:31) at org.gradle.internal.execution.steps.IdentityCacheStep.lambda$executeDeferred$1(IdentityCacheStep.java:47) ... 25 more Caused by: com.android.tools.r8.CompilationFailedException: Compilation failed to complete, origin: ~\.gradle\caches\transforms-3\4082e14c9c25a7a4e013c136023ccb8e\transformed\jetified-aspectjrt-1.9.21.jar:org/aspectj/lang/reflect/DeclareAnnotation$Kind.class at Version.fakeStackEntry(Version_4.0.52.java:0) at com.android.tools.r8.internal.vk.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:75) at com.android.tools.r8.internal.vk.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:28) at com.android.tools.r8.internal.vk.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:27) at com.android.tools.r8.internal.vk.b(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:2) at com.android.tools.r8.D8.run(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:11) at com.android.builder.dexing.D8DexArchiveBuilder.convert(D8DexArchiveBuilder.java:120) ... 115 more Caused by: java.lang.NullPointerException: Cannot invoke "String.length()" because "" is null at com.android.tools.r8.graph.e1.(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:5) at com.android.tools.r8.graph.v0.b(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:14) at com.android.tools.r8.graph.x2.b(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:9) at com.android.tools.r8.internal.Ab.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:873) at com.android.tools.r8.graph.y2.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:44) at com.android.tools.r8.internal.vk.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:101) at com.android.tools.r8.internal.vk.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:102) at com.android.tools.r8.internal.vk.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:100) at com.android.tools.r8.graph.y2.b(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:2) at com.android.tools.r8.dex.a.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:27) at com.google.common.util.concurrent.TrustedListenableFutureTask$TrustedFutureInterruptibleTask.runInterruptibly(TrustedListenableFutureTask.java:125) at com.google.common.util.concurrent.InterruptibleTask.run(InterruptibleTask.java:69) at com.google.common.util.concurrent.TrustedListenableFutureTask.run(TrustedListenableFutureTask.java:78) at com.google.common.util.concurrent.MoreExecutors$DirectExecutorService.execute(MoreExecutors.java:321) at com.google.common.util.concurrent.AbstractListeningExecutorService.submit(AbstractListeningExecutorService.java:66) at com.google.common.util.concurrent.AbstractListeningExecutorService.submit(AbstractListeningExecutorService.java:36) at com.android.tools.r8.dex.a.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:24) at com.android.tools.r8.dex.a.b(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:38) at com.android.tools.r8.dex.b.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:66) at com.android.tools.r8.dex.b.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:23) at com.android.tools.r8.dex.b.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:22) at com.android.tools.r8.D8.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:50) at com.android.tools.r8.D8.d(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:19) at com.android.tools.r8.D8.b(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:1) at com.android.tools.r8.internal.vk.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:24) ... 118 more Suppressed: java.lang.RuntimeException: java.util.concurrent.ExecutionException: com.android.tools.r8.internal.xk: java.lang.NullPointerException: Cannot invoke "String.length()" because "" is null at com.android.tools.r8.dex.b.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:86) at com.android.tools.r8.dex.b.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:23) at com.android.tools.r8.dex.b.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:22) at com.android.tools.r8.D8.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:50) at com.android.tools.r8.D8.d(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:19) at com.android.tools.r8.D8.b(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:1) at com.android.tools.r8.internal.vk.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:24) at com.android.tools.r8.internal.vk.b(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:2) at com.android.tools.r8.D8.run(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:11) at com.android.builder.dexing.D8DexArchiveBuilder.convert(D8DexArchiveBuilder.java:120) at com.android.build.gradle.internal.dependency.BaseDexingTransform.process(DexingTransform.kt:294) at com.android.build.gradle.internal.dependency.BaseDexingTransform.processNonIncrementally(DexingTransform.kt:241) at com.android.build.gradle.internal.dependency.BaseDexingTransform.doTransform(DexingTransform.kt:151) at com.android.build.gradle.internal.dependency.BaseDexingTransform.transform(DexingTransform.kt:109) at org.gradle.api.internal.artifacts.transform.DefaultTransformer.transform(DefaultTransformer.java:264) at org.gradle.api.internal.artifacts.transform.DefaultTransformerInvocationFactory$AbstractTransformerExecution$1.call(DefaultTransformerInvocationFactory.java:290) at org.gradle.api.internal.artifacts.transform.DefaultTransformerInvocationFactory$AbstractTransformerExecution$1.call(DefaultTransformerInvocationFactory.java:285) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73) at org.gradle.api.internal.artifacts.transform.DefaultTransformerInvocationFactory$AbstractTransformerExecution.execute(DefaultTransformerInvocationFactory.java:285) at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:89) at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:40) at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:53) at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:50) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73) at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:50) at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:40) at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:68) at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:38) at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:41) at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:74) at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55) at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:51) at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:29) at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.executeDelegateBroadcastingChanges(CaptureStateAfterExecutionStep.java:124) at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:80) at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:58) at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:48) at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:36) at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:181) at org.gradle.internal.execution.steps.BuildCacheStep.lambda$execute$1(BuildCacheStep.java:71) at org.gradle.internal.Either$Right.fold(Either.java:175) at org.gradle.internal.execution.caching.CachingState.fold(CachingState.java:59) at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:69) at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:47) at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:36) at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:25) at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:36) at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:22) at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:110) at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$2(SkipUpToDateStep.java:56) at java.base/java.util.Optional.orElseGet(Optional.java:364) at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:56) at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:38) at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:73) at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:44) at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37) at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27) at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:89) at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:50) at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:114) at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:57) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:76) at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:50) at org.gradle.internal.execution.steps.SkipEmptyWorkStep.executeWithNoEmptySources(SkipEmptyWorkStep.java:254) at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:91) at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:56) at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:32) at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:21) at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38) at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:43) at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:31) at org.gradle.internal.execution.steps.AssignWorkspaceStep.lambda$execute$0(AssignWorkspaceStep.java:40) at org.gradle.internal.execution.workspace.impl.DefaultImmutableWorkspaceProvider.lambda$withWorkspace$3(DefaultImmutableWorkspaceProvider.java:124) at org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess.withFileLock(LockOnDemandCrossProcessCacheAccess.java:90) at org.gradle.cache.internal.DefaultCacheAccess.withFileLock(DefaultCacheAccess.java:191) at org.gradle.cache.internal.DefaultPersistentDirectoryStore.withFileLock(DefaultPersistentDirectoryStore.java:188) at org.gradle.cache.internal.DefaultCacheFactory$ReferenceTrackingCache.withFileLock(DefaultCacheFactory.java:209) at org.gradle.internal.execution.workspace.impl.DefaultImmutableWorkspaceProvider.withWorkspace(DefaultImmutableWorkspaceProvider.java:121) at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:40) at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:30) at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:37) at org.gradle.internal.execution.steps.IdentityCacheStep.lambda$executeDeferred$0(IdentityCacheStep.java:49) at org.gradle.cache.Cache.lambda$get$0(Cache.java:31) at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708) at org.gradle.cache.ManualEvictionInMemoryCache.get(ManualEvictionInMemoryCache.java:30) at org.gradle.cache.internal.DefaultCrossBuildInMemoryCacheFactory$CrossBuildCacheRetainingDataFromPreviousBuild.get(DefaultCrossBuildInMemoryCacheFactory.java:255) at org.gradle.cache.Cache.get(Cache.java:31) at org.gradle.internal.execution.steps.IdentityCacheStep.lambda$executeDeferred$1(IdentityCacheStep.java:47) at org.gradle.api.internal.artifacts.transform.DefaultTransformerInvocationFactory$1.lambda$processDeferredOutput$0(DefaultTransformerInvocationFactory.java:152) at org.gradle.api.internal.artifacts.transform.DefaultTransformerInvocationFactory.fireTransformListeners(DefaultTransformerInvocationFactory.java:184) at org.gradle.api.internal.artifacts.transform.DefaultTransformerInvocationFactory.access$000(DefaultTransformerInvocationFactory.java:69) at org.gradle.api.internal.artifacts.transform.DefaultTransformerInvocationFactory$1.lambda$processDeferredOutput$1(DefaultTransformerInvocationFactory.java:151) at org.gradle.api.internal.artifacts.transform.CacheableInvocation$3.invoke(CacheableInvocation.java:110) at org.gradle.api.internal.artifacts.transform.CacheableInvocation$1.invoke(CacheableInvocation.java:58) at org.gradle.api.internal.artifacts.transform.TransformingAsyncArtifactListener$TransformedArtifact.finalizeValue(TransformingAsyncArtifactListener.java:203) at org.gradle.api.internal.artifacts.transform.TransformingAsyncArtifactListener$TransformedArtifact.run(TransformingAsyncArtifactListener.java:136) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationExecutor$QueueWorker.execute(DefaultBuildOperationExecutor.java:238) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runOperation(DefaultBuildOperationQueue.java:266) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.doRunBatch(DefaultBuildOperationQueue.java:247) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.lambda$runBatch$0(DefaultBuildOperationQueue.java:237) at org.gradle.internal.resources.AbstractResourceLockRegistry.whileDisallowingLockChanges(AbstractResourceLockRegistry.java:50) at org.gradle.internal.work.DefaultWorkerLeaseService.whileDisallowingProjectLockChanges(DefaultWorkerLeaseService.java:221) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.lambda$runBatch$1(DefaultBuildOperationQueue.java:237) at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:249) at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:109) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runBatch(DefaultBuildOperationQueue.java:223) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.run(DefaultBuildOperationQueue.java:191) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:840) Caused by: java.util.concurrent.ExecutionException: com.android.tools.r8.internal.xk: java.lang.NullPointerException: Cannot invoke "String.length()" because "" is null at com.google.common.util.concurrent.AbstractFuture.getDoneValue(AbstractFuture.java:566) at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:527) at com.google.common.util.concurrent.FluentFuture$TrustedFuture.get(FluentFuture.java:88) at com.android.tools.r8.utils.x.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:58) at com.android.tools.r8.dex.b.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:67) ... 129 more Caused by: com.android.tools.r8.internal.xk: java.lang.NullPointerException: Cannot invoke "String.length()" because "" is null at com.android.tools.r8.internal.xk.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:6) at com.android.tools.r8.internal.vk.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:104) at com.android.tools.r8.internal.vk.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:100) at com.android.tools.r8.graph.y2.b(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:2) at com.android.tools.r8.dex.a.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:27) at com.google.common.util.concurrent.TrustedListenableFutureTask$TrustedFutureInterruptibleTask.runInterruptibly(TrustedListenableFutureTask.java:125) at com.google.common.util.concurrent.InterruptibleTask.run(InterruptibleTask.java:69) at com.google.common.util.concurrent.TrustedListenableFutureTask.run(TrustedListenableFutureTask.java:78) at com.google.common.util.concurrent.MoreExecutors$DirectExecutorService.execute(MoreExecutors.java:321) at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) at com.google.common.util.concurrent.AbstractListeningExecutorService.submit(AbstractListeningExecutorService.java:66) at com.google.common.util.concurrent.AbstractListeningExecutorService.submit(AbstractListeningExecutorService.java:36) at com.android.tools.r8.dex.a.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:24) at com.android.tools.r8.dex.a.b(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:38) at com.android.tools.r8.dex.b.a(R8_4.0.52_5a340ca2823c7e792fe09805c75f749b9d398d230bc0518bb54ae9b6b50addbe:66) ... 129 more Caused by: [CIRCULAR REFERENCE: java.lang.NullPointerException: Cannot invoke "String.length()" because "" is null] --- app/build.gradle.kts | 22 +++---- .../WeechatAndroid/service/Connectivity.java | 57 ------------------- .../views/CircularImageButton.kt | 4 +- build.gradle.kts | 8 +-- cats/build.gradle.kts | 10 ++-- relay/build.gradle.kts | 6 +- 6 files changed, 25 insertions(+), 82 deletions(-) delete mode 100644 app/src/main/java/com/ubergeek42/WeechatAndroid/service/Connectivity.java diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 497a64ee..3586ec2f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -16,17 +16,17 @@ dependencies { implementation(project(":cats")) implementation(project(":relay")) - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.10") + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20") // these two are required for logging within the relay module. todo remove? implementation("org.slf4j:slf4j-api:2.0.9") implementation("com.noveogroup.android:android-logger:1.3.6") - implementation("androidx.core:core-ktx:1.10.1") + implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.legacy:legacy-support-v4:1.0.0") - implementation("androidx.annotation:annotation:1.7.0") // For @Nullable/@NonNull + implementation("androidx.annotation:annotation:1.7.1") // For @Nullable/@NonNull implementation("androidx.appcompat:appcompat:1.6.1") - implementation("androidx.emoji2:emoji2:1.3.0") + implementation("androidx.emoji2:emoji2:1.4.0") implementation("androidx.preference:preference-ktx:1.2.1") // preference fragment & al implementation("androidx.legacy:legacy-preference-v14:1.0.0") // styling for the fragment implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2") @@ -37,9 +37,9 @@ dependencies { implementation("com.github.bumptech.glide:glide:4.16.0") kapt("com.github.bumptech.glide:compiler:4.16.0") - implementation("com.squareup.okhttp3:okhttp:4.11.0") + implementation("com.squareup.okhttp3:okhttp:4.12.0") - val roomVersion = "2.5.2" + val roomVersion = "2.6.1" implementation("androidx.room:room-runtime:$roomVersion") annotationProcessor("androidx.room:room-compiler:$roomVersion") kapt("androidx.room:room-compiler:$roomVersion") @@ -51,15 +51,15 @@ dependencies { // needed for thread-safe date formatting as SimpleDateFormat isn"t thread-safe // the alternatives, including apache commons and threetenabp, seem to be much slower // todo perhaps replace with core library desugaring, if it"s fast - implementation("net.danlew:android.joda:2.12.5") + implementation("net.danlew:android.joda:2.12.6") implementation("org.greenrobot:eventbus:3.3.1") debugImplementation("org.aspectj:aspectjrt:1.9.20.1") debugImplementation("com.squareup.leakcanary:leakcanary-android:2.12") - testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") - testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.0") + testImplementation("org.junit.jupiter:junit-jupiter:5.10.1") + testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.1") } tasks.withType { @@ -68,14 +68,14 @@ tasks.withType { android { namespace = "com.ubergeek42.WeechatAndroid" - compileSdk = 33 + compileSdk = 34 defaultConfig { versionCode = 1_08_01 versionName = "1.8.1" minSdk = 21 - targetSdk = 33 + targetSdk = 34 buildConfigField("String", "VERSION_BANNER", "\"" + versionBanner() + "\"") vectorDrawables.useSupportLibrary = true diff --git a/app/src/main/java/com/ubergeek42/WeechatAndroid/service/Connectivity.java b/app/src/main/java/com/ubergeek42/WeechatAndroid/service/Connectivity.java deleted file mode 100644 index e95ebc78..00000000 --- a/app/src/main/java/com/ubergeek42/WeechatAndroid/service/Connectivity.java +++ /dev/null @@ -1,57 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. - -package com.ubergeek42.WeechatAndroid.service; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import androidx.annotation.MainThread; -import androidx.annotation.WorkerThread; - - -public class Connectivity extends BroadcastReceiver { - private RelayService bone; - private ConnectivityManager manager; - volatile private boolean networkAvailable = true; - - @MainThread public void register(RelayService bone) { - this.bone = bone; - this.manager = (ConnectivityManager) bone.getSystemService(Context.CONNECTIVITY_SERVICE); - bone.registerReceiver( - this, - new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION) - ); - networkAvailable = getNetworkAvailable(); - } - - @MainThread public void unregister() { - bone.unregisterReceiver(this); - this.bone = null; - this.manager = null; - } - - @WorkerThread public boolean isNetworkAvailable() { - return networkAvailable; - } - - // this message can be called multiple times - // make sure we only call _start() when network goes from unavailable to available - // NOTE: inside onReceive(), getNetworkAvailable() will only return false if the device sees - // no *possible* connections. outside of this method getNetworkAvailable() can return false - // if the device is currently switching between networks. - @MainThread @Override public void onReceive(Context context, Intent intent) { - if (networkAvailable == getNetworkAvailable()) return; - networkAvailable = !networkAvailable; - if (networkAvailable && P.reconnect && bone.state.contains(RelayService.STATE.STARTED)) - bone._start(); - } - - @MainThread private boolean getNetworkAvailable() { - NetworkInfo networkInfo = manager.getActiveNetworkInfo(); - return networkInfo != null && networkInfo.isConnected(); - } -} diff --git a/app/src/main/java/com/ubergeek42/WeechatAndroid/views/CircularImageButton.kt b/app/src/main/java/com/ubergeek42/WeechatAndroid/views/CircularImageButton.kt index 774f44eb..d6e65bba 100644 --- a/app/src/main/java/com/ubergeek42/WeechatAndroid/views/CircularImageButton.kt +++ b/app/src/main/java/com/ubergeek42/WeechatAndroid/views/CircularImageButton.kt @@ -47,8 +47,8 @@ class CircularImageButton @JvmOverloads constructor( private val backgroundPaint = Paint().apply { style = Paint.Style.FILL } - override fun onDraw(canvas: Canvas?) { - canvas?.drawPaint(backgroundPaint) + override fun onDraw(canvas: Canvas) { + canvas.drawPaint(backgroundPaint) super.onDraw(canvas) } diff --git a/build.gradle.kts b/build.gradle.kts index bb6fe626..8aa2d2d0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,9 +28,9 @@ buildscript { dependencies { classpath("com.android.tools.build:gradle:7.4.2") - classpath("org.aspectj:aspectjtools:1.9.20.1") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.10") - classpath("org.jetbrains.kotlin:kotlin-serialization:1.9.10") + classpath("org.aspectj:aspectjtools:1.9.20.1") // updating to 1.9.21 leads to dexing errors + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20") + classpath("org.jetbrains.kotlin:kotlin-serialization:1.9.20") } } @@ -75,7 +75,7 @@ subprojects { // $ ./gradlew dependencyUpdates // See https://github.com/ben-manes/gradle-versions-plugin plugins { - id("com.github.ben-manes.versions") version "0.48.0" + id("com.github.ben-manes.versions") version "0.50.0" } fun isNonStable(version: String): Boolean { diff --git a/cats/build.gradle.kts b/cats/build.gradle.kts index df86a733..ce0a5f1b 100644 --- a/cats/build.gradle.kts +++ b/cats/build.gradle.kts @@ -8,15 +8,15 @@ plugins { dependencies { implementation("org.aspectj:aspectjrt:1.9.20.1") - implementation("androidx.annotation:annotation:1.7.0") + implementation("androidx.annotation:annotation:1.7.1") - testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") - testImplementation("org.mockito:mockito-core:5.5.0") + testImplementation("org.junit.jupiter:junit-jupiter:5.10.1") + testImplementation("org.mockito:mockito-core:5.8.0") } android { namespace = "com.ubergeek42.cats" - compileSdk = 33 + compileSdk = 34 compileOptions { sourceCompatibility = JavaVersion.VERSION_17 @@ -35,7 +35,7 @@ android { } defaultConfig { - targetSdk = 33 + targetSdk = 34 minSdk = 16 } } diff --git a/relay/build.gradle.kts b/relay/build.gradle.kts index b9f53708..6517f471 100644 --- a/relay/build.gradle.kts +++ b/relay/build.gradle.kts @@ -15,10 +15,10 @@ dependencies { implementation("com.neovisionaries:nv-websocket-client:2.14") - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.10") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0") + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2") - testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") + testImplementation("org.junit.jupiter:junit-jupiter:5.10.1") } tasks.withType { From 59e8fa7b68fb39ef4978270148260e9d91d654e0 Mon Sep 17 00:00:00 2001 From: oakkitten Date: Mon, 25 Dec 2023 21:12:37 +0000 Subject: [PATCH 5/8] Fix CI Install Java 17. Using distribution Temurin as it is the one currently cached, some of the other ones take minutes to install. --- .github/workflows/main.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2c7d4be4..78e7f0b6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,6 +7,12 @@ jobs: name: Run tests runs-on: ubuntu-latest steps: + - name: Install Java 17 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + - name: Checkout repository uses: actions/checkout@v2 with: @@ -19,6 +25,12 @@ jobs: name: Build release apk runs-on: ubuntu-latest steps: + - name: Install Java 17 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + - name: Checkout repository uses: actions/checkout@v2 with: From 6adda8d4c359736df998bdd416df1cbaebe45f17 Mon Sep 17 00:00:00 2001 From: oakkitten Date: Tue, 26 Dec 2023 13:43:16 +0000 Subject: [PATCH 6/8] Fix a lint error, temporarily, until using AGP 8 --- gradle.properties | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 97bfedcf..b21b4399 100644 --- a/gradle.properties +++ b/gradle.properties @@ -46,4 +46,12 @@ android.useAndroidX=true #releaseKeyPassword=releasekeypassword # kapt is the annotation processor for Kotlin -kapt.incremental.apt=true \ No newline at end of file +kapt.incremental.apt=true + +# Linter that comes with AGP 7.4.2 doesn't support Kotlin 1.9, so force a newer version. +# Suppresses messages like: +# Module was compiled with an incompatible version of Kotlin. +# The binary version of its metadata is 1.9.0, expected version is 1.7.1. +# See answer by the_jk: https://stackoverflow.com/q/76690078/#76763654 +# TODO Remove this after updating to AGP 8 +android.experimental.lint.version=8.3.0-alpha18 \ No newline at end of file From 31ccdafa5ee3ac96f9b8b82a2bff42789d656ec9 Mon Sep 17 00:00:00 2001 From: oakkitten Date: Tue, 26 Dec 2023 13:44:10 +0000 Subject: [PATCH 7/8] Fix an R8 warning about missing class --- app/proguard-rules.pro | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index a02f049a..e5e2af16 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -133,6 +133,14 @@ -dontwarn java.beans.PropertyDescriptor +# Gets rid of the warning, +# Missing class com.google.errorprone.annotations.Immutable +# (referenced from: com.google.crypto.tink.util.Bytes) +# Should be safe to use. See: +# https://github.com/google/tink/issues/536 +# https://issuetracker.google.com/issues/195752905 +-dontwarn com.google.errorprone.annotations.Immutable + # ~*~*~*~ Historical rules, left here for lamenting and general amusement ~*~*~*~ # Looks like we aren't getting warnings anymore! From 2f8192ff0ccc57e595bbb8ceeadd123b49d3b130 Mon Sep 17 00:00:00 2001 From: oakkitten Date: Sat, 13 Jan 2024 16:09:05 +0000 Subject: [PATCH 8/8] Update translations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alexandre Macabies Co-authored-by: Nils Görs Co-authored-by: TehPeGaSuS <25697531+TehPeGaSuS@users.noreply.github.com> --- app/src/main/res/values-de/strings.xml | 26 +++++++++++++++++++++++++ app/src/main/res/values-fr/strings.xml | 27 ++++++++++++++++++++++++++ app/src/main/res/values-ru/strings.xml | 26 +++++++++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 831867cc..3172dcb2 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -173,6 +173,32 @@ Um Fotos zu erstellen, benötigt die App Schreibzugriff auf den öffentlichen Speicher Ok + + Erlaubnis erforderlich + + Maschine pingen, benötigt die Erlaubnis, genaue Alarme zu setzen. + Alternativ können man den Ping in den Verbindungseinstellungen deaktivieren. + Erlaubnis erteilen + + Erlaubnis erwünscht + + Um Benachrichtigungen anzuzeigen, benötigen wir eine Erlaubnis. + Dies ist optional. + Wenn Sie Benachrichtigungen jetzt nicht aktivieren, + können Sie diese jederzeit nachträglich in den Einstellungen aktivieren. + \n + \nWenn eine Verbindung besteht, wird eine dauerhafte Benachrichtigung angezeigt. + Um es aus der Statusleiste auszublenden, wird empfohlen, + die Benachrichtigungsminimierung für die Kategorie „Verbindungsstatus“ zu aktivieren. + \n + \nEs können Benachrichtigungen, z.B. Ton, Vibration usw. auch für einzelne Buffer angepasst werden. + Wenn mindestens eine Benachrichtigung für den entsprechenden Buffer erhalten wurde, + muss man lange auf die Benachrichtigung tippen, um zu den Einstellungen zu gelangen. + + Erlaubnis erteilen + + Fortfahren, ohne Erlaubnis zu erteilen + diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 0552e002..d64f2b38 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -177,6 +177,33 @@ Pour prendre des photos, l’application a besoin d’un accès en écriture au stockage OK + + Demande d’autorisation + + Le mécanisme de pings a besoin de l’autorisation de programmer des alarmes exactes. + Si vous préférez, vous pouvez désactiver les pings dans les paramètres de connexion. + Donner l’autorisation + + Demande d’autorisation + + Pour pouvoir afficher des notifications, + Weechat-Android a besoin d’une autorisation optionnelle. + Vous pouvez refuser maintenant et réactiver les notifications + à tout moment en allant dans les paramètres. + \n + \nUne notification restera affichée aussi longtemps que la connexion perdure. + Pour la masquer de la barre d’état, nous vous suggérons d’activer + l’option de réduire les notifications pour la catégorie « État de la connexion ». + \n + \nVous pouvez également personnaliser les notifications pour des tampons individuels, + modifier le son, les vibrations, etc. + Pour ce faire, lorsque vous avez reçu au moins une notification pour le tampon correspondant, + appuyez longuement dessus et accédez aux paramètres. + + Donner l’autorisation + + Continuer sans donner l’autorisation + diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index ce5c1e5b..ba28a78c 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -176,6 +176,32 @@ Чтобы сделать фото, приложению требуется разрешение на запись в хранилище Хорошо + + Необходимо разрешение + + Для пинга требуется разрешение на планирование запуска действий в точное время. + Альтернативно, вы можете выключить пинг в настройках подключения. + Дать разрешение + + Необходимо разрешение + + Чтобы показывать уведомления, приложению требуется разрешение. + Это необязательно. + Если вы не дадите разрешение сейчас, + вы всегда сможете дать его позже в настройках приложения. + \n + \nПри подключении отображается постоянное уведомление. + Чтобы скрыть его значок из строки состояния, + рекомендуем включить сворачиваение уведомлений для категории «Статус соединения». + \n + \nТакже вы можете настроить уведомления для отдельных буферов, изменяя звук, вибрацию и прочее. + Для этого, получив уведомление от соответствующего буфера, + выполните долгое нажатие на это уведомление и перейдите в настройки. + + Дать разрешение + + Продолжить, не дав разрешение +