import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,237 @@
/* -*- 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.delegates;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.AboutPages;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.EditBookmarkDialog;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.R;
import org.mozilla.gecko.SnackbarBuilder;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.home.HomeConfig;
import org.mozilla.gecko.promotion.SimpleHelperUI;
import org.mozilla.gecko.prompts.Prompt;
import org.mozilla.gecko.prompts.PromptListItem;
import org.mozilla.gecko.util.DrawableUtil;
import org.mozilla.gecko.util.ThreadUtils;
import java.lang.ref.WeakReference;
/**
* Delegate to watch for bookmark state changes.
*
* This is responsible for showing snackbars and helper UIs related to the addition/removal
* of bookmarks, or reader view bookmarks.
*/
public class BookmarkStateChangeDelegate extends BrowserAppDelegateWithReference implements Tabs.OnTabsChangedListener {
private static final String LOGTAG = "BookmarkDelegate";
@Override
public void onResume(BrowserApp browserApp) {
Tabs.registerOnTabsChangedListener(this);
}
@Override
public void onPause(BrowserApp browserApp) {
Tabs.unregisterOnTabsChangedListener(this);
}
@Override
public void onTabChanged(Tab tab, Tabs.TabEvents msg, String data) {
switch (msg) {
case BOOKMARK_ADDED:
// We always show the special offline snackbar whenever we bookmark a reader page.
// It's possible that the page is already stored offline, however this is highly
// unlikely, and even so it is probably nicer to show the same offline notification
// every time we bookmark an about:reader page.
if (!AboutPages.isAboutReader(tab.getURL())) {
showBookmarkAddedSnackbar();
} else {
if (!promoteReaderViewBookmarkAdded()) {
showReaderModeBookmarkAddedSnackbar();
}
}
break;
case BOOKMARK_REMOVED:
showBookmarkRemovedSnackbar();
break;
}
}
@Override
public void onActivityResult(BrowserApp browserApp, int requestCode, int resultCode, Intent data) {
if (requestCode == BrowserApp.ACTIVITY_REQUEST_FIRST_READERVIEW_BOOKMARK) {
if (resultCode == BrowserApp.ACTIVITY_RESULT_FIRST_READERVIEW_BOOKMARKS_GOTO_BOOKMARKS) {
browserApp.openUrlAndStopEditing("about:home?panel=" + HomeConfig.getIdForBuiltinPanelType(HomeConfig.PanelType.BOOKMARKS));
} else if (resultCode == BrowserApp.ACTIVITY_RESULT_FIRST_READERVIEW_BOOKMARKS_IGNORE) {
showReaderModeBookmarkAddedSnackbar();
}
}
}
private boolean promoteReaderViewBookmarkAdded() {
final BrowserApp browserApp = getBrowserApp();
if (browserApp == null) {
return false;
}
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(browserApp);
final boolean hasFirstReaderViewPromptBeenShownBefore = prefs.getBoolean(SimpleHelperUI.PREF_FIRST_RVBP_SHOWN, false);
if (hasFirstReaderViewPromptBeenShownBefore) {
return false;
}
SimpleHelperUI.show(browserApp,
SimpleHelperUI.FIRST_RVBP_SHOWN_TELEMETRYEXTRA,
BrowserApp.ACTIVITY_REQUEST_FIRST_READERVIEW_BOOKMARK,
R.string.helper_first_offline_bookmark_title, R.string.helper_first_offline_bookmark_message,
R.drawable.helper_readerview_bookmark, R.string.helper_first_offline_bookmark_button,
BrowserApp.ACTIVITY_RESULT_FIRST_READERVIEW_BOOKMARKS_GOTO_BOOKMARKS,
BrowserApp.ACTIVITY_RESULT_FIRST_READERVIEW_BOOKMARKS_IGNORE);
GeckoSharedPrefs.forProfile(browserApp)
.edit()
.putBoolean(SimpleHelperUI.PREF_FIRST_RVBP_SHOWN, true)
.apply();
return true;
}
private void showBookmarkAddedSnackbar() {
final BrowserApp browserApp = getBrowserApp();
if (browserApp == null) {
return;
}
// 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 SnackbarBuilder.SnackbarCallback callback = new SnackbarBuilder.SnackbarCallback() {
@Override
public void onClick(View v) {
Telemetry.sendUIEvent(TelemetryContract.Event.SHOW, TelemetryContract.Method.TOAST, "bookmark_options");
showBookmarkDialog(browserApp);
}
};
SnackbarBuilder.builder(browserApp)
.message(R.string.bookmark_added)
.duration(Snackbar.LENGTH_LONG)
.action(R.string.bookmark_options)
.callback(callback)
.buildAndShow();
}
private void showBookmarkRemovedSnackbar() {
final BrowserApp browserApp = getBrowserApp();
if (browserApp == null) {
return;
}
SnackbarBuilder.builder(browserApp)
.message(R.string.bookmark_removed)
.duration(Snackbar.LENGTH_LONG)
.buildAndShow();
}
private static void showBookmarkDialog(final BrowserApp browserApp) {
final Resources res = browserApp.getResources();
final Tab tab = Tabs.getInstance().getSelectedTab();
final Prompt ps = new Prompt(browserApp, new Prompt.PromptCallback() {
@Override
public void onPromptFinished(String result) {
int itemId = -1;
try {
itemId = new JSONObject(result).getInt("button");
} catch (JSONException ex) {
Log.e(LOGTAG, "Exception reading bookmark prompt result", ex);
}
if (tab == null) {
return;
}
if (itemId == 0) {
final String extrasId = res.getResourceEntryName(R.string.contextmenu_edit_bookmark);
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION,
TelemetryContract.Method.DIALOG, extrasId);
new EditBookmarkDialog(browserApp).show(tab.getURL());
} else if (itemId == 1) {
final String extrasId = res.getResourceEntryName(R.string.contextmenu_add_to_launcher);
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION,
TelemetryContract.Method.DIALOG, extrasId);
final String url = tab.getURL();
final String title = tab.getDisplayTitle();
if (url != null && title != null) {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
GeckoAppShell.createShortcut(title, url);
}
});
}
}
}
});
final PromptListItem[] items = new PromptListItem[2];
items[0] = new PromptListItem(res.getString(R.string.contextmenu_edit_bookmark));
items[1] = new PromptListItem(res.getString(R.string.contextmenu_add_to_launcher));
ps.show("", "", items, ListView.CHOICE_MODE_NONE);
}
private void showReaderModeBookmarkAddedSnackbar() {
final BrowserApp browserApp = getBrowserApp();
if (browserApp == null) {
return;
}
final Drawable iconDownloaded = DrawableUtil.tintDrawable(browserApp, R.drawable.status_icon_readercache, Color.WHITE);
final SnackbarBuilder.SnackbarCallback callback = new SnackbarBuilder.SnackbarCallback() {
@Override
public void onClick(View v) {
browserApp.openUrlAndStopEditing("about:home?panel=" + HomeConfig.getIdForBuiltinPanelType(HomeConfig.PanelType.BOOKMARKS));
}
};
SnackbarBuilder.builder(browserApp)
.message(R.string.reader_saved_offline)
.duration(Snackbar.LENGTH_LONG)
.action(R.string.reader_switch_to_bookmarks)
.callback(callback)
.icon(iconDownloaded)
.backgroundColor(ContextCompat.getColor(browserApp, R.color.link_blue))
.actionColor(Color.WHITE)
.buildAndShow();
}
}

View file

@ -0,0 +1,78 @@
/* -*- 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.delegates;
import android.content.Intent;
import android.os.Bundle;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.mozglue.SafeIntent;
import org.mozilla.gecko.tabs.TabsPanel;
/**
* Abstract class for extending the behavior of BrowserApp without adding additional code to the
* already huge class.
*/
public abstract class BrowserAppDelegate {
/**
* Called when the BrowserApp activity is first created.
*/
public void onCreate(BrowserApp browserApp, Bundle savedInstanceState) {}
/**
* Called after the BrowserApp activity has been stopped, prior to it being started again.
*/
public void onRestart(BrowserApp browserApp) {}
/**
* Called when the BrowserApp activity is becoming visible to the user.
*/
public void onStart(BrowserApp browserApp) {}
/**
* Called when the BrowserApp activity will start interacting with the user.
*/
public void onResume(BrowserApp browserApp) {}
/**
* Called when the system is about to start resuming a previous activity.
*/
public void onPause(BrowserApp browserApp) {}
/**
* Called when BrowserApp activity is no longer visible to the user.
*/
public void onStop(BrowserApp browserApp) {}
/**
* The final call before the BrowserApp activity is destroyed.
*/
public void onDestroy(BrowserApp browserApp) {}
/**
* Called when BrowserApp already exists and a new Intent to re-launch it was fired.
*/
public void onNewIntent(BrowserApp browserApp, SafeIntent intent) {}
/**
* Called when the tabs tray is opened.
*/
public void onTabsTrayShown(BrowserApp browserApp, TabsPanel tabsPanel) {}
/**
* Called when the tabs tray is closed.
*/
public void onTabsTrayHidden(BrowserApp browserApp, TabsPanel tabsPanel) {}
/**
* Called when an activity started using startActivityForResult() returns.
*
* Delegates should only use request and result codes declared in BrowserApp itself (as opposed
* to declarations in the delegate), in order to avoid conflicts.
*/
public void onActivityResult(BrowserApp browserApp, int requestCode, int resultCode, Intent data) {}
}

View file

@ -0,0 +1,29 @@
package org.mozilla.gecko.delegates;
import android.os.Bundle;
import android.support.annotation.CallSuper;
import org.mozilla.gecko.BrowserApp;
import java.lang.ref.WeakReference;
/**
* BrowserAppDelegate that stores a reference to the parent BrowserApp.
*/
public abstract class BrowserAppDelegateWithReference extends BrowserAppDelegate {
private WeakReference<BrowserApp> browserApp;
@Override
@CallSuper
public void onCreate(BrowserApp browserApp, Bundle savedInstanceState) {
this.browserApp = new WeakReference<>(browserApp);
}
/**
* Obtain the referenced BrowserApp. May return <code>null</code> if the BrowserApp no longer
* exists.
*/
protected BrowserApp getBrowserApp() {
return browserApp.get();
}
}

View file

@ -0,0 +1,119 @@
/* -*- 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.delegates;
import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.CallSuper;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import org.mozilla.gecko.AboutPages;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.R;
import org.mozilla.gecko.SnackbarBuilder;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.WeakHashMap;
/**
* Displays "Showing offline version" message when tabs are loaded from cache while offline.
*/
public class OfflineTabStatusDelegate extends TabsTrayVisibilityAwareDelegate implements Tabs.OnTabsChangedListener {
private WeakReference<Activity> activityReference;
private WeakHashMap<Tab, Void> tabsQueuedForOfflineSnackbar = new WeakHashMap<>();
@CallSuper
@Override
public void onCreate(BrowserApp browserApp, Bundle savedInstanceState) {
super.onCreate(browserApp, savedInstanceState);
activityReference = new WeakReference<Activity>(browserApp);
}
@Override
public void onResume(BrowserApp browserApp) {
Tabs.registerOnTabsChangedListener(this);
}
@Override
public void onPause(BrowserApp browserApp) {
Tabs.unregisterOnTabsChangedListener(this);
}
public void onTabChanged(final Tab tab, Tabs.TabEvents event, String data) {
if (tab == null) {
return;
}
// Ignore tabs loaded regularly.
if (!tab.hasLoadedFromCache()) {
return;
}
// Ignore tabs displaying about pages
if (AboutPages.isAboutPage(tab.getURL())) {
return;
}
// We only want to show these notifications for tabs that were loaded successfully.
if (tab.getState() != Tab.STATE_SUCCESS) {
return;
}
switch (event) {
// We listen specifically for the STOP event (as opposed to PAGE_SHOW), because we need
// to know if page load actually succeeded. When STOP is triggered, tab.getState()
// will return definitive STATE_SUCCESS or STATE_ERROR. When PAGE_SHOW is triggered,
// tab.getState() will return STATE_LOADING, which is ambiguous for our purposes.
// We don't want to show these notifications for 404 pages, for example. See Bug 1304914.
case STOP:
// Show offline notification if tab is visible, or queue it for display later.
if (!isTabsTrayVisible() && Tabs.getInstance().isSelectedTab(tab)) {
showLoadedOfflineSnackbar(activityReference.get());
} else {
tabsQueuedForOfflineSnackbar.put(tab, null);
}
break;
// Fallthrough; see Bug 1278980 for details on why this event is here.
case OPENED_FROM_TABS_TRAY:
// When tab is selected and offline notification was queued, display it if possible.
// SELECTED event might also fire when we're on a TabStrip, so check first.
case SELECTED:
if (isTabsTrayVisible()) {
break;
}
if (tabsQueuedForOfflineSnackbar.containsKey(tab)) {
showLoadedOfflineSnackbar(activityReference.get());
tabsQueuedForOfflineSnackbar.remove(tab);
}
break;
}
}
/**
* Displays the notification snackbar and logs a telemetry event.
*
* @param activity which will be used for displaying the snackbar.
*/
private static void showLoadedOfflineSnackbar(final Activity activity) {
if (activity == null) {
return;
}
Telemetry.sendUIEvent(TelemetryContract.Event.NETERROR, TelemetryContract.Method.TOAST, "usecache");
SnackbarBuilder.builder(activity)
.message(R.string.tab_offline_version)
.duration(Snackbar.LENGTH_INDEFINITE)
.backgroundColor(ContextCompat.getColor(activity, R.color.link_blue))
.buildAndShow();
}
}

View file

@ -0,0 +1,80 @@
/* -*- 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.delegates;
import android.app.Activity;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.util.Log;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.R;
import org.mozilla.gecko.ScreenshotObserver;
import org.mozilla.gecko.SnackbarBuilder;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.db.BrowserDB;
import java.lang.ref.WeakReference;
/**
* Delegate for observing screenshots being taken.
*/
public class ScreenshotDelegate extends BrowserAppDelegateWithReference implements ScreenshotObserver.OnScreenshotListener {
private static final String LOGTAG = "GeckoScreenshotDelegate";
private final ScreenshotObserver mScreenshotObserver = new ScreenshotObserver();
@Override
public void onCreate(BrowserApp browserApp, Bundle savedInstanceState) {
super.onCreate(browserApp, savedInstanceState);
mScreenshotObserver.setListener(browserApp, this);
}
@Override
public void onScreenshotTaken(String screenshotPath, String title) {
// Treat screenshots as a sharing method.
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.BUTTON, "screenshot");
if (!AppConstants.SCREENSHOTS_IN_BOOKMARKS_ENABLED) {
return;
}
final Tab selectedTab = Tabs.getInstance().getSelectedTab();
if (selectedTab == null) {
Log.w(LOGTAG, "Selected tab is null: could not page info to store screenshot.");
return;
}
final Activity activity = getBrowserApp();
if (activity == null) {
return;
}
BrowserDB.from(activity).getUrlAnnotations().insertScreenshot(
activity.getContentResolver(), selectedTab.getURL(), screenshotPath);
SnackbarBuilder.builder(activity)
.message(R.string.screenshot_added_to_bookmarks)
.duration(Snackbar.LENGTH_SHORT)
.buildAndShow();
}
@Override
public void onResume(BrowserApp browserApp) {
mScreenshotObserver.start();
}
@Override
public void onPause(BrowserApp browserApp) {
mScreenshotObserver.stop();
}
}

View file

@ -0,0 +1,38 @@
/* -*- 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.delegates;
import android.os.Bundle;
import android.support.annotation.CallSuper;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.tabs.TabsPanel;
public abstract class TabsTrayVisibilityAwareDelegate extends BrowserAppDelegate {
private boolean tabsTrayVisible;
@Override
@CallSuper
public void onCreate(BrowserApp browserApp, Bundle savedInstanceState) {
tabsTrayVisible = false;
}
@Override
@CallSuper
public void onTabsTrayShown(BrowserApp browserApp, TabsPanel tabsPanel) {
tabsTrayVisible = true;
}
@Override
@CallSuper
public void onTabsTrayHidden(BrowserApp browserApp, TabsPanel tabsPanel) {
tabsTrayVisible = false;
}
protected boolean isTabsTrayVisible() {
return tabsTrayVisible;
}
}