/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- * 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.goanna.overlays.service; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.util.Log; import android.view.View; import org.mozilla.goanna.Assert; import org.mozilla.goanna.overlays.service.sharemethods.AddBookmark; import org.mozilla.goanna.overlays.service.sharemethods.AddToReadingList; import org.mozilla.goanna.overlays.service.sharemethods.SendTab; import org.mozilla.goanna.overlays.service.sharemethods.ShareMethod; import org.mozilla.goanna.overlays.ui.OverlayToastHelper; import org.mozilla.goanna.util.ThreadUtils; import java.util.EnumMap; import java.util.Map; import static org.mozilla.goanna.overlays.OverlayConstants.ACTION_PREPARE_SHARE; import static org.mozilla.goanna.overlays.OverlayConstants.ACTION_SHARE; /** * A service to receive requests from overlays to perform actions. * See OverlayConstants for details of the intent API supported by this service. * * Currently supported operations are: * * Add bookmark* * Add to reading list* * Send tab (delegates to Sync's existing handler) * Future: Load page in background. * * * Neither of these incur a page fetch on the service... yet. That will require headless Goanna, * something we're yet to have. Refactoring Goanna as a service itself and restructing the rest of * the app to talk to it seems like the way to go there. */ public class OverlayActionService extends Service { private static final String LOGTAG = "GoannaOverlayService"; // Map used for selecting the appropriate helper object when handling a share. final Map shareTypes = new EnumMap<>(ShareMethod.Type.class); // Map relating Strings representing share types to the corresponding ShareMethods. // Share methods are initialised (and shown in the UI) in the order they are given here. // This map is used to look up the appropriate ShareMethod when handling a request, as well as // for identifying which ShareMethod needs re-initialising in response to such an intent (which // will be necessary in situations such as the deletion of Sync accounts). // Not a bindable service. @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent == null) { return START_NOT_STICKY; } // Dispatch intent to appropriate method according to its action. String action = intent.getAction(); switch (action) { case ACTION_SHARE: handleShare(intent); break; case ACTION_PREPARE_SHARE: initShareMethods(getApplicationContext()); break; default: throw new IllegalArgumentException("Unsupported intent action: " + action); } return START_NOT_STICKY; } /** * Reinitialise all ShareMethods, causing them to broadcast any UI update events necessary. */ private void initShareMethods(final Context context) { ThreadUtils.postToBackgroundThread(new Runnable() { @Override public void run() { shareTypes.clear(); shareTypes.put(ShareMethod.Type.ADD_BOOKMARK, new AddBookmark(context)); shareTypes.put(ShareMethod.Type.ADD_TO_READING_LIST, new AddToReadingList(context)); shareTypes.put(ShareMethod.Type.SEND_TAB, new SendTab(context)); } }); } public void handleShare(final Intent intent) { ThreadUtils.postToBackgroundThread(new Runnable() { @Override public void run() { ShareData shareData; try { shareData = ShareData.fromIntent(intent); } catch (IllegalArgumentException e) { Log.e(LOGTAG, "Error parsing share intent: ", e); return; } ShareMethod shareMethod = shareTypes.get(shareData.shareMethodType); final ShareMethod.Result result = shareMethod.handle(shareData); // Dispatch the share to the targeted ShareMethod. switch (result) { case SUCCESS: // \o/ OverlayToastHelper.showSuccessToast(getApplicationContext(), shareMethod.getSuccessMessage()); break; case TRANSIENT_FAILURE: // Fall-through case PERMANENT_FAILURE: // Show a failure toast without a retry button. OverlayToastHelper.showFailureToast(getApplicationContext(), shareMethod.getFailureMessage()); break; default: Assert.fail("Unknown share method result code: " + result); break; } } }); } }