mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 11:55:49 +00:00
bug 869209 order provider entries by frecency, r=mak
This commit is contained in:
parent
b69ccc0a17
commit
86b86d8e0b
@ -152,7 +152,7 @@ this.Social = {
|
||||
this.initialized = true;
|
||||
|
||||
// Retrieve the current set of providers, and set the current provider.
|
||||
SocialService.getProviderList(function (providers) {
|
||||
SocialService.getOrderedProviderList(function (providers) {
|
||||
this._updateProviderCache(providers);
|
||||
}.bind(this));
|
||||
|
||||
|
@ -4247,6 +4247,7 @@ LIBJPEG_TURBO_ARM_ASM=
|
||||
MOZ_PANGO=1
|
||||
MOZ_PERMISSIONS=1
|
||||
MOZ_PLACES=1
|
||||
MOZ_SOCIAL=1
|
||||
MOZ_PREF_EXTENSIONS=1
|
||||
MOZ_PROFILELOCKING=1
|
||||
MOZ_PSM=1
|
||||
@ -8469,6 +8470,11 @@ if test "$MOZ_PLACES"; then
|
||||
AC_DEFINE(MOZ_PLACES)
|
||||
fi
|
||||
|
||||
dnl Build SocialAPI if required
|
||||
if test "$MOZ_SOCIAL"; then
|
||||
AC_DEFINE(MOZ_SOCIAL)
|
||||
fi
|
||||
|
||||
dnl Build Common JS modules provided by services.
|
||||
AC_SUBST(MOZ_SERVICES_COMMON)
|
||||
if test -n "$MOZ_SERVICES_COMMON"; then
|
||||
@ -8578,6 +8584,7 @@ AC_SUBST(MOZ_VTUNE)
|
||||
AC_SUBST(MOZ_PROFILING)
|
||||
AC_SUBST(LIBICONV)
|
||||
AC_SUBST(MOZ_PLACES)
|
||||
AC_SUBST(MOZ_SOCIAL)
|
||||
AC_SUBST(MOZ_TOOLKIT_SEARCH)
|
||||
AC_SUBST(MOZ_FEEDS)
|
||||
AC_SUBST(NS_PRINTING)
|
||||
|
@ -34,6 +34,7 @@ fi
|
||||
MOZ_CAPTURE=1
|
||||
MOZ_RAW=1
|
||||
MOZ_PLACES=
|
||||
MOZ_SOCIAL=
|
||||
MOZ_ANDROID_HISTORY=1
|
||||
|
||||
# Needed for building our components as part of libxul
|
||||
|
@ -33,7 +33,6 @@ PARALLEL_DIRS += [
|
||||
'prompts',
|
||||
'protobuf',
|
||||
'reflect',
|
||||
'social',
|
||||
'startup',
|
||||
'statusfilter',
|
||||
'telemetry',
|
||||
@ -44,6 +43,9 @@ PARALLEL_DIRS += [
|
||||
'viewsource',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_SOCIAL']:
|
||||
PARALLEL_DIRS += ['social']
|
||||
|
||||
if CONFIG['BUILD_CTYPES']:
|
||||
PARALLEL_DIRS += ['ctypes']
|
||||
|
||||
|
@ -9,6 +9,9 @@ VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
ifdef MOZ_SOCIAL
|
||||
# social is turned off for android
|
||||
|
||||
EXTRA_JS_MODULES = \
|
||||
FrameWorker.jsm \
|
||||
MessagePortBase.jsm \
|
||||
@ -18,4 +21,6 @@ EXTRA_JS_MODULES = \
|
||||
MozSocialAPI.jsm \
|
||||
$(NULL)
|
||||
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -9,6 +9,7 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/AddonManager.jsm");
|
||||
Cu.import("resource://gre/modules/PlacesUtils.jsm");
|
||||
|
||||
const URI_EXTENSION_STRINGS = "chrome://mozapps/locale/extensions/extensions.properties";
|
||||
const ADDON_TYPE_SERVICE = "service";
|
||||
@ -20,6 +21,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "WorkerAPI", "resource://gre/modules/Wor
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "MozSocialAPI", "resource://gre/modules/MozSocialAPI.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask", "resource://gre/modules/DeferredTask.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "etld",
|
||||
"@mozilla.org/network/effective-tld-service;1",
|
||||
"nsIEffectiveTLDService");
|
||||
|
||||
/**
|
||||
* The SocialService is the public API to social providers - it tracks which
|
||||
* providers are installed and enabled, and is the entry-point for access to
|
||||
@ -76,6 +81,59 @@ let SocialServiceInternal = {
|
||||
}
|
||||
let originUri = Services.io.newURI(origin, null, null);
|
||||
return originUri.hostPort.replace('.','-');
|
||||
},
|
||||
orderedProviders: function(aCallback) {
|
||||
if (SocialServiceInternal.providerArray.length < 2) {
|
||||
schedule(function () {
|
||||
aCallback(SocialServiceInternal.providerArray);
|
||||
});
|
||||
return;
|
||||
}
|
||||
// query moz_hosts for frecency. since some providers may not have a
|
||||
// frecency entry, we need to later sort on our own. We use the providers
|
||||
// object below as an easy way to later record the frecency on the provider
|
||||
// object from the query results.
|
||||
let hosts = [];
|
||||
let providers = {};
|
||||
|
||||
for (p of SocialServiceInternal.providerArray) {
|
||||
p.frecency = 0;
|
||||
providers[p.domain] = p;
|
||||
hosts.push(p.domain);
|
||||
};
|
||||
|
||||
// cannot bind an array to stmt.params so we have to build the string
|
||||
let stmt = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
|
||||
.DBConnection.createAsyncStatement(
|
||||
"SELECT host, frecency FROM moz_hosts WHERE host IN (" +
|
||||
[ '"' + host + '"' for each (host in hosts) ].join(",") + ") "
|
||||
);
|
||||
|
||||
try {
|
||||
stmt.executeAsync({
|
||||
handleResult: function(aResultSet) {
|
||||
let row;
|
||||
while ((row = aResultSet.getNextRow())) {
|
||||
let rh = row.getResultByName("host");
|
||||
let frecency = row.getResultByName("frecency");
|
||||
providers[rh].frecency = parseInt(frecency) || 0;
|
||||
}
|
||||
},
|
||||
handleError: function(aError) {
|
||||
Cu.reportError(aError.message + " (Result = " + aError.result + ")");
|
||||
},
|
||||
handleCompletion: function(aReason) {
|
||||
// the query may not have returned all our providers, so we have
|
||||
// stamped the frecency on the provider and sort here. This makes sure
|
||||
// all enabled providers get sorted even with frecency zero.
|
||||
let providerList = SocialServiceInternal.providerArray;
|
||||
// reverse sort
|
||||
aCallback(providerList.sort(function(a, b) b.frecency - a.frecency));
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -325,9 +383,8 @@ this.SocialService = {
|
||||
SocialServiceInternal.providers[provider.origin] = provider;
|
||||
ActiveProviders.add(provider.origin);
|
||||
|
||||
schedule(function () {
|
||||
this._notifyProviderListeners("provider-added",
|
||||
SocialServiceInternal.providerArray);
|
||||
this.getOrderedProviderList(function (providers) {
|
||||
this._notifyProviderListeners("provider-added", providers);
|
||||
if (onDone)
|
||||
onDone(provider);
|
||||
}.bind(this));
|
||||
@ -360,9 +417,8 @@ this.SocialService = {
|
||||
AddonManagerPrivate.notifyAddonChanged(addon.id, ADDON_TYPE_SERVICE, false);
|
||||
}
|
||||
|
||||
schedule(function () {
|
||||
this._notifyProviderListeners("provider-removed",
|
||||
SocialServiceInternal.providerArray);
|
||||
this.getOrderedProviderList(function (providers) {
|
||||
this._notifyProviderListeners("provider-removed", providers);
|
||||
if (onDone)
|
||||
onDone();
|
||||
}.bind(this));
|
||||
@ -376,13 +432,18 @@ this.SocialService = {
|
||||
}).bind(this));
|
||||
},
|
||||
|
||||
// Returns an array of installed providers.
|
||||
getProviderList: function getProviderList(onDone) {
|
||||
// Returns an unordered array of installed providers
|
||||
getProviderList: function(onDone) {
|
||||
schedule(function () {
|
||||
onDone(SocialServiceInternal.providerArray);
|
||||
});
|
||||
},
|
||||
|
||||
// Returns an array of installed providers, sorted by frecency
|
||||
getOrderedProviderList: function(onDone) {
|
||||
SocialServiceInternal.orderedProviders(onDone);
|
||||
},
|
||||
|
||||
getOriginActivationType: function(origin) {
|
||||
let prefname = SocialServiceInternal.getManifestPrefname(origin);
|
||||
if (Services.prefs.getDefaultBranch("social.manifest.").getPrefType(prefname) == Services.prefs.PREF_STRING)
|
||||
@ -612,6 +673,12 @@ function SocialProvider(input) {
|
||||
this.principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(originUri);
|
||||
this.ambientNotificationIcons = {};
|
||||
this.errorState = null;
|
||||
this.frecency = 0;
|
||||
try {
|
||||
this.domain = etld.getBaseDomainFromHost(originUri.host);
|
||||
} catch(e) {
|
||||
this.domain = originUri.host;
|
||||
}
|
||||
}
|
||||
|
||||
SocialProvider.prototype = {
|
||||
|
@ -10,8 +10,13 @@ relativesrcdir = @relativesrcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
ifdef MOZ_SOCIAL
|
||||
# social is turned off for android
|
||||
|
||||
DISABLED_XPCSHELL_TESTS = \
|
||||
xpcshell \
|
||||
$(NULL)
|
||||
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -10,6 +10,9 @@ relativesrcdir = @relativesrcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
ifdef MOZ_SOCIAL
|
||||
# social is turned off for android
|
||||
|
||||
MOCHITEST_BROWSER_FILES = \
|
||||
head.js \
|
||||
data.json \
|
||||
@ -23,4 +26,6 @@ MOCHITEST_BROWSER_FILES = \
|
||||
browser_notifications.js \
|
||||
$(NULL)
|
||||
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -6,6 +6,11 @@ const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
|
||||
const MANIFEST_PREFS = Services.prefs.getBranch("social.manifest.");
|
||||
const gProfD = do_get_profile();
|
||||
|
||||
@ -150,3 +155,68 @@ AsyncRunner.prototype = {
|
||||
this._callbacks.consoleError(msg);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
function promiseAddVisits(aPlaceInfo)
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
let places = [];
|
||||
if (aPlaceInfo instanceof Ci.nsIURI) {
|
||||
places.push({ uri: aPlaceInfo });
|
||||
}
|
||||
else if (Array.isArray(aPlaceInfo)) {
|
||||
places = places.concat(aPlaceInfo);
|
||||
} else {
|
||||
places.push(aPlaceInfo)
|
||||
}
|
||||
|
||||
// Create mozIVisitInfo for each entry.
|
||||
let now = Date.now();
|
||||
for (let i = 0; i < places.length; i++) {
|
||||
if (!places[i].title) {
|
||||
places[i].title = "test visit for " + places[i].uri.spec;
|
||||
}
|
||||
places[i].visits = [{
|
||||
transitionType: places[i].transition === undefined ? Ci.nsINavHistoryService.TRANSITION_LINK
|
||||
: places[i].transition,
|
||||
visitDate: places[i].visitDate || (now++) * 1000,
|
||||
referrerURI: places[i].referrer
|
||||
}];
|
||||
}
|
||||
|
||||
PlacesUtils.asyncHistory.updatePlaces(
|
||||
places,
|
||||
{
|
||||
handleError: function handleError(aResultCode, aPlaceInfo) {
|
||||
let ex = new Components.Exception("Unexpected error in adding visits.",
|
||||
aResultCode);
|
||||
deferred.reject(ex);
|
||||
},
|
||||
handleResult: function () {},
|
||||
handleCompletion: function handleCompletion() {
|
||||
deferred.resolve();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseTopicObserved(aTopic)
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
|
||||
Services.obs.addObserver(
|
||||
function PTO_observe(aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(PTO_observe, aTopic);
|
||||
deferred.resolve([aSubject, aData]);
|
||||
}, aTopic, false);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseClearHistory() {
|
||||
let promise = promiseTopicObserved(PlacesUtils.TOPIC_EXPIRATION_FINISHED);
|
||||
do_execute_soon(function() PlacesUtils.bhistory.removeAllPages());
|
||||
return promise;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/PlacesUtils.jsm");
|
||||
|
||||
function run_test() {
|
||||
initApp();
|
||||
@ -13,10 +14,12 @@ function run_test() {
|
||||
{ // normal provider
|
||||
name: "provider 1",
|
||||
origin: "https://example1.com",
|
||||
sidebarURL: "https://example1.com/sidebar/",
|
||||
},
|
||||
{ // provider without workerURL
|
||||
name: "provider 2",
|
||||
origin: "https://example2.com"
|
||||
origin: "https://example2.com",
|
||||
sidebarURL: "https://example2.com/sidebar/",
|
||||
}
|
||||
];
|
||||
|
||||
@ -46,6 +49,7 @@ function run_test() {
|
||||
runner.appendIterator(testAddRemoveProvider(manifests, next));
|
||||
runner.appendIterator(testIsSameOrigin(manifests, next));
|
||||
runner.appendIterator(testResolveUri (manifests, next));
|
||||
runner.appendIterator(testOrderedProviders(manifests, next));
|
||||
runner.next();
|
||||
}
|
||||
|
||||
@ -168,3 +172,26 @@ function testResolveUri(manifests, next) {
|
||||
do_check_eq(provider.resolveUri("http://somewhereelse.com/foo.html").spec, "http://somewhereelse.com/foo.html");
|
||||
do_check_eq(provider.resolveUri("data:text/html,<p>hi").spec, "data:text/html,<p>hi");
|
||||
}
|
||||
|
||||
function testOrderedProviders(manifests, next) {
|
||||
let providers = yield SocialService.getProviderList(next);
|
||||
|
||||
// add visits for only one of the providers
|
||||
let visits = [];
|
||||
let startDate = Date.now() * 1000;
|
||||
for (let i = 0; i < 10; i++) {
|
||||
visits.push({
|
||||
uri: Services.io.newURI(providers[1].sidebarURL + i, null, null),
|
||||
visitDate: startDate + i
|
||||
});
|
||||
}
|
||||
|
||||
promiseAddVisits(visits).then(next);
|
||||
yield;
|
||||
let orderedProviders = yield SocialService.getOrderedProviderList(next);
|
||||
do_check_eq(orderedProviders[0], providers[1]);
|
||||
do_check_eq(orderedProviders[1], providers[0]);
|
||||
do_check_true(orderedProviders[0].frecency > orderedProviders[1].frecency);
|
||||
promiseClearHistory().then(next);
|
||||
yield;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user