Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2015-04-23 15:55:19 +02:00
commit 8c20d6ac92
39 changed files with 361 additions and 390 deletions

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4d87112bbf48cdd09c19e553cc9aebd2a2c4ddfd"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4d87112bbf48cdd09c19e553cc9aebd2a2c4ddfd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9a9797062c6001d6346504161c51187a2968466b"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4d87112bbf48cdd09c19e553cc9aebd2a2c4ddfd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="90f848a40efad820ab00fa52bec52dff37255b12"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4d87112bbf48cdd09c19e553cc9aebd2a2c4ddfd"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4d87112bbf48cdd09c19e553cc9aebd2a2c4ddfd"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4d87112bbf48cdd09c19e553cc9aebd2a2c4ddfd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9a9797062c6001d6346504161c51187a2968466b"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4d87112bbf48cdd09c19e553cc9aebd2a2c4ddfd"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4d87112bbf48cdd09c19e553cc9aebd2a2c4ddfd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="90f848a40efad820ab00fa52bec52dff37255b12"/>

View File

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d",
"git_revision": "4d87112bbf48cdd09c19e553cc9aebd2a2c4ddfd",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "6238380e300e25c4ec8aea2a8804d0ca3675f7fb",
"revision": "3057b08e087df6d1ee21ca3a3741e56bb78021a1",
"repo_path": "integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4d87112bbf48cdd09c19e553cc9aebd2a2c4ddfd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="90f848a40efad820ab00fa52bec52dff37255b12"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4d87112bbf48cdd09c19e553cc9aebd2a2c4ddfd"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -147,8 +147,8 @@ let gTests = [
Assert.ok(tabOpened);
Assert.equal(tokenData.code, "code1");
Assert.equal(tokenData.state, "state");
Assert.equal(keys.kAr, "kAr");
Assert.equal(keys.kBr, "kBr");
Assert.deepEqual(keys.kAr, {k: "kAr"});
Assert.deepEqual(keys.kBr, {k: "kBr"});
resolve();
};

View File

@ -16,7 +16,9 @@
state: "state",
code: "code1",
closeWindow: "signin",
keys: { kAr: 'kAr', kBr: 'kBr' },
// Keys normally contain more information, but this is enough
// to keep Loop's tests happy.
keys: { kAr: { k: 'kAr' }, kBr: { k: 'kBr' }},
},
},
},

View File

@ -202,10 +202,10 @@ let LoopRoomsInternal = {
* information.
*/
promiseEncryptRoomData: Task.async(function* (roomData) {
// For now, disable encryption/context if context is disabled, or if
// FxA is turned on.
if (!MozLoopService.getLoopPref("contextInConverations.enabled") ||
this.sessionType == LOOP_SESSION_TYPE.FXA) {
// XXX We should only return unencrypted data whilst we're still working
// on context. Once bug 1115340 is fixed, this function should no longer be
// here.
function getUnencryptedData() {
var serverRoomData = extend({}, roomData);
delete serverRoomData.decryptedContext;
@ -218,6 +218,11 @@ let LoopRoomsInternal = {
};
}
// For now, disable encryption/context if context is disabled
if (!MozLoopService.getLoopPref("contextInConverations.enabled")) {
return getUnencryptedData();
}
var newRoomData = extend({}, roomData);
if (!newRoomData.context) {
@ -227,7 +232,17 @@ let LoopRoomsInternal = {
// First get the room key.
let key = yield this.promiseGetOrCreateRoomKey(newRoomData);
newRoomData.context.wrappedKey = yield this.promiseEncryptedRoomKey(key);
try {
newRoomData.context.wrappedKey = yield this.promiseEncryptedRoomKey(key);
}
catch (ex) {
// XXX Bug 1153788 should remove this, then we can remove the whole
// try/catch.
if (ex.message == "FxA re-register not implemented") {
return getUnencryptedData();
}
return Promise.reject(ex);
}
// Now encrypt the actual data.
newRoomData.context.value = yield loopCrypto.encryptBytes(key,
@ -654,8 +669,7 @@ let LoopRoomsInternal = {
};
// If we're not encrypting currently, then only send the roomName.
if (!Services.prefs.getBoolPref("loop.contextInConverations.enabled") ||
this.sessionType == LOOP_SESSION_TYPE.FXA) {
if (!Services.prefs.getBoolPref("loop.contextInConverations.enabled")) {
sendData = {
roomName: newRoomName
};

View File

@ -959,6 +959,9 @@ let MozLoopServiceInternal = {
gFxAOAuthClientPromise = this.promiseFxAOAuthParameters().then(
parameters => {
// Add the fact that we want keys to the parameters.
parameters.keys = true;
try {
gFxAOAuthClient = new FxAccountsOAuthClient({
parameters: parameters,
@ -1031,7 +1034,10 @@ let MozLoopServiceInternal = {
* @param {Deferred} deferred used to resolve the gFxAOAuthClientPromise
* @param {Object} result (with code and state)
*/
_fxAOAuthComplete: function(deferred, result) {
_fxAOAuthComplete: function(deferred, result, keys) {
if (keys.kBr) {
Services.prefs.setCharPref("loop.key.fxa", keys.kBr.k);
}
gFxAOAuthClientPromise = null;
// Note: The state was already verified in FxAccountsOAuthClient.
deferred.resolve(result);
@ -1331,8 +1337,14 @@ this.MozLoopService = {
return new Promise((resolve, reject) => {
if (this.userProfile) {
// We're an FxA user.
// XXX Bug 1153788 will implement this for FxA.
reject(new Error("unimplemented"));
if (Services.prefs.prefHasUserValue("loop.key.fxa")) {
resolve(MozLoopService.getLoopPref("key.fxa"));
return;
}
// XXX If we don't have a key for FxA yet, then simply reject for now.
// We'll create some sign-in/sign-out UX in bug 1153788.
reject(new Error("FxA re-register not implemented"));
return;
}

View File

@ -240,6 +240,18 @@ loop.shared.mixins = (function() {
rootObject.removeEventListener("resize", this.updateVideoContainer);
},
/**
* Resets the dimensions cache, e.g. for when the session is ended, and
* before a new session, so that we always ensure we see an update when a
* new session is started.
*/
resetDimensionsCache: function() {
this._videoDimensionsCache = {
local: {},
remote: {}
};
},
/**
* Whenever the dimensions change of a video stream, this function is called
* by `updateVideoDimensions` to store the new values and notifies the callee

View File

@ -383,6 +383,12 @@ loop.standaloneRoomViews = (function(mozL10n) {
this.updateVideoContainer();
}
if (nextState.roomState === ROOM_STATES.INIT ||
nextState.roomState === ROOM_STATES.GATHER ||
nextState.roomState === ROOM_STATES.READY) {
this.resetDimensionsCache();
}
// When screen sharing stops.
if (this.state.receivingScreenShare && !nextState.receivingScreenShare) {
// Remove the custom screenshare styles on the remote camera.

View File

@ -383,6 +383,12 @@ loop.standaloneRoomViews = (function(mozL10n) {
this.updateVideoContainer();
}
if (nextState.roomState === ROOM_STATES.INIT ||
nextState.roomState === ROOM_STATES.GATHER ||
nextState.roomState === ROOM_STATES.READY) {
this.resetDimensionsCache();
}
// When screen sharing stops.
if (this.state.receivingScreenShare && !nextState.receivingScreenShare) {
// Remove the custom screenshare styles on the remote camera.

View File

@ -7,7 +7,7 @@ support-files =
google_service.sjs
head.js
loop_fxa.sjs
../../../../base/content/test/general/browser_fxa_oauth.html
../../../../base/content/test/general/browser_fxa_oauth_with_keys.html
[browser_CardDavImporter.js]
[browser_fxa_login.js]

View File

@ -134,7 +134,7 @@ function params(request, response) {
*/
function oauth_authorization(request, response) {
response.setStatusLine(request.httpVersion, 302, "Found");
response.setHeader("Location", "browser_fxa_oauth.html");
response.setHeader("Location", "browser_fxa_oauth_with_keys.html");
}
/**

View File

@ -214,6 +214,19 @@ describe("loop.standaloneRoomViews", function() {
sinon.assert.calledOnce(view.updateVideoContainer);
});
it("should reset the video dimensions cache when the gather state is entered", function() {
activeRoomStore.setStoreState({roomState: ROOM_STATES.SESSION_CONNECTED});
var view = mountTestComponent();
activeRoomStore.setStoreState({roomState: ROOM_STATES.GATHER});
expect(view._videoDimensionsCache).eql({
local: {},
remote: {}
});
})
});
describe("#publishStream", function() {

View File

@ -3,6 +3,7 @@
/* global Services, Assert */
const kGuestKeyPref = "loop.key";
const kFxAKeyPref = "loop.key.fxa";
do_register_cleanup(function() {
Services.prefs.clearUserPref(kGuestKeyPref);
@ -33,12 +34,25 @@ add_task(function* test_guestGetKey() {
Assert.equal(key, kFakeKey, "should return existing key");
});
add_task(function* test_fxaGetKey() {
// Set the userProfile to look like we're logged into FxA.
add_task(function* test_fxaGetKnownKey() {
const kFakeKey = "75312468";
// Set the userProfile to look like we're logged into FxA with a key stored.
MozLoopServiceInternal.fxAOAuthTokenData = { token_type: "bearer" };
MozLoopServiceInternal.fxAOAuthProfile = { email: "fake@invalid.com" };
Services.prefs.setCharPref(kFxAKeyPref, kFakeKey);
let key = yield MozLoopService.promiseProfileEncryptionKey();
Assert.equal(key, kFakeKey, "should return existing key");
});
add_task(function* test_fxaGetKey() {
// Set the userProfile to look like we're logged into FxA without a key stored.
MozLoopServiceInternal.fxAOAuthTokenData = { token_type: "bearer" };
MozLoopServiceInternal.fxAOAuthProfile = { email: "fake@invalid.com" };
Services.prefs.clearUserPref(kFxAKeyPref);
// Currently unimplemented, add a test when we implement the code.
yield Assert.rejects(MozLoopService.promiseProfileEncryptionKey(),
/unimplemented/, "should reject as unimplemented");
/not implemented/, "should reject as unimplemented");
});

View File

@ -118,6 +118,10 @@
#include "mozilla/EMEUtils.h"
#endif
#ifdef MOZ_WIDGET_GONK
#include <cutils/properties.h>
#endif
namespace mozilla {
namespace dom {
@ -1453,6 +1457,17 @@ Navigator::GetFeature(const nsAString& aName, ErrorResult& aRv)
} // hardware.memory
#endif
#ifdef MOZ_WIDGET_GONK
if (aName.EqualsLiteral("acl.version")) {
char value[PROPERTY_VALUE_MAX];
uint32_t len = property_get("persist.acl.version", value, nullptr);
if (len > 0) {
p->MaybeResolve(NS_ConvertUTF8toUTF16(value));
return p.forget();
}
}
#endif
p->MaybeResolve(JS::UndefinedHandleValue);
return p.forget();
}

View File

@ -50,7 +50,6 @@ UNIFIED_SOURCES += [
'src/base/pickle.cc',
'src/base/rand_util.cc',
'src/base/revocable_store.cc',
'src/base/scoped_temp_dir.cc',
'src/base/string_piece.cc',
'src/base/string_util.cc',
'src/base/thread.cc',

View File

@ -139,12 +139,6 @@ void AppendToPath(std::wstring* path, const std::wstring& new_ending) {
path->push_back(FilePath::kSeparators[0]);
path->append(new_ending);
}
bool CopyDirectory(const std::wstring& from_path, const std::wstring& to_path,
bool recursive) {
return CopyDirectory(FilePath::FromWStringHack(from_path),
FilePath::FromWStringHack(to_path),
recursive);
}
bool CopyFile(const std::wstring& from_path, const std::wstring& to_path) {
return CopyFile(FilePath::FromWStringHack(from_path),
FilePath::FromWStringHack(to_path));
@ -172,8 +166,8 @@ bool CreateTemporaryFileName(std::wstring* temp_file) {
*temp_file = temp_file_path.ToWStringHack();
return true;
}
bool Delete(const std::wstring& path, bool recursive) {
return Delete(FilePath::FromWStringHack(path), recursive);
bool Delete(const std::wstring& path) {
return Delete(FilePath::FromWStringHack(path));
}
bool DirectoryExists(const std::wstring& path) {
return DirectoryExists(FilePath::FromWStringHack(path));

View File

@ -16,7 +16,6 @@
#include <sys/stat.h>
#elif defined(OS_POSIX)
#include <sys/types.h>
#include <fts.h>
#include <sys/stat.h>
#endif
@ -87,34 +86,17 @@ void ReplaceExtension(std::wstring* file_name, const std::wstring& extension);
// Deletes the given path, whether it's a file or a directory.
// If it's a directory, it's perfectly happy to delete all of the
// directory's contents. Passing true to recursive deletes
// subdirectories and their contents as well.
// directory's contents.
// Returns true if successful, false otherwise.
//
// WARNING: USING THIS WITH recursive==true IS EQUIVALENT
// TO "rm -rf", SO USE WITH CAUTION.
bool Delete(const FilePath& path, bool recursive);
bool Delete(const FilePath& path);
// Deprecated temporary compatibility function.
bool Delete(const std::wstring& path, bool recursive);
bool Delete(const std::wstring& path);
// Copies a single file. Use CopyDirectory to copy directories.
bool CopyFile(const FilePath& from_path, const FilePath& to_path);
// Deprecated temporary compatibility function.
bool CopyFile(const std::wstring& from_path, const std::wstring& to_path);
// Copies the given path, and optionally all subdirectories and their contents
// as well.
// If there are files existing under to_path, always overwrite.
// Returns true if successful, false otherwise.
// Dont't use wildcards on the names, it may stop working without notice.
//
// If you only need to copy a file use CopyFile, it's faster.
bool CopyDirectory(const FilePath& from_path, const FilePath& to_path,
bool recursive);
// Deprecated temporary compatibility function.
bool CopyDirectory(const std::wstring& from_path, const std::wstring& to_path,
bool recursive);
// Returns true if the given path exists on the local filesystem,
// false otherwise.
bool PathExists(const FilePath& path);

View File

@ -8,13 +8,10 @@
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
#ifndef ANDROID
#include <fts.h>
#endif
#include <libgen.h>
#include <stdio.h>
#include <string.h>
#include <sys/errno.h>
#include <errno.h>
#include <sys/mman.h>
#define _DARWIN_USE_64_BIT_INODE // Use 64-bit inode data structures
#include <sys/stat.h>
@ -53,7 +50,7 @@ bool AbsolutePath(FilePath* path) {
// which works both with and without the recursive flag. I'm not sure we need
// that functionality. If not, remove from file_util_win.cc, otherwise add it
// here.
bool Delete(const FilePath& path, bool recursive) {
bool Delete(const FilePath& path) {
const char* path_str = path.value().c_str();
struct stat file_info;
int test = stat(path_str, &file_info);
@ -64,174 +61,8 @@ bool Delete(const FilePath& path, bool recursive) {
}
if (!S_ISDIR(file_info.st_mode))
return (unlink(path_str) == 0);
if (!recursive)
return (rmdir(path_str) == 0);
#ifdef ANDROID
// XXX Need ftsless impl for bionic
return false;
#else
bool success = true;
int ftsflags = FTS_PHYSICAL | FTS_NOSTAT;
char top_dir[PATH_MAX];
if (base::strlcpy(top_dir, path_str,
arraysize(top_dir)) >= arraysize(top_dir)) {
return false;
}
char* dir_list[2] = { top_dir, NULL };
FTS* fts = fts_open(dir_list, ftsflags, NULL);
if (fts) {
FTSENT* fts_ent = fts_read(fts);
while (success && fts_ent != NULL) {
switch (fts_ent->fts_info) {
case FTS_DNR:
case FTS_ERR:
// log error
success = false;
continue;
break;
case FTS_DP:
success = (rmdir(fts_ent->fts_accpath) == 0);
break;
case FTS_D:
break;
case FTS_NSOK:
case FTS_F:
case FTS_SL:
case FTS_SLNONE:
success = (unlink(fts_ent->fts_accpath) == 0);
break;
default:
DCHECK(false);
break;
}
fts_ent = fts_read(fts);
}
fts_close(fts);
}
return success;
#endif
}
bool Move(const FilePath& from_path, const FilePath& to_path) {
if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0)
return true;
if (!CopyDirectory(from_path, to_path, true))
return false;
Delete(from_path, true);
return true;
}
bool CopyDirectory(const FilePath& from_path,
const FilePath& to_path,
bool recursive) {
// Some old callers of CopyDirectory want it to support wildcards.
// After some discussion, we decided to fix those callers.
// Break loudly here if anyone tries to do this.
// TODO(evanm): remove this once we're sure it's ok.
DCHECK(to_path.value().find('*') == std::string::npos);
DCHECK(from_path.value().find('*') == std::string::npos);
char top_dir[PATH_MAX];
if (base::strlcpy(top_dir, from_path.value().c_str(),
arraysize(top_dir)) >= arraysize(top_dir)) {
return false;
}
#ifdef ANDROID
// XXX Need ftsless impl for bionic
return false;
#else
char* dir_list[] = { top_dir, NULL };
FTS* fts = fts_open(dir_list, FTS_PHYSICAL | FTS_NOSTAT, NULL);
if (!fts) {
CHROMIUM_LOG(ERROR) << "fts_open failed: " << strerror(errno);
return false;
}
int error = 0;
FTSENT* ent;
while (!error && (ent = fts_read(fts)) != NULL) {
// ent->fts_path is the source path, including from_path, so paste
// the suffix after from_path onto to_path to create the target_path.
std::string suffix(&ent->fts_path[from_path.value().size()]);
// Strip the leading '/' (if any).
if (!suffix.empty()) {
DCHECK_EQ('/', suffix[0]);
suffix.erase(0, 1);
}
const FilePath target_path = to_path.Append(suffix);
switch (ent->fts_info) {
case FTS_D: // Preorder directory.
// If we encounter a subdirectory in a non-recursive copy, prune it
// from the traversal.
if (!recursive && ent->fts_level > 0) {
if (fts_set(fts, ent, FTS_SKIP) != 0)
error = errno;
continue;
}
// Try creating the target dir, continuing on it if it exists already.
// Rely on the user's umask to produce correct permissions.
if (mkdir(target_path.value().c_str(), 0777) != 0) {
if (errno != EEXIST)
error = errno;
}
break;
case FTS_F: // Regular file.
case FTS_NSOK: // File, no stat info requested.
errno = 0;
if (!CopyFile(FilePath(ent->fts_path), target_path))
error = errno ? errno : EINVAL;
break;
case FTS_DP: // Postorder directory.
case FTS_DOT: // "." or ".."
// Skip it.
continue;
case FTS_DC: // Directory causing a cycle.
// Skip this branch.
if (fts_set(fts, ent, FTS_SKIP) != 0)
error = errno;
break;
case FTS_DNR: // Directory cannot be read.
case FTS_ERR: // Error.
case FTS_NS: // Stat failed.
// Abort with the error.
error = ent->fts_errno;
break;
case FTS_SL: // Symlink.
case FTS_SLNONE: // Symlink with broken target.
CHROMIUM_LOG(WARNING) << "CopyDirectory() skipping symbolic link: " <<
ent->fts_path;
continue;
case FTS_DEFAULT: // Some other sort of file.
CHROMIUM_LOG(WARNING) << "CopyDirectory() skipping file of unknown type: " <<
ent->fts_path;
continue;
default:
NOTREACHED();
continue; // Hope for the best!
}
}
// fts_read may have returned NULL and set errno to indicate an error.
if (!error && errno != 0)
error = errno;
if (!fts_close(fts)) {
// If we already have an error, let's use that error instead of the error
// fts_close set.
if (!error)
error = errno;
}
if (error) {
CHROMIUM_LOG(ERROR) << "CopyDirectory(): " << strerror(error);
return false;
}
return true;
#endif
return (rmdir(path_str) == 0);
}
bool PathExists(const FilePath& path) {

View File

@ -27,14 +27,14 @@ bool AbsolutePath(FilePath* path) {
return true;
}
bool Delete(const FilePath& path, bool recursive) {
bool Delete(const FilePath& path) {
if (path.value().length() >= MAX_PATH)
return false;
// If we're not recursing use DeleteFile; it should be faster. DeleteFile
// Use DeleteFile; it should be faster. DeleteFile
// fails if passed a directory though, which is why we fall through on
// failure to the SHFileOperation.
if (!recursive && DeleteFile(path.value().c_str()) != 0)
if (DeleteFile(path.value().c_str()) != 0)
return true;
// SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
@ -48,8 +48,7 @@ bool Delete(const FilePath& path, bool recursive) {
file_operation.wFunc = FO_DELETE;
file_operation.pFrom = double_terminated_path;
file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION;
if (!recursive)
file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
int err = SHFileOperation(&file_operation);
// Some versions of Windows return ERROR_FILE_NOT_FOUND when
// deleting an empty directory.
@ -98,26 +97,6 @@ bool ShellCopy(const FilePath& from_path, const FilePath& to_path,
return (SHFileOperation(&file_operation) == 0);
}
bool CopyDirectory(const FilePath& from_path, const FilePath& to_path,
bool recursive) {
if (recursive)
return ShellCopy(from_path, to_path, true);
// Instead of creating a new directory, we copy the old one to include the
// security information of the folder as part of the copy.
if (!PathExists(to_path)) {
// Except that Vista fails to do that, and instead do a recursive copy if
// the target directory doesn't exist.
if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA)
CreateDirectory(to_path);
else
ShellCopy(from_path, to_path, false);
}
FilePath directory = from_path.Append(L"*.*");
return ShellCopy(directory, to_path, false);
}
bool PathExists(const FilePath& path) {
return (GetFileAttributes(path.value().c_str()) != INVALID_FILE_ATTRIBUTES);
}

View File

@ -1,47 +0,0 @@
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/scoped_temp_dir.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/string_util.h"
ScopedTempDir::ScopedTempDir() {
}
ScopedTempDir::~ScopedTempDir() {
if (!path_.empty() && !file_util::Delete(path_, true))
CHROMIUM_LOG(ERROR) << "ScopedTempDir unable to delete " << path_.value();
}
bool ScopedTempDir::CreateUniqueTempDir() {
// This "scoped_dir" prefix is only used on Windows and serves as a template
// for the unique name.
if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("scoped_dir"),
&path_))
return false;
return true;
}
bool ScopedTempDir::Set(const FilePath& path) {
DCHECK(path_.empty());
if (!file_util::DirectoryExists(path) &&
!file_util::CreateDirectory(path)) {
return false;
}
path_ = path;
return true;
}
FilePath ScopedTempDir::Take() {
FilePath ret = path_;
path_ = FilePath();
return ret;
}
bool ScopedTempDir::IsValid() const {
return !path_.empty() && file_util::DirectoryExists(path_);
}

View File

@ -1,47 +0,0 @@
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_SCOPED_TEMP_DIR_H_
#define BASE_SCOPED_TEMP_DIR_H_
// An object representing a temporary / scratch directory that should be cleaned
// up (recursively) when this object goes out of scope. Note that since
// deletion occurs during the destructor, no further error handling is possible
// if the directory fails to be deleted. As a result, deletion is not
// guaranteed by this class.
#include "base/file_path.h"
class ScopedTempDir {
public:
// No directory is owned/created initially.
ScopedTempDir();
// Recursively delete path_
~ScopedTempDir();
// Creates a unique directory in TempPath, and takes ownership of it.
// See file_util::CreateNewTemporaryDirectory.
bool CreateUniqueTempDir();
// Takes ownership of directory at |path|, creating it if necessary.
// Don't call multiple times unless Take() has been called first.
bool Set(const FilePath& path);
// Caller takes ownership of the temporary directory so it won't be destroyed
// when this object goes out of scope.
FilePath Take();
const FilePath& path() const { return path_; }
// Returns true if path_ is non-empty and exists.
bool IsValid() const;
private:
FilePath path_;
DISALLOW_COPY_AND_ASSIGN(ScopedTempDir);
};
#endif // BASE_SCOPED_TEMP_DIR_H_

View File

@ -93,7 +93,7 @@ bool SharedMemory::Delete(const std::wstring& name) {
FilePath path(WideToUTF8(mem_filename));
if (file_util::PathExists(path)) {
return file_util::Delete(path, false);
return file_util::Delete(path);
}
// Doesn't exist, so success.
@ -170,7 +170,7 @@ bool SharedMemory::CreateOrOpen(const std::wstring &name,
// Deleting the file prevents anyone else from mapping it in
// (making it private), and prevents the need for cleanup (once
// the last fd is closed, it is truly freed).
file_util::Delete(path, false);
file_util::Delete(path);
} else {
std::wstring mem_filename;
if (FilenameForMemoryName(name, &mem_filename) == false)

View File

@ -198,20 +198,15 @@
<!ENTITY tab_queue_prompt_tip_text "you can change this later in Settings">
<!ENTITY tab_queue_prompt_positive_action_button "Enable">
<!ENTITY tab_queue_prompt_negative_action_button "Not now">
<!-- Localization note (tab_queue_notification_text_plural) : The
<!ENTITY tab_queue_notification_title "&brandShortName;">
<!-- Localization note (tab_queue_notification_text_plural2) : The
formatD is replaced with the number of tabs queued. The
number of tabs queued is always more than one. We can't use
Android plural forms, sadly. See Bug #753859. -->
<!ENTITY tab_queue_notification_text_plural "&formatD; tabs queued">
<!-- Localization note (tab_queue_notification_title_plural) : This is the
title of a notification; we expect more than one tab queued. -->
<!ENTITY tab_queue_notification_title_plural "Tabs Queued">
<!-- Localization note (tab_queue_notification_title_singular) : This is the
title of a notification; we expect only one tab queued. -->
<!ENTITY tab_queue_notification_title_singular "Tab Queued">
<!-- Localization note (tab_queue_notification_text_singular) : This is the
<!ENTITY tab_queue_notification_text_plural2 "&formatD; tabs waiting">
<!-- Localization note (tab_queue_notification_text_singular2) : This is the
text of a notification; we expect only one tab queued. -->
<!ENTITY tab_queue_notification_text_singular "1 tab queued">
<!ENTITY tab_queue_notification_text_singular2 "1 tab waiting">
<!ENTITY pref_char_encoding "Character encoding">
<!ENTITY pref_char_encoding_on "Show menu">

View File

@ -137,6 +137,8 @@ OnSharedPreferenceChangeListener
public static final String PREFS_SUGGESTED_SITES = NON_PREF_PREFIX + "home_suggested_sites";
public static final String PREFS_TAB_QUEUE = NON_PREF_PREFIX + "tab_queue";
public static final String PREFS_CUSTOMIZE_SCREEN = NON_PREF_PREFIX + "customize_screen";
public static final String PREFS_TAB_QUEUE_LAST_SITE = NON_PREF_PREFIX + "last_site";
public static final String PREFS_TAB_QUEUE_LAST_TIME = NON_PREF_PREFIX + "last_time";
// These values are chosen to be distinct from other Activity constants.
private static final int REQUEST_CODE_PREF_SCREEN = 5;

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/toast"
style="@style/Toast">
<TextView
android:id="@+id/toast_message"
style="@style/ToastMessage"
tools:text="Tab queued in firefox" />
<View
android:id="@+id/toast_divider"
style="@style/ToastDivider" />
<Button
android:id="@+id/toast_button"
style="@style/ToastButton"
android:drawableLeft="@drawable/switch_button_icon"
tools:text="Open" />
</LinearLayout>
</FrameLayout>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<resources>
<style name="Toast" parent="ToastBase">
<item name="android:layout_width">400dp</item>
</style>
</resources>

View File

@ -247,10 +247,9 @@
<string name="tab_queue_prompt_negative_action_button">&tab_queue_prompt_negative_action_button;</string>
<string name="tab_queue_toast_message">&tab_queue_toast_message2;</string>
<string name="tab_queue_toast_action">&tab_queue_toast_action;</string>
<string name="tab_queue_notification_text_singular">&tab_queue_notification_text_singular;</string>
<string name="tab_queue_notification_text_plural">&tab_queue_notification_text_plural;</string>
<string name="tab_queue_notification_title_singular">&tab_queue_notification_title_singular;</string>
<string name="tab_queue_notification_title_plural">&tab_queue_notification_title_plural;</string>
<string name="tab_queue_notification_text_singular">&tab_queue_notification_text_singular2;</string>
<string name="tab_queue_notification_text_plural">&tab_queue_notification_text_plural2;</string>
<string name="tab_queue_notification_title">&tab_queue_notification_title;</string>
<string name="pref_about_firefox">&pref_about_firefox;</string>
<string name="pref_vendor_faqs">&pref_vendor_faqs;</string>

View File

@ -21,6 +21,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.support.v4.app.NotificationCompat;
import android.text.TextUtils;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
@ -104,6 +105,45 @@ public class TabQueueHelper {
return jsonArray.length();
}
/**
* Remove a url from the file, if it exists.
* If the url exists multiple times, all instances of it will be removed.
* This should not be run on the UI thread.
*
* @param context
* @param urlToRemove URL to remove
* @param filename filename to remove URL from
* @return the number of queued urls
*/
public static int removeURLFromFile(final Context context, final String urlToRemove, final String filename) {
ThreadUtils.assertNotOnUiThread();
final GeckoProfile profile = GeckoProfile.get(context);
JSONArray jsonArray = profile.readJSONArrayFromFile(filename);
JSONArray newArray = new JSONArray();
String url;
// Since JSONArray.remove was only added in API 19, we have to use two arrays in order to remove.
for (int i = 0; i < jsonArray.length(); i++) {
try {
url = jsonArray.getString(i);
} catch (JSONException e) {
url = "";
}
if(!TextUtils.isEmpty(url) && !urlToRemove.equals(url)) {
newArray.put(url);
}
}
profile.writeFile(filename, newArray.toString());
final SharedPreferences prefs = GeckoSharedPrefs.forApp(context);
prefs.edit().putInt(PREF_TAB_QUEUE_COUNT, newArray.length()).apply();
return newArray.length();
}
/**
* Displays a notification showing the total number of tabs queue. If there is already a notification displayed, it
* will be replaced.
@ -119,19 +159,17 @@ public class TabQueueHelper {
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, resultIntent, PendingIntent.FLAG_CANCEL_CURRENT);
String title, text;
final String text;
final Resources resources = context.getResources();
if (tabsQueued == 1) {
title = resources.getString(R.string.tab_queue_notification_title_singular);
text = resources.getString(R.string.tab_queue_notification_text_singular);
} else {
title = resources.getString(R.string.tab_queue_notification_title_plural);
text = resources.getString(R.string.tab_queue_notification_text_plural, tabsQueued);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_status_logo)
.setContentTitle(title)
.setContentTitle(resources.getString(R.string.tab_queue_notification_title))
.setContentText(text)
.setContentIntent(pendingIntent);

View File

@ -5,6 +5,13 @@
package org.mozilla.gecko.tabqueue;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.R;
import org.mozilla.gecko.mozglue.ContextUtils;
import org.mozilla.gecko.preferences.GeckoPreferences;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
@ -14,6 +21,7 @@ import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@ -21,12 +29,6 @@ import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.R;
import org.mozilla.gecko.mozglue.ContextUtils;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -56,6 +58,7 @@ public class TabQueueService extends Service {
private static final String LOGTAG = "Gecko" + TabQueueService.class.getSimpleName();
private static final long TOAST_TIMEOUT = 3000;
private static final long TOAST_DOUBLE_TAP_TIMEOUT_MILLIS = 6000;
private WindowManager windowManager;
private View toastLayout;
@ -84,7 +87,7 @@ public class TabQueueService extends Service {
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
LayoutInflater layoutInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
toastLayout = layoutInflater.inflate(R.layout.button_toast, null);
toastLayout = layoutInflater.inflate(R.layout.tab_queue_toast, null);
final Resources resources = getResources();
@ -95,7 +98,7 @@ public class TabQueueService extends Service {
openNowButton.setText(resources.getText(R.string.tab_queue_toast_action));
toastLayoutParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
@ -108,6 +111,50 @@ public class TabQueueService extends Service {
@Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
// If this is a redelivery then lets bypass the entire double tap to open now code as that's a big can of worms,
// we also don't expect redeliveries because of the short time window associated with this feature.
if (flags != START_FLAG_REDELIVERY) {
final Context applicationContext = getApplicationContext();
final SharedPreferences sharedPreferences = GeckoSharedPrefs.forApp(applicationContext);
final String lastUrl = sharedPreferences.getString(GeckoPreferences.PREFS_TAB_QUEUE_LAST_SITE, "");
final ContextUtils.SafeIntent safeIntent = new ContextUtils.SafeIntent(intent);
final String intentUrl = safeIntent.getDataString();
final long lastRunTime = sharedPreferences.getLong(GeckoPreferences.PREFS_TAB_QUEUE_LAST_TIME, 0);
final boolean isWithinDoubleTapTimeLimit = System.currentTimeMillis() - lastRunTime < TOAST_DOUBLE_TAP_TIMEOUT_MILLIS;
if (!TextUtils.isEmpty(lastUrl) && lastUrl.equals(intentUrl) && isWithinDoubleTapTimeLimit) {
// Background thread because we could do some file IO if we have to remove a url from the list.
tabQueueHandler.post(new Runnable() {
@Override
public void run() {
// If there is a runnable around, that means that the previous process hasn't yet completed, so
// we will need to prevent it from running and remove the view from the window manager.
// If there is no runnable around then the url has already been added to the list, so we'll
// need to remove it before proceeding or that url will open multiple times.
if (stopServiceRunnable != null) {
tabQueueHandler.removeCallbacks(stopServiceRunnable);
stopSelfResult(stopServiceRunnable.getStartId());
stopServiceRunnable = null;
removeView();
} else {
TabQueueHelper.removeURLFromFile(applicationContext, intentUrl, TabQueueHelper.FILE_NAME);
}
openNow(safeIntent.getUnsafe());
stopSelfResult(startId);
}
});
return START_REDELIVER_INTENT;
}
sharedPreferences.edit().putString(GeckoPreferences.PREFS_TAB_QUEUE_LAST_SITE, intentUrl)
.putLong(GeckoPreferences.PREFS_TAB_QUEUE_LAST_TIME, System.currentTimeMillis())
.apply();
}
if (stopServiceRunnable != null) {
// If we're already displaying a toast, keep displaying it but store the previous url.
// The open button will refer to the most recently opened link.
@ -130,14 +177,8 @@ public class TabQueueService extends Service {
public void onClick(final View view) {
tabQueueHandler.removeCallbacks(stopServiceRunnable);
stopServiceRunnable = null;
Intent forwardIntent = new Intent(intent);
forwardIntent.setClass(getApplicationContext(), BrowserApp.class);
forwardIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(forwardIntent);
removeView();
openNow(intent);
stopSelfResult(startId);
}
});
@ -147,6 +188,17 @@ public class TabQueueService extends Service {
return START_REDELIVER_INTENT;
}
private void openNow(Intent intent) {
Intent forwardIntent = new Intent(intent);
forwardIntent.setClass(getApplicationContext(), BrowserApp.class);
forwardIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(forwardIntent);
GeckoSharedPrefs.forApp(getApplicationContext()).edit().remove(GeckoPreferences.PREFS_TAB_QUEUE_LAST_SITE)
.remove(GeckoPreferences.PREFS_TAB_QUEUE_LAST_TIME)
.apply();
}
private void removeView() {
windowManager.removeView(toastLayout);
}
@ -198,18 +250,22 @@ public class TabQueueService extends Service {
this.startId = startId;
}
public void run(final boolean shouldStopService) {
public void run() {
run(true);
}
public void run(final boolean shouldRemoveView) {
onRun();
if (shouldStopService) {
if (shouldRemoveView) {
removeView();
}
stopSelfResult(startId);
}
public void run() {
run(true);
public int getStartId() {
return startId;
}
public abstract void onRun();

View File

@ -3446,50 +3446,59 @@
"description": "PLACES: Days from last maintenance"
},
"UPDATE_CHECK_NO_UPDATE_EXTERNAL" : {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of no updates were found for a background update check (externally initiated)"
},
"UPDATE_CHECK_NO_UPDATE_NOTIFY" : {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of no updates were found for a background update check (timer initiated)"
},
"UPDATE_CHECK_CODE_EXTERNAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 50,
"description": "Update: background update check result code except for no updates found (externally initiated)"
},
"UPDATE_CHECK_CODE_NOTIFY": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 50,
"description": "Update: background update check result code except for no updates found (timer initiated)"
},
"UPDATE_CHECK_EXTENDED_ERROR_EXTERNAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"keyed": true,
"description": "Update: keyed count (key names are prefixed with AUS_CHECK_EX_ERR_) of background update check extended error code (externally initiated)"
},
"UPDATE_CHECK_EXTENDED_ERROR_NOTIFY": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"keyed": true,
"description": "Update: keyed count (key names are prefixed with AUS_CHECK_EX_ERR_) of background update check extended error code (timer initiated)"
},
"UPDATE_INVALID_LASTUPDATETIME_EXTERNAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of systems that have a last update time greater than the current time (externally initiated)"
},
"UPDATE_INVALID_LASTUPDATETIME_NOTIFY": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of systems that have a last update time greater than the current time (timer initiated)"
},
"UPDATE_LAST_NOTIFY_INTERVAL_DAYS_EXTERNAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "exponential",
"n_buckets": 60,
@ -3497,6 +3506,7 @@
"description": "Update: interval in days since the last background update check (externally initiated)"
},
"UPDATE_LAST_NOTIFY_INTERVAL_DAYS_NOTIFY": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "exponential",
"n_buckets": 30,
@ -3504,214 +3514,253 @@
"description": "Update: interval in days since the last background update check (timer initiated)"
},
"UPDATE_PING_COUNT_EXTERNAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of systems for this ping for comparison with other pings (externally initiated)"
},
"UPDATE_PING_COUNT_NOTIFY": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of systems for this ping for comparison with other pings (timer initiated)"
},
"UPDATE_SERVICE_INSTALLED_EXTERNAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "boolean",
"description": "Update: whether the service is installed (externally initiated)"
},
"UPDATE_SERVICE_INSTALLED_NOTIFY": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "boolean",
"description": "Update: whether the service is installed (timer initiated)"
},
"UPDATE_SERVICE_MANUALLY_UNINSTALLED_EXTERNAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of systems that manually uninstalled the service (externally initiated)"
},
"UPDATE_SERVICE_MANUALLY_UNINSTALLED_NOTIFY": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of systems that manually uninstalled the service (timer initiated)"
},
"UPDATE_UNABLE_TO_APPLY_EXTERNAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of systems that cannot apply updates (externally initiated)"
},
"UPDATE_UNABLE_TO_APPLY_NOTIFY": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of systems that cannot apply updates (timer initiated)"
},
"UPDATE_CANNOT_STAGE_EXTERNAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of systems that cannot stage updates (externally initiated)"
},
"UPDATE_CANNOT_STAGE_NOTIFY": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of systems that cannot stage updates (timer initiated)"
},
"UPDATE_HAS_PREF_URL_OVERRIDE_EXTERNAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of systems that have an app.update.url.override preference (externally initiated)"
},
"UPDATE_HAS_PREF_URL_OVERRIDE_NOTIFY": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of systems that have an app.update.url.override preference (timer initiated)"
},
"UPDATE_PREF_UPDATE_CANCELATIONS_EXTERNAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 100,
"description": "Update: number of sequential update elevation request cancelations greater than 0 (externally initiated)"
},
"UPDATE_PREF_UPDATE_CANCELATIONS_NOTIFY": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 100,
"description": "Update: number of sequential update elevation request cancelations greater than 0 (timer initiated)"
},
"UPDATE_PREF_SERVICE_ERRORS_EXTERNAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 30,
"description": "Update: number of sequential update service errors greater than 0 (externally initiated)"
},
"UPDATE_PREF_SERVICE_ERRORS_NOTIFY": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 30,
"description": "Update: number of sequential update service errors greater than 0 (timer initiated)"
},
"UPDATE_NOT_PREF_UPDATE_AUTO_EXTERNAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of when the app.update.auto boolean preference is not the default value of true (true values are not submitted)"
},
"UPDATE_NOT_PREF_UPDATE_AUTO_NOTIFY": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of when the app.update.auto boolean preference is not the default value of true (true values are not submitted)"
},
"UPDATE_NOT_PREF_UPDATE_ENABLED_EXTERNAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of when the app.update.enabled boolean preference is not the default value of true (true values are not submitted)"
},
"UPDATE_NOT_PREF_UPDATE_ENABLED_NOTIFY": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of when the app.update.enabled boolean preference is not the default value of true (true values are not submitted)"
},
"UPDATE_NOT_PREF_UPDATE_STAGING_ENABLED_EXTERNAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of when the app.update.staging.enabled boolean preference is not the default value of true (true values are not submitted)"
},
"UPDATE_NOT_PREF_UPDATE_STAGING_ENABLED_NOTIFY": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of when the app.update.staging.enabled boolean preference is not the default value of true (true values are not submitted)"
},
"UPDATE_NOT_PREF_UPDATE_SERVICE_ENABLED_EXTERNAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of when the app.update.service.enabled boolean preference is not the default value of true (true values are not submitted)"
},
"UPDATE_NOT_PREF_UPDATE_SERVICE_ENABLED_NOTIFY": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "count",
"description": "Update: count of when the app.update.service.enabled boolean preference is not the default value of true (true values are not submitted)"
},
"UPDATE_DOWNLOAD_CODE_COMPLETE": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 50,
"description": "Update: complete patch download result code"
},
"UPDATE_DOWNLOAD_CODE_PARTIAL": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 50,
"description": "Update: complete patch download result code"
},
"UPDATE_STATE_CODE_COMPLETE_STARTUP": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 20,
"description": "Update: the state of a complete update from update.status on startup"
},
"UPDATE_STATE_CODE_PARTIAL_STARTUP": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 20,
"description": "Update: the state of a partial patch update from update.status on startup"
},
"UPDATE_STATE_CODE_UNKNOWN_STARTUP": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 20,
"description": "Update: the state of an unknown patch update from update.status on startup"
},
"UPDATE_STATE_CODE_COMPLETE_STAGE": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 20,
"description": "Update: the state of a complete patch update from update.status after staging"
},
"UPDATE_STATE_CODE_PARTIAL_STAGE": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 20,
"description": "Update: the state of a partial patch update from update.status after staging"
},
"UPDATE_STATE_CODE_UNKNOWN_STAGE": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 20,
"description": "Update: the state of an unknown patch update from update.status after staging"
},
"UPDATE_STATUS_ERROR_CODE_COMPLETE_STARTUP": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 100,
"description": "Update: the status error code for a failed complete patch update from update.status on startup"
},
"UPDATE_STATUS_ERROR_CODE_PARTIAL_STARTUP": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 100,
"description": "Update: the status error code for a failed partial patch update from update.status on startup"
},
"UPDATE_STATUS_ERROR_CODE_UNKNOWN_STARTUP": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 100,
"description": "Update: the status error code for a failed unknown patch update from update.status on startup"
},
"UPDATE_STATUS_ERROR_CODE_COMPLETE_STAGE": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 100,
"description": "Update: the status error code for a failed complete patch update from update.status after staging"
},
"UPDATE_STATUS_ERROR_CODE_PARTIAL_STAGE": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 100,
"description": "Update: the status error code for a failed partial patch update from update.status after staging"
},
"UPDATE_STATUS_ERROR_CODE_UNKNOWN_STAGE": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 100,
"description": "Update: the status error code for a failed unknown patch update from update.status after staging"
},
"UPDATE_WIZ_LAST_PAGE_CODE": {
"alert_emails": ["application-update-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 30,