From 545e368abb70aec85c86fcf47cf23b26dcd2398a Mon Sep 17 00:00:00 2001 From: F43nd1r Date: Sat, 11 Dec 2021 00:50:08 +0100 Subject: [PATCH] Remove annotation config (#856) * remove annotation config * remove annotation test * fix tests * fix tests * add required annotations --- .../SchedulerConfiguration.kt} | 53 ++- .../acra/scheduler/AdvancedSenderScheduler.kt | 7 +- .../acra/scheduler/RestartingAdministrator.kt | 4 +- .../androidTest/java/org/acra/ACRATest.java | 4 +- .../DefaultAttachmentProviderTest.java | 5 +- .../config/CoreConfigurationBuilderTest.java | 49 --- acra-core/src/main/java/org/acra/ACRA.kt | 2 +- .../src/main/java/org/acra/ACRAConstants.kt | 2 +- .../java/org/acra/annotation/AcraCore.java | 318 ------------------ .../main/java/org/acra/annotation/AcraDsl.kt | 14 +- .../org/acra/collector/ReflectionCollector.kt | 9 +- .../config/BaseCoreConfigurationBuilder.kt | 128 ------- .../main/java/org/acra/config/ConfigUtils.kt | 30 +- .../java/org/acra/config/CoreConfiguration.kt | 254 ++++++++++++++ .../src/main/java/org/acra/ktx/Extensions.kt | 16 +- .../java/org/acra/plugins/HasConfigPlugin.kt | 4 +- .../java/org/acra/sender/SendingConductor.kt | 4 +- .../java/org/acra/annotation/AcraDialog.java | 122 ------- .../org/acra/config/DialogConfiguration.kt | 122 +++++++ .../java/org/acra/dialog/CrashReportDialog.kt | 16 +- .../org/acra/interaction/DialogInteraction.kt | 4 +- .../org/acra/annotation/AcraHttpSender.java | 154 --------- .../config/BaseHttpConfigurationBuilder.kt | 49 --- .../acra/config/HttpSenderConfiguration.kt | 154 +++++++++ .../java/org/acra/http/BaseHttpRequest.kt | 6 +- .../java/org/acra/security/KeyStoreHelper.kt | 12 +- .../main/java/org/acra/sender/HttpSender.kt | 4 +- .../java/org/acra/annotation/AcraLimiter.java | 116 ------- .../org/acra/config/LimiterConfiguration.kt | 106 ++++++ .../config/LimitingReportAdministrator.kt | 9 +- .../acra/startup/LimiterStartupProcessor.kt | 4 +- .../org/acra/annotation/AcraMailSender.java | 84 ----- .../acra/config/MailSenderConfiguration.kt | 79 +++++ .../java/org/acra/sender/EmailIntentSender.kt | 25 +- .../org/acra/annotation/AcraNotification.java | 188 ----------- .../acra/config/NotificationConfiguration.kt | 179 ++++++++++ .../interaction/NotificationInteraction.kt | 16 +- .../java/org/acra/annotation/AcraToast.java | 60 ---- .../org/acra/config/ToastConfiguration.kt | 58 ++++ .../org/acra/interaction/ToastInteraction.kt | 4 +- annotationprocessor/build.gradle.kts | 28 -- .../acra/processor/AcraAnnotationProcessor.kt | 65 ---- .../processor/creator/BuildMethodCreator.kt | 79 ----- .../acra/processor/creator/ClassCreator.kt | 133 -------- .../acra/processor/creator/ModelBuilder.kt | 117 ------- .../creator/ServiceResourceCreator.kt | 33 -- .../acra/processor/element/AbstractElement.kt | 25 -- .../acra/processor/element/AnnotationField.kt | 152 --------- .../acra/processor/element/BuilderElement.kt | 107 ------ .../acra/processor/element/ConfigElement.kt | 34 -- .../acra/processor/element/DelegateMethod.kt | 76 ----- .../org/acra/processor/element/Element.kt | 29 -- .../acra/processor/element/ElementFactory.kt | 108 ------ .../acra/processor/element/PreBuildMethod.kt | 29 -- .../processor/element/TransformedField.kt | 52 --- .../processor/element/ValidatedElement.kt | 26 -- .../processor/util/IsValidResourceVisitor.kt | 13 - .../java/org/acra/processor/util/Strings.kt | 65 ---- .../acra/processor/util/ToCodeBlockVisitor.kt | 49 --- .../java/org/acra/processor/util/Types.kt | 87 ----- .../java/org/acra/processor/util/utils.kt | 61 ---- .../gradle/incremental.annotation.processors | 1 - .../java/org/acra/annotation/AnyNonDefault.kt | 26 -- .../java/org/acra/annotation/BuilderMethod.kt | 24 -- .../java/org/acra/annotation/Configuration.kt | 28 -- .../org/acra/annotation/ConfigurationValue.kt | 24 -- .../org/acra/annotation/Instantiatable.kt | 26 -- .../main/java/org/acra/annotation/NonEmpty.kt | 26 -- .../main/java/org/acra/annotation/PreBuild.kt | 26 -- .../java/org/acra/annotation/Transform.kt | 26 -- .../kotlin/acra-android-library.gradle.kts | 4 +- .../src/main/kotlin/repositories.gradle.kts | 2 + gradle/libs.versions.toml | 7 +- settings.gradle.kts | 2 - 74 files changed, 1085 insertions(+), 2979 deletions(-) rename acra-advanced-scheduler/src/main/java/org/acra/{annotation/AcraScheduler.java => config/SchedulerConfiguration.kt} (50%) delete mode 100644 acra-core/src/androidTest/java/org/acra/config/CoreConfigurationBuilderTest.java delete mode 100644 acra-core/src/main/java/org/acra/annotation/AcraCore.java rename annotations/build.gradle.kts => acra-core/src/main/java/org/acra/annotation/AcraDsl.kt (74%) delete mode 100644 acra-core/src/main/java/org/acra/config/BaseCoreConfigurationBuilder.kt create mode 100644 acra-core/src/main/java/org/acra/config/CoreConfiguration.kt delete mode 100644 acra-dialog/src/main/java/org/acra/annotation/AcraDialog.java create mode 100644 acra-dialog/src/main/java/org/acra/config/DialogConfiguration.kt delete mode 100644 acra-http/src/main/java/org/acra/annotation/AcraHttpSender.java delete mode 100644 acra-http/src/main/java/org/acra/config/BaseHttpConfigurationBuilder.kt create mode 100644 acra-http/src/main/java/org/acra/config/HttpSenderConfiguration.kt delete mode 100644 acra-limiter/src/main/java/org/acra/annotation/AcraLimiter.java create mode 100644 acra-limiter/src/main/java/org/acra/config/LimiterConfiguration.kt delete mode 100644 acra-mail/src/main/java/org/acra/annotation/AcraMailSender.java create mode 100644 acra-mail/src/main/java/org/acra/config/MailSenderConfiguration.kt delete mode 100644 acra-notification/src/main/java/org/acra/annotation/AcraNotification.java create mode 100644 acra-notification/src/main/java/org/acra/config/NotificationConfiguration.kt delete mode 100644 acra-toast/src/main/java/org/acra/annotation/AcraToast.java create mode 100644 acra-toast/src/main/java/org/acra/config/ToastConfiguration.kt delete mode 100644 annotationprocessor/build.gradle.kts delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/AcraAnnotationProcessor.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/creator/BuildMethodCreator.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/creator/ClassCreator.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/creator/ModelBuilder.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/creator/ServiceResourceCreator.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/element/AbstractElement.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/element/AnnotationField.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/element/BuilderElement.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/element/ConfigElement.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/element/DelegateMethod.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/element/Element.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/element/ElementFactory.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/element/PreBuildMethod.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/element/TransformedField.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/element/ValidatedElement.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/util/IsValidResourceVisitor.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/util/Strings.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/util/ToCodeBlockVisitor.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/util/Types.kt delete mode 100644 annotationprocessor/src/main/java/org/acra/processor/util/utils.kt delete mode 100644 annotationprocessor/src/main/resources/META-INF/gradle/incremental.annotation.processors delete mode 100644 annotations/src/main/java/org/acra/annotation/AnyNonDefault.kt delete mode 100644 annotations/src/main/java/org/acra/annotation/BuilderMethod.kt delete mode 100644 annotations/src/main/java/org/acra/annotation/Configuration.kt delete mode 100644 annotations/src/main/java/org/acra/annotation/ConfigurationValue.kt delete mode 100644 annotations/src/main/java/org/acra/annotation/Instantiatable.kt delete mode 100644 annotations/src/main/java/org/acra/annotation/NonEmpty.kt delete mode 100644 annotations/src/main/java/org/acra/annotation/PreBuild.kt delete mode 100644 annotations/src/main/java/org/acra/annotation/Transform.kt diff --git a/acra-advanced-scheduler/src/main/java/org/acra/annotation/AcraScheduler.java b/acra-advanced-scheduler/src/main/java/org/acra/config/SchedulerConfiguration.kt similarity index 50% rename from acra-advanced-scheduler/src/main/java/org/acra/annotation/AcraScheduler.java rename to acra-advanced-scheduler/src/main/java/org/acra/config/SchedulerConfiguration.kt index efb443c984..b21bf4caa9 100644 --- a/acra-advanced-scheduler/src/main/java/org/acra/annotation/AcraScheduler.java +++ b/acra-advanced-scheduler/src/main/java/org/acra/config/SchedulerConfiguration.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 + * Copyright (c) 2021 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,63 +14,58 @@ * limitations under the License. */ -package org.acra.annotation; +package org.acra.config -import android.app.job.JobInfo; - -import java.lang.annotation.*; +import android.app.job.JobInfo +import com.faendir.kotlin.autodsl.AutoDsl +import org.acra.annotation.AcraDsl +import org.acra.ktx.plus /** * @author F43nd1r * @since 18.04.18 */ -@Deprecated -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Inherited -@Configuration -public @interface AcraScheduler { - String EXTRA_APP_RESTARTED = "acra.restarted"; +@AutoDsl(dslMarker = AcraDsl::class) +class SchedulerConfiguration( + /** + * enables this plugin + */ + val enabled: Boolean = true, /** * Network constraint for report sending - * - * @return networkType required to allow report sending * @since 5.2.0 */ - int requiresNetworkType() default JobInfo.NETWORK_TYPE_NONE; + val requiresNetworkType: Int = JobInfo.NETWORK_TYPE_NONE, /** * Charging constraint for report sending - * - * @return if reports should only be sent while charging * @since 5.2.0 */ - boolean requiresCharging() default false; + val requiresCharging: Boolean = false, /** * Idle constraint for report sending - * - * @return if reports should only be sent while the device is idle * @since 5.2.0 */ - boolean requiresDeviceIdle() default false; + val requiresDeviceIdle: Boolean = false, /** * Battery constraint for report sending - * - * @return if reports should only be sent while battery isn't low * @since 5.2.0 */ - boolean requiresBatteryNotLow() default false; + val requiresBatteryNotLow: Boolean = false, /** * Restarts the last activity immediately after a crash. - * If an activity is restarted, the {@link org.acra.annotation.AcraScheduler#EXTRA_APP_RESTARTED} extra will contain a boolean true. + * If an activity is restarted, the [org.acra.scheduler.RestartingAdministrator.EXTRA_ACTIVITY_RESTART_AFTER_CRASH] extra will contain a boolean true. * Note that this might interact badly with the crash dialog. - * - * @return if acra should attempt to restart the app after a crash * @since 5.2.0 */ - boolean restartAfterCrash() default false; + val restartAfterCrash: Boolean = false, +) : Configuration { + override fun enabled(): Boolean = enabled +} + +fun CoreConfigurationBuilder.scheduler(initializer: SchedulerConfigurationBuilder.() -> Unit) { + pluginConfigurations += SchedulerConfigurationBuilder().apply(initializer).build() } diff --git a/acra-advanced-scheduler/src/main/java/org/acra/scheduler/AdvancedSenderScheduler.kt b/acra-advanced-scheduler/src/main/java/org/acra/scheduler/AdvancedSenderScheduler.kt index 77a90f81d9..c1ef472636 100644 --- a/acra-advanced-scheduler/src/main/java/org/acra/scheduler/AdvancedSenderScheduler.kt +++ b/acra-advanced-scheduler/src/main/java/org/acra/scheduler/AdvancedSenderScheduler.kt @@ -19,9 +19,9 @@ import android.app.job.JobInfo import android.content.Context import android.os.Build import com.google.auto.service.AutoService -import org.acra.config.ConfigUtils.getPluginConfiguration import org.acra.config.CoreConfiguration import org.acra.config.SchedulerConfiguration +import org.acra.config.getPluginConfiguration import org.acra.plugins.HasConfigPlugin /** @@ -31,12 +31,13 @@ import org.acra.plugins.HasConfigPlugin * @since 18.04.18 */ class AdvancedSenderScheduler private constructor(context: Context, config: CoreConfiguration) : DefaultSenderScheduler(context, config) { - private val schedulerConfiguration: SchedulerConfiguration = getPluginConfiguration(config, SchedulerConfiguration::class.java) + private val schedulerConfiguration: SchedulerConfiguration = config.getPluginConfiguration() override fun configureJob(job: JobInfo.Builder) { job.setRequiredNetworkType(schedulerConfiguration.requiresNetworkType) job.setRequiresCharging(schedulerConfiguration.requiresCharging) job.setRequiresDeviceIdle(schedulerConfiguration.requiresDeviceIdle) - var constrained = schedulerConfiguration.requiresNetworkType != JobInfo.NETWORK_TYPE_NONE || schedulerConfiguration.requiresCharging || schedulerConfiguration.requiresDeviceIdle + var constrained = + schedulerConfiguration.requiresNetworkType != JobInfo.NETWORK_TYPE_NONE || schedulerConfiguration.requiresCharging || schedulerConfiguration.requiresDeviceIdle if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { job.setRequiresBatteryNotLow(schedulerConfiguration.requiresBatteryNotLow) constrained = constrained or schedulerConfiguration.requiresBatteryNotLow diff --git a/acra-advanced-scheduler/src/main/java/org/acra/scheduler/RestartingAdministrator.kt b/acra-advanced-scheduler/src/main/java/org/acra/scheduler/RestartingAdministrator.kt index 0f8d32442e..16d1aebd00 100644 --- a/acra-advanced-scheduler/src/main/java/org/acra/scheduler/RestartingAdministrator.kt +++ b/acra-advanced-scheduler/src/main/java/org/acra/scheduler/RestartingAdministrator.kt @@ -22,10 +22,10 @@ import android.content.Context import android.os.PersistableBundle import com.google.auto.service.AutoService import org.acra.builder.LastActivityManager -import org.acra.config.ConfigUtils.getPluginConfiguration import org.acra.config.CoreConfiguration import org.acra.config.ReportingAdministrator import org.acra.config.SchedulerConfiguration +import org.acra.config.getPluginConfiguration import org.acra.log.debug import org.acra.log.info import org.acra.log.warn @@ -39,7 +39,7 @@ import org.acra.plugins.HasConfigPlugin class RestartingAdministrator : HasConfigPlugin(SchedulerConfiguration::class.java), ReportingAdministrator { override fun shouldFinishActivity(context: Context, config: CoreConfiguration, lastActivityManager: LastActivityManager): Boolean { debug { "RestartingAdministrator entry" } - if (getPluginConfiguration(config, SchedulerConfiguration::class.java).restartAfterCrash) { + if (config.getPluginConfiguration().restartAfterCrash) { val activity = lastActivityManager.lastActivity if (activity != null) { debug { "Try to schedule last activity (" + activity.javaClass.name + ") for restart" } diff --git a/acra-core/src/androidTest/java/org/acra/ACRATest.java b/acra-core/src/androidTest/java/org/acra/ACRATest.java index b9238fbd73..9c2256fe14 100644 --- a/acra-core/src/androidTest/java/org/acra/ACRATest.java +++ b/acra-core/src/androidTest/java/org/acra/ACRATest.java @@ -44,7 +44,7 @@ public class ACRATest { @Test public void init() { Application application = ApplicationProvider.getApplicationContext(); - CoreConfigurationBuilder builder = new CoreConfigurationBuilder(application).setPluginLoader(new SimplePluginLoader(StacktraceCollector.class, TestAdministrator.class)); + CoreConfigurationBuilder builder = new CoreConfigurationBuilder().withPluginLoader(new SimplePluginLoader(StacktraceCollector.class, TestAdministrator.class)); ACRA.init(application, builder); ACRA.getErrorReporter().handleException(new RuntimeException()); } @@ -52,7 +52,7 @@ public void init() { @Test(expected = AssertionError.class) public void failing() { Application application = ApplicationProvider.getApplicationContext(); - CoreConfigurationBuilder builder = new CoreConfigurationBuilder(application).setPluginLoader(new SimplePluginLoader(FailingTestAdministrator.class)); + CoreConfigurationBuilder builder = new CoreConfigurationBuilder().withPluginLoader(new SimplePluginLoader(FailingTestAdministrator.class)); ACRA.init(application, builder); ACRA.getErrorReporter().handleException(new RuntimeException()); } diff --git a/acra-core/src/androidTest/java/org/acra/attachment/DefaultAttachmentProviderTest.java b/acra-core/src/androidTest/java/org/acra/attachment/DefaultAttachmentProviderTest.java index a4d6b115f2..8d6886a088 100644 --- a/acra-core/src/androidTest/java/org/acra/attachment/DefaultAttachmentProviderTest.java +++ b/acra-core/src/androidTest/java/org/acra/attachment/DefaultAttachmentProviderTest.java @@ -16,12 +16,9 @@ package org.acra.attachment; -import android.app.Application; import android.net.Uri; - import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; - import org.acra.config.CoreConfigurationBuilder; import org.junit.Test; import org.junit.runner.RunWith; @@ -41,7 +38,7 @@ public class DefaultAttachmentProviderTest { @Test public void getAttachments() throws Exception { Uri uri = Uri.parse("content://not-a-valid-content-uri"); - List result = new DefaultAttachmentProvider().getAttachments(ApplicationProvider.getApplicationContext(), new CoreConfigurationBuilder(new Application()).withAttachmentUris(uri.toString()).build()); + List result = new DefaultAttachmentProvider().getAttachments(ApplicationProvider.getApplicationContext(), new CoreConfigurationBuilder().withAttachmentUris(uri.toString()).build()); assertThat(result, hasSize(1)); assertEquals(uri, result.get(0)); } diff --git a/acra-core/src/androidTest/java/org/acra/config/CoreConfigurationBuilderTest.java b/acra-core/src/androidTest/java/org/acra/config/CoreConfigurationBuilderTest.java deleted file mode 100644 index 258df15c27..0000000000 --- a/acra-core/src/androidTest/java/org/acra/config/CoreConfigurationBuilderTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2020 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.acra.config; - -import android.app.Application; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import org.acra.annotation.AcraCore; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * @author F43nd1r - * @since 01.02.18 - */ -@RunWith(AndroidJUnit4.class) -public class CoreConfigurationBuilderTest { - - @Test - public void enabled() { - assertTrue(new CoreConfigurationBuilder(new AnnotatedClass()).getEnabled()); - assertFalse(new CoreConfigurationBuilder(new NonAnnotatedClass()).getEnabled()); - } - - @AcraCore - private static class AnnotatedClass extends Application { - - } - - private static class NonAnnotatedClass extends Application { - - } -} \ No newline at end of file diff --git a/acra-core/src/main/java/org/acra/ACRA.kt b/acra-core/src/main/java/org/acra/ACRA.kt index a666e9ebaf..0d39f97a59 100644 --- a/acra-core/src/main/java/org/acra/ACRA.kt +++ b/acra-core/src/main/java/org/acra/ACRA.kt @@ -121,7 +121,7 @@ object ACRA { */ @JvmOverloads @JvmStatic - fun init(app: Application, builder: CoreConfigurationBuilder = CoreConfigurationBuilder(app), checkReportsOnApplicationStart: Boolean = true) { + fun init(app: Application, builder: CoreConfigurationBuilder = CoreConfigurationBuilder(), checkReportsOnApplicationStart: Boolean = true) { try { init(app, builder.build(), checkReportsOnApplicationStart) } catch (e: ACRAConfigurationException) { diff --git a/acra-core/src/main/java/org/acra/ACRAConstants.kt b/acra-core/src/main/java/org/acra/ACRAConstants.kt index 9ac3f0db7b..1ebb8db529 100644 --- a/acra-core/src/main/java/org/acra/ACRAConstants.kt +++ b/acra-core/src/main/java/org/acra/ACRAConstants.kt @@ -63,7 +63,7 @@ object ACRAConstants { * [org.acra.annotation.AcraCore.reportContent]. */ @JvmField - val DEFAULT_REPORT_FIELDS = arrayOf(ReportField.REPORT_ID, ReportField.APP_VERSION_CODE, ReportField.APP_VERSION_NAME, ReportField.PACKAGE_NAME, ReportField.FILE_PATH, + val DEFAULT_REPORT_FIELDS = listOf(ReportField.REPORT_ID, ReportField.APP_VERSION_CODE, ReportField.APP_VERSION_NAME, ReportField.PACKAGE_NAME, ReportField.FILE_PATH, ReportField.PHONE_MODEL, ReportField.BRAND, ReportField.PRODUCT, ReportField.ANDROID_VERSION, ReportField.BUILD, ReportField.TOTAL_MEM_SIZE, ReportField.AVAILABLE_MEM_SIZE, ReportField.BUILD_CONFIG, ReportField.CUSTOM_DATA, ReportField.IS_SILENT, ReportField.STACK_TRACE, ReportField.INITIAL_CONFIGURATION, ReportField.CRASH_CONFIGURATION, ReportField.DISPLAY, ReportField.USER_COMMENT, ReportField.USER_EMAIL, ReportField.USER_APP_START_DATE, ReportField.USER_CRASH_DATE, diff --git a/acra-core/src/main/java/org/acra/annotation/AcraCore.java b/acra-core/src/main/java/org/acra/annotation/AcraCore.java deleted file mode 100644 index 7c46548651..0000000000 --- a/acra-core/src/main/java/org/acra/annotation/AcraCore.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.acra.annotation; - -import androidx.annotation.NonNull; -import androidx.annotation.StringRes; -import org.acra.ACRAConstants; -import org.acra.ReportField; -import org.acra.attachment.AttachmentUriProvider; -import org.acra.attachment.DefaultAttachmentProvider; -import org.acra.config.BaseCoreConfigurationBuilder; -import org.acra.config.DefaultRetryPolicy; -import org.acra.config.RetryPolicy; -import org.acra.data.StringFormat; -import org.acra.file.Directory; -import org.acra.sender.ReportSenderFactory; - -import java.lang.annotation.*; - -/** - * Main ACRA configuration - * - * @author F43nd1r - * @since 01.06.2017 - */ -@Deprecated -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Inherited -@Configuration(baseBuilderClass = BaseCoreConfigurationBuilder.class, isPlugin = false) -public @interface AcraCore { - - /** - * Name of the SharedPreferences that will host ACRA settings which you can make accessible to your users through a preferences screen: - *
    - *
  • {@link org.acra.ACRA#PREF_DISABLE_ACRA} or {@link org.acra.ACRA#PREF_ENABLE_ACRA}
  • - *
  • {@link org.acra.ACRA#PREF_ALWAYS_ACCEPT}
  • - *
  • {@link org.acra.ACRA#PREF_ENABLE_DEVICE_ID}
  • - *
  • {@link org.acra.ACRA#PREF_ENABLE_SYSTEM_LOGS}
  • - *
- * Default is to use the application default SharedPreferences, as retrieved with {@link android.preference.PreferenceManager#getDefaultSharedPreferences(android.content.Context)} - * - * @return SharedPreferences name. - */ - @NonNull String sharedPreferencesName() default ACRAConstants.DEFAULT_STRING_VALUE; - - /** - * If enabled, DropBox events collection will include system tags: - *
    - *
  • system_app_anr
  • - *
  • system_app_wtf
  • - *
  • system_app_crash
  • - *
  • system_server_anr
  • - *
  • system_server_wtf
  • - *
  • system_server_crash
  • - *
  • BATTERY_DISCHARGE_INFO
  • - *
  • SYSTEM_RECOVERY_LOG
  • - *
  • SYSTEM_BOOT
  • - *
  • SYSTEM_LAST_KMSG
  • - *
  • APANIC_CONSOLE
  • - *
  • APANIC_THREADS
  • - *
  • SYSTEM_RESTART
  • - *
  • SYSTEM_TOMBSTONE
  • - *
  • data_app_strictmode
  • - *
- * - * @return if system tags are to be included as part of DropBox events. - */ - boolean includeDropBoxSystemTags() default false; - - /** - * Custom tags to be included in DropBox event collection - * - * @return tags that you want to be fetched when collecting DropBox events. - */ - @NonNull String[] additionalDropBoxTags() default {}; - - /** - * DropBox event collection will look back this many minutes - * - * @return Number of minutes to look back. - */ - int dropboxCollectionMinutes() default 5; - - /** - *

- * Arguments to be passed to the logcat command line. Default is { "-t", "100", "-v", "time" } for: - *

- *
logcat -t 100 -v time
- *

- * Do not include -b arguments for buffer selection, include {@link ReportField#EVENTSLOG} and {@link ReportField#RADIOLOG} in {@link #reportContent()} to activate alternative logcat buffers reporting. - * They will use the same other arguments as those provided here. - *

- *

- * See Listing of logcat Command Options. - *

- * - * @return arguments to supply if retrieving the log as part of the report. - */ - @NonNull String[] logcatArguments() default {"-t", "" + ACRAConstants.DEFAULT_LOG_LINES, "-v", "time"}; - - /** - *

- * Redefines the list of {@link ReportField}s collected and sent in your reports. - *

- *

- * You can also use this property to modify fields order in your reports. - *

- *

- * The default list is {@link org.acra.ACRAConstants#DEFAULT_REPORT_FIELDS} - * - * @return fields to be included in the report. - */ - @NonNull ReportField[] reportContent() default {}; - - /** - * Controls whether unapproved reports are deleted on application start or not. - *

- * Silent and Toast reports are automatically approved. - * Dialog and Notification reports require explicit approval by the user before they are sent. - *

- *

- * On application restart the user is prompted with approval for one unsent report. - * So you generally don't want to accumulate unapproved reports, otherwise you will prompt them multiple times. - *

- *

- * If this is set to true then all unapproved reports bar one will be deleted on application start. - * The last report is always retained because that is the report that probably just happened. - *

- * - * @return if ACRA should delete unapproved reports on application start. - */ - boolean deleteUnapprovedReportsOnApplicationStart() default true; - - /** - * Set this to true if you prefer displaying the native force close dialog after ACRA is done. - * Recommended: Keep this set to false if using interactions with user input. - * - * @return if the native force close dialog should be displayed. - */ - boolean alsoReportToAndroidFramework() default false; - - /** - * Add here your {@link android.content.SharedPreferences} identifier Strings if you use others than your application's default. They will be added to the {@link ReportField#SHARED_PREFERENCES} field. - * - * @return names of additional preferences. - */ - @NonNull String[] additionalSharedPreferences() default {}; - - /** - * Set this to true if you want to include only logcat lines related to your Application process. Note that this is always done by android starting with API 16 (Jellybean) - * - * @return true if you want to filter logcat with your process id. - */ - boolean logcatFilterByPid() default true; - - /** - * Set this to true if you want to read logcat lines in a non blocking way for your thread. It has a default timeout of 3 seconds. - * - * @return if reading of logcat lines should not block the current thread. - */ - boolean logcatReadNonBlocking() default false; - - /** - * Set this to false if you want to disable sending reports in development mode. Only signed application packages will send reports. - * - * @return if reports should only be sent from signed packages. - */ - boolean sendReportsInDevMode() default true; - - /** - * Provide here regex patterns to be evaluated on each {@link android.content.SharedPreferences} key to exclude KV pairs from the collected SharedPreferences. - * This allows you to exclude sensitive user data like passwords from being collected. - * - * If you only want to include some keys, you may use regular expressions to do so: - * - * - * - *
only keys foo and bar
"^(?!foo|bar).*$"
only keys containing foo and bar
"^((?!foo|bar).)*$"
- * - * @return regex patterns, every matching key is not collected. - */ - @NonNull String[] excludeMatchingSharedPreferencesKeys() default {}; - - /** - * Provide here regex patterns to be evaluated on each {@link android.provider.Settings.System}, {@link android.provider.Settings.Secure} and {@link android.provider.Settings.Global} key to exclude KV pairs from being collected. - * This allows you to exclude sensitive data from being collected. - * - * If you only want to include some keys, you may use regular expressions to do so: - * - * - * - *
only keys foo and bar
"^(?!foo|bar).*$"
only keys containing foo and bar
"^((?!foo|bar).)*$"
- * - * @return regex patterns, every matching key is not collected. - */ - @NonNull String[] excludeMatchingSettingsKeys() default {}; - - /** - * The default value will be a BuildConfig class residing in the same package as the Application class. - * You only have to set this option if your BuildConfig class is obfuscated. - * - * @return BuildConfig class from which to read any BuildConfig attributes. - */ - @NonNull Class buildConfigClass() default Object.class; - - /** - * To use in combination with {@link ReportField#APPLICATION_LOG} to set the path/name of your application log file. - * - * @return path/name of your application log file. - */ - @NonNull String applicationLogFile() default ACRAConstants.DEFAULT_STRING_VALUE; - - /** - * To use in combination with {@link ReportField#APPLICATION_LOG} to set the number of latest lines of your application log file to be collected. - * Default value is 100. - * - * @return number of lines to collect. - */ - int applicationLogFileLines() default ACRAConstants.DEFAULT_LOG_LINES; - - /** - * To use in combination with {@link ReportField#APPLICATION_LOG} to set the root for the path provided in {@link #applicationLogFile()} - * - * @return the directory of the application log file - */ - @NonNull Directory applicationLogFileDir() default Directory.FILES_LEGACY; - - /** - * Implement a custom {@link RetryPolicy} to decide if a failed report should be resent or not. - * - * @return a class that decides if a report should be resent (usually if one or more senders failed). - * @since 4.9.1 - */ - @Instantiatable @NonNull Class retryPolicyClass() default DefaultRetryPolicy.class; - - /** - * If you have services which might crash on startup android will try to restart them indefinitely. Set this to true to prevent that. - * - * @return if all services running in a process should be stopped before it is killed. - * @since 4.9.2 - */ - boolean stopServicesOnCrash() default false; - - /** - * Allows to attach files to crash reports. - *

- * ACRA contains a file provider under the following Uri: - * content://[applicationId].acra/[Directory]/[Path] - * where [applicationId] is your application package name, [Directory] is one of the enum constants in {@link Directory} in lower case and [Path] is the relative path to the file in that directory - * e.g. content://org.acra.test.acra/files/thisIsATest.txt - *

- * Side effects: - *
    - *
  • POST mode: requests will be sent with content-type multipart/form-data
  • - *
  • PUT mode: There will be additional requests with the attachments. Naming scheme: [report-id]-[filename]
  • - *
  • EMAIL mode: Some email clients do not support attachments, so some email may lack these attachments. Note that attachments might be readable to email clients when they are sent.
  • - *
- * - * @return uris to be attached to crash reports. - * @since 4.9.3 - */ - @NonNull String[] attachmentUris() default {}; - - /** - * Allows {@link #attachmentUris()} configuration at runtime instead of compile time. - * - * @return a class that decides which uris should be attached to reports - * @since 4.9.3 - */ - @Instantiatable @NonNull Class attachmentUriProvider() default DefaultAttachmentProvider.class; - - /** - * Toast shown when a report is sent successfully - * - * @return Resource id for the Toast text triggered when a report was sent successfully. - * @since 5.0.0 - */ - @StringRes int resReportSendSuccessToast() default ACRAConstants.DEFAULT_RES_VALUE; - - /** - * Toast shown when report sending fails - * - * @return Resource id for the Toast text triggered when no report was sent successfully. - * @since 5.0.0 - */ - @StringRes int resReportSendFailureToast() default ACRAConstants.DEFAULT_RES_VALUE; - - /** - * Format in which the report should be sent - * - * @return report format - * @since 5.0.0 - */ - @NonNull StringFormat reportFormat() default StringFormat.JSON; - - /** - * Allow parallel collection. Increases performance but might pollute e.g. logcat output - * @return if parallel collection should be active - * @since 5.0.1 - */ - boolean parallel() default true; -} diff --git a/annotations/build.gradle.kts b/acra-core/src/main/java/org/acra/annotation/AcraDsl.kt similarity index 74% rename from annotations/build.gradle.kts rename to acra-core/src/main/java/org/acra/annotation/AcraDsl.kt index 04cd5faff1..c7fff08830 100644 --- a/annotations/build.gradle.kts +++ b/acra-core/src/main/java/org/acra/annotation/AcraDsl.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 + * Copyright (c) 2021 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,6 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -plugins { - `acra-java-library` -} + +package org.acra.annotation + +import java.lang.annotation.Inherited + +@Inherited +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.BINARY) +annotation class AcraDsl diff --git a/acra-core/src/main/java/org/acra/collector/ReflectionCollector.kt b/acra-core/src/main/java/org/acra/collector/ReflectionCollector.kt index 61a30fa87a..e8772ed396 100644 --- a/acra-core/src/main/java/org/acra/collector/ReflectionCollector.kt +++ b/acra-core/src/main/java/org/acra/collector/ReflectionCollector.kt @@ -86,14 +86,7 @@ class ReflectionCollector : BaseReportFieldCollector(ReportField.BUILD, ReportFi */ @Throws(ClassNotFoundException::class) private fun getBuildConfigClass(context: Context, config: CoreConfiguration): Class<*> { - val configuredBuildConfig: Class<*> = config.buildConfigClass - if (configuredBuildConfig != Any::class.java) { - // If set via annotations or programmatically then it will have a real value, - // otherwise it will be Object.class (default). - return configuredBuildConfig - } - val className = context.packageName + ".BuildConfig" - return Class.forName(className) + return config.buildConfigClass ?: Class.forName(context.packageName + ".BuildConfig") } companion object { diff --git a/acra-core/src/main/java/org/acra/config/BaseCoreConfigurationBuilder.kt b/acra-core/src/main/java/org/acra/config/BaseCoreConfigurationBuilder.kt deleted file mode 100644 index df1f520549..0000000000 --- a/acra-core/src/main/java/org/acra/config/BaseCoreConfigurationBuilder.kt +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2011 Kevin Gaudin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.config - -import android.content.Context -import org.acra.ACRAConstants -import org.acra.ReportField -import org.acra.annotation.BuilderMethod -import org.acra.annotation.ConfigurationValue -import org.acra.annotation.PreBuild -import org.acra.annotation.Transform -import org.acra.log.debug -import org.acra.log.warn -import org.acra.plugins.PluginLoader -import org.acra.plugins.ServicePluginLoader -import org.acra.util.StubCreator.createStub -import java.lang.reflect.Method -import java.util.* - -/** - * Contains builder methods which can't be generated - * - * @author F43nd1r - */ -class BaseCoreConfigurationBuilder internal constructor(private val app: Context) { - private val reportContentChanges: MutableMap = EnumMap(ReportField::class.java) - private lateinit var configBuilders: List - private lateinit var configurations: List - private var pluginLoader: PluginLoader = ServicePluginLoader() - - private fun configurationBuilders(): List { - if (!this::configBuilders.isInitialized) { - val factories = pluginLoader.load(ConfigurationBuilderFactory::class.java) - debug { "Found ConfigurationBuilderFactories : $factories" } - configBuilders = factories.map { it.create(app) } - } - return configBuilders - } - - /** - * Set a custom plugin loader. Note: Call this before any call to [.getPluginConfigurationBuilder] - * - * @param pluginLoader the custom implementation - */ - @BuilderMethod - fun setPluginLoader(pluginLoader: PluginLoader) { - this.pluginLoader = pluginLoader - } - - @ConfigurationValue - fun pluginLoader(): PluginLoader { - return pluginLoader - } - - @PreBuild - @Throws(ACRAConfigurationException::class) - fun preBuild() { - val builders = configurationBuilders() - debug { "Found ConfigurationBuilders : $builders" } - configurations = builders.map { it.build() } - } - - @Transform(methodName = "reportContent") - fun transformReportContent(reportFields: Array): List { - val reportContent: MutableList = ArrayList() - if (reportFields.isNotEmpty()) { - debug { "Using custom Report Fields" } - reportContent.addAll(reportFields) - } else { - debug { "Using default Report Fields" } - reportContent.addAll(ACRAConstants.DEFAULT_REPORT_FIELDS) - } - - // Add or remove any extra fields. - for ((key, value) in reportContentChanges) { - if (value) { - reportContent.add(key) - } else { - reportContent.remove(key) - } - } - return reportContent - } - - /** - * Use this if you want to keep the default configuration of reportContent, but set some fields explicitly. - * - * @param field the field to set - * @param enable if this field should be reported - */ - @BuilderMethod - fun setReportField(field: ReportField, enable: Boolean) { - reportContentChanges[field] = enable - } - - @ConfigurationValue - fun pluginConfigurations(): List { - return configurations - } - - @BuilderMethod - fun getPluginConfigurationBuilder(c: Class): R { - for (builder in configurationBuilders()) { - if (c.isAssignableFrom(builder.javaClass)) { - @Suppress("UNCHECKED_CAST") - return builder as R - } - } - if (c.isInterface) { - warn { "Couldn't find ConfigurationBuilder ${c.simpleName}. ALL CALLS TO IT WILL BE IGNORED!" } - return createStub(c) { proxy, _, _ -> proxy } - } - throw IllegalArgumentException("Class ${c.name} is not a registered ConfigurationBuilder") - } -} \ No newline at end of file diff --git a/acra-core/src/main/java/org/acra/config/ConfigUtils.kt b/acra-core/src/main/java/org/acra/config/ConfigUtils.kt index 642f705225..3c2e6a7de3 100644 --- a/acra-core/src/main/java/org/acra/config/ConfigUtils.kt +++ b/acra-core/src/main/java/org/acra/config/ConfigUtils.kt @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@file:JvmName("ConfigUtils") + package org.acra.config import org.acra.log.debug @@ -23,17 +25,23 @@ import org.acra.log.debug * @author F43nd1r * @since 01.06.2017 */ -object ConfigUtils { - @JvmStatic - fun getPluginConfiguration(config: CoreConfiguration, c: Class): T { - debug { "Checking plugin Configurations : ${config.pluginConfigurations} for class : $c" } - for (configuration in config.pluginConfigurations) { - debug { "Checking plugin Configuration : $configuration against plugin class : $c" } - if (c.isAssignableFrom(configuration.javaClass)) { - @Suppress("UNCHECKED_CAST") - return configuration as T - } + +inline fun CoreConfiguration.getPluginConfiguration() : T = getPluginConfiguration(T::class.java) + +fun CoreConfiguration.getPluginConfiguration(c: Class): T { + return findPluginConfiguration(c) ?: throw IllegalArgumentException("${c.name} is no registered configuration") +} + +inline fun CoreConfiguration.findPluginConfiguration() : T? = findPluginConfiguration(T::class.java) + +fun CoreConfiguration.findPluginConfiguration(c: Class): T? { + debug { "Checking plugin Configurations : $pluginConfigurations for class : $c" } + for (configuration in pluginConfigurations) { + debug { "Checking plugin Configuration : $configuration against plugin class : $c" } + if (c.isAssignableFrom(configuration.javaClass)) { + @Suppress("UNCHECKED_CAST") + return configuration as T } - throw IllegalArgumentException("${c.name} is no registered configuration") } + return null } \ No newline at end of file diff --git a/acra-core/src/main/java/org/acra/config/CoreConfiguration.kt b/acra-core/src/main/java/org/acra/config/CoreConfiguration.kt new file mode 100644 index 0000000000..2f6588dd35 --- /dev/null +++ b/acra-core/src/main/java/org/acra/config/CoreConfiguration.kt @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.acra.config + +import com.faendir.kotlin.autodsl.AutoDsl +import org.acra.ACRAConstants +import org.acra.ReportField +import org.acra.annotation.AcraDsl +import org.acra.attachment.AttachmentUriProvider +import org.acra.attachment.DefaultAttachmentProvider +import org.acra.data.StringFormat +import org.acra.file.Directory +import org.acra.plugins.PluginLoader +import org.acra.plugins.ServicePluginLoader +import java.io.Serializable + +@AutoDsl(dslMarker = AcraDsl::class) +class CoreConfiguration( + + /** + * Name of the SharedPreferences that will host ACRA settings which you can make accessible to your users through a preferences screen: + * + * - [org.acra.ACRA.PREF_DISABLE_ACRA] or [org.acra.ACRA.PREF_ENABLE_ACRA] + * - [org.acra.ACRA.PREF_ALWAYS_ACCEPT] + * - [org.acra.ACRA.PREF_ENABLE_DEVICE_ID] + * - [org.acra.ACRA.PREF_ENABLE_SYSTEM_LOGS] + * + * Default is to use the application default SharedPreferences, as retrieved with [android.preference.PreferenceManager.getDefaultSharedPreferences] + */ + val sharedPreferencesName: String? = null, + + /** + * If enabled, DropBox events collection will include system tags: + * + * - system_app_anr + * - system_app_wtf + * - system_app_crash + * - system_server_anr + * - system_server_wtf + * - system_server_crash + * - BATTERY_DISCHARGE_INFO + * - SYSTEM_RECOVERY_LOG + * - SYSTEM_BOOT + * - SYSTEM_LAST_KMSG + * - APANIC_CONSOLE + * - APANIC_THREADS + * - SYSTEM_RESTART + * - SYSTEM_TOMBSTONE + * - data_app_strictmode + * + */ + val includeDropBoxSystemTags: Boolean = false, + + /** + * Custom tags to be included in DropBox event collection + */ + val additionalDropBoxTags: List = emptyList(), + + /** + * DropBox event collection will look back this many minutes + */ + val dropboxCollectionMinutes: Int = 5, + + /** + * Arguments to be passed to the logcat command line. + * + * Do not include -b arguments for buffer selection, include [ReportField.EVENTSLOG] and [ReportField.RADIOLOG] in [reportContent] to activate alternative logcat buffers reporting. + * They will use the same other arguments as those provided here. + * + * See [Listing of logcat Command Options](http://developer.android.com/intl/fr/guide/developing/tools/adb.html#logcatoptions) + */ + val logcatArguments: List = listOf("-t", ACRAConstants.DEFAULT_LOG_LINES.toString(), "-v", "time"), + + /** + * Redefines the list of [ReportField]s collected and sent in your reports. + * + * You can also use this property to modify fields order in your reports. + */ + val reportContent: List = ACRAConstants.DEFAULT_REPORT_FIELDS.toList(), + + /** + * Controls whether unapproved reports are deleted on application start or not. + *

+ * Silent and Toast reports are automatically approved. + * Dialog and Notification reports require explicit approval by the user before they are sent. + *

+ *

+ * On application restart the user is prompted with approval for one unsent report. + * So you generally don't want to accumulate unapproved reports, otherwise you will prompt them multiple times. + *

+ *

+ * If this is set to true then all unapproved reports bar one will be deleted on application start. + * The last report is always retained because that is the report that probably just happened. + *

+ */ + val deleteUnapprovedReportsOnApplicationStart: Boolean = true, + + /** + * Set this to true if you prefer displaying the native force close dialog after ACRA is done. + * Recommended: Keep this set to false if using interactions with user input. + */ + val alsoReportToAndroidFramework: Boolean = false, + + /** + * Add here your [android.content.SharedPreferences] identifier Strings if you use others than your application's default. They will be added to the [ReportField.SHARED_PREFERENCES] field. + */ + val additionalSharedPreferences: List = emptyList(), + + /** + * Set this to true if you want to include only logcat lines related to your Application process. Note that this is always done by android starting with API 16 (Jellybean) + */ + val logcatFilterByPid: Boolean = true, + + /** + * Set this to true if you want to read logcat lines in a non blocking way for your thread. It has a default timeout of 3 seconds. + */ + val logcatReadNonBlocking: Boolean = false, + + /** + * Set this to false if you want to disable sending reports in development mode. Only signed application packages will send reports. + */ + val sendReportsInDevMode: Boolean = true, + + /** + * Provide here regex patterns to be evaluated on each [android.content.SharedPreferences] key to exclude KV pairs from the collected SharedPreferences. + * This allows you to exclude sensitive user data like passwords from being collected. + * + * If you only want to include some keys, you may use regular expressions to do so: + * + * + * + *
only keys foo and bar
"^(?!foo|bar).*$"
only keys containing foo and bar
"^((?!foo|bar).)*$"
+ */ + val excludeMatchingSharedPreferencesKeys: List = emptyList(), + + /** + * Provide here regex patterns to be evaluated on each [android.provider.Settings.System}, [android.provider.Settings.Secure] and [android.provider.Settings.Global] key to exclude KV pairs from being collected. + * This allows you to exclude sensitive data from being collected. + * + * If you only want to include some keys, you may use regular expressions to do so: + * + * + * + *
only keys foo and bar
"^(?!foo|bar).*$"
only keys containing foo and bar
"^((?!foo|bar).)*$"
+ */ + val excludeMatchingSettingsKeys: List = emptyList(), + + /** + * The default value will be a BuildConfig class residing in the same package as the Application class. + * You only have to set this option if your BuildConfig class is obfuscated. + */ + val buildConfigClass: Class<*>? = null, + + /** + * To use in combination with [ReportField.APPLICATION_LOG] to set the path/name of your application log file. + */ + val applicationLogFile: String = ACRAConstants.DEFAULT_STRING_VALUE, + + /** + * To use in combination with [ReportField.APPLICATION_LOG] to set the number of latest lines of your application log file to be collected. + * Default value is 100. + */ + val applicationLogFileLines: Int = ACRAConstants.DEFAULT_LOG_LINES, + + /** + * To use in combination with [ReportField.APPLICATION_LOG] to set the root for the path provided in [applicationLogFile] + */ + val applicationLogFileDir: Directory = Directory.FILES_LEGACY, + + /** + * Implement a custom [RetryPolicy] to decide if a failed report should be resent or not. + * @since 4.9.1 + */ + val retryPolicyClass: Class = DefaultRetryPolicy::class.java, + + /** + * If you have services which might crash on startup android will try to restart them indefinitely. Set this to true to prevent that. + * @since 4.9.2 + */ + val stopServicesOnCrash: Boolean = false, + + /** + * Allows to attach files to crash reports. + *

+ * ACRA contains a file provider under the following Uri: + * content://[applicationId].acra/[Directory]/[Path] + * where [applicationId] is your application package name, [Directory] is one of the enum constants in [Directory] in lower case and [Path] is the relative path to the file in that directory + * e.g. content://org.acra.test.acra/files/thisIsATest.txt + *

+ * Side effects: + * + * - POST mode: requests will be sent with content-type multipart/form-data + * - PUT mode: There will be additional requests with the attachments. Naming scheme: - + * - EMAIL mode: Some email clients do not support attachments, so some emails may lack these attachments. Note that attachments might be readable to email clients when they are sent. + * + * @since 4.9.3 + */ + val attachmentUris: List = emptyList(), + + /** + * Allows [attachmentUris] configuration at runtime instead of compile time. + * @since 4.9.3 + */ + val attachmentUriProvider: Class = DefaultAttachmentProvider::class.java, + + /** + * Toast shown when a report is sent successfully + * @since 5.0.0 + */ + val reportSendSuccessToast: String? = null, + + /** + * Toast shown when report sending fails + * @since 5.0.0 + */ + val reportSendFailureToast: String? = null, + + /** + * Format in which the report should be sent + * @since 5.0.0 + */ + val reportFormat: StringFormat = StringFormat.JSON, + + /** + * Allow parallel collection. Increases performance but might pollute e.g. logcat output + * @since 5.0.1 + */ + val parallel: Boolean = true, + + /** + * Allows custom plugin loading + */ + val pluginLoader: PluginLoader = ServicePluginLoader(), + + /** + * Plugin configurations + */ + val pluginConfigurations: List = emptyList(), +) : Serializable, Configuration { + override fun enabled(): Boolean = true +} diff --git a/acra-core/src/main/java/org/acra/ktx/Extensions.kt b/acra-core/src/main/java/org/acra/ktx/Extensions.kt index afe96639d0..fb42b1a91a 100644 --- a/acra-core/src/main/java/org/acra/ktx/Extensions.kt +++ b/acra-core/src/main/java/org/acra/ktx/Extensions.kt @@ -20,26 +20,20 @@ package org.acra.ktx import android.app.Application import org.acra.ACRA import org.acra.config.CoreConfigurationBuilder -import org.acra.config.ConfigurationBuilder - -inline fun CoreConfigurationBuilder.getPluginConfigurationBuilder(): T { - return this.getPluginConfigurationBuilder(T::class.java) -} +import kotlin.collections.plus as superPlus fun Application.initAcra(initializer: CoreConfigurationBuilder.() -> Unit = { }) { - val builder = CoreConfigurationBuilder(this) + val builder = CoreConfigurationBuilder() builder.initializer() ACRA.init(this, builder) } -inline fun CoreConfigurationBuilder.plugin(initializer: T.() -> Unit) { - this.getPluginConfigurationBuilder().initializer() -} - fun Throwable.sendWithAcra() { ACRA.errorReporter.handleException(this) } fun Throwable.sendSilentlyWithAcra() { ACRA.errorReporter.handleSilentException(this) -} \ No newline at end of file +} + +operator fun List?.plus(element: T) : List = this?.superPlus(element) ?: listOf(element) \ No newline at end of file diff --git a/acra-core/src/main/java/org/acra/plugins/HasConfigPlugin.kt b/acra-core/src/main/java/org/acra/plugins/HasConfigPlugin.kt index 37e72ffbe3..7dbf1c8761 100644 --- a/acra-core/src/main/java/org/acra/plugins/HasConfigPlugin.kt +++ b/acra-core/src/main/java/org/acra/plugins/HasConfigPlugin.kt @@ -15,14 +15,14 @@ */ package org.acra.plugins -import org.acra.config.ConfigUtils import org.acra.config.Configuration import org.acra.config.CoreConfiguration +import org.acra.config.findPluginConfiguration /** * @author F43nd1r * @since 18.04.18 */ abstract class HasConfigPlugin(private val configClass: Class) : Plugin { - override fun enabled(config: CoreConfiguration): Boolean = ConfigUtils.getPluginConfiguration(config, configClass).enabled() + override fun enabled(config: CoreConfiguration): Boolean = config.findPluginConfiguration(configClass)?.enabled() ?: false } \ No newline at end of file diff --git a/acra-core/src/main/java/org/acra/sender/SendingConductor.kt b/acra-core/src/main/java/org/acra/sender/SendingConductor.kt index f25e695435..03bea1590a 100644 --- a/acra-core/src/main/java/org/acra/sender/SendingConductor.kt +++ b/acra-core/src/main/java/org/acra/sender/SendingConductor.kt @@ -51,8 +51,8 @@ class SendingConductor(private val context: Context, private val config: CoreCon reportsSentCount++ } } - val toast: String = if (reportsSentCount > 0) config.reportSendSuccessToast else config.reportSendFailureToast - if (anyNonSilent && toast.isNotEmpty()) { + val toast: String? = if (reportsSentCount > 0) config.reportSendSuccessToast else config.reportSendFailureToast + if (anyNonSilent && toast != null && toast.isNotEmpty()) { debug { "About to show " + (if (reportsSentCount > 0) "success" else "failure") + " toast" } Handler(Looper.getMainLooper()).post { sendToast(context, toast, Toast.LENGTH_LONG) } } diff --git a/acra-dialog/src/main/java/org/acra/annotation/AcraDialog.java b/acra-dialog/src/main/java/org/acra/annotation/AcraDialog.java deleted file mode 100644 index c93515f8f8..0000000000 --- a/acra-dialog/src/main/java/org/acra/annotation/AcraDialog.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.acra.annotation; - -import android.app.Activity; -import android.content.DialogInterface; -import androidx.annotation.DrawableRes; -import androidx.annotation.NonNull; -import androidx.annotation.StringRes; -import androidx.annotation.StyleRes; -import org.acra.ACRAConstants; -import org.acra.dialog.CrashReportDialog; - -import java.lang.annotation.*; - -/** - * CrashReportDialog configuration - * - * @author F43nd1r - * @since 01.06.2017 - */ -@Deprecated -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Inherited -@Configuration -public @interface AcraDialog { - - /** - * Custom CrashReportDialog class - * - * @return The activity to use to prompt the user for crash details. Inside the activity, use {@link org.acra.dialog.CrashReportDialogHelper} to integrate it ACRA. - * @since 5.0.0 - */ - @Instantiatable @AnyNonDefault @NonNull Class reportDialogClass() default CrashReportDialog.class; - - /** - * label of the positive button - * - * @return Resource id for the positive button label in the crash dialog. - * @see android.app.AlertDialog.Builder#setPositiveButton(int, DialogInterface.OnClickListener) - * @since 5.0.0 - */ - @StringRes int resPositiveButtonText() default android.R.string.ok; - - /** - * label of the negative button - * - * @return Resource id for the negative button label in the crash dialog. - * @see android.app.AlertDialog.Builder#setNegativeButton(int, DialogInterface.OnClickListener) - * @since 5.0.0 - */ - @StringRes int resNegativeButtonText() default android.R.string.cancel; - - /** - * label of the comment input prompt. - * If not provided, removes the input field. - * - * @return Resource id for the user comment input label in the crash dialog. - * @since 5.0.0 - */ - @StringRes int resCommentPrompt() default ACRAConstants.DEFAULT_RES_VALUE; - - /** - * label of the email input prompt. - * If not provided, removes the input field. - * - * @return Resource id for the user email address input label in the crash dialog. - * @since 5.0.0 - */ - @StringRes int resEmailPrompt() default ACRAConstants.DEFAULT_RES_VALUE; - - /** - * icon of the dialog - * - * @return Resource id for the icon in the crash dialog. - * @see android.app.AlertDialog.Builder#setIcon(int) - * @since 5.0.0 - */ - @DrawableRes int resIcon() default android.R.drawable.ic_dialog_alert; - - /** - * text in the dialog - * - * @return Resource id for the text in the crash dialog. - * @since 5.0.0 - */ - @AnyNonDefault @StringRes int resText() default ACRAConstants.DEFAULT_RES_VALUE; - - /** - * title of the dialog - * - * @return Resource id for the title in the crash dialog. - * @see android.app.AlertDialog.Builder#setTitle(int) - * @since 5.0.0 - */ - @StringRes int resTitle() default ACRAConstants.DEFAULT_RES_VALUE; - - /** - * theme of the dialog - * - * @return resource id for the crash dialog theme - * @see android.app.Activity#setTheme(int) - * @since 5.0.0 - */ - @StyleRes int resTheme() default ACRAConstants.DEFAULT_RES_VALUE; -} diff --git a/acra-dialog/src/main/java/org/acra/config/DialogConfiguration.kt b/acra-dialog/src/main/java/org/acra/config/DialogConfiguration.kt new file mode 100644 index 0000000000..18a73a01f2 --- /dev/null +++ b/acra-dialog/src/main/java/org/acra/config/DialogConfiguration.kt @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.acra.config + +import android.app.Activity +import androidx.annotation.DrawableRes +import androidx.annotation.StyleRes +import com.faendir.kotlin.autodsl.AutoDsl +import com.faendir.kotlin.autodsl.AutoDslRequired +import org.acra.annotation.AcraDsl +import org.acra.dialog.CrashReportDialog +import org.acra.ktx.plus + +/** + * CrashReportDialog configuration + * + * @author F43nd1r + * @since 01.06.2017 + */ +@AutoDsl(dslMarker = AcraDsl::class) +class DialogConfiguration( + /** + * enables this plugin + */ + val enabled: Boolean = true, + + /** + * Custom CrashReportDialog class + * + * Inside the activity, use [org.acra.dialog.CrashReportDialogHelper] to integrate it ACRA. + * + * @since 5.0.0 + */ + @AutoDslRequired("main") + val reportDialogClass: Class = CrashReportDialog::class.java, + + /** + * label of the positive button + * + * Defaults to [android.R.string.ok] + * @see android.app.AlertDialog.Builder.setPositiveButton + * @since 5.0.0 + */ + val positiveButtonText: String? = null, + + /** + * label of the negative button + * + * Defaults to [android.R.string.cancel] + * @see android.app.AlertDialog.Builder.setNegativeButton + * @since 5.0.0 + */ + val negativeButtonText: String? = null, + + /** + * label of the comment input prompt. + * If not provided, removes the input field. + * @since 5.0.0 + */ + val commentPrompt: String? = null, + + /** + * label of the email input prompt. + * If not provided, removes the input field. + * @since 5.0.0 + */ + val emailPrompt: String? = null, + + /** + * icon of the dialog + * + * @see android.app.AlertDialog.Builder.setIcon + * @since 5.0.0 + */ + @DrawableRes + val resIcon: Int = android.R.drawable.ic_dialog_alert, + + /** + * text in the dialog + * + * @since 5.0.0 + */ + @AutoDslRequired("main") + val text: String? = null, + + /** + * title of the dialog + * + * @see android.app.AlertDialog.Builder.setTitle + * @since 5.0.0 + */ + val title: String? = null, + + /** + * theme of the dialog + * + * @see android.app.Activity.setTheme + * @since 5.0.0 + */ + @StyleRes + val resTheme: Int? = null, +) : Configuration { + override fun enabled(): Boolean = enabled +} + +fun CoreConfigurationBuilder.dialog(initializer: DialogConfigurationBuilder.() -> Unit) { + pluginConfigurations += DialogConfigurationBuilder().apply(initializer).build() +} diff --git a/acra-dialog/src/main/java/org/acra/dialog/CrashReportDialog.kt b/acra-dialog/src/main/java/org/acra/dialog/CrashReportDialog.kt index dbdca53321..46914869a2 100644 --- a/acra-dialog/src/main/java/org/acra/dialog/CrashReportDialog.kt +++ b/acra-dialog/src/main/java/org/acra/dialog/CrashReportDialog.kt @@ -30,8 +30,8 @@ import android.widget.TextView import androidx.annotation.CallSuper import org.acra.ACRA import org.acra.ACRAConstants -import org.acra.config.ConfigUtils.getPluginConfiguration import org.acra.config.DialogConfiguration +import org.acra.config.getPluginConfiguration import org.acra.prefs.SharedPreferencesFactory /** @@ -63,7 +63,7 @@ open class CrashReportDialog : Activity(), DialogInterface.OnClickListener { scrollable = LinearLayout(this) scrollable.orientation = LinearLayout.VERTICAL sharedPreferencesFactory = SharedPreferencesFactory(applicationContext, helper.config) - dialogConfiguration = getPluginConfiguration(helper.config, DialogConfiguration::class.java) + dialogConfiguration = helper.config.getPluginConfiguration() dialogConfiguration.resTheme.takeIf { it != ACRAConstants.DEFAULT_RES_VALUE }?.let { setTheme(it) } padding = loadPaddingFromTheme() buildAndShowDialog(savedInstanceState) @@ -79,11 +79,11 @@ open class CrashReportDialog : Activity(), DialogInterface.OnClickListener { */ protected fun buildAndShowDialog(savedInstanceState: Bundle?) { val dialogBuilder = AlertDialog.Builder(this) - dialogConfiguration.title.takeIf { it.isNotEmpty() }?.let { dialogBuilder.setTitle(title) } + dialogConfiguration.title?.takeIf { it.isNotEmpty() }?.let { dialogBuilder.setTitle(title) } dialogConfiguration.resIcon.takeIf { it != ACRAConstants.DEFAULT_RES_VALUE }?.let { dialogBuilder.setIcon(it) } dialogBuilder.setView(buildCustomView(savedInstanceState)) - .setPositiveButton(dialogConfiguration.positiveButtonText, this) - .setNegativeButton(dialogConfiguration.negativeButtonText, this) + .setPositiveButton(dialogConfiguration.positiveButtonText ?: getString(android.R.string.ok), this) + .setNegativeButton(dialogConfiguration.negativeButtonText ?: getString(android.R.string.cancel), this) dialog = dialogBuilder.create() dialog.setCanceledOnTouchOutside(false) dialog.setOnDismissListener { @@ -142,7 +142,7 @@ open class CrashReportDialog : Activity(), DialogInterface.OnClickListener { * @return the main view */ protected fun getMainView(): View { - return TextView(this).apply { dialogConfiguration.text.takeIf { it.isNotEmpty() }?.let { text = it } } + return TextView(this).apply { dialogConfiguration.text?.takeIf { it.isNotEmpty() }?.let { text = it } } } /** @@ -151,7 +151,7 @@ open class CrashReportDialog : Activity(), DialogInterface.OnClickListener { * @return the label or null if there is no resource */ protected fun getCommentLabel(): View? { - return dialogConfiguration.commentPrompt.takeIf { it.isNotEmpty() }?.let { TextView(this).apply { text = it } } + return dialogConfiguration.commentPrompt?.takeIf { it.isNotEmpty() }?.let { TextView(this).apply { text = it } } } /** @@ -173,7 +173,7 @@ open class CrashReportDialog : Activity(), DialogInterface.OnClickListener { * @return the label or null if there is no resource */ protected fun getEmailLabel(): View? { - return dialogConfiguration.emailPrompt.takeIf { it.isNotEmpty() }?.let { TextView(this).apply { text = it } } + return dialogConfiguration.emailPrompt?.takeIf { it.isNotEmpty() }?.let { TextView(this).apply { text = it } } } /** diff --git a/acra-dialog/src/main/java/org/acra/interaction/DialogInteraction.kt b/acra-dialog/src/main/java/org/acra/interaction/DialogInteraction.kt index 717f56ba26..98f8275646 100644 --- a/acra-dialog/src/main/java/org/acra/interaction/DialogInteraction.kt +++ b/acra-dialog/src/main/java/org/acra/interaction/DialogInteraction.kt @@ -19,9 +19,9 @@ import android.content.Context import android.content.Intent import com.google.auto.service.AutoService import org.acra.ACRA -import org.acra.config.ConfigUtils.getPluginConfiguration import org.acra.config.CoreConfiguration import org.acra.config.DialogConfiguration +import org.acra.config.getPluginConfiguration import org.acra.log.debug import org.acra.plugins.HasConfigPlugin import org.acra.prefs.SharedPreferencesFactory @@ -54,7 +54,7 @@ class DialogInteraction : HasConfigPlugin(DialogConfiguration::class.java), Repo */ private fun createCrashReportDialogIntent(context: Context, config: CoreConfiguration, reportFile: File): Intent { debug { "Creating DialogIntent for $reportFile" } - val dialogIntent = Intent(context, getPluginConfiguration(config, DialogConfiguration::class.java).reportDialogClass) + val dialogIntent = Intent(context, config.getPluginConfiguration().reportDialogClass) dialogIntent.putExtra(EXTRA_REPORT_FILE, reportFile) dialogIntent.putExtra(EXTRA_REPORT_CONFIG, config) return dialogIntent diff --git a/acra-http/src/main/java/org/acra/annotation/AcraHttpSender.java b/acra-http/src/main/java/org/acra/annotation/AcraHttpSender.java deleted file mode 100644 index 6f6c0131e1..0000000000 --- a/acra-http/src/main/java/org/acra/annotation/AcraHttpSender.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.acra.annotation; - -import androidx.annotation.NonNull; -import androidx.annotation.RawRes; -import org.acra.ACRAConstants; -import org.acra.config.BaseHttpConfigurationBuilder; -import org.acra.security.KeyStoreFactory; -import org.acra.security.NoKeyStoreFactory; -import org.acra.security.TLS; -import org.acra.sender.HttpSender; - -import java.lang.annotation.*; - -/** - * Http sender configuration - * - * @author F43nd1r - * @since 01.06.2017 - */ -@Deprecated -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Inherited -@Configuration(baseBuilderClass = BaseHttpConfigurationBuilder.class) -public @interface AcraHttpSender { - /** - * The Uri of your own server-side script that will receive reports. - * - * @return URI of a server to which to send reports. - * @since 5.0.0 - */ - @NonNull @AnyNonDefault String uri() default ACRAConstants.NULL_VALUE; - - /** - * you can set here and in {@link org.acra.annotation.AcraHttpSender#basicAuthPassword()} the credentials for a BASIC HTTP authentication. - * - * @return Login to use. - * @since 5.0.0 - */ - @NonNull String basicAuthLogin() default ACRAConstants.NULL_VALUE; - - /** - * you can set here and in {@link org.acra.annotation.AcraHttpSender#basicAuthLogin()} the credentials for a BASIC HTTP authentication. - * - * @return Password to use. - * @since 5.0.0 - */ - @NonNull String basicAuthPassword() default ACRAConstants.NULL_VALUE; - - /** - *

- * The {@link HttpSender.Method} to be used when posting with {@link org.acra.annotation.AcraHttpSender#uri()} . - *

- * - * @return HTTP method used when posting reports. - * @since 5.0.0 - */ - @NonNull HttpSender.Method httpMethod() default HttpSender.Method.POST; - - /** - * timeout for server connection - * - * @return Value in milliseconds for timeout attempting to connect to a network. - * @see java.net.HttpURLConnection#setConnectTimeout(int) - * @since 5.0.0 - */ - int connectionTimeout() default 5000; - - /** - * timeout for socket connection - * - * @return Value in milliseconds for timeout receiving a response to a network request. - * @see java.net.HttpURLConnection#setReadTimeout(int) - * @since 5.0.0 - */ - int socketTimeout() default 20000; - - /** - * allows to prevent resending of timed out reports, possibly relieving server stress, but also reducing received report counts - * - * @return if timed out reports should be dropped - * @since 5.0.0 - */ - boolean dropReportsOnTimeout() default false; - - /** - * A custom class supplying a {@link java.security.KeyStore}, which will be used for ssl authentication. - * A base implementation is available: {@link org.acra.security.BaseKeyStoreFactory} - * - * @return Class which creates a keystore that can contain trusted certificates - * @since 5.0.0 - */ - @NonNull Class keyStoreFactoryClass() default NoKeyStoreFactory.class; - - /** - * a certificate used for ssl authentication - * - * @return path to a custom trusted certificate. Must start with "asset://" if the file is in the assets folder - * @since 5.0.0 - */ - @NonNull String certificatePath() default ACRAConstants.DEFAULT_STRING_VALUE; - - /** - * a certificate used for ssl authentication - * - * @return resource id of a custom trusted certificate. - * @since 5.0.0 - */ - @RawRes int resCertificate() default ACRAConstants.DEFAULT_RES_VALUE; - - /** - * type of the certificate used for ssl authentication - * - * @return specify the type of the certificate set in either {@link org.acra.annotation.AcraHttpSender#certificatePath()} or {@link org.acra.annotation.AcraHttpSender#resCertificate()} - * @since 5.0.0 - */ - @NonNull String certificateType() default ACRAConstants.DEFAULT_CERTIFICATE_TYPE; - - /** - * if the server request should be compressed using gzip - * - * @return if compression should be active - * @since 5.2.0 - */ - boolean compress() default false; - - /** - * Note: Older Android versions do not support all tls versions. - * This array has to contain at least one option supported on all android versions this runs on! - * ACRA will automatically remove unsupported versions on older devices. - * - * @return accepted tls protocols - * @since 5.7.0 - * @see javax.net.ssl.SSLContext - */ - @NonNull TLS[] tlsProtocols() default {TLS.V1_3, TLS.V1_2, TLS.V1_1, TLS.V1}; -} diff --git a/acra-http/src/main/java/org/acra/config/BaseHttpConfigurationBuilder.kt b/acra-http/src/main/java/org/acra/config/BaseHttpConfigurationBuilder.kt deleted file mode 100644 index 4d4039ec18..0000000000 --- a/acra-http/src/main/java/org/acra/config/BaseHttpConfigurationBuilder.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.config - -import org.acra.annotation.BuilderMethod -import org.acra.annotation.ConfigurationValue -import java.util.* - -/** - * @author F43nd1r - * @since 01.06.2017 - */ -class BaseHttpConfigurationBuilder internal constructor() { - private val httpHeaders: MutableMap - - /** - * Set custom HTTP headers to be sent by the provided [org.acra.sender.HttpSender] - * This should be used also by third party senders. - * - * @param headers A map associating HTTP header names to their values. - */ - @BuilderMethod - fun setHttpHeaders(headers: Map) { - httpHeaders.clear() - httpHeaders.putAll(headers) - } - - @ConfigurationValue - fun httpHeaders(): Map { - return httpHeaders - } - - init { - httpHeaders = HashMap() - } -} \ No newline at end of file diff --git a/acra-http/src/main/java/org/acra/config/HttpSenderConfiguration.kt b/acra-http/src/main/java/org/acra/config/HttpSenderConfiguration.kt new file mode 100644 index 0000000000..f8e9a66d83 --- /dev/null +++ b/acra-http/src/main/java/org/acra/config/HttpSenderConfiguration.kt @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.acra.config + +import androidx.annotation.RawRes +import com.faendir.kotlin.autodsl.AutoDsl +import org.acra.annotation.AcraDsl +import org.acra.ktx.plus +import org.acra.security.KeyStoreFactory +import org.acra.security.NoKeyStoreFactory +import org.acra.security.TLS +import org.acra.sender.HttpSender + +/** + * Http sender configuration + * + * @author F43nd1r + * @since 01.06.2017 + */ +@AutoDsl(dslMarker = AcraDsl::class) +class HttpSenderConfiguration( + /** + * enables this plugin + */ + val enabled: Boolean = true, + /** + * The Uri of your own server-side script that will receive reports. + * + * @since 5.0.0 + */ + val uri: String, + + /** + * you can set here and in [basicAuthPassword] the credentials for a BASIC HTTP authentication. + * + * @since 5.0.0 + */ + val basicAuthLogin: String? = null, + + /** + * you can set here and in [basicAuthLogin] the credentials for a BASIC HTTP authentication. + * + * @since 5.0.0 + */ + val basicAuthPassword: String? = null, + + /** + * The [HttpSender.Method] to be used when posting with [uri]. + * + * @since 5.0.0 + */ + val httpMethod: HttpSender.Method = HttpSender.Method.POST, + + /** + * timeout for server connection in milliseconds + * + * @see java.net.HttpURLConnection.setConnectTimeout + * @since 5.0.0 + */ + val connectionTimeout: Int = 5000, + + /** + * timeout for socket connection in milliseconds + * + * @see java.net.HttpURLConnection.setReadTimeout + * @since 5.0.0 + */ + val socketTimeout: Int = 20000, + + /** + * allows to prevent resending of timed out reports, possibly relieving server stress, but also reducing received report counts + * + * @since 5.0.0 + */ + val dropReportsOnTimeout: Boolean = false, + + /** + * A custom class supplying a [java.security.KeyStore], which will be used for ssl authentication. + * A base implementation is available: [org.acra.security.BaseKeyStoreFactory] + * + * @since 5.0.0 + */ + val keyStoreFactoryClass: Class = NoKeyStoreFactory::class.java, + + /** + * a certificate used for ssl authentication + * + * Must start with "asset://" if the file is in the assets folder + * + * @since 5.0.0 + */ + val certificatePath: String? = null, + + /** + * a certificate used for ssl authentication + * + * @since 5.0.0 + */ + @RawRes + val resCertificate: Int? = null, + + /** + * type of the certificate used for ssl authentication, set in either [certificatePath] or [resCertificate] + * + * @since 5.0.0 + */ + val certificateType: String = "X.509", + + /** + * if the server request should be compressed using gzip + * + * @since 5.2.0 + */ + val compress: Boolean = false, + + /** + * TLS versions supported by the server. + * + * This array has to contain at least one option supported on all android versions this runs on! + * ACRA will automatically remove unsupported versions on older devices. + * + * Note: Older Android versions do not support all tls versions. + * + * @since 5.7.0 + * @see javax.net.ssl.SSLContext + */ + val tlsProtocols: List = listOf(TLS.V1_3, TLS.V1_2, TLS.V1_1, TLS.V1), + + /** + * custom HTTP headers to be sent by the provided [org.acra.sender.HttpSender] + * This should be used also by third party senders. + */ + val httpHeaders: Map = emptyMap(), +) : Configuration { + override fun enabled(): Boolean = enabled +} + +fun CoreConfigurationBuilder.httpSender(initializer: HttpSenderConfigurationBuilder.() -> Unit) { + pluginConfigurations += HttpSenderConfigurationBuilder().apply(initializer).build() +} diff --git a/acra-http/src/main/java/org/acra/http/BaseHttpRequest.kt b/acra-http/src/main/java/org/acra/http/BaseHttpRequest.kt index 108f1cfd53..c330c4c618 100644 --- a/acra-http/src/main/java/org/acra/http/BaseHttpRequest.kt +++ b/acra-http/src/main/java/org/acra/http/BaseHttpRequest.kt @@ -21,9 +21,9 @@ import android.util.Log import org.acra.ACRA import org.acra.ACRAConstants import org.acra.BuildConfig -import org.acra.config.ConfigUtils.getPluginConfiguration import org.acra.config.CoreConfiguration import org.acra.config.HttpSenderConfiguration +import org.acra.config.getPluginConfiguration import org.acra.log.debug import org.acra.log.error import org.acra.log.info @@ -51,7 +51,7 @@ import javax.net.ssl.TrustManagerFactory abstract class BaseHttpRequest(private val config: CoreConfiguration, private val context: Context, private val method: HttpSender.Method, private val login: String?, private val password: String?, private val connectionTimeOut: Int, private val socketTimeOut: Int, private val headers: Map?) : HttpRequest { - private val senderConfiguration: HttpSenderConfiguration = getPluginConfiguration(config, HttpSenderConfiguration::class.java) + private val senderConfiguration: HttpSenderConfiguration = config.getPluginConfiguration() /** * Sends to a URL. @@ -101,7 +101,7 @@ abstract class BaseHttpRequest(private val config: CoreConfiguration, private tmf.init(keyStore) val sslContext = SSLContext.getInstance("TLS") sslContext.init(null, tmf.trustManagers, null) - connection.sslSocketFactory = ProtocolSocketFactoryWrapper(sslContext.socketFactory, senderConfiguration.tlsProtocols.asList()) + connection.sslSocketFactory = ProtocolSocketFactoryWrapper(sslContext.socketFactory, senderConfiguration.tlsProtocols) } protected fun configureTimeouts(connection: HttpURLConnection, connectionTimeOut: Int, socketTimeOut: Int) { diff --git a/acra-http/src/main/java/org/acra/security/KeyStoreHelper.kt b/acra-http/src/main/java/org/acra/security/KeyStoreHelper.kt index 391133d71c..d490df519a 100644 --- a/acra-http/src/main/java/org/acra/security/KeyStoreHelper.kt +++ b/acra-http/src/main/java/org/acra/security/KeyStoreHelper.kt @@ -17,9 +17,9 @@ package org.acra.security import android.content.Context import org.acra.ACRAConstants -import org.acra.config.ConfigUtils.getPluginConfiguration import org.acra.config.CoreConfiguration import org.acra.config.HttpSenderConfiguration +import org.acra.config.getPluginConfiguration import org.acra.util.InstanceCreator import java.security.KeyStore @@ -39,16 +39,16 @@ object KeyStoreHelper { * @return the keystore, or null if none provided / failure */ fun getKeyStore(context: Context, config: CoreConfiguration): KeyStore? { - val senderConfiguration = getPluginConfiguration(config, HttpSenderConfiguration::class.java) + val senderConfiguration = config.getPluginConfiguration() var keyStore = InstanceCreator.create(senderConfiguration.keyStoreFactoryClass) { NoKeyStoreFactory() }.create(context) if (keyStore == null) { //either users factory did not create a keystore, or the configuration is default {@link NoKeyStoreFactory} - val certificateRes: Int = senderConfiguration.resCertificate - val certificatePath: String = senderConfiguration.certificatePath + val certificateRes: Int? = senderConfiguration.resCertificate + val certificatePath: String? = senderConfiguration.certificatePath val certificateType: String = senderConfiguration.certificateType - if (certificateRes != ACRAConstants.DEFAULT_RES_VALUE) { + if (certificateRes != null) { keyStore = ResourceKeyStoreFactory(certificateType, certificateRes).create(context) - } else if (certificatePath != ACRAConstants.DEFAULT_STRING_VALUE) { + } else if (certificatePath != null) { keyStore = if (certificatePath.startsWith(ASSET_PREFIX)) { AssetKeyStoreFactory(certificateType, certificatePath.substring(ASSET_PREFIX.length)).create(context) } else { diff --git a/acra-http/src/main/java/org/acra/sender/HttpSender.kt b/acra-http/src/main/java/org/acra/sender/HttpSender.kt index 7786c96b10..0de3d7b447 100644 --- a/acra-http/src/main/java/org/acra/sender/HttpSender.kt +++ b/acra-http/src/main/java/org/acra/sender/HttpSender.kt @@ -21,9 +21,9 @@ import org.acra.ACRA import org.acra.ACRAConstants import org.acra.ReportField import org.acra.attachment.DefaultAttachmentProvider -import org.acra.config.ConfigUtils.getPluginConfiguration import org.acra.config.CoreConfiguration import org.acra.config.HttpSenderConfiguration +import org.acra.config.getPluginConfiguration import org.acra.data.CrashReportData import org.acra.data.StringFormat import org.acra.http.BinaryHttpRequest @@ -67,7 +67,7 @@ import java.net.URL */ @Suppress("unused") class HttpSender @JvmOverloads constructor(private val config: CoreConfiguration, method: Method?, type: StringFormat?, formUri: String? = null) : ReportSender { - private val httpConfig: HttpSenderConfiguration = getPluginConfiguration(config, HttpSenderConfiguration::class.java) + private val httpConfig: HttpSenderConfiguration = config.getPluginConfiguration() private val mFormUri: Uri = Uri.parse(formUri ?: httpConfig.uri) private val mMethod: Method = method ?: httpConfig.httpMethod private val mType: StringFormat = type ?: config.reportFormat diff --git a/acra-limiter/src/main/java/org/acra/annotation/AcraLimiter.java b/acra-limiter/src/main/java/org/acra/annotation/AcraLimiter.java deleted file mode 100644 index 74a1022c48..0000000000 --- a/acra-limiter/src/main/java/org/acra/annotation/AcraLimiter.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.acra.annotation; - -import androidx.annotation.NonNull; -import androidx.annotation.StringRes; - -import org.acra.ACRAConstants; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.concurrent.TimeUnit; - -/** - * Limiter configuration - * - * @author F43nd1r - * @since 26.10.2017 - */ -@Deprecated -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Inherited -@Configuration -public @interface AcraLimiter { - /** - * Unit of {@link org.acra.annotation.AcraLimiter#period()} - * - * @return a time unit - * @since 5.0.0 - */ - @NonNull TimeUnit periodUnit() default TimeUnit.DAYS; - - /** - * Reports which have been collected before this will not be considered for any limits except {@link org.acra.annotation.AcraLimiter#failedReportLimit()} - * - * @return number of {@link org.acra.annotation.AcraLimiter#periodUnit()}s in which to limit reports - * @since 5.0.0 - */ - long period() default 7; - - /** - * general limit of reports - * - * @return maximum number of reports per period - * @since 5.0.0 - */ - int overallLimit() default 25; - - /** - * limit for reports with the same stacktrace - * - * @return maximum number of reports with the same stacktrace per period - * @since 5.0.0 - */ - int stacktraceLimit() default 3; - - /** - * limit for reports with the same exception class - * - * @return maximum number of reports with the same exception class per period - * @since 5.0.0 - */ - int exceptionClassLimit() default 10; - - /** - * limit for unsent reports - * - * @return maximum number of unsent reports to keep - * @since 5.0.0 - */ - int failedReportLimit() default 5; - - /** - * toast shown when a report was not collected or sent because a limit was exceeded - * - * @return Resource id for the toast shown when a crash was ignored - * @since 5.0.0 - */ - @StringRes int resIgnoredCrashToast() default ACRAConstants.DEFAULT_RES_VALUE; - - /** - * This property can be used to determine whether old (out of date) reports should be sent or not. - * - * @return if ACRA should delete any unsent reports on startup if the application has been updated. - * @since 5.3.0 - */ - boolean deleteReportsOnAppUpdate() default true; - - /** - * Resetting limits after an app update allows you to see if a bug still exists. - * - * @return if ACRA should reset all limits on startup if the application has been updated. - * @since 5.3.0 - */ - boolean resetLimitsOnAppUpdate() default true; -} diff --git a/acra-limiter/src/main/java/org/acra/config/LimiterConfiguration.kt b/acra-limiter/src/main/java/org/acra/config/LimiterConfiguration.kt new file mode 100644 index 0000000000..c383b4f631 --- /dev/null +++ b/acra-limiter/src/main/java/org/acra/config/LimiterConfiguration.kt @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.acra.config + +import com.faendir.kotlin.autodsl.AutoDsl +import org.acra.annotation.AcraDsl +import org.acra.ktx.plus +import java.util.concurrent.TimeUnit + +/** + * Limiter configuration + * + * @author F43nd1r + * @since 26.10.2017 + */ +@AutoDsl(dslMarker = AcraDsl::class) +class LimiterConfiguration( + /** + * enables this plugin + */ + val enabled: Boolean = true, + /** + * Unit of [period] + * + * @since 5.0.0 + */ + val periodUnit: TimeUnit = TimeUnit.DAYS, + + /** + * number of [periodUnit]s in which to limit reports + * + * Reports which have been collected before this will not be considered for any limits except [failedReportLimit] + * + * @since 5.0.0 + */ + val period: Long = 7, + + /** + * general limit of reports per period + * + * @since 5.0.0 + */ + val overallLimit: Int = 25, + + /** + * limit for reports with the same stacktrace per period + * + * @since 5.0.0 + */ + val stacktraceLimit: Int = 3, + + /** + * limit for reports with the same exception class per period + * + * @since 5.0.0 + */ + val exceptionClassLimit: Int = 10, + + /** + * limit for unsent reports to keep + * + * @since 5.0.0 + */ + val failedReportLimit: Int = 5, + + /** + * toast shown when a report was not collected or sent because a limit was exceeded + * + * @since 5.0.0 + */ + val ignoredCrashToast: String? = null, + + /** + * This property can be used to determine whether old (out of date) reports should be sent or not. + * + * @since 5.3.0 + */ + val deleteReportsOnAppUpdate: Boolean = true, + + /** + * Resetting limits after an app update allows you to see if a bug still exists. + * + * @since 5.3.0 + */ + val resetLimitsOnAppUpdate: Boolean = true, +) : Configuration { + override fun enabled(): Boolean = enabled +} + +fun CoreConfigurationBuilder.limiter(initializer: LimiterConfigurationBuilder.() -> Unit) { + pluginConfigurations += LimiterConfigurationBuilder().apply(initializer).build() +} diff --git a/acra-limiter/src/main/java/org/acra/config/LimitingReportAdministrator.kt b/acra-limiter/src/main/java/org/acra/config/LimitingReportAdministrator.kt index 5a7c57ac4b..5bb59eb07a 100644 --- a/acra-limiter/src/main/java/org/acra/config/LimitingReportAdministrator.kt +++ b/acra-limiter/src/main/java/org/acra/config/LimitingReportAdministrator.kt @@ -22,7 +22,6 @@ import android.os.Looper import android.widget.Toast import com.google.auto.service.AutoService import org.acra.builder.ReportBuilder -import org.acra.config.ConfigUtils.getPluginConfiguration import org.acra.config.LimiterData.Companion.load import org.acra.config.LimiterData.ReportMetadata import org.acra.data.CrashReportData @@ -45,7 +44,7 @@ import java.util.concurrent.Executors class LimitingReportAdministrator : HasConfigPlugin(LimiterConfiguration::class.java), ReportingAdministrator { override fun shouldStartCollecting(context: Context, config: CoreConfiguration, reportBuilder: ReportBuilder): Boolean { try { - val limiterConfiguration = getPluginConfiguration(config, LimiterConfiguration::class.java) + val limiterConfiguration = config.getPluginConfiguration() val reportLocator = ReportLocator(context) if (reportLocator.approvedReports.size + reportLocator.unapprovedReports.size >= limiterConfiguration.failedReportLimit) { debug { "Reached failedReportLimit, not collecting" } @@ -64,7 +63,7 @@ class LimitingReportAdministrator : HasConfigPlugin(LimiterConfiguration::class. override fun shouldSendReport(context: Context, config: CoreConfiguration, crashReportData: CrashReportData): Boolean { try { - val limiterConfiguration = getPluginConfiguration(config, LimiterConfiguration::class.java) + val limiterConfiguration = config.getPluginConfiguration() val limiterData = loadLimiterData(context, limiterConfiguration) var sameTrace = 0 var sameClass = 0 @@ -96,8 +95,8 @@ class LimitingReportAdministrator : HasConfigPlugin(LimiterConfiguration::class. } override fun notifyReportDropped(context: Context, config: CoreConfiguration) { - val limiterConfiguration = getPluginConfiguration(config, LimiterConfiguration::class.java) - if (limiterConfiguration.ignoredCrashToast.isNotEmpty()) { + val limiterConfiguration = config.getPluginConfiguration() + if (limiterConfiguration.ignoredCrashToast?.isNotEmpty() == true) { val future = Executors.newSingleThreadExecutor().submit { Looper.prepare() sendToast(context, limiterConfiguration.ignoredCrashToast, Toast.LENGTH_LONG) diff --git a/acra-limiter/src/main/java/org/acra/startup/LimiterStartupProcessor.kt b/acra-limiter/src/main/java/org/acra/startup/LimiterStartupProcessor.kt index 1713271a74..6c42c0aeff 100644 --- a/acra-limiter/src/main/java/org/acra/startup/LimiterStartupProcessor.kt +++ b/acra-limiter/src/main/java/org/acra/startup/LimiterStartupProcessor.kt @@ -18,10 +18,10 @@ package org.acra.startup import android.content.Context import com.google.auto.service.AutoService import org.acra.ACRA -import org.acra.config.ConfigUtils.getPluginConfiguration import org.acra.config.CoreConfiguration import org.acra.config.LimiterConfiguration import org.acra.config.LimiterData +import org.acra.config.getPluginConfiguration import org.acra.log.warn import org.acra.plugins.HasConfigPlugin import org.acra.prefs.SharedPreferencesFactory @@ -35,7 +35,7 @@ import java.io.IOException @AutoService(StartupProcessor::class) class LimiterStartupProcessor : HasConfigPlugin(LimiterConfiguration::class.java), StartupProcessor { override fun processReports(context: Context, config: CoreConfiguration, reports: List) { - val limiterConfiguration = getPluginConfiguration(config, LimiterConfiguration::class.java) + val limiterConfiguration = config.getPluginConfiguration() if (limiterConfiguration.deleteReportsOnAppUpdate || limiterConfiguration.resetLimitsOnAppUpdate) { val prefs = SharedPreferencesFactory(context, config).create() val lastVersionNr = prefs.getInt(ACRA.PREF_LAST_VERSION_NR, 0).toLong() diff --git a/acra-mail/src/main/java/org/acra/annotation/AcraMailSender.java b/acra-mail/src/main/java/org/acra/annotation/AcraMailSender.java deleted file mode 100644 index dde5a91602..0000000000 --- a/acra-mail/src/main/java/org/acra/annotation/AcraMailSender.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.acra.annotation; - -import androidx.annotation.NonNull; -import androidx.annotation.StringRes; - -import org.acra.ACRAConstants; -import org.acra.sender.EmailIntentSender; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @author F43nd1r - * @since 01.06.2017 - */ -@Deprecated -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Inherited -@Configuration -public @interface AcraMailSender { - - /** - * your crash reports mailbox - * - * @return email address to which to send reports. - * @since 5.0.0 - */ - @NonNull @AnyNonDefault String mailTo() default ACRAConstants.NULL_VALUE; - - /** - * Sending the report as an attachment prevents issues with report size and the user from modifying it - * - * @return if the report should be an attachment instead of plain text. - * @since 5.0.0 - */ - boolean reportAsFile() default true; - - /** - * custom file name for the report - * - * @return report file name - * @since 5.0.1 - */ - @NonNull String reportFileName() default EmailIntentSender.DEFAULT_REPORT_FILENAME; - - /** - * custom email subject. - * Default is "<applicationId> Crash Report" - * - * @return resource id of the custom email subject - * @since 5.0.1 - */ - @StringRes int resSubject() default ACRAConstants.DEFAULT_RES_VALUE; - - /** - * custom email body. - * - * @return resource id of the custom email body - * @since 5.3.0 - */ - @StringRes int resBody() default ACRAConstants.DEFAULT_RES_VALUE; -} diff --git a/acra-mail/src/main/java/org/acra/config/MailSenderConfiguration.kt b/acra-mail/src/main/java/org/acra/config/MailSenderConfiguration.kt new file mode 100644 index 0000000000..fce00aff74 --- /dev/null +++ b/acra-mail/src/main/java/org/acra/config/MailSenderConfiguration.kt @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.acra.config + +import com.faendir.kotlin.autodsl.AutoDsl +import org.acra.annotation.AcraDsl +import org.acra.ktx.plus +import org.acra.sender.EmailIntentSender + +/** + * @author F43nd1r + * @since 01.06.2017 + */ +@AutoDsl(dslMarker = AcraDsl::class) +class MailSenderConfiguration( + /** + * enables this plugin + */ + val enabled: Boolean = true, + + /** + * your crash reports mailbox address + * + * @since 5.0.0 + */ + val mailTo: String, + + /** + * report is an attachment instead of plain text. + * + * Sending the report as an attachment prevents issues with report size and the user from modifying it + * + * @since 5.0.0 + */ + val reportAsFile: Boolean = true, + + /** + * custom file name for the report + * + * @since 5.0.1 + */ + val reportFileName: String = EmailIntentSender.DEFAULT_REPORT_FILENAME, + + /** + * custom email subject. + * + * Default is " Crash Report" + * + * @since 5.0.1 + */ + val subject: String? = null, + + /** + * custom email body. + * + * @since 5.3.0 + */ + val body: String? = null, +) : Configuration { + override fun enabled(): Boolean = enabled +} + +fun CoreConfigurationBuilder.mailSender(initializer: MailSenderConfigurationBuilder.() -> Unit) { + pluginConfigurations += MailSenderConfigurationBuilder().apply(initializer).build() +} diff --git a/acra-mail/src/main/java/org/acra/sender/EmailIntentSender.kt b/acra-mail/src/main/java/org/acra/sender/EmailIntentSender.kt index 10fb430971..bee2bfc06e 100644 --- a/acra-mail/src/main/java/org/acra/sender/EmailIntentSender.kt +++ b/acra-mail/src/main/java/org/acra/sender/EmailIntentSender.kt @@ -26,12 +26,11 @@ import androidx.annotation.RequiresApi import org.acra.ACRAConstants import org.acra.attachment.AcraContentProvider import org.acra.attachment.DefaultAttachmentProvider -import org.acra.config.ConfigUtils.getPluginConfiguration import org.acra.config.CoreConfiguration import org.acra.config.MailSenderConfiguration +import org.acra.config.getPluginConfiguration import org.acra.data.CrashReportData import org.acra.log.warn -import org.acra.sender.ReportSenderException import org.acra.util.IOUtils.writeStringToFile import org.acra.util.InstanceCreator import java.io.File @@ -48,7 +47,7 @@ import java.util.* */ @Suppress("MemberVisibilityCanBePrivate") class EmailIntentSender(private val config: CoreConfiguration) : ReportSender { - private val mailConfig: MailSenderConfiguration = getPluginConfiguration(config, MailSenderConfiguration::class.java) + private val mailConfig: MailSenderConfiguration = config.getPluginConfiguration() @Throws(ReportSenderException::class) override fun send(context: Context, errorContent: CrashReportData) { @@ -58,8 +57,8 @@ class EmailIntentSender(private val config: CoreConfiguration) : ReportSender { } catch (e: Exception) { throw ReportSenderException("Failed to convert Report to text", e) } - val bodyPrefix: String = mailConfig.body - val body = if (bodyPrefix.isNotEmpty()) "$bodyPrefix\n$reportText" else reportText + val bodyPrefix: String? = mailConfig.body + val body = if (bodyPrefix?.isNotEmpty() == true) "$bodyPrefix\n$reportText" else reportText val attachments = ArrayList() val contentAttached = fillAttachmentList(context, reportText, attachments) @@ -70,8 +69,10 @@ class EmailIntentSender(private val config: CoreConfiguration) : ReportSender { } } - private fun sendLegacy(subject: String, body: String, attachments: ArrayList, - context: Context, contentAttached: Boolean, bodyPrefix: String) { + private fun sendLegacy( + subject: String, body: String, attachments: ArrayList, + context: Context, contentAttached: Boolean, bodyPrefix: String? + ) { val pm = context.packageManager //we have to resolve with sendto, because send is supported by non-email apps val resolveIntent = buildResolveIntent() @@ -110,8 +111,10 @@ class EmailIntentSender(private val config: CoreConfiguration) : ReportSender { } @RequiresApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) - private fun sendWithSelector(subject: String, body: String, attachments: ArrayList, - context: Context, contentAttached: Boolean, bodyPrefix: String) { + private fun sendWithSelector( + subject: String, body: String, attachments: ArrayList, + context: Context, contentAttached: Boolean, bodyPrefix: String? + ) { val intent = buildAttachmentIntent(subject, if (contentAttached) bodyPrefix else body, attachments) intent.selector = buildResolveIntent() grantPermission(context, intent, null, attachments) @@ -226,8 +229,8 @@ class EmailIntentSender(private val config: CoreConfiguration) : ReportSender { * @return the message subject */ protected fun buildSubject(context: Context): String { - val subject: String = mailConfig.subject - return if (subject.isNotEmpty()) { + val subject: String? = mailConfig.subject + return if (subject?.isNotEmpty() == true) { subject } else context.packageName + " Crash Report" } diff --git a/acra-notification/src/main/java/org/acra/annotation/AcraNotification.java b/acra-notification/src/main/java/org/acra/annotation/AcraNotification.java deleted file mode 100644 index ed5bd6de9d..0000000000 --- a/acra-notification/src/main/java/org/acra/annotation/AcraNotification.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.acra.annotation; - -import android.app.PendingIntent; -import androidx.annotation.DrawableRes; -import androidx.annotation.StringRes; - -import org.acra.ACRAConstants; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @author F43nd1r - * @since 15.09.2017 - */ -@Deprecated -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Inherited -@Configuration -public @interface AcraNotification { - - /** - * icon of the notification - * - * @return Resource id for the icon in the status bar notification. - * @see androidx.core.app.NotificationCompat.Builder#setSmallIcon(int) - * @since 5.0.0 - */ - @DrawableRes int resIcon() default android.R.drawable.stat_sys_warning; - - /** - * title of the notification - * - * @return Resource id for the title in the status bar notification. - * @see androidx.core.app.NotificationCompat.Builder#setContentTitle(CharSequence) - * @since 5.0.0 - */ - @StringRes int resTitle(); - - /** - * text in the notification - * - * @return Resource id for the text in the status bar notification. - * @see androidx.core.app.NotificationCompat.Builder#setContentText(CharSequence) - * @since 5.0.0 - */ - @StringRes int resText(); - - /** - * ticker text for the notification - * - * @return Resource id for the ticker text in the status bar notification. - * @see androidx.core.app.NotificationCompat.Builder#setTicker(CharSequence) - * @since 5.0.0 - */ - @StringRes int resTickerText() default ACRAConstants.DEFAULT_RES_VALUE; - - /** - * send button text shown in expanded view - * - * @return Resource id for the send button text in the status bar notification. - * @see androidx.core.app.NotificationCompat.Builder#addAction(int, CharSequence, PendingIntent) - * @since 5.0.0 - */ - @StringRes int resSendButtonText() default android.R.string.ok; - - /** - * send button icon shown in collapsed and sometimes expanded view - * - * @return Resource id for the send button icon in the status bar notification. - * @see androidx.core.app.NotificationCompat.Builder#addAction(int, CharSequence, PendingIntent) - * @since 5.0.0 - */ - @DrawableRes int resSendButtonIcon() default android.R.drawable.ic_menu_send; - - /** - * discard button text shown in expanded view - * - * @return Resource id for the discard button text in the status bar notification. - * @see androidx.core.app.NotificationCompat.Builder#addAction(int, CharSequence, PendingIntent) - * @since 5.0.0 - */ - @StringRes int resDiscardButtonText() default android.R.string.cancel; - - /** - * discard button icon shown in collapsed and sometimes expanded view - * - * @return Resource id for the discard button icon in the status bar notification. - * @see androidx.core.app.NotificationCompat.Builder#addAction(int, CharSequence, PendingIntent) - * @since 5.0.0 - */ - @DrawableRes int resDiscardButtonIcon() default android.R.drawable.ic_menu_delete; - - /** - * notification channel name. - * To learn about notification channels, visit the notification guide - * - * @return Resource id for the notification channel name - * @see android.app.NotificationChannel#NotificationChannel(String, CharSequence, int) - * @since 5.0.0 - */ - @StringRes int resChannelName(); - - /** - * notification channel description - * - * @return Resource id for the notification channel description - * @see android.app.NotificationChannel#setDescription(String) - * @since 5.0.0 - */ - @StringRes int resChannelDescription() default ACRAConstants.DEFAULT_RES_VALUE; - - /** - * notification channel importance. Must be one of - *
    - *
  • {@link android.app.NotificationManager#IMPORTANCE_NONE}
  • - *
  • {@link android.app.NotificationManager#IMPORTANCE_LOW}
  • - *
  • {@link android.app.NotificationManager#IMPORTANCE_DEFAULT}
  • - *
  • {@link android.app.NotificationManager#IMPORTANCE_HIGH}
  • - *
  • {@link android.app.NotificationManager#IMPORTANCE_MAX}
  • - *
- * - * @return notification channel importance. Default is {@link android.app.NotificationManager#IMPORTANCE_HIGH} - * @see android.app.NotificationChannel#NotificationChannel(String, CharSequence, int) - * @since 5.0.0 - */ - int resChannelImportance() default 4; - - /** - * in-line comment button text. - * No effect on pre-nougat devices. - * - * @return Resource id for the send with comment button text in the status bar notification. - * @see androidx.core.app.NotificationCompat.Builder#addAction(int, CharSequence, PendingIntent) - * @since 5.0.0 - */ - @StringRes int resSendWithCommentButtonText() default ACRAConstants.DEFAULT_RES_VALUE; - - /** - * in-line comment button icon. - * No effect on pre-nougat devices. - * - * @return Resource id for the send with comment button icon in the status bar notification. - * @see androidx.core.app.NotificationCompat.Builder#addAction(int, CharSequence, PendingIntent) - * @since 5.0.0 - */ - @DrawableRes int resSendWithCommentButtonIcon() default android.R.drawable.ic_menu_send; - - /** - * in-line comment prompt label. - * No effect on pre-nougat devices. - * - * @return Resource id for the user comment input label in the notification action. - * @see androidx.core.app.RemoteInput.Builder#setLabel(CharSequence) - * @since 5.0.0 - */ - @StringRes int resCommentPrompt() default ACRAConstants.DEFAULT_RES_VALUE; - - /** - * enable to send report even on normal click, not only on button click - * - * @return if a normal click on the notification should send the report - * @since 5.0.0 - */ - boolean sendOnClick() default false; -} diff --git a/acra-notification/src/main/java/org/acra/config/NotificationConfiguration.kt b/acra-notification/src/main/java/org/acra/config/NotificationConfiguration.kt new file mode 100644 index 0000000000..ac61fa3a02 --- /dev/null +++ b/acra-notification/src/main/java/org/acra/config/NotificationConfiguration.kt @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.acra.config + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import com.faendir.kotlin.autodsl.AutoDsl +import org.acra.ACRAConstants +import org.acra.annotation.AcraDsl +import org.acra.ktx.plus + +/** + * @author F43nd1r + * @since 15.09.2017 + */ +@AutoDsl(dslMarker = AcraDsl::class) +class NotificationConfiguration( + /** + * enables this plugin + */ + val enabled: Boolean = true, + /** + * icon of the notification + * + * @see androidx.core.app.NotificationCompat.Builder#setSmallIcon(int) + * @since 5.0.0 + */ + @DrawableRes + val resIcon: Int = android.R.drawable.stat_sys_warning, + + /** + * title of the notification + * + * @see androidx.core.app.NotificationCompat.Builder.setContentTitle + * @since 5.0.0 + */ + val title: String, + + /** + * text in the notification + * + * @see androidx.core.app.NotificationCompat.Builder.setContentText + * @since 5.0.0 + */ + val text: String, + + /** + * ticker text for the notification + * + * @see androidx.core.app.NotificationCompat.Builder.setTicker + * @since 5.0.0 + */ + val tickerText: String? = null, + + /** + * send button text shown in expanded view + * + * defaults to [android.R.string.ok] + * + * @see androidx.core.app.NotificationCompat.Builder.addAction + * @since 5.0.0 + */ + val sendButtonText: String? = null, + + /** + * send button icon shown in collapsed and sometimes expanded view + * + * @see androidx.core.app.NotificationCompat.Builder.addAction + * @since 5.0.0 + */ + @DrawableRes + val resSendButtonIcon: Int = android.R.drawable.ic_menu_send, + + /** + * discard button text shown in expanded view + * + * defaults to [android.R.string.cancel] + * + * @see androidx.core.app.NotificationCompat.Builder.addAction + * @since 5.0.0 + */ + val discardButtonText: String? = null, + + /** + * discard button icon shown in collapsed and sometimes expanded view + * + * @see androidx.core.app.NotificationCompat.Builder.addAction + * @since 5.0.0 + */ + @DrawableRes + val resDiscardButtonIcon: Int = android.R.drawable.ic_menu_delete, + + /** + * notification channel name. + * To learn about notification channels, visit the [notification guide](https://developer.android.com/guide/topics/ui/notifiers/notifications.html#ManageChannels) + * + * @see android.app.NotificationChannel + * @since 5.0.0 + */ + val channelName: String, + + /** + * notification channel description + * + * @see android.app.NotificationChannel.setDescription + * @since 5.0.0 + */ + val channelDescription: String? = null, + + /** + * notification channel importance. Must be one of + * - [android.app.NotificationManager#IMPORTANCE_NONE] + * - [android.app.NotificationManager#IMPORTANCE_LOW] + * - [android.app.NotificationManager#IMPORTANCE_DEFAULT] + * - [android.app.NotificationManager#IMPORTANCE_HIGH] + * - [android.app.NotificationManager#IMPORTANCE_MAX] + * + * Default is [android.app.NotificationManager#IMPORTANCE_HIGH] + * + * @see android.app.NotificationChannel + * @since 5.0.0 + */ + val channelImportance: Int = 4, + + /** + * in-line comment button text. + * No effect on pre-nougat devices. + * + * @see androidx.core.app.NotificationCompat.Builder.addAction + * @since 5.0.0 + */ + val sendWithCommentButtonText: String? = null, + + /** + * in-line comment button icon. + * No effect on pre-nougat devices. + * + * @see androidx.core.app.NotificationCompat.Builder.addAction + * @since 5.0.0 + */ + @DrawableRes + val resSendWithCommentButtonIcon: Int = android.R.drawable.ic_menu_send, + + /** + * in-line comment prompt label. + * No effect on pre-nougat devices. + * + * @see androidx.core.app.RemoteInput.Builder.setLabel + * @since 5.0.0 + */ + val commentPrompt: String? = null, + + /** + * enable to send report even on normal click, not only on button click + * + * @since 5.0.0 + */ + val sendOnClick: Boolean = false, +) : Configuration { + override fun enabled(): Boolean = enabled +} + +fun CoreConfigurationBuilder.notification(initializer: NotificationConfigurationBuilder.() -> Unit) { + pluginConfigurations += NotificationConfigurationBuilder().apply(initializer).build() +} diff --git a/acra-notification/src/main/java/org/acra/interaction/NotificationInteraction.kt b/acra-notification/src/main/java/org/acra/interaction/NotificationInteraction.kt index d0bc4615a8..629c791b34 100644 --- a/acra-notification/src/main/java/org/acra/interaction/NotificationInteraction.kt +++ b/acra-notification/src/main/java/org/acra/interaction/NotificationInteraction.kt @@ -15,6 +15,7 @@ */ package org.acra.interaction +import android.annotation.SuppressLint import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent @@ -26,9 +27,9 @@ import androidx.core.app.NotificationCompat import androidx.core.app.RemoteInput import com.google.auto.service.AutoService import org.acra.ACRA -import org.acra.config.ConfigUtils.getPluginConfiguration import org.acra.config.CoreConfiguration import org.acra.config.NotificationConfiguration +import org.acra.config.getPluginConfiguration import org.acra.notification.R import org.acra.plugins.HasConfigPlugin import org.acra.prefs.SharedPreferencesFactory @@ -49,12 +50,13 @@ class NotificationInteraction : HasConfigPlugin(NotificationConfiguration::class } val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager ?: return true //can't post notifications - val notificationConfig = getPluginConfiguration(config, NotificationConfiguration::class.java) + val notificationConfig = config.getPluginConfiguration() //We have to create a channel on Oreo+, because notifications without one aren't allowed if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val channel = NotificationChannel(CHANNEL, notificationConfig.channelName, notificationConfig.resChannelImportance) + @SuppressLint("WrongConstant") + val channel = NotificationChannel(CHANNEL, notificationConfig.channelName, notificationConfig.channelImportance) channel.setSound(null, null) - if (notificationConfig.channelDescription.isNotEmpty()) { + if (notificationConfig.channelDescription?.isNotEmpty() == true) { channel.description = notificationConfig.channelDescription } notificationManager.createNotificationChannel(channel) @@ -67,14 +69,14 @@ class NotificationInteraction : HasConfigPlugin(NotificationConfiguration::class .setSmallIcon(notificationConfig.resIcon) .setPriority(NotificationCompat.PRIORITY_HIGH) //add ticker if set - if (notificationConfig.tickerText.isNotEmpty()) { + if (notificationConfig.tickerText?.isNotEmpty() == true) { notification.setTicker(notificationConfig.tickerText) } val sendIntent = getSendIntent(context, config, reportFile) val discardIntent = getDiscardIntent(context) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && notificationConfig.sendWithCommentButtonText.isNotEmpty()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && notificationConfig.sendWithCommentButtonText?.isNotEmpty() == true) { val remoteInput = RemoteInput.Builder(KEY_COMMENT) - if (notificationConfig.commentPrompt.isNotEmpty()) { + if (notificationConfig.commentPrompt?.isNotEmpty() == true) { remoteInput.setLabel(notificationConfig.commentPrompt) } notification.addAction( diff --git a/acra-toast/src/main/java/org/acra/annotation/AcraToast.java b/acra-toast/src/main/java/org/acra/annotation/AcraToast.java deleted file mode 100644 index fe64d37a7d..0000000000 --- a/acra-toast/src/main/java/org/acra/annotation/AcraToast.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.acra.annotation; - -import android.content.Context; -import androidx.annotation.IntRange; -import androidx.annotation.StringRes; -import android.widget.Toast; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @author F43nd1r - * @since 02.06.2017 - */ -@Deprecated -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Inherited -@Configuration -public @interface AcraToast { - - /** - * toast text triggered when the application crashes - * - * @return Resource id for the Toast text triggered when the application crashes. - * @see android.widget.Toast#makeText(Context, int, int) - * @since 5.0.0 - */ - @StringRes int resText(); - - /** - * One of {@link android.widget.Toast#LENGTH_LONG} and {@link android.widget.Toast#LENGTH_SHORT} - * - * @return toast length - * @see android.widget.Toast#makeText(Context, int, int) - * @since 5.0.0 - */ - @IntRange(from = 0, to = 1) int length() default Toast.LENGTH_LONG; -} diff --git a/acra-toast/src/main/java/org/acra/config/ToastConfiguration.kt b/acra-toast/src/main/java/org/acra/config/ToastConfiguration.kt new file mode 100644 index 0000000000..cdee558ac8 --- /dev/null +++ b/acra-toast/src/main/java/org/acra/config/ToastConfiguration.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.acra.config + +import android.widget.Toast +import androidx.annotation.IntRange +import com.faendir.kotlin.autodsl.AutoDsl +import org.acra.annotation.AcraDsl +import org.acra.ktx.plus + +/** + * @author F43nd1r + * @since 02.06.2017 + */ +@AutoDsl(dslMarker = AcraDsl::class) +class ToastConfiguration( + /** + * enables this plugin + */ + val enabled: Boolean = true, + + /** + * toast text triggered when the application crashes + * + * @see android.widget.Toast.makeText + * @since 5.0.0 + */ + val text: String, + + /** + * One of [android.widget.Toast.LENGTH_LONG] and [android.widget.Toast.LENGTH_SHORT] + * + * @see android.widget.Toast.makeText + * @since 5.0.0 + */ + @IntRange(from = 0, to = 1) + val length: Int = Toast.LENGTH_LONG, +) : Configuration { + override fun enabled(): Boolean = enabled +} + +fun CoreConfigurationBuilder.toast(initializer: ToastConfigurationBuilder.() -> Unit) { + pluginConfigurations += ToastConfigurationBuilder().apply(initializer).build() +} diff --git a/acra-toast/src/main/java/org/acra/interaction/ToastInteraction.kt b/acra-toast/src/main/java/org/acra/interaction/ToastInteraction.kt index ba3739eb49..5aafd71754 100644 --- a/acra-toast/src/main/java/org/acra/interaction/ToastInteraction.kt +++ b/acra-toast/src/main/java/org/acra/interaction/ToastInteraction.kt @@ -21,9 +21,9 @@ import android.os.Handler import android.os.Looper import android.widget.Toast import com.google.auto.service.AutoService -import org.acra.config.ConfigUtils.getPluginConfiguration import org.acra.config.CoreConfiguration import org.acra.config.ToastConfiguration +import org.acra.config.getPluginConfiguration import org.acra.plugins.HasConfigPlugin import org.acra.util.ToastSender.sendToast import java.io.File @@ -36,7 +36,7 @@ import java.io.File class ToastInteraction : HasConfigPlugin(ToastConfiguration::class.java), ReportInteraction { override fun performInteraction(context: Context, config: CoreConfiguration, reportFile: File): Boolean { Looper.prepare() - val pluginConfig = getPluginConfiguration(config, ToastConfiguration::class.java) + val pluginConfig = config.getPluginConfiguration() sendToast(context, pluginConfig.text, pluginConfig.length) val looper = Looper.myLooper() if (looper != null) { diff --git a/annotationprocessor/build.gradle.kts b/annotationprocessor/build.gradle.kts deleted file mode 100644 index c5aecdee26..0000000000 --- a/annotationprocessor/build.gradle.kts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2020 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -plugins { - `acra-java-library` -} - -dependencies { - implementation(libs.autoCommon) - implementation(libs.kotlinPoet) - implementation(libs.kotlin.reflect) - implementation(libs.commonsText) - implementation(projects.annotations) - implementation(projects.acraJavacore) - implementation(libs.autoService.processor) -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/AcraAnnotationProcessor.kt b/annotationprocessor/src/main/java/org/acra/processor/AcraAnnotationProcessor.kt deleted file mode 100644 index 01c8c1c2e6..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/AcraAnnotationProcessor.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor - -import com.google.auto.common.MoreElements -import com.google.auto.service.AutoService -import org.acra.annotation.Configuration -import org.acra.processor.creator.ClassCreator -import org.acra.processor.creator.ServiceResourceCreator -import org.acra.processor.util.Types -import javax.annotation.processing.AbstractProcessor -import javax.annotation.processing.Processor -import javax.annotation.processing.RoundEnvironment -import javax.annotation.processing.SupportedSourceVersion -import javax.lang.model.SourceVersion -import javax.lang.model.element.ElementKind -import javax.lang.model.element.TypeElement -import javax.tools.Diagnostic - -/** - * @author F43nd1r - * @since 18.03.2017 - */ -@AutoService(Processor::class) -@SupportedSourceVersion(SourceVersion.RELEASE_8) -class AcraAnnotationProcessor : AbstractProcessor() { - private val serviceResourceCreator = ServiceResourceCreator() - - override fun getSupportedAnnotationTypes(): Set { - return Types.MARKER_ANNOTATIONS.map { it.reflectionName() }.toSet() - } - - override fun process(annotations: Set?, roundEnv: RoundEnvironment): Boolean { - try { - for (e in roundEnv.getElementsAnnotatedWith(Configuration::class.java)) { - if (e.kind == ElementKind.ANNOTATION_TYPE) { - ClassCreator(MoreElements.asType(e), e.getAnnotation(Configuration::class.java), processingEnv, serviceResourceCreator).createClasses() - } else { - processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, String.format("%s is only supported on %s", - Configuration::class.java.name, ElementKind.ANNOTATION_TYPE.name), e) - } - } - if(roundEnv.processingOver()) { - serviceResourceCreator.generateResources(processingEnv) - } - } catch (e: Throwable) { - e.printStackTrace() - processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, "Failed to generate acra classes") - } - return true - } -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/creator/BuildMethodCreator.kt b/annotationprocessor/src/main/java/org/acra/processor/creator/BuildMethodCreator.kt deleted file mode 100644 index 8a38fc3fb5..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/creator/BuildMethodCreator.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor.creator - -import com.squareup.kotlinpoet.AnnotationSpec -import com.squareup.kotlinpoet.ClassName -import com.squareup.kotlinpoet.CodeBlock -import com.squareup.kotlinpoet.FunSpec -import com.squareup.kotlinpoet.asTypeName -import org.acra.config.ACRAConfigurationException -import org.acra.config.ClassValidator -import org.acra.processor.util.Strings -import org.acra.processor.util.Types -import javax.lang.model.element.ExecutableElement - -/** - * @author F43nd1r - * @since 12.06.2017 - */ -class BuildMethodCreator(override: ExecutableElement, private val config: ClassName) { - private val methodBuilder: FunSpec.Builder = Types.overriding(override) - .returns(config) - .addAnnotation(AnnotationSpec.builder(Throws::class).addMember("exceptionClasses = [%L::class]", ACRAConfigurationException::class.asTypeName()).build()) - .beginControlFlow("if (%L)", Strings.FIELD_ENABLED) - private val anyNonDefault: MutableMap = mutableMapOf() - private val statements: MutableList = mutableListOf() - - fun addNotUnset(name: String) { - methodBuilder.beginControlFlow("if (%L == null)", name) - .addStatement("throw %T(\"%L has to be set\")", ACRAConfigurationException::class.java, name) - .endControlFlow() - } - - fun addNotEmpty(name: String) { - methodBuilder.beginControlFlow("if (%L.isEmpty())", name) - .addStatement("throw %T(\"%L cannot be empty\")", ACRAConfigurationException::class.java, name) - .endControlFlow() - } - - fun addInstantiatable(name: String) { - methodBuilder.addStatement("%T.check(%L)", ClassValidator::class.java, name) - } - - fun addAnyNonDefault(name: String, default: CodeBlock) { - anyNonDefault[name] = default - } - - fun addDelegateCall(methodName: String) { - statements.add(CodeBlock.builder().addStatement("%L.%L()", Strings.FIELD_DELEGATE, methodName).build()) - } - - fun build(): FunSpec { - if (anyNonDefault.isNotEmpty()) { - methodBuilder.beginControlFlow("if (%L)", anyNonDefault.map { CodeBlock.of("%L == %L", it.key, it.value) } - .reduce { c1: CodeBlock, c2: CodeBlock -> CodeBlock.builder().add(c1).add(" && ").add(c2).build() }) - .addStatement("throw %T(\"One·of·%L·must·not·be·default\")", ACRAConfigurationException::class.java, anyNonDefault.keys.joinToString(",·")) - .endControlFlow() - } - methodBuilder.endControlFlow() - for (s in statements) { - methodBuilder.addCode(s) - } - methodBuilder.addStatement("return %T(this)", config) - return methodBuilder.build() - } -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/creator/ClassCreator.kt b/annotationprocessor/src/main/java/org/acra/processor/creator/ClassCreator.kt deleted file mode 100644 index 1061290ac3..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/creator/ClassCreator.kt +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor.creator - -import com.google.auto.common.MoreTypes -import com.google.auto.service.AutoService -import com.squareup.kotlinpoet.AnnotationSpec -import com.squareup.kotlinpoet.ClassName -import com.squareup.kotlinpoet.CodeBlock -import com.squareup.kotlinpoet.FileSpec -import com.squareup.kotlinpoet.FunSpec -import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.LambdaTypeName -import com.squareup.kotlinpoet.ParameterSpec -import com.squareup.kotlinpoet.TypeSpec -import com.squareup.kotlinpoet.asTypeName -import org.acra.annotation.Configuration -import org.acra.config.ConfigurationBuilder -import org.acra.processor.element.BuilderElement -import org.acra.processor.element.ConfigElement -import org.acra.processor.element.Element -import org.acra.processor.element.ElementFactory -import org.acra.processor.element.ValidatedElement -import org.acra.processor.util.Strings -import org.acra.processor.util.Types -import org.acra.processor.util.writeTo -import org.apache.commons.text.WordUtils -import java.io.Serializable -import javax.annotation.processing.ProcessingEnvironment -import javax.lang.model.element.TypeElement -import javax.lang.model.type.MirroredTypeException - -/** - * @author F43nd1r - * @since 04.06.2017 - */ -class ClassCreator(private val baseAnnotation: TypeElement, private val configuration: Configuration, private val processingEnv: ProcessingEnvironment, - private val serviceResourceCreator: ServiceResourceCreator) { - private val baseName = baseAnnotation.simpleName.toString().replace("Acra", "") - private val configName: String = baseName + "Configuration" - private val builderName: String = configName + "Builder" - private val factoryName: String = builderName + "Factory" - - fun createClasses() { - val baseBuilder: TypeElement? = try { - processingEnv.elementUtils.getTypeElement(configuration.baseBuilderClass.qualifiedName) - } catch (e: MirroredTypeException) { - MoreTypes.asTypeElement(e.typeMirror) - } - val elements = ModelBuilder(baseAnnotation, ElementFactory(processingEnv.elementUtils), baseBuilder!!, processingEnv.messager).build() - createBuilderClass(elements) - createConfigClass(elements) - if (configuration.isPlugin) { - createFactoryClass() - createExtensions() - } - } - - private fun createBuilderClass(elements: List) { - val classBuilder = TypeSpec.classBuilder(builderName) - .addOriginatingElement(baseAnnotation) - val baseAnnotation = baseAnnotation.asType().asTypeName() - Strings.addClassKdoc(classBuilder, baseAnnotation) - val constructor = FunSpec.constructorBuilder() - .addParameter(ParameterSpec.builder(Strings.PARAM_0, Types.CONTEXT).build()) - .addKdoc("@param %L object annotated with {@link %T}\n", Strings.PARAM_0, baseAnnotation) - .addStatement("val %2L : %1T? = %3L.javaClass.getAnnotation(%1T::class.java)", baseAnnotation, Strings.VAR_ANNOTATION, Strings.PARAM_0) - classBuilder.addSuperinterface(ConfigurationBuilder::class.java) - val primaryConstructor = CodeBlock.builder() - val builder = ClassName(Strings.PACKAGE, builderName) - elements.filterIsInstance().forEach { it.addToBuilder(classBuilder, builder, primaryConstructor) } - classBuilder.primaryConstructor(constructor.addCode(primaryConstructor.build()).build()) - val build = BuildMethodCreator(Types.getOnlyMethod(processingEnv, ConfigurationBuilder::class.java.name), ClassName(Strings.PACKAGE, configName)) - elements.stream() - .filter { obj: Element? -> ValidatedElement::class.java.isInstance(obj) } - .map { obj: Element? -> ValidatedElement::class.java.cast(obj) } - .forEach { element: ValidatedElement -> element.addToBuildMethod(build) } - classBuilder.addFunction(build.build()) - Strings.writeClass(processingEnv, classBuilder.build()) - } - - private fun createConfigClass(elements: List) { - val classBuilder = TypeSpec.classBuilder(configName) - .addOriginatingElement(baseAnnotation) - .addSuperinterface(Serializable::class.java) - .addSuperinterface(org.acra.config.Configuration::class.java) - Strings.addClassKdoc(classBuilder, baseAnnotation.asType().asTypeName()) - val constructor = FunSpec.constructorBuilder().addModifiers(KModifier.PUBLIC) - .addParameter(ParameterSpec.builder(Strings.PARAM_0, ClassName(Strings.PACKAGE, builderName)).build()) - elements.filterIsInstance().forEach { it.addToConfig(classBuilder, constructor) } - classBuilder.addFunction(constructor.build()) - Strings.writeClass(processingEnv, classBuilder.build()) - } - - private fun createFactoryClass() { - val configurationBuilderFactory = Types.CONFIGURATION_BUILDER_FACTORY - Strings.writeClass(processingEnv, TypeSpec.classBuilder(factoryName) - .addOriginatingElement(baseAnnotation) - .addModifiers(KModifier.PUBLIC) - .addSuperinterface(configurationBuilderFactory) - .addFunction(Types.overriding(Types.getOnlyMethod(processingEnv, Strings.CONFIGURATION_BUILDER_FACTORY)) - .addStatement("return %T(%L)", ClassName(Strings.PACKAGE, builderName), Strings.PARAM_0) - .build()) - .build()) - serviceResourceCreator.addService(configurationBuilderFactory.canonicalName, "${Strings.PACKAGE}.$factoryName") - } - - private fun createExtensions() { - val builder = ClassName(Strings.PACKAGE, builderName) - FileSpec.builder(Strings.PACKAGE, "${baseName}Extensions") - .addFunction(FunSpec.builder(WordUtils.uncapitalize(baseName)) - .receiver(ClassName(Strings.PACKAGE, "CoreConfigurationBuilder")) - .addParameter(ParameterSpec("initializer", LambdaTypeName.get(builder, returnType = Unit::class.asTypeName()))) - .addStatement("val builder = this.getPluginConfigurationBuilder(%T::class.java)", builder) - .addStatement("builder.enabled = true") - .addStatement("builder.initializer()") - .build()) - .writeTo(processingEnv) - } -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/creator/ModelBuilder.kt b/annotationprocessor/src/main/java/org/acra/processor/creator/ModelBuilder.kt deleted file mode 100644 index fa5a889542..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/creator/ModelBuilder.kt +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor.creator - -import androidx.annotation.StringRes -import com.google.auto.common.MoreElements -import com.google.auto.common.MoreTypes -import com.squareup.kotlinpoet.asTypeName -import org.acra.annotation.BuilderMethod -import org.acra.annotation.Configuration -import org.acra.annotation.ConfigurationValue -import org.acra.annotation.PreBuild -import org.acra.annotation.Transform -import org.acra.processor.element.BuilderElement -import org.acra.processor.element.Element -import org.acra.processor.element.ElementFactory -import org.acra.processor.util.Types -import java.util.* -import javax.annotation.processing.Messager -import javax.lang.model.element.AnnotationMirror -import javax.lang.model.element.ExecutableElement -import javax.lang.model.element.TypeElement -import javax.lang.model.util.ElementFilter -import javax.tools.Diagnostic - -/** - * @author F43nd1r - * @since 10.01.2018 - */ -internal class ModelBuilder(private val baseAnnotation: TypeElement, private val modelFactory: ElementFactory, baseBuilder: TypeElement, private val messager: Messager) { - private val elements: MutableList - private val baseBuilder: TypeElement - private fun handleParameter() { - elements.add(BuilderElement.Context()) - elements.add(BuilderElement.Enabled()) - } - - private fun handleAnnotationMethods() { - for (method in ElementFilter.methodsIn(baseAnnotation.enclosedElements)) { - elements.add(when { - MoreElements.isAnnotationPresent(method, StringRes::class.java) -> modelFactory.fromStringResourceAnnotationMethod(method) - method.returnType.toString().endsWith("[]") -> modelFactory.fromArrayAnnotationMethod(method) - method.returnType.toString().contains("Class") -> modelFactory.fromClassAnnotationMethod(method) - else -> modelFactory.fromAnnotationMethod(method) - }) - } - } - - private fun handleBaseBuilder() { - if (!MoreTypes.isTypeOf(Any::class.java, baseBuilder.asType())) { - val constructors = ElementFilter.constructorsIn(baseBuilder.enclosedElements) - var constructor = constructors.stream().filter { c: ExecutableElement -> c.parameters.size == 0 }.findAny() - if (constructor.isPresent) { - elements.add(modelFactory.fromDelegateConstructor(constructor.get(), false)) - } else { - constructor = constructors.stream().filter { c: ExecutableElement -> c.parameters.size == 1 && Types.CONTEXT == c.parameters[0].asType().asTypeName() }.findAny() - if (constructor.isPresent) { - elements.add(modelFactory.fromDelegateConstructor(constructor.get(), true)) - } else { - val mirror = baseAnnotation.annotationMirrors.stream() - .filter { m: AnnotationMirror -> MoreTypes.isTypeOf(Configuration::class.java, m.annotationType) } - .findAny().orElseThrow { IllegalArgumentException() } - messager.printMessage(Diagnostic.Kind.ERROR, "Classes used as base builder must have a constructor which takes no arguments, " + - "or exactly one argument of type Class", baseAnnotation, mirror, mirror.elementValues.entries.firstOrNull { it.key.simpleName.toString() == "builderSuperClass" }?.value) - throw java.lang.IllegalArgumentException() - } - } - handleBaseBuilderMethods() - } - } - - private fun handleBaseBuilderMethods() { - for (method in ElementFilter.methodsIn(baseBuilder.enclosedElements)) { - when { - method.getAnnotation(PreBuild::class.java) != null -> { - elements.add(modelFactory.fromPreBuildDelegateMethod(method)) - } - method.getAnnotation(Transform::class.java) != null -> { - val transform: String = method.getAnnotation(Transform::class.java).methodName - elements.stream().filter { field: Element -> field.name == transform }.findAny() - .ifPresent { element: Element -> elements[elements.indexOf(element)] = modelFactory.fromTransformDelegateMethod(method, element) } - } - method.getAnnotation(ConfigurationValue::class.java) != null -> { - elements.add(modelFactory.fromConfigDelegateMethod(method)) - } - method.getAnnotation(BuilderMethod::class.java) != null -> { - elements.add(modelFactory.fromBuilderDelegateMethod(method)) - } - } - } - } - - fun build(): List { - handleParameter() - handleAnnotationMethods() - handleBaseBuilder() - return elements - } - - init { - elements = ArrayList() - this.baseBuilder = baseBuilder - } -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/creator/ServiceResourceCreator.kt b/annotationprocessor/src/main/java/org/acra/processor/creator/ServiceResourceCreator.kt deleted file mode 100644 index 9ea00e8825..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/creator/ServiceResourceCreator.kt +++ /dev/null @@ -1,33 +0,0 @@ -package org.acra.processor.creator - -import java.io.IOException -import javax.annotation.processing.ProcessingEnvironment -import javax.tools.StandardLocation - -class ServiceResourceCreator { - private val services = mutableMapOf>() - - fun addService(interfaceName: String, className: String) { - (services[interfaceName] ?: mutableSetOf().also { services[interfaceName] = it }).add(className) - } - - fun generateResources(processingEnv: ProcessingEnvironment) { - services.forEach { (interfaceName, services) -> - val resourceFile = "META-INF/services/${interfaceName}" - val oldContent: Set = try { - processingEnv.filer.getResource(StandardLocation.CLASS_OUTPUT, "", resourceFile).openInputStream().bufferedReader().use { - it.readLines().toSet() - } - } catch (e: IOException) { - emptySet() - } - val content: Set = oldContent + services - if (content.size > oldContent.size) { - processingEnv.filer.createResource(StandardLocation.CLASS_OUTPUT, "", resourceFile) - .openOutputStream().bufferedWriter().use { - it.write(content.joinToString("\n")) - } - } - } - } -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/element/AbstractElement.kt b/annotationprocessor/src/main/java/org/acra/processor/element/AbstractElement.kt deleted file mode 100644 index 9e22bf7f17..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/element/AbstractElement.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor.element - -import com.squareup.kotlinpoet.AnnotationSpec -import com.squareup.kotlinpoet.TypeName - -/** - * @author F43nd1r - * @since 12.01.2018 - */ -open class AbstractElement(override val name: String, override val type: TypeName, override val annotations: Collection) : Element \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/element/AnnotationField.kt b/annotationprocessor/src/main/java/org/acra/processor/element/AnnotationField.kt deleted file mode 100644 index 7e8dff1886..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/element/AnnotationField.kt +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor.element - -import com.squareup.kotlinpoet.AnnotationSpec -import com.squareup.kotlinpoet.ClassName -import com.squareup.kotlinpoet.CodeBlock -import com.squareup.kotlinpoet.FunSpec -import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.ParameterSpec -import com.squareup.kotlinpoet.ParameterizedTypeName -import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy -import com.squareup.kotlinpoet.PropertySpec -import com.squareup.kotlinpoet.TypeName -import com.squareup.kotlinpoet.TypeSpec -import com.squareup.kotlinpoet.WildcardTypeName -import org.acra.processor.creator.BuildMethodCreator -import org.acra.processor.util.IsValidResourceVisitor -import org.acra.processor.util.Strings -import org.acra.processor.util.ToCodeBlockVisitor -import org.acra.processor.util.Types -import org.apache.commons.text.WordUtils -import java.util.* -import javax.lang.model.element.AnnotationValue - -/** - * @author F43nd1r - * @since 12.01.2018 - */ -abstract class AnnotationField(override val name: String, override val type: TypeName, override val annotations: Collection, private val javadoc: String?, - private val markers: Collection, val defaultValue: AnnotationValue?) : TransformedField.Transformable { - fun hasMarker(marker: ClassName): Boolean { - return markers.contains(marker) - } - - override fun addToBuilder(builder: TypeSpec.Builder, builderName: ClassName, constructor: CodeBlock.Builder) { - super.addToBuilder(builder, builderName, constructor) - addSetter(builder, builderName) - addInitializer(constructor) - } - - override fun configureField(builder: PropertySpec.Builder) { - if (javadoc != null) { - builder.addKdoc("%L", javadoc.replace("(\n|^) ".toRegex(), "$1")) - } - } - - protected abstract fun addInitializer(constructor: CodeBlock.Builder) - override fun configureSetter(builder: FunSpec.Builder) { - if (javadoc != null) { - val name = builder.build().parameters[0].name - builder.addKdoc("%L", javadoc.replace("(\n|^) ".toRegex(), "$1").replace("@return ((.|\n)*)$".toRegex(), "@param $name $1@return this instance\n")) - } - } - - open class Normal(name: String, type: TypeName, annotations: Collection, markers: Collection, defaultValue: AnnotationValue?, javadoc: String) : - AnnotationField(name, type, annotations, javadoc, markers, defaultValue) { - public override fun addInitializer(constructor: CodeBlock.Builder) { - constructor.addStatement("%1L = %2L?.%1L ?: %3L", name, Strings.VAR_ANNOTATION, defaultValue?.accept(ToCodeBlockVisitor(), null)) - } - - override fun addToBuildMethod(method: BuildMethodCreator) { - if (defaultValue == null) { - method.addNotUnset(name) - } - if (hasMarker(Types.NON_EMPTY)) { - method.addNotEmpty(name) - } - if (hasMarker(Types.INSTANTIATABLE)) { - method.addInstantiatable(name) - } - if (hasMarker(Types.ANY_NON_DEFAULT)) { - method.addAnyNonDefault(name, defaultValue?.accept(ToCodeBlockVisitor(), null) ?: CodeBlock.of("null")) - } - } - } - - class Clazz(name: String, type: TypeName, annotations: Collection, markers: Collection, defaultValue: AnnotationValue?, javadoc: String) : - Normal(name, type, annotations, markers, defaultValue, javadoc) { - override fun addInitializer(constructor: CodeBlock.Builder) { - constructor.addStatement("%1L = %2L?.%1L?.java ?: %3L", name, Strings.VAR_ANNOTATION, defaultValue?.accept(ToCodeBlockVisitor(), null)) - } - } - - class Array(name: String, type: TypeName, annotations: Collection, markers: Collection, defaultValue: AnnotationValue?, javadoc: String) : - Normal(name, (type as ParameterizedTypeName).let { it.rawType.parameterizedBy(WildcardTypeName.producerOf(it.typeArguments.first())) }, annotations, markers, - defaultValue, javadoc) { - private val originalType = type - override fun configureSetter(builder: FunSpec.Builder) { - super.configureSetter(builder) - val param = builder.parameters.first().toBuilder(type = (originalType as ParameterizedTypeName).typeArguments.first()).addModifiers(KModifier.VARARG).build() - builder.parameters.clear() - builder.addParameter(param) - } - } - - class StringResource(private val originalName: String, annotations: Collection, markers: Collection, - defaultValue: AnnotationValue?, javadoc: String?) : - AnnotationField(if (originalName.startsWith(Strings.PREFIX_RES)) WordUtils.uncapitalize(originalName.substring(Strings.PREFIX_RES.length)) else originalName, - Types.STRING, annotations - Types.STRING_RES, javadoc, markers, defaultValue) { - private val hasDefault: Boolean = defaultValue != null && defaultValue.accept(IsValidResourceVisitor(), null) - - public override fun addInitializer(constructor: CodeBlock.Builder) { - if (hasDefault) { - constructor.addStatement("%L = %L.getString(%L?.%L.takeIf·{ it != 0 } ?: %L)", name, Strings.FIELD_CONTEXT, Strings.VAR_ANNOTATION, originalName, defaultValue) - } else { - constructor.addStatement("%L = %L?.%L.takeIf·{ it != 0 }?.let·{ %L.getString(it) } ?: \"\"", name, Strings.VAR_ANNOTATION, originalName, Strings.FIELD_CONTEXT) - } - } - - override fun addSetter(builder: TypeSpec.Builder, builderName: ClassName) { - super.addSetter(builder, builderName) - val setter = baseResSetter(builderName) - .addStatement("this.%L = %L.getString(%L)", name, Strings.FIELD_CONTEXT, Strings.ensurePrefix(Strings.PREFIX_RES, name)) - .addStatement("return this") - configureSetter(setter) - builder.addFunction(setter.build()) - } - - private fun baseResSetter(builderName: ClassName): FunSpec.Builder { - val parameterName = Strings.ensurePrefix(Strings.PREFIX_RES, name) - val annotations: MutableList = ArrayList(annotations) - annotations.add(Types.STRING_RES) - return FunSpec.builder(Strings.ensurePrefix(Strings.PREFIX_SETTER, parameterName)) - .addParameter(ParameterSpec.builder(parameterName, Int::class).addAnnotations(annotations).build()) - .addModifiers(KModifier.PUBLIC) - .returns(builderName) - } - - override fun addToBuildMethod(method: BuildMethodCreator) { - if (defaultValue == null) { - method.addNotUnset(name) - } - if (hasMarker(Types.ANY_NON_DEFAULT)) { - method.addAnyNonDefault(name, CodeBlock.of("\"\"")) - } - } - } -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/element/BuilderElement.kt b/annotationprocessor/src/main/java/org/acra/processor/element/BuilderElement.kt deleted file mode 100644 index ad31ec3d80..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/element/BuilderElement.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor.element - -import com.squareup.kotlinpoet.ClassName -import com.squareup.kotlinpoet.CodeBlock -import com.squareup.kotlinpoet.FunSpec -import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.ParameterSpec -import com.squareup.kotlinpoet.PropertySpec -import com.squareup.kotlinpoet.TypeName -import com.squareup.kotlinpoet.TypeSpec -import com.squareup.kotlinpoet.asClassName -import com.squareup.kotlinpoet.asTypeName -import org.acra.processor.util.Strings -import org.acra.processor.util.Types -import java.util.* - -/** - * @author F43nd1r - * @since 11.01.2018 - */ -interface BuilderElement : Element { - fun addToBuilder(builder: TypeSpec.Builder, builderName: ClassName, constructor: CodeBlock.Builder) { - val field = PropertySpec.builder(name, type).addAnnotations(annotations).mutable() - configureField(field) - builder.addProperty(field.build()) - } - - fun configureField(builder: PropertySpec.Builder) {} - - fun addSetter(builder: TypeSpec.Builder, builderName: ClassName) { - val method = baseSetter(builderName) - .addStatement("return apply·{ this.%1L·= %1L }", name) - configureSetter(method) - builder.addFunction(method.build()) - } - - fun baseSetter(builderName: ClassName): FunSpec.Builder { - val builder = FunSpec.builder(Strings.ensurePrefix(Strings.PREFIX_SETTER, name)) - val annotations = ArrayList(annotations) - val deprecated = annotations.find { it.typeName == Deprecated::class.asTypeName() } - if (deprecated != null) { - annotations.remove(deprecated) - builder.addAnnotation(deprecated) - } - return builder - .addParameter(ParameterSpec.builder(name, type).addAnnotations(annotations).build()) - .addModifiers(KModifier.PUBLIC) - .returns(builderName) - } - - fun configureSetter(builder: FunSpec.Builder) {} - - interface Final : BuilderElement { - override fun configureField(builder: PropertySpec.Builder) { - builder.addModifiers(KModifier.FINAL) - } - } - - class Context : AbstractElement(Strings.FIELD_CONTEXT, Types.CONTEXT, emptyList()), Final { - override fun addToBuilder(builder: TypeSpec.Builder, builderName: ClassName, constructor: CodeBlock.Builder - ) { - super.addToBuilder(builder, builderName, constructor) - constructor.addStatement("%L = %L", name, Strings.PARAM_0) - } - } - - class Delegate internal constructor(type: TypeName, private val hasContextParameter: Boolean) : AbstractElement(Strings.FIELD_DELEGATE, type, emptyList()), Final { - override fun addToBuilder(builder: TypeSpec.Builder, builderName: ClassName, constructor: CodeBlock.Builder - ) { - super.addToBuilder(builder, builderName, constructor) - if (hasContextParameter) { - constructor.addStatement("%L = %T(%L)", name, type, Strings.PARAM_0) - } else { - constructor.addStatement("%L = %T()", name, type) - } - } - } - - class Enabled : AbstractElement(Strings.FIELD_ENABLED, Boolean::class.asClassName(), emptyList()), BuilderElement, ConfigElement { - override fun addToBuilder(builder: TypeSpec.Builder, builderName: ClassName, constructor: CodeBlock.Builder - ) { - super.addToBuilder(builder, builderName, constructor) - addSetter(builder, builderName) - constructor.addStatement("%L = %L != null", name, Strings.VAR_ANNOTATION) - } - - override fun addToConfig(builder: TypeSpec.Builder, constructor: FunSpec.Builder) { - super.addToConfig(builder, constructor) - builder.addFunction(FunSpec.builder(Strings.FIELD_ENABLED).addStatement("return %L", Strings.FIELD_ENABLED).addModifiers(KModifier.OVERRIDE).returns(Boolean::class).build()) - } - } -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/element/ConfigElement.kt b/annotationprocessor/src/main/java/org/acra/processor/element/ConfigElement.kt deleted file mode 100644 index fff1b0b5df..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/element/ConfigElement.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor.element - -import com.squareup.kotlinpoet.FunSpec -import com.squareup.kotlinpoet.PropertySpec -import com.squareup.kotlinpoet.TypeSpec -import org.acra.processor.util.Strings - -/** - * @author F43nd1r - * @since 10.01.2018 - */ -interface ConfigElement : Element { - - fun addToConfig(builder: TypeSpec.Builder, constructor: FunSpec.Builder) { - //add property - builder.addProperty(PropertySpec.builder(name, type).build()) - constructor.addStatement("%1L = %2L.%1L", name, Strings.PARAM_0) - } -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/element/DelegateMethod.kt b/annotationprocessor/src/main/java/org/acra/processor/element/DelegateMethod.kt deleted file mode 100644 index 329023b46c..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/element/DelegateMethod.kt +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor.element - -import com.squareup.kotlinpoet.AnnotationSpec -import com.squareup.kotlinpoet.ClassName -import com.squareup.kotlinpoet.CodeBlock -import com.squareup.kotlinpoet.FunSpec -import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.ParameterSpec -import com.squareup.kotlinpoet.PropertySpec -import com.squareup.kotlinpoet.TypeName -import com.squareup.kotlinpoet.TypeSpec -import com.squareup.kotlinpoet.TypeVariableName -import com.squareup.kotlinpoet.asTypeName -import org.acra.processor.util.Strings -import java.util.stream.Collectors - -/** - * @author F43nd1r - * @since 10.01.2018 - */ -internal open class DelegateMethod(override val name: String, override val type: TypeName, override val annotations: Collection, private val parameters: Collection, - private val typeVariables: Collection, private val modifiers: Collection, private val javadoc: String?) : BuilderElement { - override fun addToBuilder(builder: TypeSpec.Builder, builderName: ClassName, constructor: CodeBlock.Builder) { - val method = baseMethod(builderName) - if (type == Unit::class.asTypeName()) { - method.addStatement("%L.%L(%L)", Strings.FIELD_DELEGATE, name, parameters.stream().map { p: ParameterSpec -> p.name }.collect(Collectors.joining(", "))) - .addStatement("return this") - } else { - method.addStatement("return %L.%L(%L)", Strings.FIELD_DELEGATE, name, parameters.stream().map { p: ParameterSpec -> p.name }.collect(Collectors.joining(", "))) - } - builder.addFunction(method.build()) - } - - private fun baseMethod(builderName: ClassName): FunSpec.Builder { - val method = FunSpec.builder(name) - .addModifiers(modifiers) - .addParameters(parameters) - .addTypeVariables(typeVariables) - .addAnnotations(annotations) - if (javadoc != null) { - method.addKdoc(javadoc.replace("(\n|^) ".toRegex(), "$1")) - } - if (type == Unit::class.asTypeName()) { - method.returns(builderName) - .addKdoc("@return this instance\n") - } else { - method.returns(type) - } - return method - } - - internal class Config(name: String, type: TypeName, annotations: Collection, parameters: Collection, - typeVariables: Collection, modifiers: Collection, javadoc: String?) : DelegateMethod(name, type, annotations, parameters, typeVariables, modifiers, javadoc), ConfigElement{ - - - override fun addToConfig(builder: TypeSpec.Builder, constructor: FunSpec.Builder) { - builder.addProperty(PropertySpec.builder(name, type).build()) - constructor.addStatement("%1L = %2L.%1L()", name, Strings.PARAM_0) - } - } -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/element/Element.kt b/annotationprocessor/src/main/java/org/acra/processor/element/Element.kt deleted file mode 100644 index 0caa58ef3e..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/element/Element.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor.element - -import com.squareup.kotlinpoet.AnnotationSpec -import com.squareup.kotlinpoet.TypeName - -/** - * @author F43nd1r - * @since 12.01.2018 - */ -interface Element { - val name: String - val type: TypeName - val annotations: Collection -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/element/ElementFactory.kt b/annotationprocessor/src/main/java/org/acra/processor/element/ElementFactory.kt deleted file mode 100644 index d191091b10..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/element/ElementFactory.kt +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor.element - -import androidx.annotation.NonNull -import androidx.annotation.Nullable -import com.squareup.kotlinpoet.AnnotationSpec -import com.squareup.kotlinpoet.ClassName -import com.squareup.kotlinpoet.ParameterSpec -import com.squareup.kotlinpoet.asTypeName -import com.squareup.kotlinpoet.asTypeVariableName -import org.acra.processor.util.Types -import org.acra.processor.util.javaToKotlinType -import org.acra.processor.util.toKModifier -import org.apache.commons.lang3.tuple.Pair -import java.util.* -import javax.lang.model.element.ExecutableElement -import javax.lang.model.util.Elements - -/** - * @author F43nd1r - * @since 10.01.2018 - */ -class ElementFactory(private val elements: Elements) { - fun fromAnnotationMethod(method: ExecutableElement): Element { - val annotations = getAnnotations(method) - return AnnotationField.Normal(method.simpleName.toString(), method.returnType.asTypeName().javaToKotlinType(), annotations.left, annotations.right, method.defaultValue, - elements.getDocComment(method)) - } - - fun fromClassAnnotationMethod(method: ExecutableElement): Element { - val annotations = getAnnotations(method) - return AnnotationField.Clazz(method.simpleName.toString(), method.returnType.asTypeName().javaToKotlinType(), annotations.left, annotations.right, method.defaultValue, - elements.getDocComment(method)) - } - - fun fromArrayAnnotationMethod(method: ExecutableElement): Element { - val annotations = getAnnotations(method) - return AnnotationField.Array(method.simpleName.toString(), method.returnType.asTypeName().javaToKotlinType(), annotations.left, annotations.right, method.defaultValue, - elements.getDocComment(method)) - } - - fun fromStringResourceAnnotationMethod(method: ExecutableElement): Element { - val annotations = getAnnotations(method) - return AnnotationField.StringResource(method.simpleName.toString(), annotations.left, annotations.right, - method.defaultValue, elements.getDocComment(method)) - } - - fun fromBuilderDelegateMethod(method: ExecutableElement): Element { - return DelegateMethod(method.simpleName.toString(), method.returnType.asTypeName().javaToKotlinType(), getAnnotations(method).left, - method.parameters.map { ParameterSpec.builder(it.simpleName.toString(), it.asType().asTypeName().javaToKotlinType()).build() }, - method.typeParameters.map { it.asTypeVariableName() }, method.modifiers.mapNotNull { it.toKModifier() }, elements.getDocComment(method)) - } - - fun fromConfigDelegateMethod(method: ExecutableElement): Element { - return DelegateMethod.Config(method.simpleName.toString(), method.returnType.asTypeName().javaToKotlinType(), getAnnotations(method).left, - method.parameters.map { ParameterSpec.builder(it.simpleName.toString(), it.asType().asTypeName().javaToKotlinType()).build() }, - method.typeParameters.map { it.asTypeVariableName() }, method.modifiers.mapNotNull { it.toKModifier() }, elements.getDocComment(method)) - } - - fun fromPreBuildDelegateMethod(method: ExecutableElement): Element { - return PreBuildMethod(method.simpleName.toString()) - } - - fun fromTransformDelegateMethod(method: ExecutableElement, transform: Element): Element { - return if (transform is TransformedField.Transformable) { - TransformedField(method.simpleName.toString(), method.returnType.asTypeName().javaToKotlinType(), transform) - } else transform - } - - fun fromDelegateConstructor(constructor: ExecutableElement, hasContextParameter: Boolean): Element { - return BuilderElement.Delegate(constructor.enclosingElement.asType().asTypeName(), hasContextParameter) - } - - companion object { - private fun getAnnotations(method: ExecutableElement): Pair, Set> { - val specs = method.annotationMirrors.map { AnnotationSpec.get(it) }.toMutableList() - specs.remove(AnnotationSpec.builder(NonNull::class).build()) - specs.remove(AnnotationSpec.builder(Nullable::class).build()) - specs.replaceAll { if (it == AnnotationSpec.builder(java.lang.Deprecated::class).build()) AnnotationSpec.builder(Deprecated::class).addMember("message = \"see doc\"").build() else it } - val markerAnnotations: MutableSet = HashSet() - val iterator = specs.iterator() - while (iterator.hasNext()) { - val spec = iterator.next() - for (a in Types.MARKER_ANNOTATIONS) { - if (a == spec.typeName) { - iterator.remove() - markerAnnotations.add(a) - } - } - } - return Pair.of(specs, markerAnnotations) - } - } -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/element/PreBuildMethod.kt b/annotationprocessor/src/main/java/org/acra/processor/element/PreBuildMethod.kt deleted file mode 100644 index 03ed58d439..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/element/PreBuildMethod.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor.element - -import com.squareup.kotlinpoet.asTypeName -import org.acra.processor.creator.BuildMethodCreator - -/** - * @author F43nd1r - * @since 11.01.2018 - */ -internal class PreBuildMethod(name: String) : AbstractElement(name, Unit::class.asTypeName(), emptyList()), ValidatedElement { - override fun addToBuildMethod(method: BuildMethodCreator) { - method.addDelegateCall(name) - } -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/element/TransformedField.kt b/annotationprocessor/src/main/java/org/acra/processor/element/TransformedField.kt deleted file mode 100644 index 5c40a0a3f8..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/element/TransformedField.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor.element - -import com.squareup.kotlinpoet.ClassName -import com.squareup.kotlinpoet.CodeBlock -import com.squareup.kotlinpoet.FunSpec -import com.squareup.kotlinpoet.PropertySpec -import com.squareup.kotlinpoet.TypeName -import com.squareup.kotlinpoet.TypeSpec -import org.acra.processor.creator.BuildMethodCreator -import org.acra.processor.util.Strings - -/** - * @author F43nd1r - * @since 11.01.2018 - */ -class TransformedField(val transformName: String, override val type: TypeName, private val transform: Transformable) : ConfigElement, BuilderElement, ValidatedElement { - override val name: String - get() = transform.name - override fun addToBuilder(builder: TypeSpec.Builder, builderName: ClassName, constructor: CodeBlock.Builder) { - transform.addToBuilder(builder, builderName, constructor) - builder.addFunction(FunSpec.builder(transformName).returns(type).addStatement("return %L.%L(%L)", Strings.FIELD_DELEGATE, transformName, name).build()) - } - - override fun addToBuildMethod(method: BuildMethodCreator) { - transform.addToBuildMethod(method) - } - - override fun addToConfig(builder: TypeSpec.Builder, constructor: FunSpec.Builder) { - builder.addProperty(PropertySpec.builder(name, type).build()) - constructor.addStatement("%L = %L.%L()", name, Strings.PARAM_0, transformName) - } - - override val annotations: Collection - get() = transform.annotations - - interface Transformable : ConfigElement, BuilderElement, ValidatedElement -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/element/ValidatedElement.kt b/annotationprocessor/src/main/java/org/acra/processor/element/ValidatedElement.kt deleted file mode 100644 index 87c97834fd..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/element/ValidatedElement.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor.element - -import org.acra.processor.creator.BuildMethodCreator - -/** - * @author F43nd1r - * @since 11.01.2018 - */ -interface ValidatedElement : Element { - fun addToBuildMethod(method: BuildMethodCreator) -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/util/IsValidResourceVisitor.kt b/annotationprocessor/src/main/java/org/acra/processor/util/IsValidResourceVisitor.kt deleted file mode 100644 index a501110e4f..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/util/IsValidResourceVisitor.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.acra.processor.util - -import javax.lang.model.util.SimpleAnnotationValueVisitor8 - -class IsValidResourceVisitor : SimpleAnnotationValueVisitor8() { - override fun defaultAction(o: Any, u: Unit?): Boolean { - return false - } - - override fun visitInt(i: Int, u: Unit?): Boolean { - return i != 0 - } -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/util/Strings.kt b/annotationprocessor/src/main/java/org/acra/processor/util/Strings.kt deleted file mode 100644 index bd102d3cb0..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/util/Strings.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor.util - -import com.squareup.kotlinpoet.FileSpec -import com.squareup.kotlinpoet.TypeName -import com.squareup.kotlinpoet.TypeSpec -import org.apache.commons.text.WordUtils -import java.io.IOException -import java.text.DateFormat -import java.util.* -import javax.annotation.processing.ProcessingEnvironment - -/** - * @author F43nd1r - * @since 08.01.2018 - */ -object Strings { - const val PREFIX_RES = "res" - const val PREFIX_SETTER = "with" - const val PARAM_0 = "arg0" - const val VAR_ANNOTATION = "annotation" - const val FIELD_DELEGATE = "delegate" - const val FIELD_CONTEXT = "context" - const val FIELD_ENABLED = "enabled" - const val PACKAGE = "org.acra.config" - const val CONTEXT = "android.content.Context" - const val CONFIGURATION_BUILDER_FACTORY = "org.acra.config.ConfigurationBuilderFactory" - private val DATE_FORMAT = DateFormat.getDateTimeInstance() - fun ensurePrefix(prefix: String, value: String): String { - return if (value.startsWith(prefix)) value else prefix + WordUtils.capitalize(value) - } - - fun addClassKdoc(builder: TypeSpec.Builder, base: TypeName) { - builder.addKdoc("Class generated based on [%T] (%L)\n", base, DATE_FORMAT.format(Calendar.getInstance().time)) - } - - /** - * Writes the given class to a respective file in the configuration package - * - * @param filer filer to write to - * @param typeSpec the class - * @throws IOException if writing fails - */ - @Throws(IOException::class) - fun writeClass(processingEnv: ProcessingEnvironment, typeSpec: TypeSpec) { - FileSpec.builder(PACKAGE, typeSpec.name!!) - .addType(typeSpec) - .indent(" ") - .writeTo(processingEnv) - } -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/util/ToCodeBlockVisitor.kt b/annotationprocessor/src/main/java/org/acra/processor/util/ToCodeBlockVisitor.kt deleted file mode 100644 index c13755f3d0..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/util/ToCodeBlockVisitor.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor.util - -import com.squareup.kotlinpoet.CodeBlock -import javax.lang.model.element.AnnotationValue -import javax.lang.model.element.VariableElement -import javax.lang.model.type.TypeMirror -import javax.lang.model.util.SimpleAnnotationValueVisitor8 - -/** - * @author F43nd1r - * @since 12.01.2018 - */ -class ToCodeBlockVisitor : SimpleAnnotationValueVisitor8() { - override fun defaultAction(o: Any, u: Unit?): CodeBlock { - return CodeBlock.of("%L", o) - } - - override fun visitString(s: String, u: Unit?): CodeBlock { - return CodeBlock.of("%S", s) - } - - override fun visitEnumConstant(c: VariableElement, u: Unit?): CodeBlock { - return CodeBlock.of("%T.%L", c.asType(), c.simpleName) - } - - override fun visitType(t: TypeMirror, u: Unit?): CodeBlock { - return CodeBlock.of("%T::class.java", t) - } - - override fun visitArray(values: List, u: Unit?): CodeBlock { - return CodeBlock.of("arrayOf(%L)", values.map { value: AnnotationValue? -> value!!.accept(this, null) } - .reduceOrNull { c1: CodeBlock, c2: CodeBlock -> CodeBlock.builder().add(c1).add(", ").add(c2).build() } ?: CodeBlock.builder().build()) - } -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/util/Types.kt b/annotationprocessor/src/main/java/org/acra/processor/util/Types.kt deleted file mode 100644 index ff82d48acb..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/util/Types.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.processor.util - -import androidx.annotation.StringRes -import com.squareup.kotlinpoet.AnnotationSpec -import com.squareup.kotlinpoet.ClassName -import com.squareup.kotlinpoet.FunSpec -import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.ParameterSpec -import com.squareup.kotlinpoet.asClassName -import com.squareup.kotlinpoet.asTypeName -import com.squareup.kotlinpoet.asTypeVariableName -import org.acra.annotation.AnyNonDefault -import org.acra.annotation.BuilderMethod -import org.acra.annotation.Configuration -import org.acra.annotation.ConfigurationValue -import org.acra.annotation.Instantiatable -import org.acra.annotation.NonEmpty -import org.acra.annotation.PreBuild -import org.acra.annotation.Transform -import javax.annotation.processing.ProcessingEnvironment -import javax.lang.model.element.ExecutableElement -import javax.lang.model.element.VariableElement -import javax.lang.model.util.ElementFilter -import javax.tools.Diagnostic - -/** - * @author F43nd1r - * @since 11.01.2018 - */ -object Types { - @JvmField - val STRING: ClassName = ClassName("kotlin", "String") - @JvmField - val STRING_RES = AnnotationSpec.builder(StringRes::class.java).build() - @JvmField - val ANY_NON_DEFAULT: ClassName = AnyNonDefault::class.asClassName() - val BUILDER_METHOD: ClassName = BuilderMethod::class.asClassName() - val CONFIGURATION: ClassName = Configuration::class.asClassName() - val CONFIGURATION_VALUE: ClassName = ConfigurationValue::class.asClassName() - @JvmField - val INSTANTIATABLE: ClassName = Instantiatable::class.asClassName() - @JvmField - val NON_EMPTY: ClassName = NonEmpty::class.asClassName() - val PRE_BUILD: ClassName = PreBuild::class.asClassName() - val TRANSFORM: ClassName = Transform::class.asClassName() - @JvmField - val CONTEXT: ClassName = ClassName.bestGuess(Strings.CONTEXT) - val CONFIGURATION_BUILDER_FACTORY: ClassName = ClassName.bestGuess(Strings.CONFIGURATION_BUILDER_FACTORY) - @JvmField - val MARKER_ANNOTATIONS = listOf(ANY_NON_DEFAULT, BUILDER_METHOD, CONFIGURATION, CONFIGURATION_VALUE, INSTANTIATABLE, NON_EMPTY, PRE_BUILD, TRANSFORM) - @JvmStatic - fun overriding(method: ExecutableElement): FunSpec.Builder { - return FunSpec.builder(method.simpleName.toString()) - .addModifiers(KModifier.OVERRIDE, *method.modifiers.mapNotNull { it.toKModifier() }.minus(KModifier.ABSTRACT).toTypedArray()) - .returns(method.returnType.asTypeName()) - .addTypeVariables(method.typeParameters.map { it.asTypeVariableName() }) - .addParameters(method.parameters.map { element: VariableElement -> - ParameterSpec.builder(element.simpleName.toString(), element.asType().asTypeName()).addAnnotations(element.annotationMirrors.map { AnnotationSpec.get(it) }).build() - }) - } - - fun getOnlyMethod(processingEnv: ProcessingEnvironment, className: String?): ExecutableElement { - val typeElement = processingEnv.elementUtils.getTypeElement(className) - val elements = ElementFilter.methodsIn(typeElement.enclosedElements) - return if (elements.size == 1) { - elements[0] - } else { - processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, "Needs exactly one method", typeElement) - throw IllegalArgumentException() - } - } -} \ No newline at end of file diff --git a/annotationprocessor/src/main/java/org/acra/processor/util/utils.kt b/annotationprocessor/src/main/java/org/acra/processor/util/utils.kt deleted file mode 100644 index 8d15125a95..0000000000 --- a/annotationprocessor/src/main/java/org/acra/processor/util/utils.kt +++ /dev/null @@ -1,61 +0,0 @@ -package org.acra.processor.util - -import com.squareup.kotlinpoet.ClassName -import com.squareup.kotlinpoet.FileSpec -import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.ParameterizedTypeName -import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy -import com.squareup.kotlinpoet.TypeName -import com.squareup.kotlinpoet.WildcardTypeName -import java.io.File -import java.util.* -import javax.annotation.processing.ProcessingEnvironment -import javax.lang.model.element.Modifier -import javax.tools.Diagnostic -import kotlin.reflect.jvm.internal.impl.builtins.jvm.JavaToKotlinClassMap -import kotlin.reflect.jvm.internal.impl.name.FqName - - -fun Modifier.toKModifier(): KModifier? { - return when (this) { - Modifier.PUBLIC -> KModifier.PUBLIC - Modifier.PROTECTED -> KModifier.PROTECTED - Modifier.PRIVATE -> KModifier.PRIVATE - Modifier.ABSTRACT -> KModifier.ABSTRACT - Modifier.FINAL -> KModifier.FINAL - else -> null - } -} - - -fun TypeName.javaToKotlinType(): TypeName { - return when (this) { - is ParameterizedTypeName -> (rawType.javaToKotlinType() as ClassName).parameterizedBy(*typeArguments.map { it.javaToKotlinType() }.toTypedArray()) - is WildcardTypeName -> { - if (inTypes.isNotEmpty()) WildcardTypeName.consumerOf(inTypes[0].javaToKotlinType()) - else WildcardTypeName.producerOf(outTypes[0].javaToKotlinType()) - } - else -> JavaToKotlinClassMap.INSTANCE.mapJavaToKotlin(FqName(toString()))?.asSingleFqName()?.asString()?.let { ClassName.bestGuess(it) } ?: this - } -} - -fun FileSpec.Builder.writeTo(processingEnv: ProcessingEnvironment) { - val dir = (processingEnv.options["kapt.kotlin.generated"] - ?: processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, "Can't find the target directory for generated Kotlin files.").let { throw IllegalArgumentException() }) - addComment(""" - |Copyright (c) ${Calendar.getInstance()[Calendar.YEAR]} - | - |Licensed under the Apache License, Version 2.0 (the "License"); - |you may not use this file except in compliance with the License. - | - |http://www.apache.org/licenses/LICENSE-2.0 - | - |Unless required by applicable law or agreed to in writing, software - |distributed under the License is distributed on an "AS IS" BASIS, - |WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - |See the License for the specific language governing permissions and - |limitations under the License. - """.trimMargin()) - .build() - .writeTo(File(dir)) -} \ No newline at end of file diff --git a/annotationprocessor/src/main/resources/META-INF/gradle/incremental.annotation.processors b/annotationprocessor/src/main/resources/META-INF/gradle/incremental.annotation.processors deleted file mode 100644 index ae8a241f25..0000000000 --- a/annotationprocessor/src/main/resources/META-INF/gradle/incremental.annotation.processors +++ /dev/null @@ -1 +0,0 @@ -org.acra.AcraAnnotationProcessor,isolating \ No newline at end of file diff --git a/annotations/src/main/java/org/acra/annotation/AnyNonDefault.kt b/annotations/src/main/java/org/acra/annotation/AnyNonDefault.kt deleted file mode 100644 index 227266664c..0000000000 --- a/annotations/src/main/java/org/acra/annotation/AnyNonDefault.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2017 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.annotation - -/** - * Any of the annotation methods annotated with this has to be different from the default value for the configuration to be valid - * - * @author F43nd1r - * @since 03.06.2017 - */ -@Retention(AnnotationRetention.SOURCE) -@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) -annotation class AnyNonDefault \ No newline at end of file diff --git a/annotations/src/main/java/org/acra/annotation/BuilderMethod.kt b/annotations/src/main/java/org/acra/annotation/BuilderMethod.kt deleted file mode 100644 index cb7d66be74..0000000000 --- a/annotations/src/main/java/org/acra/annotation/BuilderMethod.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.annotation - -/** - * @author F43nd1r - * @since 10.01.2018 - */ -@Retention(AnnotationRetention.SOURCE) -@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) -annotation class BuilderMethod \ No newline at end of file diff --git a/annotations/src/main/java/org/acra/annotation/Configuration.kt b/annotations/src/main/java/org/acra/annotation/Configuration.kt deleted file mode 100644 index 9cab456c8f..0000000000 --- a/annotations/src/main/java/org/acra/annotation/Configuration.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.annotation - -import kotlin.reflect.KClass - -/** - * The annotation annotated with this will be used as basis for Configurations and their Builders - * - * @author F43nd1r - * @since 17.03.2017 - */ -@Retention(AnnotationRetention.SOURCE) -@Target(AnnotationTarget.ANNOTATION_CLASS) -annotation class Configuration(val baseBuilderClass: KClass<*> = Any::class, val isPlugin: Boolean = true) \ No newline at end of file diff --git a/annotations/src/main/java/org/acra/annotation/ConfigurationValue.kt b/annotations/src/main/java/org/acra/annotation/ConfigurationValue.kt deleted file mode 100644 index 3c4ba41fb5..0000000000 --- a/annotations/src/main/java/org/acra/annotation/ConfigurationValue.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2018 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.annotation - -/** - * @author F43nd1r - * @since 10.01.2018 - */ -@Retention(AnnotationRetention.SOURCE) -@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) -annotation class ConfigurationValue \ No newline at end of file diff --git a/annotations/src/main/java/org/acra/annotation/Instantiatable.kt b/annotations/src/main/java/org/acra/annotation/Instantiatable.kt deleted file mode 100644 index efba4a5b6d..0000000000 --- a/annotations/src/main/java/org/acra/annotation/Instantiatable.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2017 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.annotation - -/** - * All classes in annotation methods with this have to have a public, no-args constructor for the configuration to be valid - * - * @author F43nd1r - * @since 03.06.2017 - */ -@Retention(AnnotationRetention.SOURCE) -@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.VALUE_PARAMETER) -annotation class Instantiatable \ No newline at end of file diff --git a/annotations/src/main/java/org/acra/annotation/NonEmpty.kt b/annotations/src/main/java/org/acra/annotation/NonEmpty.kt deleted file mode 100644 index 4794716b55..0000000000 --- a/annotations/src/main/java/org/acra/annotation/NonEmpty.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2017 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.annotation - -/** - * This array must not be empty for the configuration to be valid - * - * @author F43nd1r - * @since 03.06.2017 - */ -@Retention(AnnotationRetention.SOURCE) -@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) -annotation class NonEmpty \ No newline at end of file diff --git a/annotations/src/main/java/org/acra/annotation/PreBuild.kt b/annotations/src/main/java/org/acra/annotation/PreBuild.kt deleted file mode 100644 index 5ae78f5cda..0000000000 --- a/annotations/src/main/java/org/acra/annotation/PreBuild.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2017 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.annotation - -/** - * This method should run before the configuration is built - * - * @author F43nd1r - * @since 03.06.2017 - */ -@Retention(AnnotationRetention.SOURCE) -@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) -annotation class PreBuild \ No newline at end of file diff --git a/annotations/src/main/java/org/acra/annotation/Transform.kt b/annotations/src/main/java/org/acra/annotation/Transform.kt deleted file mode 100644 index ac3528b224..0000000000 --- a/annotations/src/main/java/org/acra/annotation/Transform.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2017 the ACRA team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.acra.annotation - -/** - * This method transforms the content of a field before it is added to the configuration - * - * @author F43nd1r - * @since 04.06.2017 - */ -@Retention(AnnotationRetention.SOURCE) -@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) -annotation class Transform(val methodName: String) \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/acra-android-library.gradle.kts b/buildSrc/src/main/kotlin/acra-android-library.gradle.kts index 99dc24585c..e050087c39 100644 --- a/buildSrc/src/main/kotlin/acra-android-library.gradle.kts +++ b/buildSrc/src/main/kotlin/acra-android-library.gradle.kts @@ -57,8 +57,8 @@ tasks.withType { dependencies { androidTestImplementation(libs.bundles.androidx.test) - "kapt"(project(":annotationprocessor")) - compileOnly(project(":annotations")) + "kapt"(libs.autoDsl.processor) + compileOnly(libs.autoDsl.annotations) } tasks.withType { diff --git a/buildSrc/src/main/kotlin/repositories.gradle.kts b/buildSrc/src/main/kotlin/repositories.gradle.kts index bd4c78ee82..3884893a7b 100644 --- a/buildSrc/src/main/kotlin/repositories.gradle.kts +++ b/buildSrc/src/main/kotlin/repositories.gradle.kts @@ -18,4 +18,6 @@ import org.gradle.kotlin.dsl.repositories repositories { mavenCentral() google() + maven { setUrl("https://jitpack.io") } + mavenLocal() } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cdf8f5a4b1..411b2741a4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,12 +16,12 @@ nexusPublish = "1.1.0" autoCommon = "1.1.2" kotlinPoet = "1.9.0" commonsText = "1.9" +autoDsl = "2.2.3" [libraries] android-build = { module = "com.android.tools.build:gradle", version.ref = "android-build" } kotlin-gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } kotlin-allopen = { module = "org.jetbrains.kotlin:kotlin-allopen", version.ref = "kotlin" } -kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" } dokka-gradle = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" } dokka-core = { module = "org.jetbrains.dokka:dokka-core", version.ref = "dokka" } jgitver = { module = "gradle.plugin.fr.brouillard.oss.gradle:gradle-jgitver-plugin", version.ref = "jgitver" } @@ -35,9 +35,8 @@ androidx-test-junit = { module = "androidx.test.ext:junit", version.ref = "andro hamcrest = { module = "org.hamcrest:hamcrest-core", version.ref = "hamcrest" } autoService-processor = { module = "com.google.auto.service:auto-service", version.ref = "autoService" } autoService-annotations = { module = "com.google.auto.service:auto-service", version.ref = "autoService" } -autoCommon = { module = "com.google.auto:auto-common", version.ref = "autoCommon" } -kotlinPoet = { module = "com.squareup:kotlinpoet", version.ref = "kotlinPoet" } -commonsText = { module = "org.apache.commons:commons-text", version.ref = "commonsText" } +autoDsl-processor = {module = "com.faendir.kotlin.autodsl:processor", version.ref = "autoDsl"} +autoDsl-annotations = {module = "com.faendir.kotlin.autodsl:annotations", version.ref = "autoDsl"} [bundles] androidx-test = ["androidx-test-core", "androidx-test-runner", "androidx-test-rules", "androidx-test-junit", "hamcrest"] diff --git a/settings.gradle.kts b/settings.gradle.kts index b146c15bc1..b1426e7646 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -14,8 +14,6 @@ * limitations under the License. */ include("acra-javacore") -include("annotationprocessor") -include("annotations") include("acra-http") include("acra-core") include("acra-mail")