diff options
Diffstat (limited to 'mobile/android/android-components/components/concept/push')
9 files changed, 298 insertions, 0 deletions
diff --git a/mobile/android/android-components/components/concept/push/README.md b/mobile/android/android-components/components/concept/push/README.md new file mode 100644 index 0000000000..dd596fdc78 --- /dev/null +++ b/mobile/android/android-components/components/concept/push/README.md @@ -0,0 +1,23 @@ +# [Android Components](../../../README.md) > Concept > Push + +An abstract definition of a push service component. + +## Usage + +### Setting up the dependency + +Use Gradle to download the library from [maven.mozilla.org](https://maven.mozilla.org/) ([Setup repository](../../../README.md)): + +```Groovy +implementation "org.mozilla.components:concept-push:{latest-version}" +``` + +### Implementing a Push service. + +TBD + +## License + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/ diff --git a/mobile/android/android-components/components/concept/push/build.gradle b/mobile/android/android-components/components/concept/push/build.gradle new file mode 100644 index 0000000000..a1999b52c9 --- /dev/null +++ b/mobile/android/android-components/components/concept/push/build.gradle @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + defaultConfig { + minSdkVersion config.minSdkVersion + compileSdk config.compileSdkVersion + targetSdkVersion config.targetSdkVersion + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + namespace 'mozilla.components.concept.push' +} + +dependencies { + implementation project(':support-base') + + testImplementation project(':support-test') + testImplementation ComponentsDependencies.testing_junit +} + +apply from: '../../../android-lint.gradle' +apply from: '../../../publish.gradle' +ext.configurePublish(config.componentsGroupId, archivesBaseName, project.ext.description) diff --git a/mobile/android/android-components/components/concept/push/src/main/AndroidManifest.xml b/mobile/android/android-components/components/concept/push/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..e16cda1d34 --- /dev/null +++ b/mobile/android/android-components/components/concept/push/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> +<manifest /> diff --git a/mobile/android/android-components/components/concept/push/src/main/java/mozilla/components/concept/push/PushProcessor.kt b/mobile/android/android-components/components/concept/push/src/main/java/mozilla/components/concept/push/PushProcessor.kt new file mode 100644 index 0000000000..909ee23737 --- /dev/null +++ b/mobile/android/android-components/components/concept/push/src/main/java/mozilla/components/concept/push/PushProcessor.kt @@ -0,0 +1,87 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package mozilla.components.concept.push + +import androidx.annotation.VisibleForTesting + +/** + * A push notification processor that handles registration and new messages from the [PushService] provided. + * Starting Push in the Application's onCreate is recommended. + */ +interface PushProcessor { + + /** + * Start the push processor and any service associated. + */ + fun initialize() + + /** + * Removes all push subscriptions from the device. + */ + fun shutdown() + + /** + * A new registration token has been received. + */ + fun onNewToken(newToken: String) + + /** + * A new push message has been received. + * The message contains the payload as sent by the + * Autopush server, and it will be read at a lower + * abstraction layer. + */ + fun onMessageReceived(message: Map<String, String>) + + /** + * An error has occurred. + */ + fun onError(error: PushError) + + /** + * Requests the [PushService] to renew it's registration with it's provider. + */ + fun renewRegistration() + + companion object { + /** + * Initialize and installs the PushProcessor into the application. + * This needs to be called in the application's onCreate before a push service has started. + */ + fun install(processor: PushProcessor) { + instance = processor + } + + @Volatile + private var instance: PushProcessor? = null + + @VisibleForTesting + internal fun reset() { + instance = null + } + val requireInstance: PushProcessor + get() = instance ?: throw IllegalStateException( + "You need to call PushProcessor.install() on your Push instance from Application.onCreate().", + ) + } +} + +/** + * Various error types. + */ +sealed class PushError(override val message: String) : Exception() { + data class Registration(override val message: String) : PushError(message) + data class Network(override val message: String) : PushError(message) + + /** + * @property cause Original exception from Rust code. + */ + data class Rust( + override val cause: Throwable?, + override val message: String = cause?.message.orEmpty(), + ) : PushError(message) + data class MalformedMessage(override val message: String) : PushError(message) + data class ServiceUnavailable(override val message: String) : PushError(message) +} diff --git a/mobile/android/android-components/components/concept/push/src/main/java/mozilla/components/concept/push/PushService.kt b/mobile/android/android-components/components/concept/push/src/main/java/mozilla/components/concept/push/PushService.kt new file mode 100644 index 0000000000..4308fb2d1e --- /dev/null +++ b/mobile/android/android-components/components/concept/push/src/main/java/mozilla/components/concept/push/PushService.kt @@ -0,0 +1,41 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package mozilla.components.concept.push + +import android.content.Context + +/** + * Implemented by push services like Firebase Cloud Messaging SDKs to allow + * the [PushProcessor] to manage their lifecycle. + */ +interface PushService { + + /** + * Starts the push service. + */ + fun start(context: Context) + + /** + * Stops the push service. + */ + fun stop() + + /** + * Tells the push service to delete the registration token. + */ + fun deleteToken() + + /** + * If the push service is support on the device. + */ + fun isServiceAvailable(context: Context): Boolean + + companion object { + /** + * Message key for "channel ID" in a push message. + */ + const val MESSAGE_KEY_CHANNEL_ID = "chid" + } +} diff --git a/mobile/android/android-components/components/concept/push/src/main/java/mozilla/components/concept/push/exceptions/SubscriptionException.kt b/mobile/android/android-components/components/concept/push/src/main/java/mozilla/components/concept/push/exceptions/SubscriptionException.kt new file mode 100644 index 0000000000..de60f5b071 --- /dev/null +++ b/mobile/android/android-components/components/concept/push/src/main/java/mozilla/components/concept/push/exceptions/SubscriptionException.kt @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@file:Suppress("MatchingDeclarationName") + +package mozilla.components.concept.push.exceptions + +/** + * Signals that a subscription method has been invoked at an illegal or inappropriate time. + * + * See also [Exception]. + */ +class SubscriptionException( + override val message: String? = null, + override val cause: Throwable? = null, +) : Exception() diff --git a/mobile/android/android-components/components/concept/push/src/test/java/mozilla/components/concept/push/PushErrorTest.kt b/mobile/android/android-components/components/concept/push/src/test/java/mozilla/components/concept/push/PushErrorTest.kt new file mode 100644 index 0000000000..13e2013597 --- /dev/null +++ b/mobile/android/android-components/components/concept/push/src/test/java/mozilla/components/concept/push/PushErrorTest.kt @@ -0,0 +1,32 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package mozilla.components.concept.push + +import org.junit.Assert.assertEquals +import org.junit.Test + +class PushErrorTest { + @Test + fun `all PushError sets description`() { + // This test is mostly to satisfy coverage. + + var error: PushError = PushError.MalformedMessage("message") + assertEquals("message", error.message) + + error = PushError.Network("network") + assertEquals("network", error.message) + + error = PushError.Registration("reg") + assertEquals("reg", error.message) + + val exception = IllegalStateException() + val rustError = PushError.Rust(exception, "rust") + assertEquals("rust", rustError.message) + assertEquals(exception, rustError.cause) + + error = PushError.ServiceUnavailable("service") + assertEquals("service", error.message) + } +} diff --git a/mobile/android/android-components/components/concept/push/src/test/java/mozilla/components/concept/push/PushProcessorTest.kt b/mobile/android/android-components/components/concept/push/src/test/java/mozilla/components/concept/push/PushProcessorTest.kt new file mode 100644 index 0000000000..f8fad03aed --- /dev/null +++ b/mobile/android/android-components/components/concept/push/src/test/java/mozilla/components/concept/push/PushProcessorTest.kt @@ -0,0 +1,55 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package mozilla.components.concept.push + +import mozilla.components.support.test.mock +import org.junit.Assert.assertNotNull +import org.junit.Before +import org.junit.Test + +class PushProcessorTest { + + @Before + fun setup() { + PushProcessor.reset() + } + + @Test + fun install() { + val processor: PushProcessor = mock() + + PushProcessor.install(processor) + + assertNotNull(PushProcessor.requireInstance) + } + + @Test(expected = IllegalStateException::class) + fun `requireInstance throws if install not called first`() { + PushProcessor.requireInstance + } + + @Test + fun init() { + val push = TestPushProcessor() + + PushProcessor.install(push) + + assertNotNull(PushProcessor.requireInstance) + } + + class TestPushProcessor : PushProcessor { + override fun initialize() {} + + override fun shutdown() {} + + override fun onNewToken(newToken: String) {} + + override fun onMessageReceived(message: Map<String, String>) {} + + override fun onError(error: PushError) {} + + override fun renewRegistration() {} + } +} diff --git a/mobile/android/android-components/components/concept/push/src/test/resources/robolectric.properties b/mobile/android/android-components/components/concept/push/src/test/resources/robolectric.properties new file mode 100644 index 0000000000..932b01b9eb --- /dev/null +++ b/mobile/android/android-components/components/concept/push/src/test/resources/robolectric.properties @@ -0,0 +1 @@ +sdk=28 |