Bug 1234295 - Add SnackbarHelper for creating and dismissing snackbars. r=mcomella draft
authorSebastian Kaspari <s.kaspari@gmail.com>
Fri, 08 Jan 2016 15:55:51 +0100
changeset 320712 4c88b86eadf4925db46196e8966824f224035e84
parent 320699 35c1ed58949d991030af52b8af23c879c8ccb364
child 320713 bb1dd091701ee4470028fe28aecca54674e76eb1
push id9284
push users.kaspari@gmail.com
push dateTue, 12 Jan 2016 10:44:30 +0000
reviewersmcomella
bugs1234295
milestone46.0a1
Bug 1234295 - Add SnackbarHelper for creating and dismissing snackbars. r=mcomella
mobile/android/base/java/org/mozilla/gecko/SnackbarHelper.java
mobile/android/base/moz.build
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/SnackbarHelper.java
@@ -0,0 +1,123 @@
+/* -*- 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.gecko;
+
+import org.mozilla.gecko.util.EventCallback;
+
+import android.app.Activity;
+import android.support.design.widget.Snackbar;
+import android.support.v4.content.ContextCompat;
+import android.text.TextUtils;
+import android.view.View;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Helper class for creating and dismissing snackbars. Use this class to guarantee a consistent style and behavior
+ * across the app.
+ */
+public class SnackbarHelper {
+    /**
+     * Combined interface for handling all callbacks from a snackbar because anonymous classes can only extend one
+     * interface or class.
+     */
+    public static abstract class SnackbarCallback extends Snackbar.Callback implements View.OnClickListener {}
+
+    /**
+     * SnackbarCallback implementation for delegating snackbar events to an EventCallback.
+     */
+    public static class SnackbarEventCallback extends SnackbarCallback {
+        private EventCallback callback;
+
+        public SnackbarEventCallback(EventCallback callback) {
+            this.callback = callback;
+        }
+
+        @Override
+        public synchronized void onClick(View view) {
+            if (callback == null) {
+                return;
+            }
+
+            callback.sendSuccess(null);
+            callback = null; // Releasing reference. We only want to execute the callback once.
+        }
+
+        @Override
+        public synchronized void onDismissed(Snackbar snackbar, int event) {
+            if (callback == null || event == Snackbar.Callback.DISMISS_EVENT_ACTION) {
+                return;
+            }
+
+            callback.sendError(null);
+            callback = null; // Releasing reference. We only want to execute the callback once.
+        }
+    }
+
+    private static final Object currentSnackbarLock = new Object();
+    private static WeakReference<Snackbar> currentSnackbar = new WeakReference<>(null); // Guarded by 'currentSnackbarLock'
+
+    /**
+     * Show a snackbar to display a message.
+     *
+     * @param activity Activity to show the snackbar in.
+     * @param message The text to show. Can be formatted text.
+     * @param duration How long to display the message.
+     */
+    public static void showSnackbar(Activity activity, String message, int duration) {
+        showSnackbarWithAction(activity, message, duration, null, null);
+    }
+
+    /**
+     * Show a snackbar to display a message and an action.
+     *
+     * @param activity Activity to show the snackbar in.
+     * @param message The text to show. Can be formatted text.
+     * @param duration How long to display the message.
+     * @param action Action text to display.
+     * @param callback Callback to be invoked when the action is clicked or the snackbar is dismissed.
+     */
+    public static void showSnackbarWithAction(Activity activity, String message, int duration, String action, SnackbarCallback callback) {
+        final View parentView = findBestParentView(activity);
+        final Snackbar snackbar = Snackbar.make(parentView, message, duration);
+
+        if (callback != null && !TextUtils.isEmpty(action)) {
+            snackbar.setAction(action, callback);
+            snackbar.setActionTextColor(ContextCompat.getColor(activity, R.color.fennec_ui_orange));
+            snackbar.setCallback(callback);
+        }
+
+        snackbar.show();
+
+        synchronized (currentSnackbarLock) {
+            currentSnackbar = new WeakReference<>(snackbar);
+        }
+    }
+
+    /**
+     * Dismiss the currently visible snackbar.
+     */
+    public static void dismissCurrentSnackbar() {
+        synchronized (currentSnackbarLock) {
+            final Snackbar snackbar = currentSnackbar.get();
+            if (snackbar != null && snackbar.isShown()) {
+                snackbar.dismiss();
+            }
+        }
+    }
+
+    /**
+     * Find the best parent view to hold the Snackbar's view. The Snackbar implementation of the support
+     * library will use this view to walk up the view tree to find an actual suitable parent (if needed).
+     */
+    private static View findBestParentView(Activity activity) {
+        if (activity instanceof GeckoApp) {
+            return activity.findViewById(R.id.root_layout);
+        }
+
+        return activity.findViewById(android.R.id.content);
+    }
+}
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -504,16 +504,17 @@ gbjar.sources += ['java/org/mozilla/geck
     'restrictions/RestrictedProfileConfiguration.java',
     'restrictions/RestrictionConfiguration.java',
     'restrictions/RestrictionProvider.java',
     'ServiceNotificationClient.java',
     'SessionParser.java',
     'SharedPreferencesHelper.java',
     'SiteIdentity.java',
     'SmsManager.java',
+    'SnackbarHelper.java',
     'sqlite/ByteBufferInputStream.java',
     'sqlite/MatrixBlobCursor.java',
     'sqlite/SQLiteBridge.java',
     'sqlite/SQLiteBridgeException.java',
     'SuggestClient.java',
     'SurfaceBits.java',
     'Tab.java',
     'tabqueue/TabQueueDispatcher.java',