--- 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) {