Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* vim: ts=4 sw=4 expandtab:
* 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 org.mozilla.geckoview;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoThread;
import org.mozilla.gecko.util.BundleEventListener;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.util.ThreadUtils;
public class WebPushController {
private static final String LOGTAG = "WebPushController";
private WebPushDelegate mDelegate;
private BundleEventListener mEventListener;
/* package */ WebPushController() {
mEventListener = new EventListener();
EventDispatcher.getInstance()
.registerUiThreadListener(
mEventListener,
"GeckoView:PushSubscribe",
"GeckoView:PushUnsubscribe",
"GeckoView:PushGetSubscription");
}
/**
* Sets the {@link WebPushDelegate} for this instance.
*
* @param delegate The {@link WebPushDelegate} instance.
*/
@UiThread
public void setDelegate(final @Nullable WebPushDelegate delegate) {
ThreadUtils.assertOnUiThread();
mDelegate = delegate;
}
/**
* Gets the {@link WebPushDelegate} for this instance.
*
* @return delegate The {@link WebPushDelegate} instance.
*/
@UiThread
@Nullable
public WebPushDelegate getDelegate() {
ThreadUtils.assertOnUiThread();
return mDelegate;
}
/**
* Send a push event for a given subscription.
*
* @param scope The Service Worker scope associated with this subscription.
*/
@UiThread
public void onPushEvent(final @NonNull String scope) {
ThreadUtils.assertOnUiThread();
onPushEvent(scope, null);
}
/**
* Send a push event with a payload for a given subscription.
*
* @param scope The Service Worker scope associated with this subscription.
* @param data The unencrypted payload.
*/
@UiThread
public void onPushEvent(final @NonNull String scope, final @Nullable byte[] data) {
ThreadUtils.assertOnUiThread();
GeckoThread.waitForState(GeckoThread.State.JNI_READY)
.accept(
val -> {
final GeckoBundle msg = new GeckoBundle(2);
msg.putString("scope", scope);
msg.putString("data", Base64Utils.encode(data));
EventDispatcher.getInstance().dispatch("GeckoView:PushEvent", msg);
},
e -> Log.e(LOGTAG, "Unable to deliver Web Push message", e));
}
/**
* Notify that a given subscription has changed. This is normally a signal to the content that it
* needs to re-subscribe.
*
* @param scope The Service Worker scope associated with this subscription.
*/
@UiThread
public void onSubscriptionChanged(final @NonNull String scope) {
ThreadUtils.assertOnUiThread();
final GeckoBundle msg = new GeckoBundle(1);
msg.putString("scope", scope);
EventDispatcher.getInstance().dispatch("GeckoView:PushSubscriptionChanged", msg);
}
private class EventListener implements BundleEventListener {
@Override
public void handleMessage(
final String event, final GeckoBundle message, final EventCallback callback) {
if (mDelegate == null) {
callback.sendError("Not allowed");
return;
}
switch (event) {
case "GeckoView:PushSubscribe":
{
byte[] appServerKey = null;
if (message.containsKey("appServerKey")) {
appServerKey = Base64Utils.decode(message.getString("appServerKey"));
}
final GeckoResult<WebPushSubscription> result =
mDelegate.onSubscribe(message.getString("scope"), appServerKey);
if (result == null) {
callback.sendSuccess(null);
return;
}
result.accept(
subscription ->
callback.sendSuccess(subscription != null ? subscription.toBundle() : null),
error -> callback.sendSuccess(null));
break;
}
case "GeckoView:PushUnsubscribe":
{
final GeckoResult<Void> result = mDelegate.onUnsubscribe(message.getString("scope"));
if (result == null) {
callback.sendSuccess(null);
return;
}
callback.resolveTo(result.map(val -> null));
break;
}
case "GeckoView:PushGetSubscription":
{
final GeckoResult<WebPushSubscription> result =
mDelegate.onGetSubscription(message.getString("scope"));
if (result == null) {
callback.sendSuccess(null);
return;
}
callback.resolveTo(
result.map(subscription -> subscription != null ? subscription.toBundle() : null));
break;
}
}
}
}
}