Bug 1234295 - Use SnackbarHelper everywhere to create snackbars. r=mcomella draft
authorSebastian Kaspari <s.kaspari@gmail.com>
Fri, 08 Jan 2016 15:57:28 +0100
changeset 320713 bb1dd091701ee4470028fe28aecca54674e76eb1
parent 320712 4c88b86eadf4925db46196e8966824f224035e84
child 320714 cb7c2921600c63de1595eb0ff24c47c208d41817
push id9284
push users.kaspari@gmail.com
push dateTue, 12 Jan 2016 10:44:30 +0000
reviewersmcomella
bugs1234295
milestone46.0a1
Bug 1234295 - Use SnackbarHelper everywhere to create snackbars. r=mcomella
mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
mobile/android/base/java/org/mozilla/gecko/EditBookmarkDialog.java
mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java
mobile/android/base/java/org/mozilla/gecko/home/HomeFragment.java
mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
mobile/android/base/java/org/mozilla/gecko/preferences/SearchEnginePreference.java
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -398,58 +398,65 @@ public class BrowserApp extends GeckoApp
             hideBrowserSearch();
         }
     }
 
     private void showBookmarkAddedSnackbar() {
         // This flow is from the option menu which has check to see if a bookmark was already added.
         // So, it is safe here to show the snackbar that bookmark_added without any checks.
 
-        final SnackbarCallback callback = new SnackbarCallback() {
+        final SnackbarHelper.SnackbarCallback callback = new SnackbarHelper.SnackbarCallback() {
             @Override
             public void onClick(View v) {
                 Telemetry.sendUIEvent(TelemetryContract.Event.SHOW, TelemetryContract.Method.TOAST, "bookmark_options");
                 showBookmarkDialog();
             }
         };
 
-        showSnackbar(getResources().getString(R.string.bookmark_added),
-                     Snackbar.LENGTH_LONG,
-                     getResources().getString(R.string.bookmark_options),
-                     callback);
+        SnackbarHelper.showSnackbarWithAction(this,
+                getResources().getString(R.string.bookmark_added),
+                Snackbar.LENGTH_LONG,
+                getResources().getString(R.string.bookmark_options),
+                callback);
     }
 
     private void showBookmarkRemovedSnackbar() {
-        showSnackbar(getResources().getString(R.string.bookmark_removed), Snackbar.LENGTH_SHORT, null, null);
+        SnackbarHelper.showSnackbar(this, getResources().getString(R.string.bookmark_removed), Snackbar.LENGTH_SHORT);
     }
 
     private void showSwitchToReadingListSnackbar(String message) {
-        final SnackbarCallback callback = new SnackbarCallback() {
+        final SnackbarHelper.SnackbarCallback callback = new SnackbarHelper.SnackbarCallback() {
             @Override
             public void onClick(View v) {
                 Telemetry.sendUIEvent(TelemetryContract.Event.SHOW, TelemetryContract.Method.TOAST, "reading_list");
 
                 final String aboutPageUrl = AboutPages.getURLForBuiltinPanelType(PanelType.READING_LIST);
                 Tabs.getInstance().loadUrlInTab(aboutPageUrl);
             }
         };
 
-        showSnackbar(message, Snackbar.LENGTH_LONG, getResources().getString(R.string.switch_button_message), callback);
+        SnackbarHelper.showSnackbarWithAction(this,
+                message,
+                Snackbar.LENGTH_LONG,
+                getResources().getString(R.string.switch_button_message),
+                callback);
     }
 
     public void onAddedToReadingList(String url) {
         showSwitchToReadingListSnackbar(getResources().getString(R.string.reading_list_added));
     }
 
     public void onAlreadyInReadingList(String url) {
         showSwitchToReadingListSnackbar(getResources().getString(R.string.reading_list_duplicate));
     }
 
     public void onRemovedFromReadingList(String url) {
-        showSnackbar(getResources().getString(R.string.reading_list_removed), Snackbar.LENGTH_SHORT, null, null);
+        SnackbarHelper.showSnackbar(this,
+                getResources().getString(R.string.reading_list_removed),
+                Snackbar.LENGTH_SHORT);
     }
 
     @Override
     public boolean onKey(View v, int keyCode, KeyEvent event) {
         if (AndroidGamepadManager.handleKeyEvent(event)) {
             return true;
         }
 
@@ -2721,20 +2728,18 @@ public class BrowserApp extends GeckoApp
      * user touches the main layout.
      */
     private class HideOnTouchListener implements TouchEventInterceptor {
         private boolean mIsHidingTabs;
         private final Rect mTempRect = new Rect();
 
         @Override
         public boolean onInterceptTouchEvent(View view, MotionEvent event) {
-            if (event.getActionMasked() == MotionEvent.ACTION_DOWN
-                    && mSnackbar != null
-                    && mSnackbar.isShown()) {
-                mSnackbar.dismiss();
+            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+                SnackbarHelper.dismissCurrentSnackbar();
             }
 
             // Only try to hide the button toast if it's already inflated and if we are starting a tap action.
             // By only hiding a toast at the start of a tap action, a button toast opened in response to a tap
             // action is not immediately hidden as the tap action continues.
             if (event.getActionMasked() == MotionEvent.ACTION_DOWN && mToast != null) {
                 mToast.hide(false, ButtonToast.ReasonHidden.TOUCH_OUTSIDE);
             }
@@ -3726,31 +3731,31 @@ public class BrowserApp extends GeckoApp
         final Tab newTab = Tabs.getInstance().loadUrl(url, loadFlags);
 
         // We switch to the desired tab by unique ID, which closes any window
         // for a race between opening the tab and closing it, and switching to
         // it. We could also switch to the Tab explicitly, but we don't want to
         // hold a reference to the Tab itself in the anonymous listener class.
         final int newTabId = newTab.getId();
 
-        final SnackbarCallback callback = new SnackbarCallback() {
+        final SnackbarHelper.SnackbarCallback callback = new SnackbarHelper.SnackbarCallback() {
             @Override
             public void onClick(View v) {
                 Telemetry.sendUIEvent(TelemetryContract.Event.SHOW, TelemetryContract.Method.TOAST, "switchtab");
 
                 maybeSwitchToTab(newTabId);
             }
         };
 
         final String message = isPrivate ?
                 getResources().getString(R.string.new_private_tab_opened) :
                 getResources().getString(R.string.new_tab_opened);
         final String buttonMessage = getResources().getString(R.string.switch_button_message);
 
-        showSnackbar(message, Snackbar.LENGTH_LONG, buttonMessage, callback);
+        SnackbarHelper.showSnackbarWithAction(this, message, Snackbar.LENGTH_LONG, buttonMessage, callback);
     }
 
     // BrowserSearch.OnSearchListener
     @Override
     public void onSearch(SearchEngine engine, String text) {
         // Don't store searches that happen in private tabs. This assumes the user can only
         // perform a search inside the currently selected tab, which is true for searches
         // that come from SearchEngineRow.
--- a/mobile/android/base/java/org/mozilla/gecko/EditBookmarkDialog.java
+++ b/mobile/android/base/java/org/mozilla/gecko/EditBookmarkDialog.java
@@ -212,18 +212,19 @@ public class EditBookmarkDialog {
                         String newKeyword = keywordText.getText().toString().trim();
 
                         db.updateBookmark(context.getContentResolver(), id, newUrl, nameText.getText().toString(), newKeyword);
                         return null;
                     }
 
                     @Override
                     public void onPostExecute(Void result) {
-                        View view = ((Activity)context).findViewById(android.R.id.content);
-                        Snackbar.make(view, R.string.bookmark_updated, Snackbar.LENGTH_SHORT).show();
+                        SnackbarHelper.showSnackbar((Activity) context,
+                                context.getString(R.string.bookmark_updated),
+                                Snackbar.LENGTH_SHORT);
                     }
                 }).execute();
             }
         });
 
         editPrompt.setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
             @Override
             public void onClick(DialogInterface dialog, int whichButton) {
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -1,16 +1,15 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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.AppConstants;
 import android.widget.AdapterView;
 import android.widget.Button;
 import org.mozilla.gecko.AppConstants.Versions;
 import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.favicons.Favicons;
 import org.mozilla.gecko.gfx.BitmapUtils;
 import org.mozilla.gecko.gfx.FullScreenState;
@@ -45,17 +44,16 @@ import org.mozilla.gecko.util.PrefUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.webapp.EventListener;
 import org.mozilla.gecko.webapp.UninstallListener;
 import org.mozilla.gecko.widget.ButtonToast;
 
 import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.app.AlertDialog;
-import android.app.Dialog;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -71,19 +69,17 @@ import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.StrictMode;
 import android.provider.ContactsContract;
 import android.provider.MediaStore.Images.Media;
-import android.support.annotation.Nullable;
 import android.support.design.widget.Snackbar;
-import android.support.v4.content.ContextCompat;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Base64;
 import android.util.Log;
 import android.util.SparseBooleanArray;
 import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.Menu;
@@ -191,17 +187,16 @@ public abstract class GeckoApp
 
     private ContactService mContactService;
     private PromptService mPromptService;
     private TextSelection mTextSelection;
 
     protected DoorHangerPopup mDoorHangerPopup;
     protected FormAssistPopup mFormAssistPopup;
     protected ButtonToast mToast;
-    protected Snackbar mSnackbar;
 
     protected LayerView mLayerView;
     private AbsoluteLayout mPluginContainer;
 
     private FullScreenHolder mFullScreenPluginContainer;
     private View mFullScreenPluginView;
 
     private final HashMap<String, PowerManager.WakeLock> mWakeLocks = new HashMap<String, PowerManager.WakeLock>();
@@ -574,17 +569,17 @@ public abstract class GeckoApp
             ThreadUtils.postToBackgroundThread(new Runnable() {
                 @Override
                 public void run() {
                     final boolean bookmarkAdded = db.addBookmark(getContentResolver(), title, url);
                     final int resId = bookmarkAdded ? R.string.bookmark_added : R.string.bookmark_already_added;
                     ThreadUtils.postToUiThread(new Runnable() {
                         @Override
                         public void run() {
-                            showSnackbar(getString(resId), Snackbar.LENGTH_SHORT, null, null);
+                            SnackbarHelper.showSnackbar(GeckoApp.this, getString(resId), Snackbar.LENGTH_SHORT);
                         }
                     });
                 }
             });
 
         } else if ("Contact:Add".equals(event)) {
             final String email = message.optString("email", null);
             final String phone = message.optString("phone", null);
@@ -651,22 +646,22 @@ public abstract class GeckoApp
             Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST, "text");
 
         } else if ("Snackbar:Show".equals(event)) {
             final String msg = message.getString("message");
             final int duration = message.getInt("duration");
 
             NativeJSObject action = message.optObject("action", null);
 
-            final SnackbarEventCallback snackbarCallback = new SnackbarEventCallback(callback);
-
-            showSnackbar(msg,
+            SnackbarHelper.showSnackbarWithAction(this,
+                    msg,
                     duration,
                     action != null ? action.optString("label", null) : null,
-                    snackbarCallback);
+                    new SnackbarHelper.SnackbarEventCallback(callback)
+            );
         } else if ("SystemUI:Visibility".equals(event)) {
             setSystemUiVisible(message.getBoolean("visible"));
 
         } else if ("ToggleChrome:Focus".equals(event)) {
             focusChrome();
 
         } else if ("ToggleChrome:Hide".equals(event)) {
             toggleChrome(false);
@@ -839,68 +834,16 @@ public abstract class GeckoApp
         }
 
         ViewStub toastStub = (ViewStub) findViewById(R.id.toast_stub);
         mToast = new ButtonToast(toastStub.inflate());
 
         return mToast;
     }
 
-    void showSnackbar(final String message, final int duration, @Nullable final String action,
-                      final @Nullable SnackbarCallback callback) {
-        final Snackbar snackbar = Snackbar.make(mRootLayout, message, duration);
-
-        if (callback != null && !TextUtils.isEmpty(action)) {
-            snackbar.setAction(action, callback);
-            snackbar.setActionTextColor(ContextCompat.getColor(this, R.color.fennec_ui_orange));
-            snackbar.setCallback(callback);
-        }
-
-        snackbar.show();
-
-        this.mSnackbar = snackbar;
-    }
-
-    /**
-     * 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.
-     */
-    private 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;
-        }
-
-        @Override
-        public synchronized void onDismissed(Snackbar snackbar, int event) {
-            if (callback == null || event == Snackbar.Callback.DISMISS_EVENT_ACTION) {
-                return;
-            }
-
-            callback.sendError(null);
-            callback = null;
-        }
-    }
-
     void showButtonToast(final String message, final String duration,
                          final String buttonText, final String buttonIcon,
                          final String buttonId) {
         BitmapUtils.getDrawable(GeckoApp.this, buttonIcon, new BitmapUtils.BitmapLoader() {
             @Override
             public void onBitmapFound(final Drawable d) {
                 final int toastDuration = duration.equals("long") ? ButtonToast.LENGTH_LONG : ButtonToast.LENGTH_SHORT;
                 getButtonToast().show(false, message, toastDuration ,buttonText, d, new ButtonToast.ToastListener() {
@@ -1056,39 +999,39 @@ public abstract class GeckoApp
                 byte[] imgBuffer = os.toByteArray();
                 image = BitmapUtils.decodeByteArray(imgBuffer);
             }
             if (image != null) {
                 // Some devices don't have a DCIM folder and the Media.insertImage call will fail.
                 File dcimDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
 
                 if (!dcimDir.mkdirs() && !dcimDir.isDirectory()) {
-                    showSnackbar(getString(R.string.set_image_path_fail), Snackbar.LENGTH_SHORT, null, null);
+                    SnackbarHelper.showSnackbar(this, getString(R.string.set_image_path_fail), Snackbar.LENGTH_SHORT);
                     return;
                 }
                 String path = Media.insertImage(getContentResolver(),image, null, null);
                 if (path == null) {
-                    showSnackbar(getString(R.string.set_image_path_fail), Snackbar.LENGTH_SHORT, null, null);
+                    SnackbarHelper.showSnackbar(this, getString(R.string.set_image_path_fail), Snackbar.LENGTH_SHORT);
                     return;
                 }
                 final Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
                 intent.addCategory(Intent.CATEGORY_DEFAULT);
                 intent.setData(Uri.parse(path));
 
                 // Removes the image from storage once the chooser activity ends.
                 Intent chooser = Intent.createChooser(intent, getString(R.string.set_image_chooser_title));
                 ActivityResultHandler handler = new ActivityResultHandler() {
                     @Override
                     public void onActivityResult (int resultCode, Intent data) {
                         getContentResolver().delete(intent.getData(), null, null);
                     }
                 };
                 ActivityHandlerHelper.startIntentForActivity(this, chooser, handler);
             } else {
-                showSnackbar(getString(R.string.set_image_fail), Snackbar.LENGTH_SHORT, null, null);
+                SnackbarHelper.showSnackbar(this, getString(R.string.set_image_fail), Snackbar.LENGTH_SHORT);
             }
         } catch(OutOfMemoryError ome) {
             Log.e(LOGTAG, "Out of Memory when converting to byte array", ome);
         } catch(IOException ioe) {
             Log.e(LOGTAG, "I/O Exception while setting wallpaper", ioe);
         } finally {
             if (is != null) {
                 try {
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java
@@ -2668,18 +2668,20 @@ public class GeckoAppShell
             // If something went wrong, we'll just leave the intent un-changed
         } finally {
             IOUtils.safeStreamClose(os);
         }
     }
 
     // Don't fail silently, tell the user that we weren't able to share the image
     private static final void showImageShareFailureSnackbar() {
-        View rootView = ((Activity)getContext()).findViewById(android.R.id.content);
-        Snackbar.make(rootView, R.string.share_image_failed, Snackbar.LENGTH_SHORT).show();
+        SnackbarHelper.showSnackbar((Activity) getContext(),
+                getApplicationContext().getString(R.string.share_image_failed),
+                Snackbar.LENGTH_SHORT
+        );
     }
 
     @WrapForJNI(allowMultithread = true)
     static InputStream createInputStream(URLConnection connection) throws IOException {
         return connection.getInputStream();
     }
 
     private static class BitmapConnection extends URLConnection {
--- a/mobile/android/base/java/org/mozilla/gecko/home/HomeFragment.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/HomeFragment.java
@@ -10,16 +10,17 @@ import java.util.EnumSet;
 import android.os.AsyncTask;
 import org.mozilla.gecko.EditBookmarkDialog;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.GeckoProfile;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.ReaderModeUtils;
 import org.mozilla.gecko.Restrictions;
+import org.mozilla.gecko.SnackbarHelper;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.db.BrowserContract.SuggestedSites;
 import org.mozilla.gecko.favicons.Favicons;
 import org.mozilla.gecko.home.HomeContextMenuInfo.RemoveItemType;
 import org.mozilla.gecko.home.HomePager.OnUrlOpenInBackgroundListener;
 import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
@@ -408,13 +409,14 @@ public abstract class HomeFragment exten
                     Log.e(LOGTAG, "Can't remove item type " + mType.toString());
                     break;
             }
             return null;
         }
 
         @Override
         public void onPostExecute(Void result) {
-            View rootView = ((Activity)mContext).findViewById(android.R.id.content);
-            Snackbar.make(rootView, R.string.page_removed, Snackbar.LENGTH_SHORT).show();
+            SnackbarHelper.showSnackbar((Activity) mContext,
+                    mContext.getString(R.string.page_removed),
+                    Snackbar.LENGTH_SHORT);
         }
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
+++ b/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
@@ -20,28 +20,30 @@ import org.mozilla.gecko.GeckoApplicatio
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.GeckoProfile;
 import org.mozilla.gecko.GeckoSharedPrefs;
 import org.mozilla.gecko.LocaleManager;
 import org.mozilla.gecko.Locales;
 import org.mozilla.gecko.PrefsHelper;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Restrictions;
+import org.mozilla.gecko.SnackbarHelper;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.TelemetryContract.Method;
 import org.mozilla.gecko.background.common.GlobalConstants;
 import org.mozilla.gecko.db.BrowserContract.SuggestedSites;
 import org.mozilla.gecko.restrictions.Restrictable;
 import org.mozilla.gecko.tabqueue.TabQueueHelper;
 import org.mozilla.gecko.updater.UpdateService;
 import org.mozilla.gecko.updater.UpdateServiceHelper;
 import org.mozilla.gecko.util.GeckoEventListener;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.InputOptionsUtils;
+import org.mozilla.gecko.util.NativeEventListener;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.widget.FloatingHintEditText;
 
 import android.app.ActionBar;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.Fragment;
 import android.app.FragmentManager;
@@ -612,23 +614,20 @@ OnSharedPreferenceChangeListener
     }
 
     @Override
     public void handleMessage(String event, JSONObject message) {
         try {
             if (event.equals("Sanitize:Finished")) {
                 boolean success = message.getBoolean("success");
                 final int stringRes = success ? R.string.private_data_success : R.string.private_data_fail;
-                final Context context = this;
-                ThreadUtils.postToUiThread(new Runnable () {
-                    @Override
-                    public void run() {
-                        Snackbar.make(findViewById(android.R.id.content), stringRes, Snackbar.LENGTH_SHORT).show();
-                    }
-                });
+
+                SnackbarHelper.showSnackbar(GeckoPreferences.this,
+                        getString(stringRes),
+                        Snackbar.LENGTH_SHORT);
             }
         } catch (Exception e) {
             Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
         }
     }
 
     /**
       * Initialize all of the preferences (native of Gecko ones) for this screen.
--- a/mobile/android/base/java/org/mozilla/gecko/preferences/SearchEnginePreference.java
+++ b/mobile/android/base/java/org/mozilla/gecko/preferences/SearchEnginePreference.java
@@ -2,16 +2,17 @@
  * 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.preferences;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.R;
+import org.mozilla.gecko.SnackbarHelper;
 import org.mozilla.gecko.favicons.Favicons;
 import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
 import org.mozilla.gecko.favicons.decoders.FaviconDecoder;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.widget.FaviconView;
 
 import android.app.Activity;
 import android.app.AlertDialog;
@@ -84,23 +85,22 @@ public class SearchEnginePreference exte
                               LABEL_REMOVE };
     }
 
     @Override
     public void showDialog() {
         // If this is the last engine, then we are the default, and none of the options
         // on this menu can do anything.
         if (mParentCategory.getPreferenceCount() == 1) {
-            ThreadUtils.postToUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    Activity activity = (Activity)getContext();
-                    Snackbar.make(activity.findViewById(android.R.id.content), R.string.pref_search_last_toast, Snackbar.LENGTH_SHORT).show();
-                }
-            });
+            Activity activity = (Activity) getContext();
+
+            SnackbarHelper.showSnackbar(activity,
+                    activity.getString(R.string.pref_search_last_toast),
+                    Snackbar.LENGTH_SHORT);
+
             return;
         }
 
         super.showDialog();
     }
 
     @Override
     protected void configureDialogBuilder(AlertDialog.Builder builder) {