Merge m-c to inbound. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-08-14 22:30:51 -04:00
commit 57bec315e1
48 changed files with 714 additions and 174 deletions

View File

@ -19,13 +19,13 @@
<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="c7f8938522a18454809fb6ea0fd3eddef10a73ea"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9979fccc6321be72cd17370f3a20c65bc376af33"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="f0592d4814d738e3f8d840915ef799c13601bdef"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="88261785a21d8a50b848180228af72a1505a173d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>

View File

@ -17,10 +17,10 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c7f8938522a18454809fb6ea0fd3eddef10a73ea"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9979fccc6321be72cd17370f3a20c65bc376af33"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="88261785a21d8a50b848180228af72a1505a173d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="7945ca73e687be5edbc7b928dc7fe3a208242144">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c7f8938522a18454809fb6ea0fd3eddef10a73ea"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9979fccc6321be72cd17370f3a20c65bc376af33"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
@ -23,7 +23,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="88261785a21d8a50b848180228af72a1505a173d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>

View File

@ -19,13 +19,13 @@
<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="c7f8938522a18454809fb6ea0fd3eddef10a73ea"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9979fccc6321be72cd17370f3a20c65bc376af33"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="f0592d4814d738e3f8d840915ef799c13601bdef"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="88261785a21d8a50b848180228af72a1505a173d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>

View File

@ -17,10 +17,10 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c7f8938522a18454809fb6ea0fd3eddef10a73ea"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9979fccc6321be72cd17370f3a20c65bc376af33"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="88261785a21d8a50b848180228af72a1505a173d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "a5d998cfe7cd004c7967e40efaaad0ccb829ecc4",
"revision": "a58ab122a6565b5157cda6db25ea2e15a34fb49d",
"repo_path": "/integration/gaia-central"
}

View File

@ -17,12 +17,12 @@
<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="c7f8938522a18454809fb6ea0fd3eddef10a73ea"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9979fccc6321be72cd17370f3a20c65bc376af33"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="88261785a21d8a50b848180228af72a1505a173d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>

View File

@ -15,7 +15,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="c7f8938522a18454809fb6ea0fd3eddef10a73ea"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9979fccc6321be72cd17370f3a20c65bc376af33"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -17,10 +17,10 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="c7f8938522a18454809fb6ea0fd3eddef10a73ea"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9979fccc6321be72cd17370f3a20c65bc376af33"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="88261785a21d8a50b848180228af72a1505a173d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->

View File

@ -17,12 +17,12 @@
<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="c7f8938522a18454809fb6ea0fd3eddef10a73ea"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9979fccc6321be72cd17370f3a20c65bc376af33"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="88261785a21d8a50b848180228af72a1505a173d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ac3d46419118a5ac515940f748aaed3273d165d8"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>

View File

@ -7,7 +7,7 @@
/**
* Define various fixed dimensions
*/
const GRID_BOTTOM_EXTRA = 4; // title's line-height extends 4px past the margin
const GRID_BOTTOM_EXTRA = 7; // title's line-height extends 7px past the margin
const GRID_WIDTH_EXTRA = 1; // provide 1px buffer to allow for rounding error
/**
@ -203,7 +203,6 @@ let gGrid = {
}
let availSpace = document.documentElement.clientHeight - this._cellMargin -
document.querySelector("#newtab-margin-undo-container").offsetHeight -
document.querySelector("#newtab-search-container").offsetHeight;
let visibleRows = Math.floor(availSpace / this._cellHeight);
this._node.style.height = this._computeHeight() + "px";

View File

@ -28,7 +28,6 @@ input[type=button] {
#newtab-undo-container {
transition: opacity 100ms ease-out;
display: -moz-box;
margin-bottom: 26px; /* 32 - 6 search form top "padding" */
-moz-box-align: center;
-moz-box-pack: center;
}
@ -60,7 +59,15 @@ input[type=button] {
#newtab-margin-undo-container {
display: -moz-box;
-moz-box-pack: center;
left: 6px;
position: absolute;
top: 6px;
z-index: 1;
}
#newtab-margin-undo-container:-moz-locale-dir(rtl) {
left: auto;
right: 6px;
}
#newtab-horizontal-margin {
@ -109,7 +116,7 @@ input[type=button] {
.newtab-cell {
display: -moz-box;
height: 180px;
margin: 16px 10px;
margin: 20px 10px;
width: 290px;
}
@ -143,7 +150,7 @@ input[type=button] {
/* TITLES */
.newtab-title {
bottom: -21px;
bottom: -26px;
font-size: 13px;
left: 0;
overflow: hidden;
@ -249,7 +256,7 @@ input[type=button] {
-moz-box-orient: horizontal;
-moz-box-align: center;
height: 44px; /* 32 + 6 logo top "padding" + 6 logo bottom "padding" */
margin: 0 20px 10px; /* bottom: 32 - 16 tiles top margin - 6 logo bottom "padding" */
margin: 26px 20px 10px; /* top: 32 - 6 search form top "padding", bottom: 32 - 16 tiles top margin - 6 logo bottom "padding" */
max-width: 600px; /* 2 * (290 cell width + 10 cell margin) */
}

View File

@ -5,10 +5,10 @@ const PRELOAD_PREF = "browser.newtab.preload";
gDirectorySource = "data:application/json," + JSON.stringify({
"en-US": [{
url: "http://organic.localhost/",
url: "http://example.com/organic",
type: "organic"
}, {
url: "http://sponsored.localhost/",
url: "http://localhost/sponsored",
type: "sponsored"
}]
});

View File

@ -497,6 +497,8 @@ function createExternalDropIframe() {
iframe.setAttribute("src", url);
iframe.style.width = "50px";
iframe.style.height = "50px";
iframe.style.position = "absolute";
iframe.style.zIndex = 50;
let margin = doc.getElementById("newtab-margin-top");
margin.appendChild(iframe);

View File

@ -132,7 +132,6 @@ browser.jar:
skin/classic/browser/newtab/controls.png (../shared/newtab/controls.png)
skin/classic/browser/newtab/controls@2x.png (../shared/newtab/controls@2x.png)
skin/classic/browser/newtab/controls.svg (../shared/newtab/controls.svg)
skin/classic/browser/newtab/texture.png (../shared/newtab/texture.png)
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png)
skin/classic/browser/places/bookmarksToolbar-menuPanel.png (places/bookmarksToolbar-menuPanel.png)

View File

@ -206,7 +206,6 @@ browser.jar:
skin/classic/browser/newtab/controls.png (../shared/newtab/controls.png)
skin/classic/browser/newtab/controls@2x.png (../shared/newtab/controls@2x.png)
skin/classic/browser/newtab/controls.svg (../shared/newtab/controls.svg)
skin/classic/browser/newtab/texture.png (../shared/newtab/texture.png)
skin/classic/browser/setDesktopBackground.css
skin/classic/browser/monitor.png
skin/classic/browser/monitor_16-10.png

View File

@ -15,7 +15,7 @@
/* Glyph Styles */
.glyphShape-style {
fill: #7a7a7a;
fill: #737373;
}
.glyphShape-style-hover-gear {

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -9,10 +9,13 @@
}
/* SCROLLBOX */
#newtab-scrollbox:not([page-disabled]),
#newtab-scrollbox:not([page-disabled]) #newtab-margin-bottom {
#newtab-scrollbox:not([page-disabled]) {
color: rgb(0,0,0);
background-image: url(chrome://browser/skin/newtab/texture.png);
background-color: #f9f9f9;
}
#newtab-scrollbox:not([page-disabled]) #newtab-margin-bottom {
background: inherit;
}
/* UNDO */
@ -74,12 +77,12 @@
/* CELLS */
.newtab-cell {
background-color: rgba(255,255,255,.2);
border-radius: 12px;
border-radius: 8px;
}
.newtab-cell:empty {
outline: 2px dashed #c1c1c1;
-moz-outline-radius: 12px;
-moz-outline-radius: 8px;
}
/* SITES */
@ -92,8 +95,8 @@
.newtab-cell:not([ignorehover]) > .newtab-site:hover,
.newtab-site[dragged] {
border: 2px solid #4a90e2;
box-shadow: 0 0 10px 3px #4cb1ff;
border: 2px solid white;
box-shadow: 0 0 6px 2px #4cb1ff;
margin: -2px;
}
@ -104,7 +107,7 @@
/* LINKS */
.newtab-link {
border-radius: 10px;
border-radius: 6px;
}
/* THUMBNAILS */
@ -131,7 +134,7 @@
/* Use a pseudo-element to overlay a gradient on the thumbnail */
.newtab-site[type=history]:not(:hover) .newtab-thumbnail:first-child::after {
background-image: linear-gradient(0deg, rgba(251, 251, 251, 0.8), rgba(251, 251, 251, 0) 50%);
background-image: linear-gradient(0deg, rgba(251, 251, 251, 0.8), rgba(251, 251, 251, 0) 33%);
border-radius: inherit;
bottom: 0;
content: "";
@ -144,7 +147,7 @@
/* TITLES */
.newtab-title {
color: #9b9b9b;
color: #737373;
}
.newtab-site:hover .newtab-title {
@ -175,12 +178,12 @@
.newtab-control-pin:hover,
.newtab-site[pinned] .newtab-control-pin:hover {
background-image: -moz-image-rect(url(chrome://browser/skin/newtab/controls.svg), 0, 128, 32, 96);
background-image: -moz-image-rect(url(chrome://browser/skin/newtab/controls.svg), 0, 160, 32, 128);
}
.newtab-control-pin:hover:active,
.newtab-site[pinned] .newtab-control-pin {
background-image: -moz-image-rect(url(chrome://browser/skin/newtab/controls.svg), 0, 160, 32, 128);
background-image: -moz-image-rect(url(chrome://browser/skin/newtab/controls.svg), 0, 128, 32, 96);
}
.newtab-control-block {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -155,7 +155,6 @@ browser.jar:
skin/classic/browser/newtab/controls.png (../shared/newtab/controls.png)
skin/classic/browser/newtab/controls@2x.png (../shared/newtab/controls@2x.png)
skin/classic/browser/newtab/controls.svg (../shared/newtab/controls.svg)
skin/classic/browser/newtab/texture.png (../shared/newtab/texture.png)
skin/classic/browser/places/places.css (places/places.css)
* skin/classic/browser/places/organizer.css (places/organizer.css)
skin/classic/browser/places/bookmark.png (places/bookmark.png)
@ -582,7 +581,6 @@ browser.jar:
skin/classic/aero/browser/newtab/controls.png (../shared/newtab/controls.png)
skin/classic/aero/browser/newtab/controls@2x.png (../shared/newtab/controls@2x.png)
skin/classic/aero/browser/newtab/controls.svg (../shared/newtab/controls.svg)
skin/classic/aero/browser/newtab/texture.png (../shared/newtab/texture.png)
* skin/classic/aero/browser/places/places.css (places/places-aero.css)
* skin/classic/aero/browser/places/organizer.css (places/organizer-aero.css)
skin/classic/aero/browser/places/bookmark.png (places/bookmark-aero.png)

View File

@ -11,7 +11,6 @@ support-files =
file_select_all_without_body.html
green.png
[test_CF_HTML_clipboard.html]
[test_bug200416.html]
[test_bug289384.html]
skip-if = os != "mac"
@ -19,7 +18,7 @@ skip-if = os != "mac"
[test_bug291780.html]
[test_bug316447.html]
[test_bug332636.html]
[test_bug332636.html^headers^]
support-files = test_bug332636.html^headers^
[test_bug372345.html]
skip-if = toolkit == 'android'
[test_bug404320.html]
@ -99,8 +98,10 @@ skip-if = os != "win"
[test_bug966552.html]
skip-if = os != "win"
[test_bug998188.html]
[test_CF_HTML_clipboard.html]
[test_contenteditable_focus.html]
[test_dom_input_event_on_htmleditor.html]
skip-if = android_version == "10" # bug 1054087
[test_keypress_untrusted_event.html]
[test_root_element_replacement.html]
[test_select_all_without_body.html]

View File

@ -186,7 +186,7 @@ public class FormAssistPopup extends RelativeLayout implements GeckoEventListene
sValidationTextLayoutNormal = new RelativeLayout.LayoutParams(mValidationMessageText.getLayoutParams());
sValidationTextLayoutNormal.setMargins(0, sValidationTextMarginTop, 0, 0);
sValidationTextLayoutInverted = new RelativeLayout.LayoutParams(sValidationTextLayoutNormal);
sValidationTextLayoutInverted = new RelativeLayout.LayoutParams((ViewGroup.MarginLayoutParams) sValidationTextLayoutNormal);
sValidationTextLayoutInverted.setMargins(0, 0, 0, 0);
mValidationMessageArrow = (ImageView) mValidationMessage.findViewById(R.id.validation_message_arrow);

View File

@ -24,12 +24,13 @@ import android.content.res.TypedArray;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class GeckoView extends LayerView
implements GeckoEventListener, ContextGetter {
implements ContextGetter {
private static final String DEFAULT_SHARED_PREFERENCES_FILE = "GeckoView";
private static final String LOGTAG = "GeckoView";
@ -37,6 +38,36 @@ public class GeckoView extends LayerView
private ChromeDelegate mChromeDelegate;
private ContentDelegate mContentDelegate;
private final GeckoEventListener mEventListener = new GeckoEventListener() {
@Override
public void handleMessage(final String event, final JSONObject message) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
try {
if (event.equals("Gecko:Ready")) {
handleReady(message);
} else if (event.equals("Content:StateChange")) {
handleStateChange(message);
} else if (event.equals("Content:LoadError")) {
handleLoadError(message);
} else if (event.equals("Content:PageShow")) {
handlePageShow(message);
} else if (event.equals("DOMTitleChanged")) {
handleTitleChanged(message);
} else if (event.equals("Link:Favicon")) {
handleLinkFavicon(message);
} else if (event.equals("Prompt:Show") || event.equals("Prompt:ShowTop")) {
handlePrompt(message);
}
} catch (Exception e) {
Log.e(LOGTAG, "handleMessage threw for " + event, e);
}
}
});
}
};
public GeckoView(Context context) {
super(context);
init(context, null, true);
@ -93,7 +124,7 @@ public class GeckoView extends LayerView
tabs.attachToContext(context);
}
EventDispatcher.getInstance().registerGeckoThreadListener(this,
EventDispatcher.getInstance().registerGeckoThreadListener(mEventListener,
"Gecko:Ready",
"Content:StateChange",
"Content:LoadError",
@ -179,36 +210,6 @@ public class GeckoView extends LayerView
return Collections.unmodifiableList(browsers);
}
/**
* Not part of the public API. Ignore.
*/
public void handleMessage(final String event, final JSONObject message) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
try {
if (event.equals("Gecko:Ready")) {
GeckoView.this.handleReady(message);
} else if (event.equals("Content:StateChange")) {
GeckoView.this.handleStateChange(message);
} else if (event.equals("Content:LoadError")) {
GeckoView.this.handleLoadError(message);
} else if (event.equals("Content:PageShow")) {
GeckoView.this.handlePageShow(message);
} else if (event.equals("DOMTitleChanged")) {
GeckoView.this.handleTitleChanged(message);
} else if (event.equals("Link:Favicon")) {
GeckoView.this.handleLinkFavicon(message);
} else if (event.equals("Prompt:Show") || event.equals("Prompt:ShowTop")) {
GeckoView.this.handlePrompt(message);
}
} catch (Exception e) {
Log.w(LOGTAG, "handleMessage threw for " + event, e);
}
}
});
}
private void connectToGecko() {
GeckoThread.setLaunchState(GeckoThread.LaunchState.GeckoRunning);
Tab selectedTab = Tabs.getInstance().getSelectedTab();

View File

@ -15,7 +15,7 @@ ac_add_options --enable-elf-hack
ANDROID_NDK_VERSION="r8e"
ANDROID_NDK_VERSION_32BIT="r8c"
ANDROID_SDK_VERSION="17"
ANDROID_SDK_VERSION="20"
# Build Fennec
ac_add_options --enable-application=mobile/android

View File

@ -6,8 +6,8 @@
"filename": "android-ndk.tar.bz2"
},
{
"size": 190380996,
"digest": "9e2da00cd4783e10a52c144d2dc9de71b9ab9772f26c9a4e36b9a744e05edd1d13c212b976a3d2f6cbcb86bce00b78fd262b47f8573eff2ab9db0ed2d4cfb8c5",
"size": 207966812,
"digest": "9f6d50e5e67e6a6784dea3b5573178a869b017d2d0c7588af9eb53fdd23c7d1bd6f775f07a9ad1510ba36bf1608d21baa4e26e92afe61e190429870a6371b97d",
"algorithm": "sha512",
"filename": "android-sdk.tar.xz"
},

View File

@ -6,8 +6,8 @@
"filename": "android-ndk.tar.bz2"
},
{
"size": 190380996,
"digest": "9e2da00cd4783e10a52c144d2dc9de71b9ab9772f26c9a4e36b9a744e05edd1d13c212b976a3d2f6cbcb86bce00b78fd262b47f8573eff2ab9db0ed2d4cfb8c5",
"size": 207966812,
"digest": "9f6d50e5e67e6a6784dea3b5573178a869b017d2d0c7588af9eb53fdd23c7d1bd6f775f07a9ad1510ba36bf1608d21baa4e26e92afe61e190429870a6371b97d",
"algorithm": "sha512",
"filename": "android-sdk.tar.xz"
},

View File

@ -6,8 +6,8 @@
"filename": "android-ndk.tar.bz2"
},
{
"size": 190380996,
"digest": "9e2da00cd4783e10a52c144d2dc9de71b9ab9772f26c9a4e36b9a744e05edd1d13c212b976a3d2f6cbcb86bce00b78fd262b47f8573eff2ab9db0ed2d4cfb8c5",
"size": 207966812,
"digest": "9f6d50e5e67e6a6784dea3b5573178a869b017d2d0c7588af9eb53fdd23c7d1bd6f775f07a9ad1510ba36bf1608d21baa4e26e92afe61e190429870a6371b97d",
"algorithm": "sha512",
"filename": "android-sdk.tar.xz"
},

View File

@ -68,9 +68,7 @@ let RequestService = {
* task asynchronously. For example:
* RequestService.addListener({
* onRequest: function* (aMessage, aData) {
* let deferred = Promise.defer();
* setTimeout(deferred.resolve, 2000);
* yield deferred.resolve;
* yield new Promise(resolve => setTimeout(resolve, 2000));
* return { response: "bar" };
* }
* }, "Demo:Request");

View File

@ -20,11 +20,11 @@ public class Constants {
public static final String PRESEARCH_FRAGMENT = "org.mozilla.search.PRESEARCH_FRAGMENT";
public static final String SEARCH_FRAGMENT = "org.mozilla.search.SEARCH_FRAGMENT";
public static final String YAHOO_WEB_SEARCH_BASE_URL = "https://search.yahoo.com/search?p=";
public static final String YAHOO_WEB_SEARCH_RESULTS_FILTER = "//search.yahoo.com";
public static final String INTENT_START_SEARCH = "org.mozilla.search.intent.START_SEARCH";
public static final String INTENT_START_SEARCH_QUERY_EXTRA = "org.mozilla.search.intent.START_SEARCH_QUERY_EXTRA";
public static final int SUGGESTION_MAX = 5;
public static final String ABOUT_BLANK = "about:blank";
// The default search engine for new users. This should match one of
// the SearchEngineFactory.Engine enum values.
public static final String DEFAULT_SEARCH_ENGINE = "YAHOO";
}

View File

@ -4,6 +4,7 @@
package org.mozilla.search;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
@ -21,21 +22,18 @@ import android.widget.ProgressBar;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.search.providers.SearchEngine;
import org.mozilla.search.providers.SearchEngineManager;
public class PostSearchFragment extends Fragment {
private static final String LOGTAG = "PostSearchFragment";
private static final String ABOUT_BLANK = "about:blank";
private static final String LOG_TAG = "PostSearchFragment";
private ProgressBar progressBar;
private SearchEngineManager searchEngineManager;
private WebView webview;
private static final String HIDE_BANNER_SCRIPT = "javascript:(function(){var tag=document.createElement('style');" +
"tag.type='text/css';document.getElementsByTagName('head')[0].appendChild(tag);tag.innerText='#nav,#header{display:none}'})();";
public PostSearchFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
@ -61,32 +59,34 @@ public class PostSearchFragment extends Fragment {
progressBar = null;
}
/**
* Test if a given URL should be opened in an external browser.
* <p>
* Search results pages will be shown in the embedded view. Other pages are
* opened in external browsers.
*
* @param url to test.
* @return true if <code>url</code> should be sent to Fennec.
*/
private boolean shouldSendToBrowser(String url) {
return !(TextUtils.equals(ABOUT_BLANK, url) || url.contains(Constants.YAHOO_WEB_SEARCH_RESULTS_FILTER));
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
searchEngineManager = new SearchEngineManager(activity);
}
public void startSearch(String query) {
setUrl(Constants.YAHOO_WEB_SEARCH_BASE_URL + Uri.encode(query));
@Override
public void onDetach() {
super.onDetach();
searchEngineManager.destroy();
searchEngineManager = null;
}
private void setUrl(String url) {
// Only load URLs if they're different than what's already
// loaded in the webview.
if (!TextUtils.equals(webview.getUrl(), url)) {
webview.loadUrl(ABOUT_BLANK);
webview.loadUrl(url);
}
public void startSearch(final String query) {
searchEngineManager.getEngine(new SearchEngineManager.SearchEngineCallback() {
@Override
public void execute(SearchEngine engine) {
final String url = engine.resultsUriForQuery(query);
// Only load urls if the url is different than the webview's current url.
if (!TextUtils.equals(webview.getUrl(), url)) {
webview.loadUrl(Constants.ABOUT_BLANK);
webview.loadUrl(url);
}
}
});
}
/**
* A custom WebViewClient that intercepts every page load. This allows
* us to decide whether to load the url here, or send it to Android
@ -95,18 +95,29 @@ public class PostSearchFragment extends Fragment {
private class LinkInterceptingClient extends WebViewClient {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
if (shouldSendToBrowser(url)) {
view.stopLoading();
public void onPageStarted(WebView view, final String url, Bitmap favicon) {
searchEngineManager.getEngine(new SearchEngineManager.SearchEngineCallback() {
@Override
public void execute(SearchEngine engine) {
// We keep URLs in the webview that are either about:blank or a search engine result page.
if (TextUtils.equals(url, Constants.ABOUT_BLANK) || engine.isSearchResultsPage(url)) {
// Keeping the URL in the webview is a noop.
return;
}
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL,
TelemetryContract.Method.CONTENT, "search-result");
webview.stopLoading();
final Intent i = new Intent(Intent.ACTION_VIEW);
i.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.BROWSER_INTENT_CLASS_NAME);
i.setData(Uri.parse(url));
startActivity(i);
}
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL,
TelemetryContract.Method.CONTENT, "search-result");
final Intent i = new Intent(Intent.ACTION_VIEW);
// This sends the URL directly to fennec, rather than to Android.
i.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.BROWSER_INTENT_CLASS_NAME);
i.setData(Uri.parse(url));
startActivity(i);
}
});
}
}
@ -121,9 +132,14 @@ public class PostSearchFragment extends Fragment {
private class ChromeClient extends WebChromeClient {
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
view.loadUrl(HIDE_BANNER_SCRIPT);
public void onReceivedTitle(final WebView view, String title) {
searchEngineManager.getEngine(new SearchEngineManager.SearchEngineCallback() {
@Override
public void execute(SearchEngine engine) {
view.loadUrl(engine.getInjectableJs());
}
});
}
@Override

View File

@ -6,14 +6,18 @@ package org.mozilla.search;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.db.BrowserContract;
@ -28,15 +32,21 @@ import org.mozilla.gecko.db.BrowserContract;
*
* TODO: Change this to PreferenceFragment when we stop supporting devices older than SDK 11.
*/
public class SearchPreferenceActivity extends PreferenceActivity {
public class SearchPreferenceActivity extends PreferenceActivity
implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String LOGTAG = "SearchPreferenceActivity";
private static final String LOG_TAG = "SearchPreferenceActivity";
private static final String CLEAR_SEARCH_HISTORY_BUTTON_KEY = "clear_search_history_button";
public static final String PREF_CLEAR_HISTORY_KEY = "search.not_a_preference.clear_history";
public static final String PREF_SEARCH_ENGINE_KEY = "search.engines.default";
@Override
@SuppressWarnings("deprecation")
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getPreferenceManager().setSharedPreferencesName(GeckoSharedPrefs.APP_PREFS_NAME);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(true);
@ -44,6 +54,18 @@ public class SearchPreferenceActivity extends PreferenceActivity {
}
}
@Override
protected void onResume() {
super.onResume();
GeckoSharedPrefs.forApp(this).registerOnSharedPreferenceChangeListener(this);
}
@Override
protected void onPause() {
super.onPause();
GeckoSharedPrefs.forApp(this).unregisterOnSharedPreferenceChangeListener(this);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
@ -54,7 +76,8 @@ public class SearchPreferenceActivity extends PreferenceActivity {
private void setupPrefsScreen() {
addPreferencesFromResource(R.xml.search_preferences);
final Preference clearHistoryButton = findPreference(CLEAR_SEARCH_HISTORY_BUTTON_KEY);
// Attach click listener to clear history button.
final Preference clearHistoryButton = findPreference(PREF_CLEAR_HISTORY_KEY);
clearHistoryButton.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
@ -67,11 +90,18 @@ public class SearchPreferenceActivity extends PreferenceActivity {
clearHistory();
}
});
dialogBuilder.setMessage(R.string.search_pref_clear_history_dialog_message);
dialogBuilder.setMessage(R.string.pref_clearHistory_dialogMessage);
dialogBuilder.show();
return false;
}
});
// Set summary for search engine picker.
final ListPreference searchEnginePref = (ListPreference) findPreference(PREF_SEARCH_ENGINE_KEY);
if (searchEnginePref.getValue() == null) {
searchEnginePref.setValue(Constants.DEFAULT_SEARCH_ENGINE);
}
searchEnginePref.setSummary(searchEnginePref.getEntry());
}
private void clearHistory() {
@ -88,12 +118,24 @@ public class SearchPreferenceActivity extends PreferenceActivity {
if (success) {
getContentResolver().notifyChange(BrowserContract.SearchHistory.CONTENT_URI, null);
Toast.makeText(SearchPreferenceActivity.this, SearchPreferenceActivity.this.getResources()
.getString(R.string.search_pref_clear_history_confirmation), Toast.LENGTH_SHORT).show();
.getString(R.string.pref_clearHistory_confirmation), Toast.LENGTH_SHORT).show();
} else {
Log.e(LOGTAG, "Error clearing search history.");
Log.e(LOG_TAG, "Error clearing search history.");
}
}
};
clearHistoryTask.execute();
}
/**
* Update summaries when the value of a shared preference changes.
*/
@Override
@SuppressWarnings("deprecation")
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (TextUtils.equals(PREF_SEARCH_ENGINE_KEY, key)) {
final ListPreference searchEnginePref = (ListPreference) findPreference(PREF_SEARCH_ENGINE_KEY);
searchEnginePref.setSummary(searchEnginePref.getEntry());
}
}
}

View File

@ -14,6 +14,7 @@ import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -26,16 +27,18 @@ import org.mozilla.search.AcceptsSearchQuery;
import org.mozilla.search.AcceptsSearchQuery.SuggestionAnimation;
import org.mozilla.search.Constants;
import org.mozilla.search.R;
import org.mozilla.search.providers.SearchEngine;
import org.mozilla.search.providers.SearchEngineManager;
import java.util.ArrayList;
import java.util.List;
/**
* A fragment to show search suggestions.
* <p/>
* TODO: Add more search providers (other than the dictionary)
*/
public class SuggestionsFragment extends Fragment {
public class SuggestionsFragment extends Fragment implements SearchEngineManager.SearchEngineCallback {
private static final String LOG_TAG = "SuggestionsFragment";
private static final int LOADER_ID_SUGGESTION = 0;
private static final String KEY_SEARCH_TERM = "search_term";
@ -46,7 +49,14 @@ public class SuggestionsFragment extends Fragment {
// Color of search term match in search suggestion
private static final int SUGGESTION_HIGHLIGHT_COLOR = 0xFF999999;
public static final String GECKO_SEARCH_TERMS_URL_PARAM = "__searchTerms__";
private AcceptsSearchQuery searchListener;
private SearchEngineManager searchEngineManager;
// Suggest client gets setup outside of the normal fragment lifecycle, therefore
// clients should ensure that this isn't null before using it.
private SuggestClient suggestClient;
private SuggestionLoaderCallbacks suggestionLoaderCallbacks;
@ -68,14 +78,20 @@ public class SuggestionsFragment extends Fragment {
throw new ClassCastException(activity.toString() + " must implement AcceptsSearchQuery.");
}
// TODO: Don't hard-code this template string (bug 1039758)
final String template = "https://search.yahoo.com/sugg/ff?" +
"output=fxjson&appid=ffm&command=__searchTerms__&nresults=" + Constants.SUGGESTION_MAX;
suggestClient = new SuggestClient(activity, template, SUGGESTION_TIMEOUT, Constants.SUGGESTION_MAX);
suggestionLoaderCallbacks = new SuggestionLoaderCallbacks();
autoCompleteAdapter = new AutoCompleteAdapter(activity);
searchEngineManager = new SearchEngineManager(activity);
searchEngineManager.setChangeCallback(this);
// Initialize the suggest client. This may happen asynchronously, so any clients should
// still perform a null check.
searchEngineManager.getEngine(new SearchEngineManager.SearchEngineCallback() {
@Override
public void execute(SearchEngine engine) {
suggestClient = new SuggestClient(getActivity(), engine.getSuggestionTemplate(GECKO_SEARCH_TERMS_URL_PARAM),
SUGGESTION_TIMEOUT, Constants.SUGGESTION_MAX);
}
});
}
@Override
@ -83,9 +99,11 @@ public class SuggestionsFragment extends Fragment {
super.onDetach();
searchListener = null;
suggestClient = null;
suggestionLoaderCallbacks = null;
autoCompleteAdapter = null;
searchEngineManager.destroy();
searchEngineManager = null;
suggestClient = null;
}
@Override
@ -129,10 +147,25 @@ public class SuggestionsFragment extends Fragment {
}
}
@Override
public void execute(SearchEngine engine) {
suggestClient = new SuggestClient(getActivity(), engine.getSuggestionTemplate(GECKO_SEARCH_TERMS_URL_PARAM),
SUGGESTION_TIMEOUT, Constants.SUGGESTION_MAX);
}
public void loadSuggestions(String query) {
final Bundle args = new Bundle();
args.putString(KEY_SEARCH_TERM, query);
getLoaderManager().restartLoader(LOADER_ID_SUGGESTION, args, suggestionLoaderCallbacks);
final LoaderManager loaderManager = getLoaderManager();
// Ensure that we don't try to restart a loader that doesn't exist. This becomes
// an issue because SuggestionLoaderCallbacks.onCreateLoader can return null
// as a loader if we don't have a suggestClient available yet.
if (loaderManager.getLoader(LOADER_ID_SUGGESTION) == null) {
loaderManager.initLoader(LOADER_ID_SUGGESTION, args, suggestionLoaderCallbacks);
} else {
loaderManager.restartLoader(LOADER_ID_SUGGESTION, args, suggestionLoaderCallbacks);
}
}
public static class Suggestion {
@ -159,7 +192,13 @@ public class SuggestionsFragment extends Fragment {
private class SuggestionLoaderCallbacks implements LoaderManager.LoaderCallbacks<List<Suggestion>> {
@Override
public Loader<List<Suggestion>> onCreateLoader(int id, Bundle args) {
return new SuggestionAsyncLoader(getActivity(), suggestClient, args.getString(KEY_SEARCH_TERM));
// We drop the user's search if suggestclient isn't ready. This happens if the
// user is really fast and starts typing before we can read shared prefs.
if (suggestClient != null) {
return new SuggestionAsyncLoader(getActivity(), suggestClient, args.getString(KEY_SEARCH_TERM));
}
Log.e(LOG_TAG, "Autocomplete setup failed; suggestClient not ready yet.");
return null;
}
@Override

View File

@ -0,0 +1,43 @@
/* 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.search.providers;
import android.net.Uri;
public class BingSearchEngine extends SearchEngine {
private static final String HIDE_BANNER_CSS = "#mHeader{display:none}#contentWrapper{margin-top:0}";
private static final Uri RESULTS_URI = Uri.parse("https://www.bing.com/search");
private static final String RESULTS_URI_QUERY_PARAM = "q";
private static final Uri SUGGEST_URI = Uri.parse("http://api.bing.com/osjson.aspx");
private static final String SUGGEST_URI_QUERY_PARAM = "query";
@Override
public String getInjectableCss() {
return HIDE_BANNER_CSS;
}
@Override
protected Uri getResultsUri() {
return RESULTS_URI;
}
@Override
protected Uri getSuggestionUri() {
return SUGGEST_URI;
}
@Override
protected String getSuggestionQueryParam() {
return SUGGEST_URI_QUERY_PARAM;
}
@Override
protected String getResultsQueryParam() {
return RESULTS_URI_QUERY_PARAM;
}
}

View File

@ -0,0 +1,44 @@
/* 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.search.providers;
import android.net.Uri;
public class GoogleSearchEngine extends SearchEngine {
private static final String HIDE_BANNER_CSS = "#sfcnt,#top_nav{display:none}";
private static final Uri RESULTS_URI = Uri.parse("https://www.google.com/search");
private static final String RESULTS_URI_QUERY_PARAM = "q";
private static final Uri SUGGEST_URI = Uri.parse("https://www.google.com/complete/search?client=firefox");
private static final String SUGGEST_URI_QUERY_PARAM = "q";
@Override
public String getInjectableCss() {
return HIDE_BANNER_CSS;
}
@Override
protected Uri getResultsUri() {
return RESULTS_URI;
}
@Override
protected Uri getSuggestionUri() {
return SUGGEST_URI;
}
@Override
protected String getSuggestionQueryParam() {
return SUGGEST_URI_QUERY_PARAM;
}
@Override
protected String getResultsQueryParam() {
return RESULTS_URI_QUERY_PARAM;
}
}

View File

@ -0,0 +1,102 @@
/* 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.search.providers;
import android.net.Uri;
/**
* Extend this class to add a new search engine to
* the search activity.
*/
public abstract class SearchEngine {
// Boilerplate bookmarklet-style JS for injecting CSS into the
// head of a web page. The actual CSS is inserted at `%s`.
private static final String STYLE_INJECTION_SCRIPT =
"javascript:(function(){" +
"var tag=document.createElement('style');" +
"tag.type='text/css';" +
"document.getElementsByTagName('head')[0].appendChild(tag);" +
"tag.innerText='%s'})();";
private String suggestionTemplate;
/**
* Retrieve a JS snippet, in bookmarklet style, that can be used
* to modify the results page.
*/
public String getInjectableJs() {
return String.format(STYLE_INJECTION_SCRIPT, getInjectableCss());
}
/**
* Determine whether a particular url belongs to this search engine. If not,
* the url will be sent to Fennec.
*/
final public boolean isSearchResultsPage(String url) {
return getResultsUri().getAuthority().equalsIgnoreCase(Uri.parse(url).getAuthority());
}
/**
* Create a uri string that can be used to fetch suggestions.
*
* @param query The user's partial query. This method will handle url escaping.
*/
final public String suggestUriForQuery(String query) {
return getSuggestionUri().buildUpon().appendQueryParameter(getSuggestionQueryParam(), query).build().toString();
}
/**
* Create a uri strung that can be used to fetch the results page.
*
* @param query The user's query. This method will handle url escaping.
*/
final public String resultsUriForQuery(String query) {
return getResultsUri().buildUpon().appendQueryParameter(getResultsQueryParam(), query).build().toString();
}
/**
* Create a suggestion uri that can be used by SuggestClient
*/
final public String getSuggestionTemplate(String placeholder) {
if (suggestionTemplate == null) {
suggestionTemplate = suggestUriForQuery(placeholder);
}
return suggestionTemplate;
}
/**
* Retrieve a snippet of CSS that can be used to modify the appearance
* of the search results page. Currently this is used to hide
* the web site's search bar and facet bar.
*/
protected abstract String getInjectableCss();
/**
* Retrieve the base Uri that should be used when retrieving
* the results page. This may include params that do not vary --
* for example, the user's locale.
*/
protected abstract Uri getResultsUri();
/**
* Retrieve the base Uri that should be used when fetching
* suggestions. This may include params that do not vary --
* for example, the user's locale.
*/
protected abstract Uri getSuggestionUri();
/**
* Retrieve the uri query param for the user's partial query.
* Used for suggestions.
*/
protected abstract String getSuggestionQueryParam();
/**
* Retrieve the uri query param that holds the user's final query.
* Used for results.
*/
protected abstract String getResultsQueryParam();
}

View File

@ -0,0 +1,135 @@
/* 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.search.providers;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.text.TextUtils;
import android.util.Log;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.search.Constants;
import org.mozilla.search.SearchPreferenceActivity;
public class SearchEngineManager implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String LOG_TAG = "SearchEngineManager";
private Context context;
private SearchEngineCallback changeCallback;
private SearchEngine engine;
// Add new engines to this enum. Also update createInstance, the factory method below.
public static enum Engine {
BING,
GOOGLE,
YAHOO
}
public static interface SearchEngineCallback {
public void execute(SearchEngine engine);
}
public SearchEngineManager(Context context) {
this.context = context;
GeckoSharedPrefs.forApp(context).registerOnSharedPreferenceChangeListener(this);
}
public void setChangeCallback(SearchEngineCallback changeCallback) {
this.changeCallback = changeCallback;
}
/**
* Perform an action with the user's default search engine.
*
* @param callback The callback to be used with the user's default search engine. The call
* may be sync or async; if the call is async, it will be called on the
* ui thread.
*/
public void getEngine(SearchEngineCallback callback) {
if (engine != null) {
callback.execute(engine);
} else {
getEngineFromPrefs(callback);
}
}
public void destroy() {
GeckoSharedPrefs.forApp(context).unregisterOnSharedPreferenceChangeListener(this);
context = null;
changeCallback = null;
engine = null;
}
/**
* Manually lookup the current search engine.
*
* @param callback a SearchEngineCallback to be called after successfully looking
* up the search engine. This will run on the UI thread.
*/
private void getEngineFromPrefs(final SearchEngineCallback callback) {
final AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
return GeckoSharedPrefs.forApp(context).getString(SearchPreferenceActivity.PREF_SEARCH_ENGINE_KEY, null);
}
@Override
protected void onPostExecute(String engineName) {
updateEngine(engineName);
callback.execute(engine);
}
};
task.execute();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (TextUtils.equals(SearchPreferenceActivity.PREF_SEARCH_ENGINE_KEY, key)) {
updateEngine(sharedPreferences.getString(key, null));
if (changeCallback != null) {
changeCallback.execute(engine);
}
}
}
/**
* Notify the searchEngineChangeListener that the default search engine has changed.
*
* @param engineName The name of the new search engine. This should be a member
* of SearchEngineFactory.Engine. If null, then it will use the
* default search engine.
* @return true if this caused the engine to be changed.
*/
private void updateEngine(String engineName) {
if (TextUtils.isEmpty(engineName)) {
engineName = Constants.DEFAULT_SEARCH_ENGINE;
}
try {
engine = createEngine(engineName);
} catch (IllegalArgumentException e) {
Log.e(LOG_TAG, "Search engine not found for " + engineName + " reverting to default engine.", e);
engine = createEngine(Constants.DEFAULT_SEARCH_ENGINE);
}
}
private static SearchEngine createEngine(String engineName) {
switch (Engine.valueOf(engineName)) {
case BING:
return new BingSearchEngine();
case GOOGLE:
return new GoogleSearchEngine();
case YAHOO:
return new YahooSearchEngine();
}
// The return statement is unreachable since Engine.valueOf will throw
// IllegalArgumentException if engineName cannot be resolved.
return null;
}
}

View File

@ -0,0 +1,47 @@
/* 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.search.providers;
import android.net.Uri;
import org.mozilla.search.Constants;
public class YahooSearchEngine extends SearchEngine {
private static final String HIDE_BANNER_CSS = "#nav,#header{display:none}";
private static final Uri RESULTS_URI = Uri.parse("https://search.yahoo.com/search");
private static final String RESULTS_URI_QUERY_PARAM = "p";
private static final Uri SUGGEST_URI = Uri.parse(
"https://search.yahoo.com/sugg/ff?output=fxjson&appid=ffm&nresults=" + Constants.SUGGESTION_MAX);
private static final String SUGGEST_URI_QUERY_PARAM = "command";
@Override
public String getInjectableCss() {
return HIDE_BANNER_CSS;
}
@Override
protected Uri getResultsUri() {
return RESULTS_URI;
}
@Override
protected Uri getSuggestionUri() {
return SUGGEST_URI;
}
@Override
protected String getSuggestionQueryParam() {
return SUGGEST_URI_QUERY_PARAM;
}
@Override
protected String getResultsQueryParam() {
return RESULTS_URI_QUERY_PARAM;
}
}

View File

@ -4,10 +4,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_focused="true"
android:drawable="@drawable/edit_text_focused"/>
<item android:drawable="@android:color/transparent"/>
<item android:state_focused="true" android:drawable="@drawable/edit_text_focused"/>
<item android:drawable="@drawable/edit_text_default"/>
</selector>

View File

@ -0,0 +1,22 @@
<!-- 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/. -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Make sure the border only appears at the bottom of the background -->
<item
android:top="-1dp"
android:right="-1dp"
android:left="-1dp">
<shape>
<!-- Padding creates vertical space between the text and the underline -->
<padding
android:top="@dimen/search_bar_padding_y"
android:bottom="@dimen/search_bar_padding_y"/>
<solid android:color="@android:color/transparent"/>
<stroke android:width="1dp" android:color="@color/edit_text_default"/>
</shape>
</item>
</layer-list>

View File

@ -4,14 +4,12 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Make sure the border only appears at the bottom of the background -->
<item
android:top="-2dp"
android:right="-2dp"
android:left="-2dp">
<shape>
<padding
android:top="10dp"
android:bottom="10dp"/>
<solid android:color="@android:color/transparent"/>
<stroke android:width="2dp" android:color="@color/highlight_orange"/>
</shape>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="pref_searchProvider_entries">
<item>@string/pref_searchProvider_bing</item>
<item>@string/pref_searchProvider_google</item>
<item>@string/pref_searchProvider_yahoo</item>
</string-array>
<string-array name="pref_searchProvider_values">
<item>BING</item>
<item>GOOGLE</item>
<item>YAHOO</item>
</string-array>
</resources>

View File

@ -8,6 +8,8 @@
<color name="highlight_orange">#FF9500</color>
<color name="edit_text_default">#AFB1B3</color>
<!-- card colors -->
<color name="card_background">#ffffff</color>
<color name="card_background_pressed">#DCDCE1</color>

View File

@ -4,6 +4,13 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<Preference
android:key="clear_search_history_button"
android:title="@string/search_pref_clear_history_title"/>
android:key="search.not_a_preference.clear_history"
android:title="@string/pref_clearHistory_title"/>
<ListPreference
android:key="search.engines.default"
android:title="@string/pref_searchProvider_title"
android:dialogTitle="@string/pref_searchProvider_title"
android:entries="@array/pref_searchProvider_entries"
android:entryValues="@array/pref_searchProvider_values" />
</PreferenceScreen>

View File

@ -14,6 +14,11 @@ search_activity_sources = [
'java/org/mozilla/search/MainActivity.java',
'java/org/mozilla/search/PostSearchFragment.java',
'java/org/mozilla/search/PreSearchFragment.java',
'java/org/mozilla/search/providers/BingSearchEngine.java',
'java/org/mozilla/search/providers/GoogleSearchEngine.java',
'java/org/mozilla/search/providers/SearchEngine.java',
'java/org/mozilla/search/providers/SearchEngineManager.java',
'java/org/mozilla/search/providers/YahooSearchEngine.java',
'java/org/mozilla/search/SearchPreferenceActivity.java',
'java/org/mozilla/search/SearchWidget.java',
]

View File

@ -10,10 +10,17 @@
<!ENTITY search_plus_content_description 'Add to search bar'>
<!ENTITY search_pref_title 'Settings'>
<!ENTITY search_pref_clear_history_confirmation 'History cleared'>
<!ENTITY search_pref_clear_history_dialog_message 'Delete all search history from this device?'>
<!ENTITY search_pref_clear_history_title 'Clear search history'>
<!ENTITY search_pref_button_content_description 'Settings'>
<!ENTITY pref_clearHistory_confirmation 'History cleared'>
<!ENTITY pref_clearHistory_dialogMessage 'Delete all search history from this device?'>
<!ENTITY pref_clearHistory_title 'Clear search history'>
<!ENTITY pref_searchProvider_title 'Search engine'>
<!ENTITY pref_searchProvider_bing 'Bing'>
<!ENTITY pref_searchProvider_google 'Google'>
<!ENTITY pref_searchProvider_yahoo 'Yahoo'>
<!ENTITY search_widget_button_label 'Search'>

View File

@ -4,10 +4,17 @@
<string name="search_for_something">&search_for_something;</string>
<string name="search_pref_title">&search_pref_title;</string>
<string name="search_pref_clear_history_confirmation">&search_pref_clear_history_confirmation;</string>
<string name="search_pref_clear_history_dialog_message">&search_pref_clear_history_dialog_message;</string>
<string name="search_pref_clear_history_title">&search_pref_clear_history_title;</string>
<string name="search_pref_button_content_description">&search_pref_button_content_description;</string>
<string name="pref_clearHistory_confirmation">&pref_clearHistory_confirmation;</string>
<string name="pref_clearHistory_dialogMessage">&pref_clearHistory_dialogMessage;</string>
<string name="pref_clearHistory_title">&pref_clearHistory_title;</string>
<string name="pref_searchProvider_title">&pref_searchProvider_title;</string>
<string name="pref_searchProvider_bing">&pref_searchProvider_bing;</string>
<string name="pref_searchProvider_google">&pref_searchProvider_google;</string>
<string name="pref_searchProvider_yahoo">&pref_searchProvider_yahoo;</string>
<string name="search_widget_name">&search_app_name;</string>
<string name="search_widget_button_label">&search_widget_button_label;</string>

View File

@ -156,7 +156,11 @@ let DirectoryLinksProvider = {
*/
_extractSite: function DirectoryLinksProvider_extractSite(url) {
let linkURI = Services.io.newURI(url, null, null);
return Services.eTLD.getBaseDomain(linkURI);
try {
return Services.eTLD.getBaseDomain(linkURI);
}
catch(ex) {}
return linkURI.asciiHost;
},
_fetchAndCacheLinks: function DirectoryLinksProvider_fetchAndCacheLinks(uri) {

View File

@ -233,7 +233,7 @@ add_task(function test_fetchAndCacheLinks_malformedURI() {
add_task(function test_fetchAndCacheLinks_unknownHost() {
yield DirectoryLinksProvider.init();
yield cleanJsonFile();
let nonExistentServer = "http://nosuchhost.localhost";
let nonExistentServer = "http://localhost:56789/";
try {
yield DirectoryLinksProvider._fetchAndCacheLinks(nonExistentServer);
do_throw("BAD URIs should fail");
@ -314,7 +314,7 @@ add_task(function test_DirectoryLinksProvider__prefObserver_url() {
// tests these 2 things:
// 1. _linksURL is properly set after the pref change
// 2. invalid source url is correctly handled
let exampleUrl = 'http://nosuchhost.localhost/bad';
let exampleUrl = 'http://localhost:56789/bad';
yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, exampleUrl);
do_check_eq(DirectoryLinksProvider._linksURL, exampleUrl);
@ -503,6 +503,8 @@ add_task(function test_DirectoryLinksProvider_getEnhancedLink() {
// Undefined for not enhanced
checkEnhanced("http://example.org", undefined);
checkEnhanced("http://localhost", undefined);
checkEnhanced("http://127.0.0.1", undefined);
// Make sure old data is not cached
data = {"en-US": [