push notifications initial
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
@@ -58,6 +59,22 @@
|
|||||||
android:theme="@style/Theme.AppCompat.Translucent"
|
android:theme="@style/Theme.AppCompat.Translucent"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:launchMode="singleTop" />
|
android:launchMode="singleTop" />
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name="org.ironfoxoss.unifiedpush.PushReceiver"
|
||||||
|
tools:node="remove" />
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name="eu.weblibre.flutter_mozilla_components.receivers.UnifiedPushReceiver"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="org.unifiedpush.android.connector.MESSAGE" />
|
||||||
|
<action android:name="org.unifiedpush.android.connector.UNREGISTERED" />
|
||||||
|
<action android:name="org.unifiedpush.android.connector.NEW_ENDPOINT" />
|
||||||
|
<action android:name="org.unifiedpush.android.connector.REGISTRATION_FAILED" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
import 'package:fading_scroll/fading_scroll.dart';
|
import 'package:fading_scroll/fading_scroll.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||||
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:weblibre/features/settings/presentation/controllers/save_settings.dart';
|
import 'package:weblibre/features/settings/presentation/controllers/save_settings.dart';
|
||||||
import 'package:weblibre/features/settings/presentation/widgets/sections.dart';
|
import 'package:weblibre/features/settings/presentation/widgets/sections.dart';
|
||||||
@@ -43,6 +44,8 @@ class ExperimentalSettingsScreen extends StatelessWidget {
|
|||||||
controller: controller,
|
controller: controller,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||||
children: const [
|
children: const [
|
||||||
|
SettingSection(name: 'Web Push'),
|
||||||
|
_UnifiedPushDistributorTile(),
|
||||||
SettingSection(name: 'Runtime & Startup'),
|
SettingSection(name: 'Runtime & Startup'),
|
||||||
_IsolatedProcessEnabledTile(),
|
_IsolatedProcessEnabledTile(),
|
||||||
_AppZygoteProcessEnabledTile(),
|
_AppZygoteProcessEnabledTile(),
|
||||||
@@ -55,6 +58,41 @@ class ExperimentalSettingsScreen extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _UnifiedPushDistributorTile extends StatelessWidget {
|
||||||
|
const _UnifiedPushDistributorTile();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListTile(
|
||||||
|
leading: const Icon(MdiIcons.bellBadgeOutline),
|
||||||
|
title: const Text('Choose UnifiedPush Distributor'),
|
||||||
|
subtitle: const Text(
|
||||||
|
'Select the app that should deliver website push notifications to WebLibre.',
|
||||||
|
),
|
||||||
|
trailing: const Icon(Icons.chevron_right),
|
||||||
|
onTap: () async {
|
||||||
|
final messenger = ScaffoldMessenger.of(context);
|
||||||
|
final success = await GeckoBrowserService()
|
||||||
|
.pickUnifiedPushDistributor();
|
||||||
|
|
||||||
|
if (!context.mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
messenger.showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
success
|
||||||
|
? 'UnifiedPush distributor configured.'
|
||||||
|
: 'Could not configure UnifiedPush. Install a distributor and try again.',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _IsolatedProcessEnabledTile extends HookConsumerWidget {
|
class _IsolatedProcessEnabledTile extends HookConsumerWidget {
|
||||||
const _IsolatedProcessEnabledTile();
|
const _IsolatedProcessEnabledTile();
|
||||||
|
|
||||||
|
|||||||
@@ -139,6 +139,10 @@ dependencies {
|
|||||||
implementation "org.mozilla.components:lib-publicsuffixlist:$mozillaComponentsVersion"
|
implementation "org.mozilla.components:lib-publicsuffixlist:$mozillaComponentsVersion"
|
||||||
implementation "org.mozilla.components:service-firefox-accounts:$mozillaComponentsVersion"
|
implementation "org.mozilla.components:service-firefox-accounts:$mozillaComponentsVersion"
|
||||||
implementation "org.mozilla.components:support-appservices:$mozillaComponentsVersion"
|
implementation "org.mozilla.components:support-appservices:$mozillaComponentsVersion"
|
||||||
|
implementation "org.ironfoxoss.unifiedpush:unifiedpush:$mozillaComponentsVersion"
|
||||||
|
implementation ('org.unifiedpush.android:connector:3.3.2') {
|
||||||
|
exclude group: 'com.google.protobuf', module: 'protobuf-java'
|
||||||
|
}
|
||||||
|
|
||||||
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.3.0'
|
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.3.0'
|
||||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0'
|
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0'
|
||||||
|
|||||||
+2
@@ -12,6 +12,7 @@ import eu.weblibre.flutter_mozilla_components.components.Core
|
|||||||
import eu.weblibre.flutter_mozilla_components.components.BackgroundServices
|
import eu.weblibre.flutter_mozilla_components.components.BackgroundServices
|
||||||
import eu.weblibre.flutter_mozilla_components.components.Events
|
import eu.weblibre.flutter_mozilla_components.components.Events
|
||||||
import eu.weblibre.flutter_mozilla_components.components.Features
|
import eu.weblibre.flutter_mozilla_components.components.Features
|
||||||
|
import eu.weblibre.flutter_mozilla_components.components.Push
|
||||||
import eu.weblibre.flutter_mozilla_components.components.Search
|
import eu.weblibre.flutter_mozilla_components.components.Search
|
||||||
import eu.weblibre.flutter_mozilla_components.components.Services
|
import eu.weblibre.flutter_mozilla_components.components.Services
|
||||||
import eu.weblibre.flutter_mozilla_components.components.UseCases
|
import eu.weblibre.flutter_mozilla_components.components.UseCases
|
||||||
@@ -74,6 +75,7 @@ class Components(val profileApplicationContext: ProfileContext,
|
|||||||
}
|
}
|
||||||
val features by lazy { Features(core.engine, core.store, addonEvents, tabContentEvents) }
|
val features by lazy { Features(core.engine, core.store, addonEvents, tabContentEvents) }
|
||||||
val search by lazy { Search(profileApplicationContext, core, useCases) }
|
val search by lazy { Search(profileApplicationContext, core, useCases) }
|
||||||
|
val push by lazy { Push(this) }
|
||||||
|
|
||||||
var mainBrowserEngineView: EngineView? = null
|
var mainBrowserEngineView: EngineView? = null
|
||||||
var externalAppEngineView: EngineView? = null
|
var externalAppEngineView: EngineView? = null
|
||||||
|
|||||||
+2
@@ -289,6 +289,8 @@ object GlobalComponents {
|
|||||||
} else {
|
} else {
|
||||||
restorePreviousCustomTabs()
|
restorePreviousCustomTabs()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newComponents.push.initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
|||||||
+17
@@ -456,6 +456,23 @@ class GeckoBrowserApiImpl : GeckoBrowserApi {
|
|||||||
currentActivity.startActivity(intent)
|
currentActivity.startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun pickUnifiedPushDistributor(callback: (Result<Boolean>) -> Unit) {
|
||||||
|
val currentActivity = activity
|
||||||
|
if (currentActivity == null) {
|
||||||
|
callback(Result.success(false))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
runCatching {
|
||||||
|
components.push.pickDistributor(currentActivity) { success ->
|
||||||
|
callback(Result.success(success))
|
||||||
|
}
|
||||||
|
}.onFailure { error ->
|
||||||
|
logger.error("$TAG: Failed to pick UnifiedPush distributor", error)
|
||||||
|
callback(Result.failure(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun shutdown() {
|
override fun shutdown() {
|
||||||
logger.debug("$TAG: Shutting down GeckoView engine")
|
logger.debug("$TAG: Shutting down GeckoView engine")
|
||||||
|
|
||||||
|
|||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
/* 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 https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package eu.weblibre.flutter_mozilla_components.components
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import eu.weblibre.flutter_mozilla_components.Components
|
||||||
|
import eu.weblibre.flutter_mozilla_components.push.WebPushEngineIntegration
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
import org.ironfoxoss.unifiedpush.UnifiedPushFeature
|
||||||
|
import org.unifiedpush.android.connector.UnifiedPush
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component group for web push services backed by UnifiedPush.
|
||||||
|
*/
|
||||||
|
class Push(
|
||||||
|
private val components: Components,
|
||||||
|
) {
|
||||||
|
private val initialized = AtomicBoolean(false)
|
||||||
|
|
||||||
|
private val feature by lazy {
|
||||||
|
UnifiedPushFeature(
|
||||||
|
context = components.profileApplicationContext,
|
||||||
|
disableRateLimit = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val webPushEngineIntegration by lazy {
|
||||||
|
WebPushEngineIntegration(components.core.engine, feature)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun initialize() {
|
||||||
|
if (!initialized.compareAndSet(false, true)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the store-side WebNotificationFeature is installed before push events arrive.
|
||||||
|
components.core.store
|
||||||
|
webPushEngineIntegration.start()
|
||||||
|
feature.initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pickDistributor(activity: Activity, callback: (Boolean) -> Unit) {
|
||||||
|
initialize()
|
||||||
|
UnifiedPush.tryPickDistributor(activity) { success ->
|
||||||
|
if (success) {
|
||||||
|
feature.renewRegistration()
|
||||||
|
}
|
||||||
|
callback(success)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
@@ -5656,6 +5656,7 @@ interface GeckoBrowserApi {
|
|||||||
fun openInCustomTab(url: String, private: Boolean, contextId: String?)
|
fun openInCustomTab(url: String, private: Boolean, contextId: String?)
|
||||||
fun isDefaultBrowser(): Boolean
|
fun isDefaultBrowser(): Boolean
|
||||||
fun requestDefaultBrowser()
|
fun requestDefaultBrowser()
|
||||||
|
fun pickUnifiedPushDistributor(callback: (Result<Boolean>) -> Unit)
|
||||||
fun shutdown()
|
fun shutdown()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -5790,6 +5791,24 @@ interface GeckoBrowserApi {
|
|||||||
channel.setMessageHandler(null)
|
channel.setMessageHandler(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
run {
|
||||||
|
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoBrowserApi.pickUnifiedPushDistributor$separatedMessageChannelSuffix", codec)
|
||||||
|
if (api != null) {
|
||||||
|
channel.setMessageHandler { _, reply ->
|
||||||
|
api.pickUnifiedPushDistributor{ result: Result<Boolean> ->
|
||||||
|
val error = result.exceptionOrNull()
|
||||||
|
if (error != null) {
|
||||||
|
reply.reply(GeckoPigeonUtils.wrapError(error))
|
||||||
|
} else {
|
||||||
|
val data = result.getOrNull()
|
||||||
|
reply.reply(GeckoPigeonUtils.wrapResult(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
channel.setMessageHandler(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
run {
|
run {
|
||||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoBrowserApi.shutdown$separatedMessageChannelSuffix", codec)
|
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoBrowserApi.shutdown$separatedMessageChannelSuffix", codec)
|
||||||
if (api != null) {
|
if (api != null) {
|
||||||
|
|||||||
+113
@@ -0,0 +1,113 @@
|
|||||||
|
/* 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 https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package eu.weblibre.flutter_mozilla_components.push
|
||||||
|
|
||||||
|
import android.util.Base64
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.MainScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import mozilla.components.concept.engine.Engine
|
||||||
|
import mozilla.components.concept.engine.webpush.WebPushDelegate
|
||||||
|
import mozilla.components.concept.engine.webpush.WebPushHandler
|
||||||
|
import mozilla.components.concept.engine.webpush.WebPushSubscription
|
||||||
|
import mozilla.components.support.base.log.logger.Logger
|
||||||
|
import org.ironfoxoss.unifiedpush.AutoPushSubscription
|
||||||
|
import org.ironfoxoss.unifiedpush.PushObserver
|
||||||
|
import org.ironfoxoss.unifiedpush.PushScope
|
||||||
|
import org.ironfoxoss.unifiedpush.PushSubscriptionProcessor
|
||||||
|
import org.ironfoxoss.unifiedpush.Pusher
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Engine integration with UnifiedPush-backed web push support.
|
||||||
|
*/
|
||||||
|
class WebPushEngineIntegration(
|
||||||
|
private val engine: Engine,
|
||||||
|
private val pushFeature: Pusher,
|
||||||
|
private val coroutineScope: CoroutineScope = MainScope(),
|
||||||
|
stringDecoder: (String) -> ByteArray =
|
||||||
|
{ s -> Base64.decode(s.toByteArray(), Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP) },
|
||||||
|
byteArrayEncoder: (ByteArray) -> String =
|
||||||
|
{ ba -> Base64.encodeToString(ba, Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP) },
|
||||||
|
) : PushObserver {
|
||||||
|
|
||||||
|
private var handler: WebPushHandler? = null
|
||||||
|
private val delegate = WebPushEngineDelegate(pushFeature, stringDecoder, byteArrayEncoder)
|
||||||
|
|
||||||
|
fun start() {
|
||||||
|
handler = engine.registerWebPushDelegate(delegate)
|
||||||
|
pushFeature.register(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stop() {
|
||||||
|
pushFeature.unregister(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMessageReceived(scope: PushScope, message: ByteArray?) {
|
||||||
|
coroutineScope.launch {
|
||||||
|
handler?.onPushMessage(scope, message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSubscriptionChanged(scope: PushScope) {
|
||||||
|
coroutineScope.launch {
|
||||||
|
handler?.onSubscriptionChanged(scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class WebPushEngineDelegate(
|
||||||
|
private val pushFeature: PushSubscriptionProcessor,
|
||||||
|
private val stringDecoder: (String) -> ByteArray,
|
||||||
|
private val byteArrayEncoder: (ByteArray) -> String,
|
||||||
|
) : WebPushDelegate {
|
||||||
|
private val logger = Logger("WebPushEngineDelegate")
|
||||||
|
|
||||||
|
override fun onGetSubscription(scope: String, onSubscription: (WebPushSubscription?) -> Unit) {
|
||||||
|
pushFeature.getSubscription(scope) {
|
||||||
|
onSubscription(it?.toEnginePushSubscription(stringDecoder))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSubscribe(
|
||||||
|
scope: String,
|
||||||
|
serverKey: ByteArray?,
|
||||||
|
onSubscribe: (WebPushSubscription?) -> Unit,
|
||||||
|
) {
|
||||||
|
pushFeature.subscribe(
|
||||||
|
scope = scope,
|
||||||
|
appServerKey = serverKey?.let { byteArrayEncoder(it) },
|
||||||
|
onSubscribeError = {
|
||||||
|
logger.error("Error on push onSubscribe.")
|
||||||
|
onSubscribe(null)
|
||||||
|
},
|
||||||
|
onSubscribe = { subscription ->
|
||||||
|
onSubscribe(subscription.toEnginePushSubscription(stringDecoder))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUnsubscribe(scope: String, onUnsubscribe: (Boolean) -> Unit) {
|
||||||
|
pushFeature.unsubscribe(
|
||||||
|
scope = scope,
|
||||||
|
onUnsubscribeError = {
|
||||||
|
logger.error("Error on push onUnsubscribe.")
|
||||||
|
onUnsubscribe(false)
|
||||||
|
},
|
||||||
|
onUnsubscribe = {
|
||||||
|
onUnsubscribe(it)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun AutoPushSubscription.toEnginePushSubscription(stringDecoder: (String) -> ByteArray) = WebPushSubscription(
|
||||||
|
scope = scope,
|
||||||
|
publicKey = stringDecoder(publicKey),
|
||||||
|
endpoint = endpoint,
|
||||||
|
authSecret = stringDecoder(authKey),
|
||||||
|
// The app server key is only available during subscription creation, so we preserve Gecko's
|
||||||
|
// previous value by leaving it null for cached subscriptions.
|
||||||
|
appServerKey = null,
|
||||||
|
)
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
/* 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 https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package eu.weblibre.flutter_mozilla_components.receivers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.util.Log
|
||||||
|
import eu.weblibre.flutter_mozilla_components.ActiveProfile
|
||||||
|
import eu.weblibre.flutter_mozilla_components.GlobalComponents
|
||||||
|
import org.ironfoxoss.unifiedpush.PushError
|
||||||
|
import org.ironfoxoss.unifiedpush.UnifiedPushProcessor
|
||||||
|
import org.unifiedpush.android.connector.FailedReason
|
||||||
|
import org.unifiedpush.android.connector.MessagingReceiver
|
||||||
|
import org.unifiedpush.android.connector.data.PushEndpoint
|
||||||
|
import org.unifiedpush.android.connector.data.PushMessage
|
||||||
|
|
||||||
|
class UnifiedPushReceiver : MessagingReceiver() {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "UnifiedPushReceiver"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
ActiveProfile.resolveFromDisk(context.applicationContext)
|
||||||
|
|
||||||
|
if (GlobalComponents.components == null &&
|
||||||
|
!GlobalComponents.ensureExternalComponents(context.applicationContext)
|
||||||
|
) {
|
||||||
|
Log.e(TAG, "Unable to initialize components for UnifiedPush delivery")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalComponents.components?.push?.initialize()
|
||||||
|
|
||||||
|
if (GlobalComponents.components == null) {
|
||||||
|
Log.e(TAG, "UnifiedPush delivery aborted because components are unavailable")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onReceive(context, intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMessage(context: Context, message: PushMessage, instance: String) {
|
||||||
|
UnifiedPushProcessor.requireInstance.onMessage(
|
||||||
|
scope = instance,
|
||||||
|
message = message,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNewEndpoint(context: Context, endpoint: PushEndpoint, instance: String) {
|
||||||
|
UnifiedPushProcessor.requireInstance.onNewEndpoint(
|
||||||
|
scope = instance,
|
||||||
|
newEndpoint = endpoint,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRegistrationFailed(context: Context, reason: FailedReason, instance: String) {
|
||||||
|
UnifiedPushProcessor.requireInstance.onError(reason.toPushError())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUnregistered(context: Context, instance: String) {
|
||||||
|
UnifiedPushProcessor.requireInstance.onUnregistered(scope = instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FailedReason.toPushError(): PushError {
|
||||||
|
return when (this) {
|
||||||
|
FailedReason.NETWORK -> PushError.Network("Push service needs network to register")
|
||||||
|
FailedReason.INTERNAL_ERROR -> PushError.ServiceUnavailable("Unknown error")
|
||||||
|
FailedReason.ACTION_REQUIRED ->
|
||||||
|
PushError.ServiceUnavailable("Push service waits for a user action")
|
||||||
|
FailedReason.VAPID_REQUIRED -> PushError.Registration("Push service requires VAPID")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -65,6 +65,10 @@ class GeckoBrowserService {
|
|||||||
return _api.requestDefaultBrowser();
|
return _api.requestDefaultBrowser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> pickUnifiedPushDistributor() {
|
||||||
|
return _api.pickUnifiedPushDistributor();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> shutdown() {
|
Future<void> shutdown() {
|
||||||
return _api.shutdown();
|
return _api.shutdown();
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1140,6 +1140,8 @@ abstract class GeckoBrowserApi {
|
|||||||
});
|
});
|
||||||
bool isDefaultBrowser();
|
bool isDefaultBrowser();
|
||||||
void requestDefaultBrowser();
|
void requestDefaultBrowser();
|
||||||
|
@async
|
||||||
|
bool pickUnifiedPushDistributor();
|
||||||
void shutdown();
|
void shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user