// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium; import org.apache.cordova.CordovaArgs; import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaPlugin; import org.apache.cordova.PluginResult; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import android.content.Intent; import android.util.Log; import java.lang.ref.WeakReference; import java.util.Iterator; import java.util.List; import java.util.ArrayList; public class BackgroundEventHandler<TPlugin extends CordovaPlugin> { private static final String LOG_TAG = "BackgroundEventHandler"; private static List< WeakReference<BackgroundEventHandler> > handlers = new ArrayList< WeakReference<BackgroundEventHandler> >(); // TODO: we should make these maps of viewId -> pluginInstance in order to support // multiple webviews. private TPlugin pluginInstance; private CallbackContext messageChannel; private List<BackgroundEventInfo> pendingEvents = new ArrayList<BackgroundEventInfo>(); protected BackgroundEventHandler() { handlerCreated(this); } public void handleBroadcast(Context context, Intent intent) { BackgroundEventInfo event = mapBroadcast(context, intent); if (event == null) { // No corresponding event generated, meaning the broadcast is to be ignored return; } if (pluginInstance != null && messageChannel != null) { Log.d(LOG_TAG, "Firing notification to already running web view"); sendEventMessage(event); } else { pendingEvents.add(event); if (pluginInstance == null) { BackgroundActivity.launchBackground(context); } } } public void makeBackgroundEventIntent(Intent intent) { } public void pluginInitialize(TPlugin instance) { pluginInstance = instance; } public boolean pluginExecute(TPlugin instance, String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException { // TODO: Do we need to verify that the given instance matches the stored pluginInstance? if ("messageChannel".equals(action)) { messageChannel = callbackContext; firePendingEvents(); return true; } return false; } protected BackgroundEventInfo mapBroadcast(Context context, Intent intent) { return new BackgroundEventInfo(intent.getAction()); } protected void mapEventToMessage(BackgroundEventInfo event, JSONObject message) throws JSONException { if (event.action != null) { message.put("action", event.action); } } protected TPlugin getCurrentPlugin() { return pluginInstance; } private void firePendingEvents() { for (BackgroundEventInfo event : pendingEvents) { sendEventMessage(event); } pendingEvents.clear(); } private void sendEventMessage(BackgroundEventInfo event) { JSONObject message = new JSONObject(); try { mapEventToMessage(event, message); } catch (JSONException e) { Log.e(LOG_TAG, "Failed to create background event message", e); } PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, message); pluginResult.setKeepCallback(true); messageChannel.sendPluginResult(pluginResult); } private void releaseMessageChannel() { messageChannel = null; } private static void handlerCreated(BackgroundEventHandler handler) { handlers.add(new WeakReference<BackgroundEventHandler>(handler)); } static void releaseMessageChannels() { for (Iterator<WeakReference<BackgroundEventHandler>> iterator = handlers.iterator(); iterator.hasNext();) { BackgroundEventHandler handler = iterator.next().get(); if (handler == null) { // Remove reference as the handler has been garbage collected iterator.remove(); continue; } handler.releaseMessageChannel(); } } }