зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1277467 - Add OfflineTabStatusDelegate for displaying tab-is-offline notifiations when appropriate r=sebastian
- Use Content:PageShow event to inform Tabs that they were actively loaded from cache - Move offline notification logic away from browser.js and into a delegate, which displays notifications when tab in question is user-visible MozReview-Commit-ID: 2qCACHyWOlp --HG-- extra : rebase_source : 457a42ebba5cfc32ab7dabce0a8a11d6511b9c08
This commit is contained in:
Родитель
c09864a3eb
Коммит
26648ad110
|
@ -24,6 +24,7 @@ import org.mozilla.gecko.db.BrowserContract;
|
|||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.db.SuggestedSites;
|
||||
import org.mozilla.gecko.delegates.BrowserAppDelegate;
|
||||
import org.mozilla.gecko.delegates.OfflineTabStatusDelegate;
|
||||
import org.mozilla.gecko.delegates.ScreenshotDelegate;
|
||||
import org.mozilla.gecko.distribution.Distribution;
|
||||
import org.mozilla.gecko.distribution.DistributionStoreCallback;
|
||||
|
@ -312,7 +313,8 @@ public class BrowserApp extends GeckoApp
|
|||
(BrowserAppDelegate) new ReaderViewBookmarkPromotion(),
|
||||
(BrowserAppDelegate) new ContentNotificationsDelegate(),
|
||||
(BrowserAppDelegate) new PostUpdateHandler(),
|
||||
new TelemetryCorePingDelegate()
|
||||
new TelemetryCorePingDelegate(),
|
||||
new OfflineTabStatusDelegate()
|
||||
));
|
||||
|
||||
@NonNull
|
||||
|
|
|
@ -104,6 +104,9 @@ public class Tab {
|
|||
private boolean mIsEditing;
|
||||
private final TabEditingState mEditingState = new TabEditingState();
|
||||
|
||||
// Will be true when tab is loaded from cache while device was offline.
|
||||
private boolean mLoadedFromCache;
|
||||
|
||||
public static final int STATE_DELAYED = 0;
|
||||
public static final int STATE_LOADING = 1;
|
||||
public static final int STATE_SUCCESS = 2;
|
||||
|
@ -301,6 +304,10 @@ public class Tab {
|
|||
return mHasOpenSearch;
|
||||
}
|
||||
|
||||
public boolean hasLoadedFromCache() {
|
||||
return mLoadedFromCache;
|
||||
}
|
||||
|
||||
public SiteIdentity getSiteIdentity() {
|
||||
return mSiteIdentity;
|
||||
}
|
||||
|
@ -536,6 +543,10 @@ public class Tab {
|
|||
mHasOpenSearch = hasOpenSearch;
|
||||
}
|
||||
|
||||
public void setLoadedFromCache(boolean loadedFromCache) {
|
||||
mLoadedFromCache = loadedFromCache;
|
||||
}
|
||||
|
||||
public void updateIdentityData(JSONObject identityData) {
|
||||
mSiteIdentity.update(identityData);
|
||||
}
|
||||
|
|
|
@ -105,6 +105,7 @@ public class Tabs implements GeckoEventListener {
|
|||
"Tab:Added",
|
||||
"Tab:Close",
|
||||
"Tab:Select",
|
||||
"Tab:LoadedFromCache",
|
||||
"Content:LocationChange",
|
||||
"Content:SecurityChange",
|
||||
"Content:StateChange",
|
||||
|
@ -505,8 +506,9 @@ public class Tabs implements GeckoEventListener {
|
|||
tab.handleContentLoaded();
|
||||
notifyListeners(tab, Tabs.TabEvents.LOAD_ERROR);
|
||||
} else if (event.equals("Content:PageShow")) {
|
||||
notifyListeners(tab, TabEvents.PAGE_SHOW);
|
||||
tab.setLoadedFromCache(message.getBoolean("fromCache"));
|
||||
tab.updateUserRequested(message.getString("userRequested"));
|
||||
notifyListeners(tab, TabEvents.PAGE_SHOW);
|
||||
} else if (event.equals("DOMContentLoaded")) {
|
||||
tab.handleContentLoaded();
|
||||
String backgroundColor = message.getString("bgColor");
|
||||
|
|
|
@ -104,6 +104,9 @@ public interface TelemetryContract {
|
|||
// Stop holding a resource (reader, bookmark, etc) for viewing later.
|
||||
UNSAVE("unsave.1"),
|
||||
|
||||
// When the user performs actions on the in-content network error page.
|
||||
NETERROR("neterror.1"),
|
||||
|
||||
// VALUES BELOW THIS LINE ARE EXCLUSIVE TO TESTING.
|
||||
_TEST1("_test_event_1.1"),
|
||||
_TEST2("_test_event_2.1"),
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/* -*- 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.SnackbarHelper;
|
||||
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;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
// Show offline notification if tab is visible, or queue it for display later.
|
||||
case PAGE_SHOW:
|
||||
if (!isTabsTrayVisible() && Tabs.getInstance().isSelectedTab(tab)) {
|
||||
showLoadedOfflineSnackbar(activityReference.get());
|
||||
} else {
|
||||
tabsQueuedForOfflineSnackbar.put(tab, null);
|
||||
}
|
||||
break;
|
||||
// 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");
|
||||
|
||||
SnackbarHelper.showSnackbarWithActionAndColors(
|
||||
activity,
|
||||
activity.getResources().getString(R.string.tab_offline_version),
|
||||
Snackbar.LENGTH_INDEFINITE,
|
||||
null, null, null,
|
||||
ContextCompat.getColor(activity, R.color.link_blue),
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import android.app.Activity;
|
|||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.CallSuper;
|
||||
import android.util.Log;
|
||||
|
||||
import com.keepsafe.switchboard.SwitchBoard;
|
||||
|
@ -23,7 +24,7 @@ import org.mozilla.gecko.Tabs;
|
|||
import org.mozilla.gecko.db.BrowserContract;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.db.UrlAnnotations;
|
||||
import org.mozilla.gecko.delegates.ForegroundAwareDelegate;
|
||||
import org.mozilla.gecko.delegates.TabsTrayVisibilityAwareDelegate;
|
||||
import org.mozilla.gecko.util.Experiments;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
|
@ -34,7 +35,7 @@ import ch.boye.httpclientandroidlib.util.TextUtils;
|
|||
/**
|
||||
* Promote "Add to home screen" if user visits website often.
|
||||
*/
|
||||
public class AddToHomeScreenPromotion extends ForegroundAwareDelegate implements Tabs.OnTabsChangedListener {
|
||||
public class AddToHomeScreenPromotion extends TabsTrayVisibilityAwareDelegate implements Tabs.OnTabsChangedListener {
|
||||
private static class URLHistory {
|
||||
public final long visits;
|
||||
public final long lastVisit;
|
||||
|
@ -57,6 +58,7 @@ public class AddToHomeScreenPromotion extends ForegroundAwareDelegate implements
|
|||
private int lastVisitMinimumAgeMs;
|
||||
private int lastVisitMaximumAgeMs;
|
||||
|
||||
@CallSuper
|
||||
@Override
|
||||
public void onCreate(BrowserApp browserApp, Bundle savedInstanceState) {
|
||||
super.onCreate(browserApp, savedInstanceState);
|
||||
|
@ -127,7 +129,7 @@ public class AddToHomeScreenPromotion extends ForegroundAwareDelegate implements
|
|||
return;
|
||||
}
|
||||
|
||||
if (!isInForeground) {
|
||||
if (isTabsTrayVisible()) {
|
||||
// We only want to show this prompt if this tab is in the foreground and not on top
|
||||
// of the tabs tray.
|
||||
return;
|
||||
|
|
|
@ -47,6 +47,9 @@
|
|||
|
||||
<!ENTITY switch_to_tab "Switch to tab">
|
||||
|
||||
<!-- Localization note: Shown in a snackbar when tab is loaded from cache while device was offline. -->
|
||||
<!ENTITY tab_offline_version "Showing offline version">
|
||||
|
||||
<!ENTITY crash_reporter_title "&brandShortName; Crash Reporter">
|
||||
<!ENTITY crash_message2 "&brandShortName; had a problem and crashed. Your tabs should be listed on the &brandShortName; Start page when you restart.">
|
||||
<!ENTITY crash_send_report_message3 "Tell &vendorShortName; about this crash so they can fix it">
|
||||
|
|
|
@ -262,6 +262,7 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
|
|||
'delegates/BookmarkStateChangeDelegate.java',
|
||||
'delegates/BrowserAppDelegate.java',
|
||||
'delegates/BrowserAppDelegateWithReference.java',
|
||||
'delegates/OfflineTabStatusDelegate.java',
|
||||
'delegates/ScreenshotDelegate.java',
|
||||
'delegates/TabsTrayVisibilityAwareDelegate.java',
|
||||
'DevToolsAuthHelper.java',
|
||||
|
|
|
@ -68,6 +68,8 @@
|
|||
|
||||
<string name="switch_to_tab">&switch_to_tab;</string>
|
||||
|
||||
<string name="tab_offline_version">&tab_offline_version;</string>
|
||||
|
||||
<string name="crash_reporter_title">&crash_reporter_title;</string>
|
||||
<string name="crash_message2">&crash_message2;</string>
|
||||
<string name="crash_send_report_message3">&crash_send_report_message3;</string>
|
||||
|
|
|
@ -4297,7 +4297,8 @@ Tab.prototype = {
|
|||
Messaging.sendRequest({
|
||||
type: "Content:PageShow",
|
||||
tabID: this.id,
|
||||
userRequested: this.userRequested
|
||||
userRequested: this.userRequested,
|
||||
fromCache: Tabs.useCache
|
||||
});
|
||||
|
||||
this.isSearch = false;
|
||||
|
@ -7377,25 +7378,6 @@ var Tabs = {
|
|||
// Clear the domain cache whenever a page is loaded into any browser.
|
||||
this._domains.clear();
|
||||
|
||||
// Notify if we are loading a page from cache.
|
||||
if (this._useCache) {
|
||||
let targetDoc = aEvent.originalTarget;
|
||||
let isTopLevel = (targetDoc.defaultView.parent === targetDoc.defaultView);
|
||||
|
||||
// Ignore any about: pages, especially about:neterror since it means we failed to find the page in cache.
|
||||
let targetURI = targetDoc.documentURI;
|
||||
if (isTopLevel && !targetURI.startsWith("about:")) {
|
||||
UITelemetry.addEvent("neterror.1", "toast", null, "usecache");
|
||||
Snackbars.show(
|
||||
Strings.browser.GetStringFromName("networkOffline.message2"),
|
||||
Snackbars.LENGTH_INDEFINITE,
|
||||
{
|
||||
// link_blue
|
||||
backgroundColor: "#0096DD"
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "TabOpen":
|
||||
// Use opening a new tab as a trigger to expire the most stale tab.
|
||||
|
|
|
@ -434,9 +434,6 @@ openInApp.pageAction = Open in App
|
|||
openInApp.ok = OK
|
||||
openInApp.cancel = Cancel
|
||||
|
||||
#Network Offline
|
||||
networkOffline.message2 = Showing offline version
|
||||
|
||||
#Tab sharing
|
||||
tabshare.title = "Choose a tab to stream"
|
||||
#Tabs in context menus
|
||||
|
|
Загрузка…
Ссылка в новой задаче