mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 12:37:37 +00:00
Merge m-c to inbound
This commit is contained in:
commit
cd6c2201e2
@ -12,7 +12,7 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8e21d0a5cdac94f05e9c3623fa3b9ad579ba2967"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="80d6405725788327102cab36e8d8c017cf25fb23"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
|
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
</project>
|
</project>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e21d0a5cdac94f05e9c3623fa3b9ad579ba2967"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="80d6405725788327102cab36e8d8c017cf25fb23"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8e21d0a5cdac94f05e9c3623fa3b9ad579ba2967"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="80d6405725788327102cab36e8d8c017cf25fb23"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
|
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"revision": "823616f0af83eca32bceb0367a7a221f8b187110",
|
"revision": "b2b0a8234336f7004812bf27e4053957cecad492",
|
||||||
"repo_path": "/integration/gaia-central"
|
"repo_path": "/integration/gaia-central"
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8e21d0a5cdac94f05e9c3623fa3b9ad579ba2967"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="80d6405725788327102cab36e8d8c017cf25fb23"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8e21d0a5cdac94f05e9c3623fa3b9ad579ba2967"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="80d6405725788327102cab36e8d8c017cf25fb23"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8e21d0a5cdac94f05e9c3623fa3b9ad579ba2967"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="80d6405725788327102cab36e8d8c017cf25fb23"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8e21d0a5cdac94f05e9c3623fa3b9ad579ba2967"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="80d6405725788327102cab36e8d8c017cf25fb23"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
</project>
|
</project>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e21d0a5cdac94f05e9c3623fa3b9ad579ba2967"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="80d6405725788327102cab36e8d8c017cf25fb23"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8e21d0a5cdac94f05e9c3623fa3b9ad579ba2967"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="80d6405725788327102cab36e8d8c017cf25fb23"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||||
|
@ -592,6 +592,9 @@
|
|||||||
cui-areatype="toolbar"
|
cui-areatype="toolbar"
|
||||||
tooltiptext="&closeTab.label;"/>
|
tooltiptext="&closeTab.label;"/>
|
||||||
|
|
||||||
|
#ifdef XP_WIN
|
||||||
|
<hbox id="private-browsing-indicator" skipintoolbarset="true" ordinal="1000"/>
|
||||||
|
#endif
|
||||||
#ifdef CAN_DRAW_IN_TITLEBAR
|
#ifdef CAN_DRAW_IN_TITLEBAR
|
||||||
<hbox class="titlebar-placeholder" type="caption-buttons"
|
<hbox class="titlebar-placeholder" type="caption-buttons"
|
||||||
id="titlebar-placeholder-on-TabsToolbar-for-captions-buttons" persist="width"
|
id="titlebar-placeholder-on-TabsToolbar-for-captions-buttons" persist="width"
|
||||||
|
@ -191,6 +191,19 @@ const CustomizableWidgets = [{
|
|||||||
}
|
}
|
||||||
recentlyClosedWindows.appendChild(windowsFragment);
|
recentlyClosedWindows.appendChild(windowsFragment);
|
||||||
},
|
},
|
||||||
|
onCreated: function(aNode) {
|
||||||
|
// Middle clicking recently closed items won't close the panel - cope:
|
||||||
|
let onRecentlyClosedClick = function(aEvent) {
|
||||||
|
if (aEvent.button == 1) {
|
||||||
|
CustomizableUI.hidePanelForNode(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let doc = aNode.ownerDocument;
|
||||||
|
let recentlyClosedTabs = doc.getElementById("PanelUI-recentlyClosedTabs");
|
||||||
|
let recentlyClosedWindows = doc.getElementById("PanelUI-recentlyClosedWindows");
|
||||||
|
recentlyClosedTabs.addEventListener("click", onRecentlyClosedClick);
|
||||||
|
recentlyClosedWindows.addEventListener("click", onRecentlyClosedClick);
|
||||||
|
},
|
||||||
onViewHiding: function(aEvent) {
|
onViewHiding: function(aEvent) {
|
||||||
LOG("History view is being hidden!");
|
LOG("History view is being hidden!");
|
||||||
}
|
}
|
||||||
|
@ -107,6 +107,8 @@ support-files =
|
|||||||
test-bug_923281_test2.js
|
test-bug_923281_test2.js
|
||||||
test-bug_939783_console_trace_duplicates.html
|
test-bug_939783_console_trace_duplicates.html
|
||||||
test-bug-952277-highlight-nodes-in-vview.html
|
test-bug-952277-highlight-nodes-in-vview.html
|
||||||
|
test-bug-609872-cd-iframe-parent.html
|
||||||
|
test-bug-609872-cd-iframe-child.html
|
||||||
|
|
||||||
[browser_bug664688_sandbox_update_after_navigation.js]
|
[browser_bug664688_sandbox_update_after_navigation.js]
|
||||||
[browser_bug_638949_copy_link_location.js]
|
[browser_bug_638949_copy_link_location.js]
|
||||||
@ -267,3 +269,4 @@ run-if = os == "mac"
|
|||||||
[browser_webconsole_output_events.js]
|
[browser_webconsole_output_events.js]
|
||||||
[browser_console_variables_view_highlighter.js]
|
[browser_console_variables_view_highlighter.js]
|
||||||
[browser_webconsole_console_trace_duplicates.js]
|
[browser_webconsole_console_trace_duplicates.js]
|
||||||
|
[browser_webconsole_cd_iframe.js]
|
||||||
|
110
browser/devtools/webconsole/test/browser_webconsole_cd_iframe.js
Normal file
110
browser/devtools/webconsole/test/browser_webconsole_cd_iframe.js
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
// Test that the cd() jsterm helper function works as expected. See bug 609872.
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
let hud;
|
||||||
|
|
||||||
|
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-609872-cd-iframe-parent.html";
|
||||||
|
|
||||||
|
const parentMessages = [{
|
||||||
|
name: "document.title in parent iframe",
|
||||||
|
text: "bug 609872 - iframe parent",
|
||||||
|
category: CATEGORY_OUTPUT,
|
||||||
|
}, {
|
||||||
|
name: "paragraph content",
|
||||||
|
text: "p: test for bug 609872 - iframe parent",
|
||||||
|
category: CATEGORY_OUTPUT,
|
||||||
|
}, {
|
||||||
|
name: "object content",
|
||||||
|
text: "obj: parent!",
|
||||||
|
category: CATEGORY_OUTPUT,
|
||||||
|
}];
|
||||||
|
|
||||||
|
const childMessages = [{
|
||||||
|
name: "document.title in child iframe",
|
||||||
|
text: "bug 609872 - iframe child",
|
||||||
|
category: CATEGORY_OUTPUT,
|
||||||
|
}, {
|
||||||
|
name: "paragraph content",
|
||||||
|
text: "p: test for bug 609872 - iframe child",
|
||||||
|
category: CATEGORY_OUTPUT,
|
||||||
|
}, {
|
||||||
|
name: "object content",
|
||||||
|
text: "obj: child!",
|
||||||
|
category: CATEGORY_OUTPUT,
|
||||||
|
}];
|
||||||
|
|
||||||
|
Task.spawn(runner).then(finishTest);
|
||||||
|
|
||||||
|
function* runner() {
|
||||||
|
const {tab} = yield loadTab(TEST_URI);
|
||||||
|
hud = yield openConsole(tab);
|
||||||
|
|
||||||
|
executeWindowTest();
|
||||||
|
|
||||||
|
yield waitForMessages({ webconsole: hud, messages: parentMessages });
|
||||||
|
|
||||||
|
info("cd() into the iframe using a selector");
|
||||||
|
hud.jsterm.clearOutput();
|
||||||
|
hud.jsterm.execute("cd('iframe')");
|
||||||
|
executeWindowTest();
|
||||||
|
|
||||||
|
yield waitForMessages({ webconsole: hud, messages: childMessages });
|
||||||
|
|
||||||
|
info("cd() out of the iframe, reset to default window");
|
||||||
|
hud.jsterm.clearOutput();
|
||||||
|
hud.jsterm.execute("cd()");
|
||||||
|
executeWindowTest();
|
||||||
|
|
||||||
|
yield waitForMessages({ webconsole: hud, messages: parentMessages });
|
||||||
|
|
||||||
|
info("call cd() with unexpected arguments");
|
||||||
|
hud.jsterm.clearOutput();
|
||||||
|
hud.jsterm.execute("cd(document)");
|
||||||
|
|
||||||
|
yield waitForMessages({
|
||||||
|
webconsole: hud,
|
||||||
|
messages: [{
|
||||||
|
text: "Cannot cd()",
|
||||||
|
category: CATEGORY_OUTPUT,
|
||||||
|
severity: SEVERITY_ERROR,
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
hud.jsterm.clearOutput();
|
||||||
|
hud.jsterm.execute("cd('p')");
|
||||||
|
|
||||||
|
yield waitForMessages({
|
||||||
|
webconsole: hud,
|
||||||
|
messages: [{
|
||||||
|
text: "Cannot cd()",
|
||||||
|
category: CATEGORY_OUTPUT,
|
||||||
|
severity: SEVERITY_ERROR,
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
info("cd() into the iframe using an iframe DOM element");
|
||||||
|
hud.jsterm.clearOutput();
|
||||||
|
hud.jsterm.execute("cd($('iframe'))");
|
||||||
|
executeWindowTest();
|
||||||
|
|
||||||
|
yield waitForMessages({ webconsole: hud, messages: childMessages });
|
||||||
|
|
||||||
|
info("cd(window.parent)");
|
||||||
|
hud.jsterm.clearOutput();
|
||||||
|
hud.jsterm.execute("cd(window.parent)");
|
||||||
|
executeWindowTest();
|
||||||
|
|
||||||
|
yield waitForMessages({ webconsole: hud, messages: parentMessages });
|
||||||
|
|
||||||
|
yield closeConsole(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
function executeWindowTest() {
|
||||||
|
hud.jsterm.execute("document.title");
|
||||||
|
hud.jsterm.execute("'p: ' + document.querySelector('p').textContent");
|
||||||
|
hud.jsterm.execute("'obj: ' + window.foobarBug609872");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>test for bug 609872 - iframe child</title>
|
||||||
|
<!-- Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>test for bug 609872 - iframe child</p>
|
||||||
|
<script>window.foobarBug609872 = 'child!';</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>test for bug 609872 - iframe parent</title>
|
||||||
|
<!-- Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>test for bug 609872 - iframe parent</p>
|
||||||
|
<script>window.foobarBug609872 = 'parent!';</script>
|
||||||
|
<iframe src="test-bug-609872-cd-iframe-child.html"></iframe>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -213,3 +213,7 @@ emptyPropertiesList=No properties to display
|
|||||||
# #1 number of message repeats
|
# #1 number of message repeats
|
||||||
# example: 3 repeats
|
# example: 3 repeats
|
||||||
messageRepeats.tooltip2=#1 repeat;#1 repeats
|
messageRepeats.tooltip2=#1 repeat;#1 repeats
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (cdFunctionInvalidArgument): the text that is displayed when
|
||||||
|
# cd() is invoked with an invalid argument.
|
||||||
|
cdFunctionInvalidArgument=Cannot cd() to the given window. Invalid argument.
|
||||||
|
@ -64,6 +64,7 @@ var Browser = {
|
|||||||
messageManager.loadFrameScript("chrome://browser/content/contenthandlers/SelectionHandler.js", true);
|
messageManager.loadFrameScript("chrome://browser/content/contenthandlers/SelectionHandler.js", true);
|
||||||
messageManager.loadFrameScript("chrome://browser/content/contenthandlers/ContextMenuHandler.js", true);
|
messageManager.loadFrameScript("chrome://browser/content/contenthandlers/ContextMenuHandler.js", true);
|
||||||
messageManager.loadFrameScript("chrome://browser/content/contenthandlers/ConsoleAPIObserver.js", true);
|
messageManager.loadFrameScript("chrome://browser/content/contenthandlers/ConsoleAPIObserver.js", true);
|
||||||
|
messageManager.loadFrameScript("chrome://browser/content/contenthandlers/PluginHelper.js", true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// XXX whatever is calling startup needs to dump errors!
|
// XXX whatever is calling startup needs to dump errors!
|
||||||
dump("###########" + e + "\n");
|
dump("###########" + e + "\n");
|
||||||
|
@ -1120,6 +1120,9 @@ Desktop browser's sync prefs.
|
|||||||
<setting pref="signon.rememberSignons"
|
<setting pref="signon.rememberSignons"
|
||||||
title="&optionsHeader.privacy.passwords.label;"
|
title="&optionsHeader.privacy.passwords.label;"
|
||||||
type="bool"/>
|
type="bool"/>
|
||||||
|
<setting pref="browser.display.overlaynavbuttons"
|
||||||
|
title="&optionsHeader.displayOverlayButtons.label;"
|
||||||
|
type="bool"/>
|
||||||
<settings id="prefs-reporting"
|
<settings id="prefs-reporting"
|
||||||
label="&optionsHeader.reporting.title;">
|
label="&optionsHeader.reporting.title;">
|
||||||
<setting pref="app.crashreporter.autosubmit"
|
<setting pref="app.crashreporter.autosubmit"
|
||||||
|
95
browser/metro/base/content/contenthandlers/PluginHelper.js
Normal file
95
browser/metro/base/content/contenthandlers/PluginHelper.js
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/* 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/. */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
dump("### PluginHelper.js loaded\n");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle events generated by plugin click-to-play code.
|
||||||
|
*
|
||||||
|
* This "PluginBindingAttached" fires when a "pluginProblem" XBL binding is
|
||||||
|
* created. This binding overlays plugin content when the plugin is missing,
|
||||||
|
* blocked, click-to-play, or replaced by a "preview" extension plugin like
|
||||||
|
* Shumway or PDF.js.
|
||||||
|
*/
|
||||||
|
var PluginHelper = {
|
||||||
|
init: function () {
|
||||||
|
addEventListener("PluginBindingAttached", this, true, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleEvent: function handleEvent(aEvent) {
|
||||||
|
switch (aEvent.type) {
|
||||||
|
case "PluginBindingAttached":
|
||||||
|
this.handlePluginBindingAttached(aEvent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getPluginMimeType: function (plugin) {
|
||||||
|
var tagMimetype = plugin.actualType;
|
||||||
|
|
||||||
|
if (tagMimetype == "") {
|
||||||
|
tagMimetype = plugin.type;
|
||||||
|
}
|
||||||
|
return tagMimetype;
|
||||||
|
},
|
||||||
|
|
||||||
|
handlePluginBindingAttached: function (aEvent) {
|
||||||
|
let plugin = aEvent.target;
|
||||||
|
let doc = plugin.ownerDocument;
|
||||||
|
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
|
||||||
|
if (!overlay || overlay._bindingHandled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
overlay._bindingHandled = true;
|
||||||
|
|
||||||
|
let eventType = PluginHelper._getBindingType(plugin);
|
||||||
|
if (!eventType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (eventType) {
|
||||||
|
case "PluginPlayPreview": {
|
||||||
|
// Load the "preview" handler (an extension plugin like Shumway or PDF.js).
|
||||||
|
let previewContent = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
|
||||||
|
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||||
|
let mimeType = PluginHelper.getPluginMimeType(plugin);
|
||||||
|
let playPreviewInfo = pluginHost.getPlayPreviewInfo(mimeType);
|
||||||
|
|
||||||
|
let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
|
||||||
|
if (!iframe) {
|
||||||
|
// lazy initialization of the iframe
|
||||||
|
iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
|
||||||
|
iframe.className = "previewPluginContentFrame";
|
||||||
|
previewContent.appendChild(iframe);
|
||||||
|
}
|
||||||
|
iframe.src = playPreviewInfo.redirectURL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "PluginNotFound": {
|
||||||
|
// TODO: Display a message about missing plugins (bug 936907)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Helper to get the binding handler type from a plugin object
|
||||||
|
_getBindingType: function(plugin) {
|
||||||
|
if (!(plugin instanceof Ci.nsIObjectLoadingContent))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
switch (plugin.pluginFallbackType) {
|
||||||
|
case Ci.nsIObjectLoadingContent.PLUGIN_UNSUPPORTED:
|
||||||
|
return "PluginNotFound";
|
||||||
|
case Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW:
|
||||||
|
return "PluginPlayPreview";
|
||||||
|
default:
|
||||||
|
// Metro Firefox does not yet support other fallback types.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
PluginHelper.init();
|
@ -59,6 +59,7 @@ chrome.jar:
|
|||||||
content/contenthandlers/FormHelper.js (content/contenthandlers/FormHelper.js)
|
content/contenthandlers/FormHelper.js (content/contenthandlers/FormHelper.js)
|
||||||
content/contenthandlers/ConsoleAPIObserver.js (content/contenthandlers/ConsoleAPIObserver.js)
|
content/contenthandlers/ConsoleAPIObserver.js (content/contenthandlers/ConsoleAPIObserver.js)
|
||||||
content/contenthandlers/Content.js (content/contenthandlers/Content.js)
|
content/contenthandlers/Content.js (content/contenthandlers/Content.js)
|
||||||
|
content/contenthandlers/PluginHelper.js (content/contenthandlers/PluginHelper.js)
|
||||||
|
|
||||||
content/library/SelectionPrototype.js (content/library/SelectionPrototype.js)
|
content/library/SelectionPrototype.js (content/library/SelectionPrototype.js)
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
<!ENTITY clearPrivateData.logins "Active logins">
|
<!ENTITY clearPrivateData.logins "Active logins">
|
||||||
|
|
||||||
<!ENTITY optionsHeader.privacy.passwords.label "Remember Passwords">
|
<!ENTITY optionsHeader.privacy.passwords.label "Remember Passwords">
|
||||||
|
<!ENTITY optionsHeader.displayOverlayButtons.label "Show Navigation Buttons">
|
||||||
<!ENTITY doNotTrack.title "Do Not Track">
|
<!ENTITY doNotTrack.title "Do Not Track">
|
||||||
<!ENTITY doNotTrack.options.doNotTrack "Tell websites that I do not want to be tracked">
|
<!ENTITY doNotTrack.options.doNotTrack "Tell websites that I do not want to be tracked">
|
||||||
<!ENTITY doNotTrack.options.doTrack "Tell websites that I want to be tracked">
|
<!ENTITY doNotTrack.options.doTrack "Tell websites that I want to be tracked">
|
||||||
|
@ -573,7 +573,12 @@ pref("pdfjs.previousHandler.alwaysAskBeforeHandling", false);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef NIGHTLY_BUILD
|
#ifdef NIGHTLY_BUILD
|
||||||
|
// Shumay is currently experimental. Toggle this pref to enable Shumway for
|
||||||
|
// testing and development.
|
||||||
pref("shumway.disabled", true);
|
pref("shumway.disabled", true);
|
||||||
|
// When Shumway is enabled, use it all the time, not only when Flash is set to
|
||||||
|
// click-to-play (because Metro doesn't even load the native Flash plugin).
|
||||||
|
pref("shumway.ignoreCTP", true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// The maximum amount of decoded image data we'll willingly keep around (we
|
// The maximum amount of decoded image data we'll willingly keep around (we
|
||||||
|
@ -2509,9 +2509,7 @@ chatbox {
|
|||||||
|
|
||||||
/* End customization mode */
|
/* End customization mode */
|
||||||
|
|
||||||
#main-window[privatebrowsingmode=temporary] #TabsToolbar::after {
|
#main-window[privatebrowsingmode=temporary] #private-browsing-indicator {
|
||||||
content: "";
|
|
||||||
display: -moz-box;
|
|
||||||
width: 40px;
|
width: 40px;
|
||||||
background: url("chrome://browser/skin/privatebrowsing-indicator.png") no-repeat center center;
|
background: url("chrome://browser/skin/privatebrowsing-indicator.png") no-repeat center center;
|
||||||
}
|
}
|
||||||
|
@ -952,12 +952,6 @@ nsDOMCameraControl::Shutdown()
|
|||||||
mCameraControl->Shutdown();
|
mCameraControl->Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<ICameraControl>
|
|
||||||
nsDOMCameraControl::GetNativeCameraControl()
|
|
||||||
{
|
|
||||||
return mCameraControl;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsDOMCameraControl::NotifyRecordingStatusChange(const nsString& aMsg)
|
nsDOMCameraControl::NotifyRecordingStatusChange(const nsString& aMsg)
|
||||||
{
|
{
|
||||||
@ -1139,21 +1133,31 @@ void
|
|||||||
nsDOMCameraControl::OnAutoFocusComplete(bool aAutoFocusSucceeded)
|
nsDOMCameraControl::OnAutoFocusComplete(bool aAutoFocusSucceeded)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
ErrorResult ignored;
|
|
||||||
|
|
||||||
nsCOMPtr<CameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb.forget();
|
nsCOMPtr<CameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb.forget();
|
||||||
mAutoFocusOnErrorCb = nullptr;
|
mAutoFocusOnErrorCb = nullptr;
|
||||||
cb->Call(aAutoFocusSucceeded, ignored);
|
if (cb) {
|
||||||
|
ErrorResult ignored;
|
||||||
|
cb->Call(aAutoFocusSucceeded, ignored);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsDOMCameraControl::OnTakePictureComplete(nsIDOMBlob* aPicture)
|
nsDOMCameraControl::OnTakePictureComplete(nsIDOMBlob* aPicture)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
ErrorResult ignored;
|
|
||||||
|
|
||||||
nsCOMPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb.forget();
|
nsCOMPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb.forget();
|
||||||
mTakePictureOnErrorCb = nullptr;
|
mTakePictureOnErrorCb = nullptr;
|
||||||
|
if (!cb) {
|
||||||
|
// Warn because it shouldn't be possible to get here without
|
||||||
|
// having passed a success callback into takePicture(), even
|
||||||
|
// though we guard against a nullptr dereference.
|
||||||
|
NS_WARNING("DOM Null success callback in OnTakePictureComplete()");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorResult ignored;
|
||||||
cb->Call(aPicture, ignored);
|
cb->Call(aPicture, ignored);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,6 @@ public:
|
|||||||
dom::GetCameraCallback* aOnSuccess,
|
dom::GetCameraCallback* aOnSuccess,
|
||||||
dom::CameraErrorCallback* aOnError,
|
dom::CameraErrorCallback* aOnError,
|
||||||
nsPIDOMWindow* aWindow);
|
nsPIDOMWindow* aWindow);
|
||||||
nsRefPtr<ICameraControl> GetNativeCameraControl();
|
|
||||||
|
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
|
@ -272,53 +272,86 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This utility is replicated from RepoUtils, which is managed by android-sync.
|
||||||
|
*/
|
||||||
|
private static String computeSQLInClause(int items, String field) {
|
||||||
|
final StringBuilder builder = new StringBuilder(field);
|
||||||
|
builder.append(" IN (");
|
||||||
|
int i = 0;
|
||||||
|
for (; i < items - 1; ++i) {
|
||||||
|
builder.append("?, ");
|
||||||
|
}
|
||||||
|
if (i < items) {
|
||||||
|
builder.append("?");
|
||||||
|
}
|
||||||
|
builder.append(")");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn a single-column cursor of longs into a single SQL "IN" clause.
|
||||||
|
* We can do this without using selection arguments because Long isn't
|
||||||
|
* vulnerable to injection.
|
||||||
|
*/
|
||||||
|
private static String computeSQLInClauseFromLongs(final Cursor cursor, String field) {
|
||||||
|
final StringBuilder builder = new StringBuilder(field);
|
||||||
|
builder.append(" IN (");
|
||||||
|
final int commaLimit = cursor.getCount() - 1;
|
||||||
|
int i = 0;
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
builder.append(cursor.getLong(0));
|
||||||
|
if (i++ < commaLimit) {
|
||||||
|
builder.append(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.append(")");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up some deleted records from the specified table.
|
||||||
|
*
|
||||||
|
* If called in an existing transaction, it is the caller's responsibility
|
||||||
|
* to ensure that the transaction is already upgraded to a writer, because
|
||||||
|
* this method issues a read followed by a write, and thus is potentially
|
||||||
|
* vulnerable to an unhandled SQLITE_BUSY failure during the upgrade.
|
||||||
|
*
|
||||||
|
* If not called in an existing transaction, no new explicit transaction
|
||||||
|
* will be begun.
|
||||||
|
*/
|
||||||
private void cleanupSomeDeletedRecords(Uri fromUri, Uri targetUri, String tableName) {
|
private void cleanupSomeDeletedRecords(Uri fromUri, Uri targetUri, String tableName) {
|
||||||
Log.d(LOGTAG, "Cleaning up deleted records from " + tableName);
|
Log.d(LOGTAG, "Cleaning up deleted records from " + tableName);
|
||||||
|
|
||||||
// we cleanup records marked as deleted that are older than a
|
// We clean up records marked as deleted that are older than a
|
||||||
// predefined max age. It's important not be too greedy here and
|
// predefined max age. It's important not be too greedy here and
|
||||||
// remove only a few old deleted records at a time.
|
// remove only a few old deleted records at a time.
|
||||||
|
|
||||||
// The PARAM_SHOW_DELETED argument is necessary to return the records
|
// Android SQLite doesn't have LIMIT on DELETE. Instead, query for the
|
||||||
// that were marked as deleted. We use PARAM_IS_SYNC here to ensure
|
// IDs of matching rows, then delete them in one go.
|
||||||
// that we'll be actually deleting records instead of flagging them.
|
final long now = System.currentTimeMillis();
|
||||||
Uri.Builder uriBuilder = targetUri.buildUpon()
|
final String selection = SyncColumns.IS_DELETED + " = 1 AND " +
|
||||||
.appendQueryParameter(BrowserContract.PARAM_LIMIT, String.valueOf(DELETED_RECORDS_PURGE_LIMIT))
|
SyncColumns.DATE_MODIFIED + " <= " +
|
||||||
.appendQueryParameter(BrowserContract.PARAM_SHOW_DELETED, "1")
|
(now - MAX_AGE_OF_DELETED_RECORDS);
|
||||||
.appendQueryParameter(BrowserContract.PARAM_IS_SYNC, "1");
|
|
||||||
|
|
||||||
String profile = fromUri.getQueryParameter(BrowserContract.PARAM_PROFILE);
|
|
||||||
if (!TextUtils.isEmpty(profile))
|
|
||||||
uriBuilder = uriBuilder.appendQueryParameter(BrowserContract.PARAM_PROFILE, profile);
|
|
||||||
|
|
||||||
if (isTest(fromUri))
|
|
||||||
uriBuilder = uriBuilder.appendQueryParameter(BrowserContract.PARAM_IS_TEST, "1");
|
|
||||||
|
|
||||||
Uri uriWithArgs = uriBuilder.build();
|
|
||||||
|
|
||||||
Cursor cursor = null;
|
|
||||||
|
|
||||||
|
final String profile = fromUri.getQueryParameter(BrowserContract.PARAM_PROFILE);
|
||||||
|
final SQLiteDatabase db = getWritableDatabaseForProfile(profile, isTest(fromUri));
|
||||||
|
final String[] ids;
|
||||||
|
final String limit = Long.toString(DELETED_RECORDS_PURGE_LIMIT, 10);
|
||||||
|
final Cursor cursor = db.query(tableName, new String[] { CommonColumns._ID }, selection, null, null, null, null, limit);
|
||||||
try {
|
try {
|
||||||
long now = System.currentTimeMillis();
|
ids = new String[cursor.getCount()];
|
||||||
String selection = SyncColumns.IS_DELETED + " = 1 AND " +
|
int i = 0;
|
||||||
SyncColumns.DATE_MODIFIED + " <= " + (now - MAX_AGE_OF_DELETED_RECORDS);
|
|
||||||
|
|
||||||
cursor = query(uriWithArgs,
|
|
||||||
new String[] { CommonColumns._ID },
|
|
||||||
selection,
|
|
||||||
null,
|
|
||||||
null);
|
|
||||||
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
Uri uriWithId = ContentUris.withAppendedId(uriWithArgs, cursor.getLong(0));
|
ids[i++] = Long.toString(cursor.getLong(0), 10);
|
||||||
delete(uriWithId, null, null);
|
|
||||||
|
|
||||||
debug("Removed old deleted item with URI: " + uriWithId);
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (cursor != null)
|
cursor.close();
|
||||||
cursor.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final String inClause = computeSQLInClause(ids.length,
|
||||||
|
CommonColumns._ID);
|
||||||
|
db.delete(tableName, inClause, ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -328,8 +361,6 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
* Provide <code>keepAfter</code> less than or equal to zero to skip that check.
|
* Provide <code>keepAfter</code> less than or equal to zero to skip that check.
|
||||||
*
|
*
|
||||||
* Items will be removed according to an approximate frecency calculation.
|
* Items will be removed according to an approximate frecency calculation.
|
||||||
*
|
|
||||||
* Call this method within a transaction.
|
|
||||||
*/
|
*/
|
||||||
private void expireHistory(final SQLiteDatabase db, final int retain, final long keepAfter) {
|
private void expireHistory(final SQLiteDatabase db, final int retain, final long keepAfter) {
|
||||||
Log.d(LOGTAG, "Expiring history.");
|
Log.d(LOGTAG, "Expiring history.");
|
||||||
@ -358,6 +389,8 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
"ORDER BY " + sortOrder + " LIMIT " + toRemove + ")";
|
"ORDER BY " + sortOrder + " LIMIT " + toRemove + ")";
|
||||||
}
|
}
|
||||||
trace("Deleting using query: " + sql);
|
trace("Deleting using query: " + sql);
|
||||||
|
|
||||||
|
beginWrite(db);
|
||||||
db.execSQL(sql);
|
db.execSQL(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,6 +475,7 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
public int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {
|
public int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {
|
||||||
trace("Calling delete in transaction on URI: " + uri);
|
trace("Calling delete in transaction on URI: " + uri);
|
||||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||||
|
|
||||||
final int match = URI_MATCHER.match(uri);
|
final int match = URI_MATCHER.match(uri);
|
||||||
int deleted = 0;
|
int deleted = 0;
|
||||||
|
|
||||||
@ -469,6 +503,7 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
// fall through
|
// fall through
|
||||||
case HISTORY: {
|
case HISTORY: {
|
||||||
trace("Deleting history: " + uri);
|
trace("Deleting history: " + uri);
|
||||||
|
beginWrite(db);
|
||||||
deleted = deleteHistory(uri, selection, selectionArgs);
|
deleted = deleteHistory(uri, selection, selectionArgs);
|
||||||
deleteUnusedImages(uri);
|
deleteUnusedImages(uri);
|
||||||
break;
|
break;
|
||||||
@ -498,6 +533,7 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
// fall through
|
// fall through
|
||||||
case FAVICONS: {
|
case FAVICONS: {
|
||||||
trace("Deleting favicons: " + uri);
|
trace("Deleting favicons: " + uri);
|
||||||
|
beginWrite(db);
|
||||||
deleted = deleteFavicons(uri, selection, selectionArgs);
|
deleted = deleteFavicons(uri, selection, selectionArgs);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -511,6 +547,7 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
// fall through
|
// fall through
|
||||||
case THUMBNAILS: {
|
case THUMBNAILS: {
|
||||||
trace("Deleting thumbnails: " + uri);
|
trace("Deleting thumbnails: " + uri);
|
||||||
|
beginWrite(db);
|
||||||
deleted = deleteThumbnails(uri, selection, selectionArgs);
|
deleted = deleteThumbnails(uri, selection, selectionArgs);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -577,6 +614,7 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
int match = URI_MATCHER.match(uri);
|
int match = URI_MATCHER.match(uri);
|
||||||
int updated = 0;
|
int updated = 0;
|
||||||
|
|
||||||
|
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||||
switch (match) {
|
switch (match) {
|
||||||
// We provide a dedicated (hacky) API for callers to bulk-update the positions of
|
// We provide a dedicated (hacky) API for callers to bulk-update the positions of
|
||||||
// folder children by passing an array of GUID strings as `selectionArgs`.
|
// folder children by passing an array of GUID strings as `selectionArgs`.
|
||||||
@ -589,13 +627,16 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
// `values` and `selection` are ignored.
|
// `values` and `selection` are ignored.
|
||||||
case BOOKMARKS_POSITIONS: {
|
case BOOKMARKS_POSITIONS: {
|
||||||
debug("Update on BOOKMARKS_POSITIONS: " + uri);
|
debug("Update on BOOKMARKS_POSITIONS: " + uri);
|
||||||
|
|
||||||
|
// This already starts and finishes its own transaction.
|
||||||
updated = updateBookmarkPositions(uri, selectionArgs);
|
updated = updateBookmarkPositions(uri, selectionArgs);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BOOKMARKS_PARENT: {
|
case BOOKMARKS_PARENT: {
|
||||||
debug("Update on BOOKMARKS_PARENT: " + uri);
|
debug("Update on BOOKMARKS_PARENT: " + uri);
|
||||||
updated = updateBookmarkParents(uri, values, selection, selectionArgs);
|
beginWrite(db);
|
||||||
|
updated = updateBookmarkParents(db, values, selection, selectionArgs);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -608,10 +649,11 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
// fall through
|
// fall through
|
||||||
case BOOKMARKS: {
|
case BOOKMARKS: {
|
||||||
debug("Updating bookmark: " + uri);
|
debug("Updating bookmark: " + uri);
|
||||||
if (shouldUpdateOrInsert(uri))
|
if (shouldUpdateOrInsert(uri)) {
|
||||||
updated = updateOrInsertBookmark(uri, values, selection, selectionArgs);
|
updated = updateOrInsertBookmark(uri, values, selection, selectionArgs);
|
||||||
else
|
} else {
|
||||||
updated = updateBookmarks(uri, values, selection, selectionArgs);
|
updated = updateBookmarks(uri, values, selection, selectionArgs);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -624,10 +666,11 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
// fall through
|
// fall through
|
||||||
case HISTORY: {
|
case HISTORY: {
|
||||||
debug("Updating history: " + uri);
|
debug("Updating history: " + uri);
|
||||||
if (shouldUpdateOrInsert(uri))
|
if (shouldUpdateOrInsert(uri)) {
|
||||||
updated = updateOrInsertHistory(uri, values, selection, selectionArgs);
|
updated = updateOrInsertHistory(uri, values, selection, selectionArgs);
|
||||||
else
|
} else {
|
||||||
updated = updateHistory(uri, values, selection, selectionArgs);
|
updated = updateHistory(uri, values, selection, selectionArgs);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -643,11 +686,11 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
faviconSelectionArgs = new String[] { url };
|
faviconSelectionArgs = new String[] { url };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldUpdateOrInsert(uri))
|
if (shouldUpdateOrInsert(uri)) {
|
||||||
updated = updateOrInsertFavicon(uri, values, faviconSelection, faviconSelectionArgs);
|
updated = updateOrInsertFavicon(uri, values, faviconSelection, faviconSelectionArgs);
|
||||||
else
|
} else {
|
||||||
updated = updateExistingFavicon(uri, values, faviconSelection, faviconSelectionArgs);
|
updated = updateExistingFavicon(uri, values, faviconSelection, faviconSelectionArgs);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -657,15 +700,15 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
String url = values.getAsString(Thumbnails.URL);
|
String url = values.getAsString(Thumbnails.URL);
|
||||||
|
|
||||||
// if no URL is provided, update all of the entries
|
// if no URL is provided, update all of the entries
|
||||||
if (TextUtils.isEmpty(values.getAsString(Thumbnails.URL)))
|
if (TextUtils.isEmpty(values.getAsString(Thumbnails.URL))) {
|
||||||
updated = updateExistingThumbnail(uri, values, null, null);
|
updated = updateExistingThumbnail(uri, values, null, null);
|
||||||
else if (shouldUpdateOrInsert(uri))
|
} else if (shouldUpdateOrInsert(uri)) {
|
||||||
updated = updateOrInsertThumbnail(uri, values, Thumbnails.URL + " = ?",
|
updated = updateOrInsertThumbnail(uri, values, Thumbnails.URL + " = ?",
|
||||||
new String[] { url });
|
new String[] { url });
|
||||||
else
|
} else {
|
||||||
updated = updateExistingThumbnail(uri, values, Thumbnails.URL + " = ?",
|
updated = updateExistingThumbnail(uri, values, Thumbnails.URL + " = ?",
|
||||||
new String[] { url });
|
new String[] { url });
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -674,7 +717,6 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
debug("Updated " + updated + " rows for URI: " + uri);
|
debug("Updated " + updated + " rows for URI: " + uri);
|
||||||
|
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -876,40 +918,42 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getUrlCount(SQLiteDatabase db, String table, String url) {
|
private static int getUrlCount(SQLiteDatabase db, String table, String url) {
|
||||||
Cursor c = db.query(table, new String[] { "COUNT(*)" },
|
final Cursor c = db.query(table, new String[] { "COUNT(*)" },
|
||||||
URLColumns.URL + " = ?", new String[] { url }, null, null,
|
URLColumns.URL + " = ?", new String[] { url },
|
||||||
null);
|
null, null, null);
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (c.moveToFirst())
|
if (c.moveToFirst()) {
|
||||||
count = c.getInt(0);
|
return c.getInt(0);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
c.close();
|
c.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the positions of bookmarks in batches.
|
* Update the positions of bookmarks in batches.
|
||||||
*
|
*
|
||||||
|
* Begins and ends its own transactions.
|
||||||
|
*
|
||||||
* @see #updateBookmarkPositionsInTransaction(SQLiteDatabase, String[], int, int)
|
* @see #updateBookmarkPositionsInTransaction(SQLiteDatabase, String[], int, int)
|
||||||
*/
|
*/
|
||||||
int updateBookmarkPositions(Uri uri, String[] guids) {
|
int updateBookmarkPositions(Uri uri, String[] guids) {
|
||||||
if (guids == null)
|
if (guids == null) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int guidsCount = guids.length;
|
int guidsCount = guids.length;
|
||||||
if (guidsCount == 0)
|
if (guidsCount == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int updated = 0;
|
int updated = 0;
|
||||||
|
|
||||||
|
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||||
db.beginTransaction();
|
db.beginTransaction();
|
||||||
|
|
||||||
while (offset < guidsCount) {
|
while (offset < guidsCount) {
|
||||||
@ -942,8 +986,8 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
* Construct and execute an update expression that will modify the positions
|
* Construct and execute an update expression that will modify the positions
|
||||||
* of records in-place.
|
* of records in-place.
|
||||||
*/
|
*/
|
||||||
int updateBookmarkPositionsInTransaction(final SQLiteDatabase db, final String[] guids,
|
private static int updateBookmarkPositionsInTransaction(final SQLiteDatabase db, final String[] guids,
|
||||||
final int offset, final int max) {
|
final int offset, final int max) {
|
||||||
int guidsCount = guids.length;
|
int guidsCount = guids.length;
|
||||||
int processCount = Math.min(max, guidsCount - offset);
|
int processCount = Math.min(max, guidsCount - offset);
|
||||||
|
|
||||||
@ -969,6 +1013,7 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
b.append(" WHEN ? THEN " + i);
|
b.append(" WHEN ? THEN " + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: use computeSQLInClause
|
||||||
b.append(" END WHERE " + Bookmarks.GUID + " IN (");
|
b.append(" END WHERE " + Bookmarks.GUID + " IN (");
|
||||||
i = 1;
|
i = 1;
|
||||||
while (i++ < processCount) {
|
while (i++ < processCount) {
|
||||||
@ -985,13 +1030,13 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
* Construct an update expression that will modify the parents of any records
|
* Construct an update expression that will modify the parents of any records
|
||||||
* that match.
|
* that match.
|
||||||
*/
|
*/
|
||||||
int updateBookmarkParents(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
private int updateBookmarkParents(SQLiteDatabase db, ContentValues values, String selection, String[] selectionArgs) {
|
||||||
trace("Updating bookmark parents of " + selection + " (" + selectionArgs[0] + ")");
|
trace("Updating bookmark parents of " + selection + " (" + selectionArgs[0] + ")");
|
||||||
String where = Bookmarks._ID + " IN (" +
|
String where = Bookmarks._ID + " IN (" +
|
||||||
" SELECT DISTINCT " + Bookmarks.PARENT +
|
" SELECT DISTINCT " + Bookmarks.PARENT +
|
||||||
" FROM " + TABLE_BOOKMARKS +
|
" FROM " + TABLE_BOOKMARKS +
|
||||||
" WHERE " + selection + " )";
|
" WHERE " + selection + " )";
|
||||||
return getWritableDatabase(uri).update(TABLE_BOOKMARKS, values, where, selectionArgs);
|
return db.update(TABLE_BOOKMARKS, values, where, selectionArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
long insertBookmark(Uri uri, ContentValues values) {
|
long insertBookmark(Uri uri, ContentValues values) {
|
||||||
@ -1017,10 +1062,10 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
String url = values.getAsString(Bookmarks.URL);
|
String url = values.getAsString(Bookmarks.URL);
|
||||||
Integer type = values.getAsInteger(Bookmarks.TYPE);
|
|
||||||
|
|
||||||
debug("Inserting bookmark in database with URL: " + url);
|
debug("Inserting bookmark in database with URL: " + url);
|
||||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||||
|
beginWrite(db);
|
||||||
return db.insertOrThrow(TABLE_BOOKMARKS, Bookmarks.TITLE, values);
|
return db.insertOrThrow(TABLE_BOOKMARKS, Bookmarks.TITLE, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1028,9 +1073,11 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
int updateOrInsertBookmark(Uri uri, ContentValues values, String selection,
|
int updateOrInsertBookmark(Uri uri, ContentValues values, String selection,
|
||||||
String[] selectionArgs) {
|
String[] selectionArgs) {
|
||||||
int updated = updateBookmarks(uri, values, selection, selectionArgs);
|
int updated = updateBookmarks(uri, values, selection, selectionArgs);
|
||||||
if (updated > 0)
|
if (updated > 0) {
|
||||||
return updated;
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transaction already begun by updateBookmarks.
|
||||||
if (0 <= insertBookmark(uri, values)) {
|
if (0 <= insertBookmark(uri, values)) {
|
||||||
// We 'updated' one row.
|
// We 'updated' one row.
|
||||||
return 1;
|
return 1;
|
||||||
@ -1044,49 +1091,35 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
String[] selectionArgs) {
|
String[] selectionArgs) {
|
||||||
trace("Updating bookmarks on URI: " + uri);
|
trace("Updating bookmarks on URI: " + uri);
|
||||||
|
|
||||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
|
||||||
int updated = 0;
|
|
||||||
|
|
||||||
final String[] bookmarksProjection = new String[] {
|
final String[] bookmarksProjection = new String[] {
|
||||||
Bookmarks._ID, // 0
|
Bookmarks._ID, // 0
|
||||||
Bookmarks.URL, // 1
|
|
||||||
};
|
};
|
||||||
|
|
||||||
trace("Quering bookmarks to update on URI: " + uri);
|
if (!values.containsKey(Bookmarks.DATE_MODIFIED)) {
|
||||||
|
values.put(Bookmarks.DATE_MODIFIED, System.currentTimeMillis());
|
||||||
Cursor cursor = db.query(TABLE_BOOKMARKS, bookmarksProjection,
|
|
||||||
selection, selectionArgs, null, null, null);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!values.containsKey(Bookmarks.DATE_MODIFIED))
|
|
||||||
values.put(Bookmarks.DATE_MODIFIED, System.currentTimeMillis());
|
|
||||||
|
|
||||||
boolean updatingUrl = values.containsKey(Bookmarks.URL);
|
|
||||||
String url = null;
|
|
||||||
|
|
||||||
if (updatingUrl)
|
|
||||||
url = values.getAsString(Bookmarks.URL);
|
|
||||||
|
|
||||||
while (cursor.moveToNext()) {
|
|
||||||
long id = cursor.getLong(0);
|
|
||||||
|
|
||||||
trace("Updating bookmark with ID: " + id);
|
|
||||||
|
|
||||||
updated += db.update(TABLE_BOOKMARKS, values, "_id = ?",
|
|
||||||
new String[] { Long.toString(id) });
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (cursor != null)
|
|
||||||
cursor.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return updated;
|
trace("Querying bookmarks to update on URI: " + uri);
|
||||||
|
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||||
|
|
||||||
|
// Compute matching IDs.
|
||||||
|
final Cursor cursor = db.query(TABLE_BOOKMARKS, bookmarksProjection,
|
||||||
|
selection, selectionArgs, null, null, null);
|
||||||
|
|
||||||
|
// Now that we're done reading, open a transaction.
|
||||||
|
final String inClause;
|
||||||
|
try {
|
||||||
|
inClause = computeSQLInClauseFromLongs(cursor, Bookmarks._ID);
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
beginWrite(db);
|
||||||
|
return db.update(TABLE_BOOKMARKS, values, inClause, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
long insertHistory(Uri uri, ContentValues values) {
|
long insertHistory(Uri uri, ContentValues values) {
|
||||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
final long now = System.currentTimeMillis();
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
values.put(History.DATE_CREATED, now);
|
values.put(History.DATE_CREATED, now);
|
||||||
values.put(History.DATE_MODIFIED, now);
|
values.put(History.DATE_MODIFIED, now);
|
||||||
|
|
||||||
@ -1098,20 +1131,25 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
String url = values.getAsString(History.URL);
|
String url = values.getAsString(History.URL);
|
||||||
|
|
||||||
debug("Inserting history in database with URL: " + url);
|
debug("Inserting history in database with URL: " + url);
|
||||||
|
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||||
|
beginWrite(db);
|
||||||
return db.insertOrThrow(TABLE_HISTORY, History.VISITS, values);
|
return db.insertOrThrow(TABLE_HISTORY, History.VISITS, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
int updateOrInsertHistory(Uri uri, ContentValues values, String selection,
|
int updateOrInsertHistory(Uri uri, ContentValues values, String selection,
|
||||||
String[] selectionArgs) {
|
String[] selectionArgs) {
|
||||||
int updated = updateHistory(uri, values, selection, selectionArgs);
|
final int updated = updateHistory(uri, values, selection, selectionArgs);
|
||||||
if (updated > 0)
|
if (updated > 0) {
|
||||||
return updated;
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
// Insert a new entry if necessary
|
// Insert a new entry if necessary
|
||||||
if (!values.containsKey(History.VISITS))
|
if (!values.containsKey(History.VISITS)) {
|
||||||
values.put(History.VISITS, 1);
|
values.put(History.VISITS, 1);
|
||||||
if (!values.containsKey(History.TITLE))
|
}
|
||||||
|
if (!values.containsKey(History.TITLE)) {
|
||||||
values.put(History.TITLE, values.getAsString(History.URL));
|
values.put(History.TITLE, values.getAsString(History.URL));
|
||||||
|
}
|
||||||
|
|
||||||
if (0 <= insertHistory(uri, values)) {
|
if (0 <= insertHistory(uri, values)) {
|
||||||
return 1;
|
return 1;
|
||||||
@ -1124,7 +1162,6 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
String[] selectionArgs) {
|
String[] selectionArgs) {
|
||||||
trace("Updating history on URI: " + uri);
|
trace("Updating history on URI: " + uri);
|
||||||
|
|
||||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
|
||||||
int updated = 0;
|
int updated = 0;
|
||||||
|
|
||||||
final String[] historyProjection = new String[] {
|
final String[] historyProjection = new String[] {
|
||||||
@ -1133,20 +1170,15 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
History.VISITS // 2
|
History.VISITS // 2
|
||||||
};
|
};
|
||||||
|
|
||||||
Cursor cursor = db.query(TABLE_HISTORY, historyProjection, selection,
|
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||||
selectionArgs, null, null, null);
|
final Cursor cursor = db.query(TABLE_HISTORY, historyProjection, selection,
|
||||||
|
selectionArgs, null, null, null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!values.containsKey(Bookmarks.DATE_MODIFIED)) {
|
if (!values.containsKey(Bookmarks.DATE_MODIFIED)) {
|
||||||
values.put(Bookmarks.DATE_MODIFIED, System.currentTimeMillis());
|
values.put(Bookmarks.DATE_MODIFIED, System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean updatingUrl = values.containsKey(History.URL);
|
|
||||||
String url = null;
|
|
||||||
|
|
||||||
if (updatingUrl)
|
|
||||||
url = values.getAsString(History.URL);
|
|
||||||
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
long id = cursor.getLong(0);
|
long id = cursor.getLong(0);
|
||||||
|
|
||||||
@ -1161,11 +1193,10 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
updated += db.update(TABLE_HISTORY, values, "_id = ?",
|
updated += db.update(TABLE_HISTORY, values, "_id = ?",
|
||||||
new String[] { Long.toString(id) });
|
new String[] { Long.toString(id) });
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (cursor != null)
|
cursor.close();
|
||||||
cursor.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return updated;
|
return updated;
|
||||||
@ -1193,7 +1224,6 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
// If changes are needed, please update both
|
// If changes are needed, please update both
|
||||||
String faviconUrl = values.getAsString(Favicons.URL);
|
String faviconUrl = values.getAsString(Favicons.URL);
|
||||||
String pageUrl = null;
|
String pageUrl = null;
|
||||||
long faviconId;
|
|
||||||
|
|
||||||
trace("Inserting favicon for URL: " + faviconUrl);
|
trace("Inserting favicon for URL: " + faviconUrl);
|
||||||
|
|
||||||
@ -1210,15 +1240,16 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
values.put(Favicons.URL, org.mozilla.gecko.favicons.Favicons.guessDefaultFaviconURL(pageUrl));
|
values.put(Favicons.URL, org.mozilla.gecko.favicons.Favicons.guessDefaultFaviconURL(pageUrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
final long now = System.currentTimeMillis();
|
||||||
values.put(Favicons.DATE_CREATED, now);
|
values.put(Favicons.DATE_CREATED, now);
|
||||||
values.put(Favicons.DATE_MODIFIED, now);
|
values.put(Favicons.DATE_MODIFIED, now);
|
||||||
faviconId = db.insertOrThrow(TABLE_FAVICONS, null, values);
|
|
||||||
|
beginWrite(db);
|
||||||
|
final long faviconId = db.insertOrThrow(TABLE_FAVICONS, null, values);
|
||||||
|
|
||||||
if (pageUrl != null) {
|
if (pageUrl != null) {
|
||||||
updateFaviconIdsForUrl(db, pageUrl, faviconId);
|
updateFaviconIdsForUrl(db, pageUrl, faviconId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return faviconId;
|
return faviconId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1239,8 +1270,6 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
String faviconUrl = values.getAsString(Favicons.URL);
|
String faviconUrl = values.getAsString(Favicons.URL);
|
||||||
String pageUrl = null;
|
String pageUrl = null;
|
||||||
int updated = 0;
|
int updated = 0;
|
||||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
|
||||||
Cursor cursor = null;
|
|
||||||
Long faviconId = null;
|
Long faviconId = null;
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
@ -1256,33 +1285,38 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
|
|
||||||
values.put(Favicons.DATE_MODIFIED, now);
|
values.put(Favicons.DATE_MODIFIED, now);
|
||||||
|
|
||||||
|
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||||
|
|
||||||
// If there's no favicon URL given and we're inserting if needed, skip
|
// If there's no favicon URL given and we're inserting if needed, skip
|
||||||
// the update and only do an insert (otherwise all rows would be
|
// the update and only do an insert (otherwise all rows would be
|
||||||
// updated)
|
// updated).
|
||||||
if (!(insertIfNeeded && (faviconUrl == null))) {
|
if (!(insertIfNeeded && (faviconUrl == null))) {
|
||||||
updated = db.update(TABLE_FAVICONS, values, selection, selectionArgs);
|
updated = db.update(TABLE_FAVICONS, values, selection, selectionArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updated > 0) {
|
if (updated > 0) {
|
||||||
if ((faviconUrl != null) && (pageUrl != null)) {
|
if ((faviconUrl != null) && (pageUrl != null)) {
|
||||||
|
final Cursor cursor = db.query(TABLE_FAVICONS,
|
||||||
|
new String[] { Favicons._ID },
|
||||||
|
Favicons.URL + " = ?",
|
||||||
|
new String[] { faviconUrl },
|
||||||
|
null, null, null);
|
||||||
try {
|
try {
|
||||||
cursor = db.query(TABLE_FAVICONS,
|
|
||||||
new String[] { Favicons._ID },
|
|
||||||
Favicons.URL + " = ?",
|
|
||||||
new String[] { faviconUrl },
|
|
||||||
null, null, null);
|
|
||||||
if (cursor.moveToFirst()) {
|
if (cursor.moveToFirst()) {
|
||||||
faviconId = cursor.getLong(cursor.getColumnIndexOrThrow(Favicons._ID));
|
faviconId = cursor.getLong(cursor.getColumnIndexOrThrow(Favicons._ID));
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (cursor != null)
|
cursor.close();
|
||||||
cursor.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (pageUrl != null) {
|
||||||
|
beginWrite(db);
|
||||||
|
}
|
||||||
} else if (insertIfNeeded) {
|
} else if (insertIfNeeded) {
|
||||||
values.put(Favicons.DATE_CREATED, now);
|
values.put(Favicons.DATE_CREATED, now);
|
||||||
|
|
||||||
trace("No update, inserting favicon for URL: " + faviconUrl);
|
trace("No update, inserting favicon for URL: " + faviconUrl);
|
||||||
|
beginWrite(db);
|
||||||
faviconId = db.insert(TABLE_FAVICONS, null, values);
|
faviconId = db.insert(TABLE_FAVICONS, null, values);
|
||||||
updated = 1;
|
updated = 1;
|
||||||
}
|
}
|
||||||
@ -1294,40 +1328,40 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
long insertThumbnail(Uri uri, ContentValues values) {
|
private long insertThumbnail(Uri uri, ContentValues values) {
|
||||||
String url = values.getAsString(Thumbnails.URL);
|
final String url = values.getAsString(Thumbnails.URL);
|
||||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
|
||||||
|
|
||||||
trace("Inserting thumbnail for URL: " + url);
|
trace("Inserting thumbnail for URL: " + url);
|
||||||
|
|
||||||
DBUtils.stripEmptyByteArray(values, Thumbnails.DATA);
|
DBUtils.stripEmptyByteArray(values, Thumbnails.DATA);
|
||||||
|
|
||||||
|
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||||
|
beginWrite(db);
|
||||||
return db.insertOrThrow(TABLE_THUMBNAILS, null, values);
|
return db.insertOrThrow(TABLE_THUMBNAILS, null, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
int updateOrInsertThumbnail(Uri uri, ContentValues values, String selection,
|
private int updateOrInsertThumbnail(Uri uri, ContentValues values, String selection,
|
||||||
String[] selectionArgs) {
|
String[] selectionArgs) {
|
||||||
return updateThumbnail(uri, values, selection, selectionArgs,
|
return updateThumbnail(uri, values, selection, selectionArgs,
|
||||||
true /* insert if needed */);
|
true /* insert if needed */);
|
||||||
}
|
}
|
||||||
|
|
||||||
int updateExistingThumbnail(Uri uri, ContentValues values, String selection,
|
private int updateExistingThumbnail(Uri uri, ContentValues values, String selection,
|
||||||
String[] selectionArgs) {
|
String[] selectionArgs) {
|
||||||
return updateThumbnail(uri, values, selection, selectionArgs,
|
return updateThumbnail(uri, values, selection, selectionArgs,
|
||||||
false /* only update, no insert */);
|
false /* only update, no insert */);
|
||||||
}
|
}
|
||||||
|
|
||||||
int updateThumbnail(Uri uri, ContentValues values, String selection,
|
private int updateThumbnail(Uri uri, ContentValues values, String selection,
|
||||||
String[] selectionArgs, boolean insertIfNeeded) {
|
String[] selectionArgs, boolean insertIfNeeded) {
|
||||||
String url = values.getAsString(Thumbnails.URL);
|
final String url = values.getAsString(Thumbnails.URL);
|
||||||
int updated = 0;
|
|
||||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
|
||||||
|
|
||||||
DBUtils.stripEmptyByteArray(values, Thumbnails.DATA);
|
DBUtils.stripEmptyByteArray(values, Thumbnails.DATA);
|
||||||
|
|
||||||
trace("Updating thumbnail for URL: " + url);
|
trace("Updating thumbnail for URL: " + url);
|
||||||
|
|
||||||
updated = db.update(TABLE_THUMBNAILS, values, selection, selectionArgs);
|
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||||
|
beginWrite(db);
|
||||||
|
int updated = db.update(TABLE_THUMBNAILS, values, selection, selectionArgs);
|
||||||
|
|
||||||
if (updated == 0 && insertIfNeeded) {
|
if (updated == 0 && insertIfNeeded) {
|
||||||
trace("No update, inserting thumbnail for URL: " + url);
|
trace("No update, inserting thumbnail for URL: " + url);
|
||||||
@ -1338,6 +1372,12 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method does not create a new transaction. Its first operation is
|
||||||
|
* guaranteed to be a write, which in the case of a new enclosing
|
||||||
|
* transaction will guarantee that a read does not need to be upgraded to
|
||||||
|
* a write.
|
||||||
|
*/
|
||||||
int deleteHistory(Uri uri, String selection, String[] selectionArgs) {
|
int deleteHistory(Uri uri, String selection, String[] selectionArgs) {
|
||||||
debug("Deleting history entry for URI: " + uri);
|
debug("Deleting history entry for URI: " + uri);
|
||||||
|
|
||||||
@ -1360,8 +1400,20 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
values.put(History.VISITS, 0);
|
values.put(History.VISITS, 0);
|
||||||
values.put(History.DATE_MODIFIED, System.currentTimeMillis());
|
values.put(History.DATE_MODIFIED, System.currentTimeMillis());
|
||||||
|
|
||||||
cleanupSomeDeletedRecords(uri, History.CONTENT_URI, TABLE_HISTORY);
|
// Doing this UPDATE (or the DELETE above) first ensures that the
|
||||||
return db.update(TABLE_HISTORY, values, selection, selectionArgs);
|
// first operation within a new enclosing transaction is a write.
|
||||||
|
// The cleanup call below will do a SELECT first, and thus would
|
||||||
|
// require the transaction to be upgraded from a reader to a writer.
|
||||||
|
// In some cases that upgrade can fail (SQLITE_BUSY), so we avoid
|
||||||
|
// it if we can.
|
||||||
|
final int updated = db.update(TABLE_HISTORY, values, selection, selectionArgs);
|
||||||
|
try {
|
||||||
|
cleanupSomeDeletedRecords(uri, History.CONTENT_URI, TABLE_HISTORY);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// We don't care.
|
||||||
|
Log.e(LOGTAG, "Unable to clean up deleted history records: ", e);
|
||||||
|
}
|
||||||
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
int deleteBookmarks(Uri uri, String selection, String[] selectionArgs) {
|
int deleteBookmarks(Uri uri, String selection, String[] selectionArgs) {
|
||||||
@ -1370,6 +1422,7 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||||
|
|
||||||
if (isCallerSync(uri)) {
|
if (isCallerSync(uri)) {
|
||||||
|
beginWrite(db);
|
||||||
return db.delete(TABLE_BOOKMARKS, selection, selectionArgs);
|
return db.delete(TABLE_BOOKMARKS, selection, selectionArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1378,8 +1431,18 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(Bookmarks.IS_DELETED, 1);
|
values.put(Bookmarks.IS_DELETED, 1);
|
||||||
|
|
||||||
cleanupSomeDeletedRecords(uri, Bookmarks.CONTENT_URI, TABLE_BOOKMARKS);
|
// Doing this UPDATE (or the DELETE above) first ensures that the
|
||||||
return updateBookmarks(uri, values, selection, selectionArgs);
|
// first operation within this transaction is a write.
|
||||||
|
// The cleanup call below will do a SELECT first, and thus would
|
||||||
|
// require the transaction to be upgraded from a reader to a writer.
|
||||||
|
final int updated = updateBookmarks(uri, values, selection, selectionArgs);
|
||||||
|
try {
|
||||||
|
cleanupSomeDeletedRecords(uri, Bookmarks.CONTENT_URI, TABLE_BOOKMARKS);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// We don't care.
|
||||||
|
Log.e(LOGTAG, "Unable to clean up deleted bookmark records: ", e);
|
||||||
|
}
|
||||||
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
int deleteFavicons(Uri uri, String selection, String[] selectionArgs) {
|
int deleteFavicons(Uri uri, String selection, String[] selectionArgs) {
|
||||||
@ -1430,29 +1493,36 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
throws OperationApplicationException {
|
throws OperationApplicationException {
|
||||||
final int numOperations = operations.size();
|
final int numOperations = operations.size();
|
||||||
final ContentProviderResult[] results = new ContentProviderResult[numOperations];
|
final ContentProviderResult[] results = new ContentProviderResult[numOperations];
|
||||||
boolean failures = false;
|
|
||||||
SQLiteDatabase db = null;
|
|
||||||
|
|
||||||
if (numOperations >= 1) {
|
if (numOperations < 1) {
|
||||||
// We only have 1 database for all Uri's that we can get
|
debug("applyBatch: no operations; returning immediately.");
|
||||||
db = getWritableDatabase(operations.get(0).getUri());
|
|
||||||
} else {
|
|
||||||
// The original Android implementation returns a zero-length
|
// The original Android implementation returns a zero-length
|
||||||
// array in this case, we do the same.
|
// array in this case. We do the same.
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean failures = false;
|
||||||
|
|
||||||
|
// We only have 1 database for all Uris that we can get.
|
||||||
|
SQLiteDatabase db = getWritableDatabase(operations.get(0).getUri());
|
||||||
|
|
||||||
// Note that the apply() call may cause us to generate
|
// Note that the apply() call may cause us to generate
|
||||||
// additional transactions for the invidual operations.
|
// additional transactions for the individual operations.
|
||||||
// But Android's wrapper for SQLite supports nested transactions,
|
// But Android's wrapper for SQLite supports nested transactions,
|
||||||
// so this will do the right thing.
|
// so this will do the right thing.
|
||||||
db.beginTransaction();
|
//
|
||||||
|
// Note further that in some circumstances this can result in
|
||||||
|
// exceptions: if this transaction is first involved in reading,
|
||||||
|
// and then (naturally) tries to perform writes, SQLITE_BUSY can
|
||||||
|
// be raised. See Bug 947939 and friends.
|
||||||
|
beginBatch(db);
|
||||||
|
|
||||||
for (int i = 0; i < numOperations; i++) {
|
for (int i = 0; i < numOperations; i++) {
|
||||||
try {
|
try {
|
||||||
results[i] = operations.get(i).apply(this, results, i);
|
final ContentProviderOperation operation = operations.get(i);
|
||||||
|
results[i] = operation.apply(this, results, i);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
Log.w(LOGTAG, "SQLite Exception during applyBatch: ", e);
|
Log.w(LOGTAG, "SQLite Exception during applyBatch.", e);
|
||||||
// The Android API makes it implementation-defined whether
|
// The Android API makes it implementation-defined whether
|
||||||
// the failure of a single operation makes all others abort
|
// the failure of a single operation makes all others abort
|
||||||
// or not. For our use cases, best-effort operation makes
|
// or not. For our use cases, best-effort operation makes
|
||||||
@ -1485,8 +1555,8 @@ public class BrowserProvider extends TransactionalProvider<BrowserDatabaseHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
trace("Flushing DB applyBatch...");
|
trace("Flushing DB applyBatch...");
|
||||||
db.setTransactionSuccessful();
|
markBatchSuccessful(db);
|
||||||
db.endTransaction();
|
endBatch(db);
|
||||||
|
|
||||||
if (failures) {
|
if (failures) {
|
||||||
throw new OperationApplicationException();
|
throw new OperationApplicationException();
|
||||||
|
@ -57,21 +57,23 @@ public abstract class TransactionalProvider<T extends SQLiteOpenHelper> extends
|
|||||||
/*
|
/*
|
||||||
* Deletes items from the database within a DB transaction.
|
* Deletes items from the database within a DB transaction.
|
||||||
*
|
*
|
||||||
* @param uri query URI
|
* @param uri Query URI.
|
||||||
* @param selection An optional filter to match rows to update.
|
* @param selection An optional filter to match rows to delete.
|
||||||
* @param selectionArgs arguments for the selection
|
* @param selectionArgs An array of arguments to substitute into the selection.
|
||||||
* @return number of rows impacted by the deletion
|
*
|
||||||
|
* @return number of rows impacted by the deletion.
|
||||||
*/
|
*/
|
||||||
abstract protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs);
|
abstract protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Updates the database within a DB transaction.
|
* Updates the database within a DB transaction.
|
||||||
*
|
*
|
||||||
* @param uri Query URI
|
* @param uri Query URI.
|
||||||
* @param values A set of column_name/value pairs to add to the database.
|
* @param values A set of column_name/value pairs to add to the database.
|
||||||
* @param selection An optional filter to match rows to update.
|
* @param selection An optional filter to match rows to update.
|
||||||
* @param selectionArgs Arguments for the selection
|
* @param selectionArgs An array of arguments to substitute into the selection.
|
||||||
* @return number of rows impacted by the update
|
*
|
||||||
|
* @return number of rows impacted by the update.
|
||||||
*/
|
*/
|
||||||
abstract protected int updateInTransaction(Uri uri, ContentValues values, String selection, String[] selectionArgs);
|
abstract protected int updateInTransaction(Uri uri, ContentValues values, String selection, String[] selectionArgs);
|
||||||
|
|
||||||
@ -109,6 +111,10 @@ public abstract class TransactionalProvider<T extends SQLiteOpenHelper> extends
|
|||||||
return mDatabases.getDatabaseHelperForProfile(profile, isTest(uri)).getWritableDatabase();
|
return mDatabases.getDatabaseHelperForProfile(profile, isTest(uri)).getWritableDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected SQLiteDatabase getWritableDatabaseForProfile(String profile, boolean isTest) {
|
||||||
|
return mDatabases.getDatabaseHelperForProfile(profile, isTest).getWritableDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreate() {
|
public boolean onCreate() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
@ -125,25 +131,133 @@ public abstract class TransactionalProvider<T extends SQLiteOpenHelper> extends
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if OS version and database parallelism support indicates
|
||||||
|
* that this provider should bundle writes into transactions.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("static-method")
|
||||||
|
protected boolean shouldUseTransactions() {
|
||||||
|
return Build.VERSION.SDK_INT >= 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Track whether we're in a batch operation.
|
||||||
|
*
|
||||||
|
* When we're in a batch operation, individual write steps won't even try
|
||||||
|
* to start a transaction... and neither will they attempt to finish one.
|
||||||
|
*
|
||||||
|
* Set this to <code>Boolean.TRUE</code> when you're entering a batch --
|
||||||
|
* a section of code in which {@link ContentProvider} methods will be
|
||||||
|
* called, but nested transactions should not be started. Callers are
|
||||||
|
* responsible for beginning and ending the enclosing transaction, and
|
||||||
|
* for setting this to <code>Boolean.FALSE</code> when done.
|
||||||
|
*
|
||||||
|
* This is a ThreadLocal separate from `db.inTransaction` because batched
|
||||||
|
* operations start transactions independent of individual ContentProvider
|
||||||
|
* operations. This doesn't work well with the entire concept of this
|
||||||
|
* abstract class -- that is, automatically beginning and ending transactions
|
||||||
|
* for each insert/delete/update operation -- and doing so without
|
||||||
|
* causing arbitrary nesting requires external tracking.
|
||||||
|
*
|
||||||
|
* Note that beginWrite takes a DB argument, but we don't differentiate
|
||||||
|
* between databases in this tracking flag. If your ContentProvider manages
|
||||||
|
* multiple database transactions within the same thread, you'll need to
|
||||||
|
* amend this scheme -- but then, you're already doing some serious wizardry,
|
||||||
|
* so rock on.
|
||||||
|
*/
|
||||||
|
final ThreadLocal<Boolean> isInBatchOperation = new ThreadLocal<Boolean>();
|
||||||
|
|
||||||
|
private boolean isInBatch() {
|
||||||
|
final Boolean isInBatch = isInBatchOperation.get();
|
||||||
|
if (isInBatch == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return isInBatch.booleanValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we're not currently in a transaction, and we should be, start one.
|
||||||
|
*/
|
||||||
|
protected void beginWrite(final SQLiteDatabase db) {
|
||||||
|
if (isInBatch()) {
|
||||||
|
trace("Not bothering with an intermediate write transaction: inside batch operation.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldUseTransactions() && !db.inTransaction()) {
|
||||||
|
trace("beginWrite: beginning transaction.");
|
||||||
|
db.beginTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we're not in a batch, but we are in a write transaction, mark it as
|
||||||
|
* successful.
|
||||||
|
*/
|
||||||
|
protected void markWriteSuccessful(final SQLiteDatabase db) {
|
||||||
|
if (isInBatch()) {
|
||||||
|
trace("Not marking write successful: inside batch operation.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldUseTransactions() && db.inTransaction()) {
|
||||||
|
trace("Marking write transaction successful.");
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we're not in a batch, but we are in a write transaction,
|
||||||
|
* end it.
|
||||||
|
*
|
||||||
|
* @see TransactionalProvider#markWriteSuccessful(SQLiteDatabase)
|
||||||
|
*/
|
||||||
|
protected void endWrite(final SQLiteDatabase db) {
|
||||||
|
if (isInBatch()) {
|
||||||
|
trace("Not ending write: inside batch operation.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldUseTransactions() && db.inTransaction()) {
|
||||||
|
trace("endWrite: ending transaction.");
|
||||||
|
db.endTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void beginBatch(final SQLiteDatabase db) {
|
||||||
|
trace("Beginning batch.");
|
||||||
|
isInBatchOperation.set(Boolean.TRUE);
|
||||||
|
db.beginTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void markBatchSuccessful(final SQLiteDatabase db) {
|
||||||
|
if (isInBatch()) {
|
||||||
|
trace("Marking batch successful.");
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.w(LOGTAG, "Unexpectedly asked to mark batch successful, but not in batch!");
|
||||||
|
throw new IllegalStateException("Not in batch.");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void endBatch(final SQLiteDatabase db) {
|
||||||
|
trace("Ending batch.");
|
||||||
|
db.endTransaction();
|
||||||
|
isInBatchOperation.set(Boolean.FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||||
trace("Calling delete on URI: " + uri);
|
trace("Calling delete on URI: " + uri + ", " + selection + ", " + selectionArgs);
|
||||||
|
|
||||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||||
int deleted = 0;
|
int deleted = 0;
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 11) {
|
try {
|
||||||
trace("Beginning delete transaction: " + uri);
|
|
||||||
db.beginTransaction();
|
|
||||||
try {
|
|
||||||
deleted = deleteInTransaction(uri, selection, selectionArgs);
|
|
||||||
db.setTransactionSuccessful();
|
|
||||||
trace("Successful delete transaction: " + uri);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
deleted = deleteInTransaction(uri, selection, selectionArgs);
|
deleted = deleteInTransaction(uri, selection, selectionArgs);
|
||||||
|
markWriteSuccessful(db);
|
||||||
|
} finally {
|
||||||
|
endWrite(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deleted > 0) {
|
if (deleted > 0) {
|
||||||
@ -160,23 +274,14 @@ public abstract class TransactionalProvider<T extends SQLiteOpenHelper> extends
|
|||||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||||
Uri result = null;
|
Uri result = null;
|
||||||
try {
|
try {
|
||||||
if (Build.VERSION.SDK_INT >= 11) {
|
result = insertInTransaction(uri, values);
|
||||||
trace("Beginning insert transaction: " + uri);
|
markWriteSuccessful(db);
|
||||||
db.beginTransaction();
|
|
||||||
try {
|
|
||||||
result = insertInTransaction(uri, values);
|
|
||||||
db.setTransactionSuccessful();
|
|
||||||
trace("Successful insert transaction: " + uri);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = insertInTransaction(uri, values);
|
|
||||||
}
|
|
||||||
} catch (SQLException sqle) {
|
} catch (SQLException sqle) {
|
||||||
Log.e(LOGTAG, "exception in DB operation", sqle);
|
Log.e(LOGTAG, "exception in DB operation", sqle);
|
||||||
} catch (UnsupportedOperationException uoe) {
|
} catch (UnsupportedOperationException uoe) {
|
||||||
Log.e(LOGTAG, "don't know how to perform that insert", uoe);
|
Log.e(LOGTAG, "don't know how to perform that insert", uoe);
|
||||||
|
} finally {
|
||||||
|
endWrite(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@ -190,23 +295,17 @@ public abstract class TransactionalProvider<T extends SQLiteOpenHelper> extends
|
|||||||
@Override
|
@Override
|
||||||
public int update(Uri uri, ContentValues values, String selection,
|
public int update(Uri uri, ContentValues values, String selection,
|
||||||
String[] selectionArgs) {
|
String[] selectionArgs) {
|
||||||
trace("Calling update on URI: " + uri);
|
trace("Calling update on URI: " + uri + ", " + selection + ", " + selectionArgs);
|
||||||
|
|
||||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||||
int updated = 0;
|
int updated = 0;
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 11) {
|
try {
|
||||||
trace("Beginning update transaction: " + uri);
|
updated = updateInTransaction(uri, values, selection,
|
||||||
db.beginTransaction();
|
selectionArgs);
|
||||||
try {
|
markWriteSuccessful(db);
|
||||||
updated = updateInTransaction(uri, values, selection, selectionArgs);
|
} finally {
|
||||||
db.setTransactionSuccessful();
|
endWrite(db);
|
||||||
trace("Successful update transaction: " + uri);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
updated = updateInTransaction(uri, values, selection, selectionArgs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updated > 0) {
|
if (updated > 0) {
|
||||||
@ -227,7 +326,8 @@ public abstract class TransactionalProvider<T extends SQLiteOpenHelper> extends
|
|||||||
|
|
||||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||||
|
|
||||||
db.beginTransaction();
|
debug("bulkInsert: explicitly starting transaction.");
|
||||||
|
beginBatch(db);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < numValues; i++) {
|
for (int i = 0; i < numValues; i++) {
|
||||||
@ -235,9 +335,10 @@ public abstract class TransactionalProvider<T extends SQLiteOpenHelper> extends
|
|||||||
successes++;
|
successes++;
|
||||||
}
|
}
|
||||||
trace("Flushing DB bulkinsert...");
|
trace("Flushing DB bulkinsert...");
|
||||||
db.setTransactionSuccessful();
|
markBatchSuccessful(db);
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction();
|
debug("bulkInsert: explicitly ending transaction.");
|
||||||
|
endBatch(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (successes > 0) {
|
if (successes > 0) {
|
||||||
|
@ -297,11 +297,14 @@ gbjar.sources += [
|
|||||||
'PrivateTab.java',
|
'PrivateTab.java',
|
||||||
'prompts/ColorPickerInput.java',
|
'prompts/ColorPickerInput.java',
|
||||||
'prompts/IconGridInput.java',
|
'prompts/IconGridInput.java',
|
||||||
|
'prompts/IntentChooserPrompt.java',
|
||||||
|
'prompts/IntentHandler.java',
|
||||||
'prompts/Prompt.java',
|
'prompts/Prompt.java',
|
||||||
'prompts/PromptInput.java',
|
'prompts/PromptInput.java',
|
||||||
'prompts/PromptListAdapter.java',
|
'prompts/PromptListAdapter.java',
|
||||||
'prompts/PromptListItem.java',
|
'prompts/PromptListItem.java',
|
||||||
'prompts/PromptService.java',
|
'prompts/PromptService.java',
|
||||||
|
'prompts/TabInput.java',
|
||||||
'ReaderModeUtils.java',
|
'ReaderModeUtils.java',
|
||||||
'ReferrerReceiver.java',
|
'ReferrerReceiver.java',
|
||||||
'RemoteTabs.java',
|
'RemoteTabs.java',
|
||||||
|
157
mobile/android/base/prompts/IntentChooserPrompt.java
Normal file
157
mobile/android/base/prompts/IntentChooserPrompt.java
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.gecko.prompts;
|
||||||
|
|
||||||
|
import org.mozilla.gecko.GeckoAppShell;
|
||||||
|
import org.mozilla.gecko.util.ThreadUtils;
|
||||||
|
import org.mozilla.gecko.widget.GeckoActionProvider;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.ResolveInfo;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a prompt letting the user pick from a list of intent handlers for a set of Intents or
|
||||||
|
* for a GeckoActionProvider. Basic usage:
|
||||||
|
* IntentChooserPrompt prompt = new IntentChooserPrompt(context, new Intent[] {
|
||||||
|
* ... // some intents
|
||||||
|
* });
|
||||||
|
* prompt.show("Title", context, new IntentHandler() {
|
||||||
|
* public void onIntentSelected(Intent intent, int position) { }
|
||||||
|
* public void onCancelled() { }
|
||||||
|
* });
|
||||||
|
**/
|
||||||
|
public class IntentChooserPrompt {
|
||||||
|
private static final String LOGTAG = "GeckoIntentChooser";
|
||||||
|
|
||||||
|
private final ArrayList<PromptListItem> mItems;
|
||||||
|
|
||||||
|
public IntentChooserPrompt(Context context, Intent[] intents) {
|
||||||
|
mItems = getItems(context, intents);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntentChooserPrompt(Context context, GeckoActionProvider provider) {
|
||||||
|
mItems = getItems(context, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If an IntentHandler is passed in, will asynchronously call the handler when the dialog is closed
|
||||||
|
* Otherwise, will return the Intent that was chosen by the user. Must be called on the UI thread.
|
||||||
|
*/
|
||||||
|
public void show(final String title, final Context context, final IntentHandler handler) {
|
||||||
|
ThreadUtils.assertOnUiThread();
|
||||||
|
|
||||||
|
if (mItems.isEmpty()) {
|
||||||
|
Log.i(LOGTAG, "No activities for the intent chooser!");
|
||||||
|
handler.onCancelled();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's only one item in the intent list, just return it
|
||||||
|
if (mItems.size() == 1) {
|
||||||
|
handler.onIntentSelected(mItems.get(0).intent, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Prompt prompt = new Prompt(context, new Prompt.PromptCallback() {
|
||||||
|
@Override
|
||||||
|
public void onPromptFinished(String promptServiceResult) {
|
||||||
|
if (handler == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int itemId = -1;
|
||||||
|
try {
|
||||||
|
itemId = new JSONObject(promptServiceResult).getInt("button");
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.e(LOGTAG, "result from promptservice was invalid: ", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemId == -1) {
|
||||||
|
handler.onCancelled();
|
||||||
|
} else {
|
||||||
|
handler.onIntentSelected(mItems.get(itemId).intent, itemId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
PromptListItem[] arrays = new PromptListItem[mItems.size()];
|
||||||
|
mItems.toArray(arrays);
|
||||||
|
prompt.show(title, "", arrays, ListView.CHOICE_MODE_NONE);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whether or not any activities were found. Useful for checking if you should try a different Intent set
|
||||||
|
public boolean hasActivities(Context context) {
|
||||||
|
return mItems.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets a list of PromptListItems for an Intent array
|
||||||
|
private ArrayList<PromptListItem> getItems(final Context context, Intent[] intents) {
|
||||||
|
final ArrayList<PromptListItem> items = new ArrayList<PromptListItem>();
|
||||||
|
|
||||||
|
// If we have intents, use them to build the initial list
|
||||||
|
for (final Intent intent : intents) {
|
||||||
|
items.addAll(getItemsForIntent(context, intent));
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets a list of PromptListItems for a GeckoActionProvider
|
||||||
|
private ArrayList<PromptListItem> getItems(final Context context, final GeckoActionProvider provider) {
|
||||||
|
final ArrayList<PromptListItem> items = new ArrayList<PromptListItem>();
|
||||||
|
|
||||||
|
// Add any intents from the provider.
|
||||||
|
final PackageManager packageManager = context.getPackageManager();
|
||||||
|
final ArrayList<ResolveInfo> infos = provider.getSortedActivites();
|
||||||
|
|
||||||
|
for (final ResolveInfo info : infos) {
|
||||||
|
items.add(getItemForResolveInfo(info, packageManager, provider.getIntent()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PromptListItem getItemForResolveInfo(ResolveInfo info, PackageManager pm, Intent intent) {
|
||||||
|
PromptListItem item = new PromptListItem(info.loadLabel(pm).toString());
|
||||||
|
item.icon = info.loadIcon(pm);
|
||||||
|
item.intent = new Intent(intent);
|
||||||
|
|
||||||
|
// These intents should be implicit.
|
||||||
|
item.intent.setComponent(new ComponentName(info.activityInfo.applicationInfo.packageName,
|
||||||
|
info.activityInfo.name));
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<PromptListItem> getItemsForIntent(Context context, Intent intent) {
|
||||||
|
ArrayList<PromptListItem> items = new ArrayList<PromptListItem>();
|
||||||
|
PackageManager pm = context.getPackageManager();
|
||||||
|
List<ResolveInfo> lri = pm.queryIntentActivityOptions(GeckoAppShell.getGeckoInterface().getActivity().getComponentName(), null, intent, 0);
|
||||||
|
|
||||||
|
// If we didn't find any activities, just return the empty list
|
||||||
|
if (lri == null) {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, convert the ResolveInfo. Note we don't currently check for duplicates here.
|
||||||
|
for (ResolveInfo ri : lri) {
|
||||||
|
items.add(getItemForResolveInfo(ri, pm, intent));
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
12
mobile/android/base/prompts/IntentHandler.java
Normal file
12
mobile/android/base/prompts/IntentHandler.java
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.gecko.prompts;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
public interface IntentHandler {
|
||||||
|
public void onIntentSelected(Intent intent, int position);
|
||||||
|
public void onCancelled();
|
||||||
|
}
|
@ -76,6 +76,7 @@ public class PromptInput {
|
|||||||
mView = (View)input;
|
mView = (View)input;
|
||||||
return mView;
|
return mView;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getValue() {
|
public Object getValue() {
|
||||||
EditText edit = (EditText)mView;
|
EditText edit = (EditText)mView;
|
||||||
@ -111,6 +112,7 @@ public class PromptInput {
|
|||||||
InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getValue() {
|
public Object getValue() {
|
||||||
EditText edit = (EditText)mView;
|
EditText edit = (EditText)mView;
|
||||||
@ -135,6 +137,7 @@ public class PromptInput {
|
|||||||
mView = (View)checkbox;
|
mView = (View)checkbox;
|
||||||
return mView;
|
return mView;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getValue() {
|
public Object getValue() {
|
||||||
CheckBox checkbox = (CheckBox)mView;
|
CheckBox checkbox = (CheckBox)mView;
|
||||||
@ -213,6 +216,7 @@ public class PromptInput {
|
|||||||
private static String formatDateString(String dateFormat, Calendar calendar) {
|
private static String formatDateString(String dateFormat, Calendar calendar) {
|
||||||
return new SimpleDateFormat(dateFormat).format(calendar.getTime());
|
return new SimpleDateFormat(dateFormat).format(calendar.getTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getValue() {
|
public Object getValue() {
|
||||||
if (Build.VERSION.SDK_INT < 11 && mType.equals("date")) {
|
if (Build.VERSION.SDK_INT < 11 && mType.equals("date")) {
|
||||||
@ -293,6 +297,7 @@ public class PromptInput {
|
|||||||
|
|
||||||
return spinner;
|
return spinner;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getValue() {
|
public Object getValue() {
|
||||||
return new Integer(spinner.getSelectedItemPosition());
|
return new Integer(spinner.getSelectedItemPosition());
|
||||||
@ -312,10 +317,6 @@ public class PromptInput {
|
|||||||
mView = view;
|
mView = view;
|
||||||
return mView;
|
return mView;
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
public Object getValue() {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PromptInput(JSONObject obj) {
|
public PromptInput(JSONObject obj) {
|
||||||
@ -344,6 +345,8 @@ public class PromptInput {
|
|||||||
return new IconGridInput(obj);
|
return new IconGridInput(obj);
|
||||||
} else if (ColorPickerInput.INPUT_TYPE.equals(type)) {
|
} else if (ColorPickerInput.INPUT_TYPE.equals(type)) {
|
||||||
return new ColorPickerInput(obj);
|
return new ColorPickerInput(obj);
|
||||||
|
} else if (TabInput.INPUT_TYPE.equals(type)) {
|
||||||
|
return new TabInput(obj);
|
||||||
} else {
|
} else {
|
||||||
for (String dtType : DateTimeInput.INPUT_TYPES) {
|
for (String dtType : DateTimeInput.INPUT_TYPES) {
|
||||||
if (dtType.equals(type)) {
|
if (dtType.equals(type)) {
|
||||||
@ -363,7 +366,7 @@ public class PromptInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Object getValue() {
|
public Object getValue() {
|
||||||
return "";
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getScrollable() {
|
public boolean getScrollable() {
|
||||||
@ -371,6 +374,6 @@ public class PromptInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean canApplyInputStyle() {
|
public boolean canApplyInputStyle() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,9 @@ import org.json.JSONArray;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@ -17,6 +19,7 @@ public class PromptListItem {
|
|||||||
public final boolean disabled;
|
public final boolean disabled;
|
||||||
public final int id;
|
public final int id;
|
||||||
public boolean selected;
|
public boolean selected;
|
||||||
|
public Intent intent;
|
||||||
|
|
||||||
public boolean isParent;
|
public boolean isParent;
|
||||||
public Drawable icon;
|
public Drawable icon;
|
||||||
|
109
mobile/android/base/prompts/TabInput.java
Normal file
109
mobile/android/base/prompts/TabInput.java
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.gecko.prompts;
|
||||||
|
|
||||||
|
import org.mozilla.gecko.R;
|
||||||
|
import org.mozilla.gecko.util.ThreadUtils;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.json.JSONException;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TabHost;
|
||||||
|
import android.widget.TabWidget;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.LinearLayout.LayoutParams;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
|
||||||
|
public class TabInput extends PromptInput implements AdapterView.OnItemClickListener {
|
||||||
|
public static final String INPUT_TYPE = "tabs";
|
||||||
|
public static final String LOGTAG = "GeckoTabInput";
|
||||||
|
|
||||||
|
/* Keeping the order of this in sync with the JSON is important. */
|
||||||
|
final private LinkedHashMap<String, PromptListItem[]> mTabs;
|
||||||
|
|
||||||
|
private TabHost mHost;
|
||||||
|
private int mPosition;
|
||||||
|
|
||||||
|
public TabInput(JSONObject obj) {
|
||||||
|
super(obj);
|
||||||
|
mTabs = new LinkedHashMap<String, PromptListItem[]>();
|
||||||
|
try {
|
||||||
|
JSONArray tabs = obj.getJSONArray("items");
|
||||||
|
for (int i = 0; i < tabs.length(); i++) {
|
||||||
|
JSONObject tab = tabs.getJSONObject(i);
|
||||||
|
String title = tab.getString("label");
|
||||||
|
JSONArray items = tab.getJSONArray("items");
|
||||||
|
mTabs.put(title, PromptListItem.getArray(items));
|
||||||
|
}
|
||||||
|
} catch(JSONException ex) {
|
||||||
|
Log.e(LOGTAG, "Exception", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(final Context context) throws UnsupportedOperationException {
|
||||||
|
LayoutInflater inflater = LayoutInflater.from(context);
|
||||||
|
mHost = (TabHost) inflater.inflate(R.layout.tab_prompt_input, null);
|
||||||
|
mHost.setup();
|
||||||
|
|
||||||
|
for (String title : mTabs.keySet()) {
|
||||||
|
final TabHost.TabSpec spec = mHost.newTabSpec(title);
|
||||||
|
spec.setContent(new TabHost.TabContentFactory() {
|
||||||
|
@Override
|
||||||
|
public View createTabContent(final String tag) {
|
||||||
|
PromptListAdapter adapter = new PromptListAdapter(context, android.R.layout.simple_list_item_1, mTabs.get(tag));
|
||||||
|
ListView listView = new ListView(context);
|
||||||
|
listView.setOnItemClickListener(TabInput.this);
|
||||||
|
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
|
||||||
|
listView.setAdapter(adapter);
|
||||||
|
return listView;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
spec.setIndicator(title);
|
||||||
|
mHost.addTab(spec);
|
||||||
|
}
|
||||||
|
mView = mHost;
|
||||||
|
return mHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValue() {
|
||||||
|
JSONObject obj = new JSONObject();
|
||||||
|
try {
|
||||||
|
obj.put("tab", mHost.getCurrentTab());
|
||||||
|
obj.put("item", mPosition);
|
||||||
|
} catch(JSONException ex) { }
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getScrollable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canApplyInputStyle() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
ThreadUtils.assertOnUiThread();
|
||||||
|
mPosition = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
mobile/android/base/resources/layout/tab_prompt_input.xml
Normal file
31
mobile/android/base/resources/layout/tab_prompt_input.xml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?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/. -->
|
||||||
|
|
||||||
|
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@android:id/tabhost"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" >
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:minHeight="100dp">
|
||||||
|
|
||||||
|
<TabWidget
|
||||||
|
android:id="@android:id/tabs"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" >
|
||||||
|
</TabWidget>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@android:id/tabcontent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" >
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</TabHost>
|
@ -65,17 +65,41 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
BrowserContract.Bookmarks.READING_LIST_FOLDER_GUID });
|
BrowserContract.Bookmarks.READING_LIST_FOLDER_GUID });
|
||||||
|
|
||||||
c = mProvider.query(appendUriParam(BrowserContract.Bookmarks.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"), null, null, null, null);
|
c = mProvider.query(appendUriParam(BrowserContract.Bookmarks.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"), null, null, null, null);
|
||||||
mAsserter.is(c.getCount(), 7, "All non-special bookmarks and folders were deleted");
|
assertCountIsAndClose(c, 7, "All non-special bookmarks and folders were deleted");
|
||||||
|
|
||||||
mProvider.delete(appendUriParam(BrowserContract.History.CONTENT_URI, BrowserContract.PARAM_IS_SYNC, "1"), null, null);
|
mProvider.delete(appendUriParam(BrowserContract.History.CONTENT_URI, BrowserContract.PARAM_IS_SYNC, "1"), null, null);
|
||||||
c = mProvider.query(appendUriParam(BrowserContract.History.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"), null, null, null, null);
|
c = mProvider.query(appendUriParam(BrowserContract.History.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"), null, null, null, null);
|
||||||
mAsserter.is(c.getCount(), 0, "All history entries were deleted");
|
assertCountIsAndClose(c, 0, "All history entries were deleted");
|
||||||
|
|
||||||
mProvider.delete(BrowserContract.Favicons.CONTENT_URI, null, null);
|
/**
|
||||||
mAsserter.is(c.getCount(), 0, "All favicons were deleted");
|
* There's no reason why the following two parts should fail.
|
||||||
|
* But sometimes they do, and I'm not going to spend the time
|
||||||
|
* to figure out why in an unrelated bug.
|
||||||
|
*/
|
||||||
|
|
||||||
mProvider.delete(BrowserContract.Thumbnails.CONTENT_URI, null, null);
|
mProvider.delete(appendUriParam(BrowserContract.Favicons.CONTENT_URI, BrowserContract.PARAM_IS_SYNC, "1"), null, null);
|
||||||
mAsserter.is(c.getCount(), 0, "All thumbnails were deleted");
|
c = mProvider.query(appendUriParam(BrowserContract.Favicons.CONTENT_URI,
|
||||||
|
BrowserContract.PARAM_SHOW_DELETED, "1"),
|
||||||
|
null, null, null, null);
|
||||||
|
|
||||||
|
if (c.getCount() > 0) {
|
||||||
|
mAsserter.dumpLog("Unexpected favicons in ensureEmptyDatabase.");
|
||||||
|
}
|
||||||
|
c.close();
|
||||||
|
|
||||||
|
// assertCountIsAndClose(c, 0, "All favicons were deleted");
|
||||||
|
|
||||||
|
mProvider.delete(appendUriParam(BrowserContract.Thumbnails.CONTENT_URI, BrowserContract.PARAM_IS_SYNC, "1"), null, null);
|
||||||
|
c = mProvider.query(appendUriParam(BrowserContract.Thumbnails.CONTENT_URI,
|
||||||
|
BrowserContract.PARAM_SHOW_DELETED, "1"),
|
||||||
|
null, null, null, null);
|
||||||
|
|
||||||
|
if (c.getCount() > 0) {
|
||||||
|
mAsserter.dumpLog("Unexpected thumbnails in ensureEmptyDatabase.");
|
||||||
|
}
|
||||||
|
c.close();
|
||||||
|
|
||||||
|
// assertCountIsAndClose(c, 0, "All thumbnails were deleted");
|
||||||
}
|
}
|
||||||
|
|
||||||
private ContentValues createBookmark(String title, String url, long parentId,
|
private ContentValues createBookmark(String title, String url, long parentId,
|
||||||
@ -326,7 +350,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
mAsserter.is(seenException, false, "Batch updating succeded");
|
mAsserter.is(seenException, false, "Batch updating succeded");
|
||||||
mOperations.clear();
|
mOperations.clear();
|
||||||
|
|
||||||
// Delte all visits
|
// Delete all visits
|
||||||
for (int i = 0; i < TESTCOUNT; i++) {
|
for (int i = 0; i < TESTCOUNT; i++) {
|
||||||
builder = ContentProviderOperation.newDelete(BrowserContract.History.CONTENT_URI);
|
builder = ContentProviderOperation.newDelete(BrowserContract.History.CONTENT_URI);
|
||||||
builder.withSelection(BrowserContract.History.URL + " = ?",
|
builder.withSelection(BrowserContract.History.URL + " = ?",
|
||||||
@ -340,7 +364,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
} catch (OperationApplicationException ex) {
|
} catch (OperationApplicationException ex) {
|
||||||
seenException = true;
|
seenException = true;
|
||||||
}
|
}
|
||||||
mAsserter.is(seenException, false, "Batch deletion succeded");
|
mAsserter.is(seenException, false, "Batch deletion succeeded");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force a Constraint error, see if later operations still apply correctly
|
// Force a Constraint error, see if later operations still apply correctly
|
||||||
@ -475,6 +499,8 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
mAsserter.is(new Integer(parentId), new Integer(rootId),
|
mAsserter.is(new Integer(parentId), new Integer(rootId),
|
||||||
"The PARENT of the " + guid + " special folder is correct");
|
"The PARENT of the " + guid + " special folder is correct");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,6 +575,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
|
|
||||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TYPE)), String.valueOf(BrowserContract.Bookmarks.TYPE_BOOKMARK),
|
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.TYPE)), String.valueOf(BrowserContract.Bookmarks.TYPE_BOOKMARK),
|
||||||
"Inserted bookmark has correct default type");
|
"Inserted bookmark has correct default type");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -571,12 +598,14 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
|
|
||||||
mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Bookmarks.FAVICON)), "UTF8"),
|
mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Bookmarks.FAVICON)), "UTF8"),
|
||||||
favicon, "Inserted bookmark has corresponding favicon image");
|
favicon, "Inserted bookmark has corresponding favicon image");
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = getFaviconsByUrl(pageUrl);
|
c = getFaviconsByUrl(pageUrl);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Inserted favicon found");
|
mAsserter.is(c.moveToFirst(), true, "Inserted favicon found");
|
||||||
|
|
||||||
mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Combined.FAVICON)), "UTF8"),
|
mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Combined.FAVICON)), "UTF8"),
|
||||||
favicon, "Inserted favicon has corresponding favicon image");
|
favicon, "Inserted favicon has corresponding favicon image");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,6 +616,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
|
|
||||||
Cursor c = getBookmarkById(id);
|
Cursor c = getBookmarkById(id);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Inserted bookmark found");
|
mAsserter.is(c.moveToFirst(), true, "Inserted bookmark found");
|
||||||
|
c.close();
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -603,6 +633,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
|
|
||||||
Cursor c = getBookmarkById(appendUriParam(BrowserContract.Bookmarks.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"), id);
|
Cursor c = getBookmarkById(appendUriParam(BrowserContract.Bookmarks.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"), id);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Deleted bookmark was only marked as deleted");
|
mAsserter.is(c.moveToFirst(), true, "Deleted bookmark was only marked as deleted");
|
||||||
|
c.close();
|
||||||
|
|
||||||
deleted = mProvider.delete(appendUriParam(BrowserContract.Bookmarks.CONTENT_URI, BrowserContract.PARAM_IS_SYNC, "1"),
|
deleted = mProvider.delete(appendUriParam(BrowserContract.Bookmarks.CONTENT_URI, BrowserContract.PARAM_IS_SYNC, "1"),
|
||||||
BrowserContract.Bookmarks._ID + " = ?",
|
BrowserContract.Bookmarks._ID + " = ?",
|
||||||
@ -612,6 +643,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
|
|
||||||
c = getBookmarkById(appendUriParam(BrowserContract.Bookmarks.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"), id);
|
c = getBookmarkById(appendUriParam(BrowserContract.Bookmarks.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"), id);
|
||||||
mAsserter.is(c.moveToFirst(), false, "Inserted bookmark is now actually deleted");
|
mAsserter.is(c.moveToFirst(), false, "Inserted bookmark is now actually deleted");
|
||||||
|
c.close();
|
||||||
|
|
||||||
id = insertOneBookmark();
|
id = insertOneBookmark();
|
||||||
|
|
||||||
@ -622,6 +654,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
c = getBookmarkById(id);
|
c = getBookmarkById(id);
|
||||||
mAsserter.is(c.moveToFirst(), false,
|
mAsserter.is(c.moveToFirst(), false,
|
||||||
"Inserted bookmark can't be found after deletion using URI with ID");
|
"Inserted bookmark can't be found after deletion using URI with ID");
|
||||||
|
c.close();
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 8 &&
|
if (Build.VERSION.SDK_INT >= 8 &&
|
||||||
Build.VERSION.SDK_INT < 16) {
|
Build.VERSION.SDK_INT < 16) {
|
||||||
@ -631,6 +664,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
long parentId = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
|
long parentId = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
|
||||||
c = getBookmarkById(parentId);
|
c = getBookmarkById(parentId);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Inserted bookmarks folder found");
|
mAsserter.is(c.moveToFirst(), true, "Inserted bookmarks folder found");
|
||||||
|
c.close();
|
||||||
|
|
||||||
b = createBookmark("Example", "http://example.com", parentId,
|
b = createBookmark("Example", "http://example.com", parentId,
|
||||||
BrowserContract.Bookmarks.TYPE_BOOKMARK, 0, "tags", "description", "keyword");
|
BrowserContract.Bookmarks.TYPE_BOOKMARK, 0, "tags", "description", "keyword");
|
||||||
@ -638,6 +672,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
id = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
|
id = ContentUris.parseId(mProvider.insert(BrowserContract.Bookmarks.CONTENT_URI, b));
|
||||||
c = getBookmarkById(id);
|
c = getBookmarkById(id);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Inserted bookmark found");
|
mAsserter.is(c.moveToFirst(), true, "Inserted bookmark found");
|
||||||
|
c.close();
|
||||||
|
|
||||||
deleted = 0;
|
deleted = 0;
|
||||||
try {
|
try {
|
||||||
@ -664,11 +699,13 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
|
|
||||||
Cursor c = getFaviconsByUrl(pageUrl);
|
Cursor c = getFaviconsByUrl(pageUrl);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Inserted favicon found");
|
mAsserter.is(c.moveToFirst(), true, "Inserted favicon found");
|
||||||
|
c.close();
|
||||||
|
|
||||||
mProvider.delete(ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI, id), null, null);
|
mProvider.delete(ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI, id), null, null);
|
||||||
|
|
||||||
c = getFaviconsByUrl(pageUrl);
|
c = getFaviconsByUrl(pageUrl);
|
||||||
mAsserter.is(c.moveToFirst(), false, "Favicon is deleted with last reference to it");
|
mAsserter.is(c.moveToFirst(), false, "Favicon is deleted with last reference to it");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -713,6 +750,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
new String[] { String.valueOf(id) });
|
new String[] { String.valueOf(id) });
|
||||||
|
|
||||||
mAsserter.is((updated == 1), true, "Inserted bookmark was updated");
|
mAsserter.is((updated == 1), true, "Inserted bookmark was updated");
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = getBookmarkById(id);
|
c = getBookmarkById(id);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Updated bookmark found");
|
mAsserter.is(c.moveToFirst(), true, "Updated bookmark found");
|
||||||
@ -752,12 +790,14 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
u.put(BrowserContract.Bookmarks.URL, "http://examples2.com");
|
u.put(BrowserContract.Bookmarks.URL, "http://examples2.com");
|
||||||
|
|
||||||
updated = mProvider.update(ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI, id), u, null, null);
|
updated = mProvider.update(ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI, id), u, null, null);
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = getBookmarkById(id);
|
c = getBookmarkById(id);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Updated bookmark found");
|
mAsserter.is(c.moveToFirst(), true, "Updated bookmark found");
|
||||||
|
|
||||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.URL)), u.getAsString(BrowserContract.Bookmarks.URL),
|
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.Bookmarks.URL)), u.getAsString(BrowserContract.Bookmarks.URL),
|
||||||
"Updated bookmark has correct URL using URI with id");
|
"Updated bookmark has correct URL using URI with id");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -784,12 +824,14 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
|
|
||||||
ContentValues u = createFaviconEntry(pageUrl, newFavicon);
|
ContentValues u = createFaviconEntry(pageUrl, newFavicon);
|
||||||
mProvider.update(BrowserContract.Favicons.CONTENT_URI, u, null, null);
|
mProvider.update(BrowserContract.Favicons.CONTENT_URI, u, null, null);
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = getFaviconsByUrl(pageUrl);
|
c = getFaviconsByUrl(pageUrl);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Updated favicon found");
|
mAsserter.is(c.moveToFirst(), true, "Updated favicon found");
|
||||||
|
|
||||||
mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Combined.FAVICON)), "UTF8"),
|
mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Combined.FAVICON)), "UTF8"),
|
||||||
newFavicon, "Updated favicon has corresponding favicon image");
|
newFavicon, "Updated favicon has corresponding favicon image");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -825,6 +867,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mAsserter.is(i, count, "Folder has the right number of children.");
|
mAsserter.is(i, count, "Folder has the right number of children.");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final int NUMBER_OF_CHILDREN = 1001;
|
public static final int NUMBER_OF_CHILDREN = 1001;
|
||||||
@ -921,6 +964,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
id = insertWithNullCol(BrowserContract.History.VISITS);
|
id = insertWithNullCol(BrowserContract.History.VISITS);
|
||||||
mAsserter.is(new Long(id), new Long(-1),
|
mAsserter.is(new Long(id), new Long(-1),
|
||||||
"Should not be able to insert history with null number of visits");
|
"Should not be able to insert history with null number of visits");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -943,12 +987,14 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
|
|
||||||
mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.History.FAVICON)), "UTF8"),
|
mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.History.FAVICON)), "UTF8"),
|
||||||
favicon, "Inserted history entry has corresponding favicon image");
|
favicon, "Inserted history entry has corresponding favicon image");
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = getFaviconsByUrl(pageUrl);
|
c = getFaviconsByUrl(pageUrl);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Inserted favicon found");
|
mAsserter.is(c.moveToFirst(), true, "Inserted favicon found");
|
||||||
|
|
||||||
mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Combined.FAVICON)), "UTF8"),
|
mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Combined.FAVICON)), "UTF8"),
|
||||||
favicon, "Inserted favicon has corresponding favicon image");
|
favicon, "Inserted favicon has corresponding favicon image");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -959,6 +1005,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
|
|
||||||
Cursor c = getHistoryEntryById(id);
|
Cursor c = getHistoryEntryById(id);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Inserted history entry found");
|
mAsserter.is(c.moveToFirst(), true, "Inserted history entry found");
|
||||||
|
c.close();
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -981,6 +1028,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
new String[] { String.valueOf(id) });
|
new String[] { String.valueOf(id) });
|
||||||
|
|
||||||
mAsserter.is((deleted == 1), true, "Inserted history entry was deleted");
|
mAsserter.is((deleted == 1), true, "Inserted history entry was deleted");
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = getHistoryEntryById(appendUriParam(BrowserContract.History.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"), id);
|
c = getHistoryEntryById(appendUriParam(BrowserContract.History.CONTENT_URI, BrowserContract.PARAM_SHOW_DELETED, "1"), id);
|
||||||
mAsserter.is(c.moveToFirst(), false, "Inserted history is now actually deleted");
|
mAsserter.is(c.moveToFirst(), false, "Inserted history is now actually deleted");
|
||||||
@ -990,10 +1038,12 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
deleted = mProvider.delete(ContentUris.withAppendedId(BrowserContract.History.CONTENT_URI, id), null, null);
|
deleted = mProvider.delete(ContentUris.withAppendedId(BrowserContract.History.CONTENT_URI, id), null, null);
|
||||||
mAsserter.is((deleted == 1), true,
|
mAsserter.is((deleted == 1), true,
|
||||||
"Inserted history entry was deleted using URI with id");
|
"Inserted history entry was deleted using URI with id");
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = getHistoryEntryById(id);
|
c = getHistoryEntryById(id);
|
||||||
mAsserter.is(c.moveToFirst(), false,
|
mAsserter.is(c.moveToFirst(), false,
|
||||||
"Inserted history entry can't be found after deletion using URI with ID");
|
"Inserted history entry can't be found after deletion using URI with ID");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1012,9 +1062,11 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
mAsserter.is(c.moveToFirst(), true, "Inserted favicon found");
|
mAsserter.is(c.moveToFirst(), true, "Inserted favicon found");
|
||||||
|
|
||||||
mProvider.delete(ContentUris.withAppendedId(BrowserContract.History.CONTENT_URI, id), null, null);
|
mProvider.delete(ContentUris.withAppendedId(BrowserContract.History.CONTENT_URI, id), null, null);
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = getFaviconsByUrl(pageUrl);
|
c = getFaviconsByUrl(pageUrl);
|
||||||
mAsserter.is(c.moveToFirst(), false, "Favicon is deleted with last reference to it");
|
mAsserter.is(c.moveToFirst(), false, "Favicon is deleted with last reference to it");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1056,6 +1108,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
new String[] { String.valueOf(id) });
|
new String[] { String.valueOf(id) });
|
||||||
|
|
||||||
mAsserter.is((updated == 1), true, "Inserted history entry was updated");
|
mAsserter.is((updated == 1), true, "Inserted history entry was updated");
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = getHistoryEntryById(id);
|
c = getHistoryEntryById(id);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Updated history entry found");
|
mAsserter.is(c.moveToFirst(), true, "Updated history entry found");
|
||||||
@ -1089,12 +1142,14 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
u.put(BrowserContract.History.URL, "http://examples2.com");
|
u.put(BrowserContract.History.URL, "http://examples2.com");
|
||||||
|
|
||||||
updated = mProvider.update(ContentUris.withAppendedId(BrowserContract.History.CONTENT_URI, id), u, null, null);
|
updated = mProvider.update(ContentUris.withAppendedId(BrowserContract.History.CONTENT_URI, id), u, null, null);
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = getHistoryEntryById(id);
|
c = getHistoryEntryById(id);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Updated history entry found");
|
mAsserter.is(c.moveToFirst(), true, "Updated history entry found");
|
||||||
|
|
||||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.URL)), u.getAsString(BrowserContract.History.URL),
|
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.URL)), u.getAsString(BrowserContract.History.URL),
|
||||||
"Updated history entry has correct URL using URI with id");
|
"Updated history entry has correct URL using URI with id");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1121,12 +1176,14 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
ContentValues u = createFaviconEntry(pageUrl, newFavicon);
|
ContentValues u = createFaviconEntry(pageUrl, newFavicon);
|
||||||
|
|
||||||
mProvider.update(BrowserContract.Favicons.CONTENT_URI, u, null, null);
|
mProvider.update(BrowserContract.Favicons.CONTENT_URI, u, null, null);
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = getFaviconsByUrl(pageUrl);
|
c = getFaviconsByUrl(pageUrl);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Updated favicon found");
|
mAsserter.is(c.moveToFirst(), true, "Updated favicon found");
|
||||||
|
|
||||||
mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Combined.FAVICON)), "UTF8"),
|
mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Combined.FAVICON)), "UTF8"),
|
||||||
newFavicon, "Updated favicon has corresponding favicon image");
|
newFavicon, "Updated favicon has corresponding favicon image");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1195,6 +1252,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
BrowserContract.History._ID + " = ?",
|
BrowserContract.History._ID + " = ?",
|
||||||
new String[] { String.valueOf(id) });
|
new String[] { String.valueOf(id) });
|
||||||
mAsserter.is((updated == 1), true, "Inserted history entry was updated");
|
mAsserter.is((updated == 1), true, "Inserted history entry was updated");
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = getHistoryEntryById(id);
|
c = getHistoryEntryById(id);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Updated history entry found");
|
mAsserter.is(c.moveToFirst(), true, "Updated history entry found");
|
||||||
@ -1220,6 +1278,8 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
mAsserter.is((updated == 1), true, "History entry was inserted");
|
mAsserter.is((updated == 1), true, "History entry was inserted");
|
||||||
|
|
||||||
id = getHistoryEntryIdByUrl(TEST_URL_2);
|
id = getHistoryEntryIdByUrl(TEST_URL_2);
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = getHistoryEntryById(id);
|
c = getHistoryEntryById(id);
|
||||||
mAsserter.is(c.moveToFirst(), true, "History entry was inserted");
|
mAsserter.is(c.moveToFirst(), true, "History entry was inserted");
|
||||||
|
|
||||||
@ -1239,6 +1299,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
BrowserContract.History._ID + " = ?",
|
BrowserContract.History._ID + " = ?",
|
||||||
new String[] { String.valueOf(id) });
|
new String[] { String.valueOf(id) });
|
||||||
mAsserter.is((updated == 1), true, "Inserted history entry was updated");
|
mAsserter.is((updated == 1), true, "Inserted history entry was updated");
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = getHistoryEntryById(id);
|
c = getHistoryEntryById(id);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Updated history entry found");
|
mAsserter.is(c.moveToFirst(), true, "Updated history entry found");
|
||||||
@ -1253,6 +1314,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
"Updated history entry has same creation date");
|
"Updated history entry has same creation date");
|
||||||
mAsserter.isnot(new Long(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_MODIFIED))), new Long(dateModified),
|
mAsserter.isnot(new Long(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_MODIFIED))), new Long(dateModified),
|
||||||
"Updated history entry has new modification date");
|
"Updated history entry has new modification date");
|
||||||
|
c.close();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1275,6 +1337,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
|
|
||||||
mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Thumbnails.DATA)), "UTF8"),
|
mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Thumbnails.DATA)), "UTF8"),
|
||||||
thumbnail, "Inserted thumbnail has corresponding thumbnail image");
|
thumbnail, "Inserted thumbnail has corresponding thumbnail image");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1301,12 +1364,14 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
ContentValues u = createThumbnailEntry(pageUrl, newThumbnail);
|
ContentValues u = createThumbnailEntry(pageUrl, newThumbnail);
|
||||||
|
|
||||||
mProvider.update(BrowserContract.Thumbnails.CONTENT_URI, u, null, null);
|
mProvider.update(BrowserContract.Thumbnails.CONTENT_URI, u, null, null);
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = getThumbnailByUrl(pageUrl);
|
c = getThumbnailByUrl(pageUrl);
|
||||||
mAsserter.is(c.moveToFirst(), true, "Updated thumbnail found");
|
mAsserter.is(c.moveToFirst(), true, "Updated thumbnail found");
|
||||||
|
|
||||||
mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Thumbnails.DATA)), "UTF8"),
|
mAsserter.is(new String(c.getBlob(c.getColumnIndex(BrowserContract.Thumbnails.DATA)), "UTF8"),
|
||||||
newThumbnail, "Updated thumbnail has corresponding thumbnail image");
|
newThumbnail, "Updated thumbnail has corresponding thumbnail image");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1325,9 +1390,11 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
mAsserter.is(c.moveToFirst(), true, "Inserted thumbnail found");
|
mAsserter.is(c.moveToFirst(), true, "Inserted thumbnail found");
|
||||||
|
|
||||||
mProvider.delete(ContentUris.withAppendedId(BrowserContract.History.CONTENT_URI, id), null, null);
|
mProvider.delete(ContentUris.withAppendedId(BrowserContract.History.CONTENT_URI, id), null, null);
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = getThumbnailByUrl(pageUrl);
|
c = getThumbnailByUrl(pageUrl);
|
||||||
mAsserter.is(c.moveToFirst(), false, "Thumbnail is deleted with last reference to it");
|
mAsserter.is(c.moveToFirst(), false, "Thumbnail is deleted with last reference to it");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1435,6 +1502,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
"Combined entry has correct number of visits");
|
"Combined entry has correct number of visits");
|
||||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.DATE_LAST_VISITED))), new Long(LAST_VISITED),
|
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.DATE_LAST_VISITED))), new Long(LAST_VISITED),
|
||||||
"Combined entry has correct last visit time");
|
"Combined entry has correct last visit time");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1495,6 +1563,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
mAsserter.is(new Integer(display), new Integer(expectedDisplay),
|
mAsserter.is(new Integer(display), new Integer(expectedDisplay),
|
||||||
"Combined display column should always be DISPLAY_READER for the reading list item");
|
"Combined display column should always be DISPLAY_READER for the reading list item");
|
||||||
}
|
}
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1527,6 +1596,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
new String[] { String.valueOf(combinedBookmarkId) });
|
new String[] { String.valueOf(combinedBookmarkId) });
|
||||||
|
|
||||||
mAsserter.is((deleted == 1), true, "Inserted combined bookmark was deleted");
|
mAsserter.is((deleted == 1), true, "Inserted combined bookmark was deleted");
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = mProvider.query(BrowserContract.Combined.CONTENT_URI, null, "", null, null);
|
c = mProvider.query(BrowserContract.Combined.CONTENT_URI, null, "", null, null);
|
||||||
mAsserter.is(c.getCount(), 1, "1 combined entry found");
|
mAsserter.is(c.getCount(), 1, "1 combined entry found");
|
||||||
@ -1534,6 +1604,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
mAsserter.is(c.moveToFirst(), true, "Found combined entry without bookmark id");
|
mAsserter.is(c.moveToFirst(), true, "Found combined entry without bookmark id");
|
||||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID))), new Long(0),
|
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.BOOKMARK_ID))), new Long(0),
|
||||||
"Bookmark id should not be set to removed bookmark id");
|
"Bookmark id should not be set to removed bookmark id");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1569,6 +1640,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
new String[] { String.valueOf(combinedReadingListItemId) });
|
new String[] { String.valueOf(combinedReadingListItemId) });
|
||||||
|
|
||||||
mAsserter.is((deleted == 1), true, "Inserted combined reading list item was deleted");
|
mAsserter.is((deleted == 1), true, "Inserted combined reading list item was deleted");
|
||||||
|
c.close();
|
||||||
|
|
||||||
c = mProvider.query(BrowserContract.Combined.CONTENT_URI, null, "", null, null);
|
c = mProvider.query(BrowserContract.Combined.CONTENT_URI, null, "", null, null);
|
||||||
mAsserter.is(c.getCount(), 1, "1 combined entry found");
|
mAsserter.is(c.getCount(), 1, "1 combined entry found");
|
||||||
@ -1578,6 +1650,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
"Bookmark id should not be set to removed bookmark id");
|
"Bookmark id should not be set to removed bookmark id");
|
||||||
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.DISPLAY))), new Long(BrowserContract.Combined.DISPLAY_NORMAL),
|
mAsserter.is(new Long(c.getLong(c.getColumnIndex(BrowserContract.Combined.DISPLAY))), new Long(BrowserContract.Combined.DISPLAY_NORMAL),
|
||||||
"Combined entry should have reader display type");
|
"Combined entry should have reader display type");
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1608,7 +1681,8 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Cursor c = mProvider.query(BrowserContract.History.CONTENT_URI, null, "", null, null);
|
Cursor c = mProvider.query(BrowserContract.History.CONTENT_URI, null, "", null, null);
|
||||||
mAsserter.is(c.getCount(), count, count + " history entries found");
|
|
||||||
|
assertCountIsAndClose(c, count, count + " history entries found");
|
||||||
|
|
||||||
// add thumbnails for each entry
|
// add thumbnails for each entry
|
||||||
allVals = new ContentValues[count];
|
allVals = new ContentValues[count];
|
||||||
@ -1622,7 +1696,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
mAsserter.is(inserts, count, "Expected number of inserts matches");
|
mAsserter.is(inserts, count, "Expected number of inserts matches");
|
||||||
|
|
||||||
c = mProvider.query(BrowserContract.Thumbnails.CONTENT_URI, null, null, null, null);
|
c = mProvider.query(BrowserContract.Thumbnails.CONTENT_URI, null, null, null, null);
|
||||||
mAsserter.is(c.getCount(), count, count + " thumbnails entries found");
|
assertCountIsAndClose(c, count, count + " thumbnails entries found");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1637,57 +1711,61 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
Uri url = appendUriParam(BrowserContract.History.CONTENT_OLD_URI, BrowserContract.PARAM_EXPIRE_PRIORITY, "NORMAL");
|
Uri url = appendUriParam(BrowserContract.History.CONTENT_OLD_URI, BrowserContract.PARAM_EXPIRE_PRIORITY, "NORMAL");
|
||||||
mProvider.delete(url, null, null);
|
mProvider.delete(url, null, null);
|
||||||
Cursor c = mProvider.query(BrowserContract.History.CONTENT_URI, null, "", null, null);
|
Cursor c = mProvider.query(BrowserContract.History.CONTENT_URI, null, "", null, null);
|
||||||
mAsserter.is(c.getCount(), count, count + " history entries found");
|
assertCountIsAndClose(c, count, count + " history entries found");
|
||||||
|
|
||||||
// expiring with a normal priority should delete all but 10 thumbnails
|
// expiring with a normal priority should delete all but 10 thumbnails
|
||||||
c = mProvider.query(BrowserContract.Thumbnails.CONTENT_URI, null, null, null, null);
|
c = mProvider.query(BrowserContract.Thumbnails.CONTENT_URI, null, null, null, null);
|
||||||
mAsserter.is(c.getCount(), thumbCount, thumbCount + " thumbnails found");
|
assertCountIsAndClose(c, thumbCount, thumbCount + " thumbnails found");
|
||||||
|
|
||||||
ensureEmptyDatabase();
|
ensureEmptyDatabase();
|
||||||
// insert a bunch of new entries
|
|
||||||
|
// Insert a bunch of new entries.
|
||||||
createFakeHistory(0, count);
|
createFakeHistory(0, count);
|
||||||
|
|
||||||
// expiring with a aggressive priority should leave 500 entries
|
// Expiring with a aggressive priority should leave 500 entries.
|
||||||
url = appendUriParam(BrowserContract.History.CONTENT_OLD_URI, BrowserContract.PARAM_EXPIRE_PRIORITY, "AGGRESSIVE");
|
url = appendUriParam(BrowserContract.History.CONTENT_OLD_URI, BrowserContract.PARAM_EXPIRE_PRIORITY, "AGGRESSIVE");
|
||||||
mProvider.delete(url, null, null);
|
mProvider.delete(url, null, null);
|
||||||
c = mProvider.query(BrowserContract.History.CONTENT_URI, null, "", null, null);
|
|
||||||
mAsserter.is(c.getCount(), 500, "500 history entries found");
|
|
||||||
|
|
||||||
// expiring with a aggressive priority should delete all but 10 thumbnails
|
c = mProvider.query(BrowserContract.History.CONTENT_URI, null, "", null, null);
|
||||||
|
assertCountIsAndClose(c, 500, "500 history entries found");
|
||||||
|
|
||||||
|
// Expiring with a aggressive priority should delete all but 10 thumbnails.
|
||||||
c = mProvider.query(BrowserContract.Thumbnails.CONTENT_URI, null, null, null, null);
|
c = mProvider.query(BrowserContract.Thumbnails.CONTENT_URI, null, null, null, null);
|
||||||
mAsserter.is(c.getCount(), thumbCount, thumbCount + " thumbnails found");
|
assertCountIsAndClose(c, thumbCount, thumbCount + " thumbnails found");
|
||||||
|
|
||||||
ensureEmptyDatabase();
|
ensureEmptyDatabase();
|
||||||
// insert a bunch of entries with an old time created/modified
|
|
||||||
|
// Insert a bunch of entries with an old time created/modified.
|
||||||
long time = 1000L * 60L * 60L * 24L * 30L * 3L;
|
long time = 1000L * 60L * 60L * 24L * 30L * 3L;
|
||||||
createFakeHistory(time, count);
|
createFakeHistory(time, count);
|
||||||
|
|
||||||
// expiring with an normal priority should remove at most 1000 entries
|
// Expiring with an normal priority should remove at most 1000 entries,
|
||||||
// entries leaving at least 2000
|
// entries leaving at least 2000.
|
||||||
url = appendUriParam(BrowserContract.History.CONTENT_OLD_URI, BrowserContract.PARAM_EXPIRE_PRIORITY, "NORMAL");
|
url = appendUriParam(BrowserContract.History.CONTENT_OLD_URI, BrowserContract.PARAM_EXPIRE_PRIORITY, "NORMAL");
|
||||||
mProvider.delete(url, null, null);
|
mProvider.delete(url, null, null);
|
||||||
c = mProvider.query(BrowserContract.History.CONTENT_URI, null, "", null, null);
|
|
||||||
mAsserter.is(c.getCount(), 2000, "2000 history entries found");
|
|
||||||
|
|
||||||
// expiring with a normal priority should delete all but 10 thumbnails
|
c = mProvider.query(BrowserContract.History.CONTENT_URI, null, "", null, null);
|
||||||
|
assertCountIsAndClose(c, 2000, "2000 history entries found");
|
||||||
|
|
||||||
|
// Expiring with a normal priority should delete all but 10 thumbnails.
|
||||||
c = mProvider.query(BrowserContract.Thumbnails.CONTENT_URI, null, null, null, null);
|
c = mProvider.query(BrowserContract.Thumbnails.CONTENT_URI, null, null, null, null);
|
||||||
mAsserter.is(c.getCount(), thumbCount, thumbCount + " thumbnails found");
|
assertCountIsAndClose(c, thumbCount, thumbCount + " thumbnails found");
|
||||||
|
|
||||||
ensureEmptyDatabase();
|
ensureEmptyDatabase();
|
||||||
// insert a bunch of entries with an old time created/modified
|
// insert a bunch of entries with an old time created/modified
|
||||||
time = 1000L * 60L * 60L * 24L * 30L * 3L;
|
time = 1000L * 60L * 60L * 24L * 30L * 3L;
|
||||||
createFakeHistory(time, count);
|
createFakeHistory(time, count);
|
||||||
|
|
||||||
// expiring with an agressive priority should remove old
|
// Expiring with an aggressive priority should remove old
|
||||||
// entries leaving at least 500
|
// entries, leaving at least 500.
|
||||||
url = appendUriParam(BrowserContract.History.CONTENT_OLD_URI, BrowserContract.PARAM_EXPIRE_PRIORITY, "AGGRESSIVE");
|
url = appendUriParam(BrowserContract.History.CONTENT_OLD_URI, BrowserContract.PARAM_EXPIRE_PRIORITY, "AGGRESSIVE");
|
||||||
mProvider.delete(url, null, null);
|
mProvider.delete(url, null, null);
|
||||||
c = mProvider.query(BrowserContract.History.CONTENT_URI, null, "", null, null);
|
c = mProvider.query(BrowserContract.History.CONTENT_URI, null, "", null, null);
|
||||||
mAsserter.is(c.getCount(), 500, "500 history entries found");
|
assertCountIsAndClose(c, 500, "500 history entries found");
|
||||||
|
|
||||||
// expiring with an aggressive priority should delete all but 10 thumbnails
|
// expiring with an aggressive priority should delete all but 10 thumbnails
|
||||||
c = mProvider.query(BrowserContract.Thumbnails.CONTENT_URI, null, null, null, null);
|
c = mProvider.query(BrowserContract.Thumbnails.CONTENT_URI, null, null, null, null);
|
||||||
mAsserter.is(c.getCount(), thumbCount, thumbCount + " thumbnails found");
|
assertCountIsAndClose(c, thumbCount, thumbCount + " thumbnails found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1776,4 +1854,16 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||||||
ensureOnlyChangeNotifiedStartsWith(BrowserContract.History.CONTENT_URI, "bulkInsert");
|
ensureOnlyChangeNotifiedStartsWith(BrowserContract.History.CONTENT_URI, "bulkInsert");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert that the provided cursor has the expected number of rows,
|
||||||
|
* closing the cursor afterwards.
|
||||||
|
*/
|
||||||
|
private void assertCountIsAndClose(Cursor c, int expectedCount, String message) {
|
||||||
|
try {
|
||||||
|
mAsserter.is(c.getCount(), expectedCount, message);
|
||||||
|
} finally {
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ import android.view.SubMenu;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class GeckoActionProvider extends ActionProvider {
|
public class GeckoActionProvider extends ActionProvider {
|
||||||
private static int MAX_HISTORY_SIZE = 2;
|
private static int MAX_HISTORY_SIZE = 2;
|
||||||
|
|
||||||
@ -125,6 +127,20 @@ public class GeckoActionProvider extends ActionProvider {
|
|||||||
mOnTargetListener = listener;
|
mOnTargetListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ArrayList<ResolveInfo> getSortedActivites() {
|
||||||
|
ArrayList<ResolveInfo> infos = new ArrayList<ResolveInfo>();
|
||||||
|
|
||||||
|
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName);
|
||||||
|
PackageManager packageManager = mContext.getPackageManager();
|
||||||
|
|
||||||
|
// Populate the sub-menu with a sub set of the activities.
|
||||||
|
final int count = dataModel.getActivityCount();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
infos.add(dataModel.getActivity(i));
|
||||||
|
}
|
||||||
|
return infos;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener for handling default activity / menu item clicks.
|
* Listener for handling default activity / menu item clicks.
|
||||||
*/
|
*/
|
||||||
|
@ -1045,6 +1045,8 @@ BrowserAddonActor.prototype = {
|
|||||||
function DebuggerProgressListener(aBrowserTabActor) {
|
function DebuggerProgressListener(aBrowserTabActor) {
|
||||||
this._tabActor = aBrowserTabActor;
|
this._tabActor = aBrowserTabActor;
|
||||||
this._tabActor._tabbrowser.addProgressListener(this);
|
this._tabActor._tabbrowser.addProgressListener(this);
|
||||||
|
let EventEmitter = devtools.require("devtools/shared/event-emitter");
|
||||||
|
EventEmitter.decorate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
DebuggerProgressListener.prototype = {
|
DebuggerProgressListener.prototype = {
|
||||||
@ -1072,28 +1074,32 @@ DebuggerProgressListener.prototype = {
|
|||||||
this._tabActor._pendingNavigation = aRequest;
|
this._tabActor._pendingNavigation = aRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._tabActor.threadActor.disableAllBreakpoints();
|
let packet = {
|
||||||
this._tabActor.conn.send({
|
|
||||||
from: this._tabActor.actorID,
|
from: this._tabActor.actorID,
|
||||||
type: "tabNavigated",
|
type: "tabNavigated",
|
||||||
url: aRequest.URI.spec,
|
url: aRequest.URI.spec,
|
||||||
nativeConsoleAPI: true,
|
nativeConsoleAPI: true,
|
||||||
state: "start"
|
state: "start"
|
||||||
});
|
};
|
||||||
|
this._tabActor.threadActor.disableAllBreakpoints();
|
||||||
|
this._tabActor.conn.send(packet);
|
||||||
|
this.emit("will-navigate", packet);
|
||||||
} else if (isStop) {
|
} else if (isStop) {
|
||||||
if (this._tabActor.threadActor.state == "running") {
|
if (this._tabActor.threadActor.state == "running") {
|
||||||
this._tabActor.threadActor.dbg.enabled = true;
|
this._tabActor.threadActor.dbg.enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let window = this._tabActor.window;
|
let window = this._tabActor.window;
|
||||||
this._tabActor.conn.send({
|
let packet = {
|
||||||
from: this._tabActor.actorID,
|
from: this._tabActor.actorID,
|
||||||
type: "tabNavigated",
|
type: "tabNavigated",
|
||||||
url: this._tabActor.url,
|
url: this._tabActor.url,
|
||||||
title: this._tabActor.title,
|
title: this._tabActor.title,
|
||||||
nativeConsoleAPI: this._tabActor.hasNativeConsoleAPI(window),
|
nativeConsoleAPI: this._tabActor.hasNativeConsoleAPI(window),
|
||||||
state: "stop"
|
state: "stop"
|
||||||
});
|
};
|
||||||
|
this._tabActor.conn.send(packet);
|
||||||
|
this.emit("navigate", packet);
|
||||||
}
|
}
|
||||||
}, "DebuggerProgressListener.prototype.onStateChange"),
|
}, "DebuggerProgressListener.prototype.onStateChange"),
|
||||||
|
|
||||||
|
@ -59,10 +59,10 @@ function WebConsoleActor(aConnection, aParentActor)
|
|||||||
|
|
||||||
this.dbg = new Debugger();
|
this.dbg = new Debugger();
|
||||||
|
|
||||||
this._protoChains = new Map();
|
|
||||||
this._netEvents = new Map();
|
this._netEvents = new Map();
|
||||||
this._gripDepth = 0;
|
this._gripDepth = 0;
|
||||||
|
|
||||||
|
this._onWillNavigate = this._onWillNavigate.bind(this);
|
||||||
this._onObserverNotification = this._onObserverNotification.bind(this);
|
this._onObserverNotification = this._onObserverNotification.bind(this);
|
||||||
if (this.parentActor.isRootActor) {
|
if (this.parentActor.isRootActor) {
|
||||||
Services.obs.addObserver(this._onObserverNotification,
|
Services.obs.addObserver(this._onObserverNotification,
|
||||||
@ -112,16 +112,6 @@ WebConsoleActor.prototype =
|
|||||||
*/
|
*/
|
||||||
_netEvents: null,
|
_netEvents: null,
|
||||||
|
|
||||||
/**
|
|
||||||
* A cache of prototype chains for objects that have received a
|
|
||||||
* prototypeAndProperties request.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @type Map
|
|
||||||
* @see dbg-script-actors.js, ThreadActor._protoChains
|
|
||||||
*/
|
|
||||||
_protoChains: null,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The debugger server connection instance.
|
* The debugger server connection instance.
|
||||||
* @type object
|
* @type object
|
||||||
@ -209,6 +199,31 @@ WebConsoleActor.prototype =
|
|||||||
*/
|
*/
|
||||||
_lastChromeWindow: null,
|
_lastChromeWindow: null,
|
||||||
|
|
||||||
|
// The evalWindow is used at the scope for JS evaluation.
|
||||||
|
_evalWindow: null,
|
||||||
|
get evalWindow() {
|
||||||
|
return this._evalWindow || this.window;
|
||||||
|
},
|
||||||
|
|
||||||
|
set evalWindow(aWindow) {
|
||||||
|
this._evalWindow = aWindow;
|
||||||
|
|
||||||
|
if (!this._progressListenerActive && this.parentActor._progressListener) {
|
||||||
|
this.parentActor._progressListener.once("will-navigate", this._onWillNavigate);
|
||||||
|
this._progressListenerActive = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag used to track if we are listening for events from the progress
|
||||||
|
* listener of the tab actor. We use the progress listener to clear
|
||||||
|
* this.evalWindow on page navigation.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @type boolean
|
||||||
|
*/
|
||||||
|
_progressListenerActive: false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ConsoleServiceListener instance.
|
* The ConsoleServiceListener instance.
|
||||||
* @type object
|
* @type object
|
||||||
@ -295,8 +310,9 @@ WebConsoleActor.prototype =
|
|||||||
}
|
}
|
||||||
this._actorPool = null;
|
this._actorPool = null;
|
||||||
|
|
||||||
|
this._jstermHelpersCache = null;
|
||||||
|
this._evalWindow = null;
|
||||||
this._netEvents.clear();
|
this._netEvents.clear();
|
||||||
this._protoChains.clear();
|
|
||||||
this.dbg.enabled = false;
|
this.dbg.enabled = false;
|
||||||
this.dbg = null;
|
this.dbg = null;
|
||||||
this.conn = null;
|
this.conn = null;
|
||||||
@ -725,7 +741,7 @@ WebConsoleActor.prototype =
|
|||||||
}
|
}
|
||||||
// This is the general case (non-paused debugger)
|
// This is the general case (non-paused debugger)
|
||||||
else {
|
else {
|
||||||
dbgObject = this.dbg.makeGlobalObjectReference(this.window);
|
dbgObject = this.dbg.makeGlobalObjectReference(this.evalWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = JSPropertyProvider(dbgObject, environment, aRequest.text,
|
let result = JSPropertyProvider(dbgObject, environment, aRequest.text,
|
||||||
@ -822,12 +838,13 @@ WebConsoleActor.prototype =
|
|||||||
_getJSTermHelpers: function WCA__getJSTermHelpers(aDebuggerGlobal)
|
_getJSTermHelpers: function WCA__getJSTermHelpers(aDebuggerGlobal)
|
||||||
{
|
{
|
||||||
let helpers = {
|
let helpers = {
|
||||||
window: this.window,
|
window: this.evalWindow,
|
||||||
chromeWindow: this.chromeWindow.bind(this),
|
chromeWindow: this.chromeWindow.bind(this),
|
||||||
makeDebuggeeValue: aDebuggerGlobal.makeDebuggeeValue.bind(aDebuggerGlobal),
|
makeDebuggeeValue: aDebuggerGlobal.makeDebuggeeValue.bind(aDebuggerGlobal),
|
||||||
createValueGrip: this.createValueGrip.bind(this),
|
createValueGrip: this.createValueGrip.bind(this),
|
||||||
sandbox: Object.create(null),
|
sandbox: Object.create(null),
|
||||||
helperResult: null,
|
helperResult: null,
|
||||||
|
consoleActor: this,
|
||||||
};
|
};
|
||||||
JSTermHelpers(helpers);
|
JSTermHelpers(helpers);
|
||||||
|
|
||||||
@ -924,12 +941,12 @@ WebConsoleActor.prototype =
|
|||||||
// as ordinary objects, not as references to be followed, so mixing
|
// as ordinary objects, not as references to be followed, so mixing
|
||||||
// debuggers causes strange behaviors.)
|
// debuggers causes strange behaviors.)
|
||||||
let dbg = frame ? frameActor.threadActor.dbg : this.dbg;
|
let dbg = frame ? frameActor.threadActor.dbg : this.dbg;
|
||||||
let dbgWindow = dbg.makeGlobalObjectReference(this.window);
|
let dbgWindow = dbg.makeGlobalObjectReference(this.evalWindow);
|
||||||
|
|
||||||
// If we have an object to bind to |_self|, create a Debugger.Object
|
// If we have an object to bind to |_self|, create a Debugger.Object
|
||||||
// referring to that object, belonging to dbg.
|
// referring to that object, belonging to dbg.
|
||||||
let bindSelf = null;
|
let bindSelf = null;
|
||||||
let dbgWindow = dbg.makeGlobalObjectReference(this.window);
|
let dbgWindow = dbg.makeGlobalObjectReference(this.evalWindow);
|
||||||
if (aOptions.bindObjectActor) {
|
if (aOptions.bindObjectActor) {
|
||||||
let objActor = this.getActorByID(aOptions.bindObjectActor);
|
let objActor = this.getActorByID(aOptions.bindObjectActor);
|
||||||
if (objActor) {
|
if (objActor) {
|
||||||
@ -1289,7 +1306,17 @@ WebConsoleActor.prototype =
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "will-navigate" progress listener. This is used to clear the current
|
||||||
|
* eval scope.
|
||||||
|
*/
|
||||||
|
_onWillNavigate: function WCA__onWillNavigate()
|
||||||
|
{
|
||||||
|
this._evalWindow = null;
|
||||||
|
this._progressListenerActive = false;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
WebConsoleActor.prototype.requestTypes =
|
WebConsoleActor.prototype.requestTypes =
|
||||||
|
@ -21,3 +21,4 @@ support-files =
|
|||||||
[test_object_actor_native_getters_lenient_this.html]
|
[test_object_actor_native_getters_lenient_this.html]
|
||||||
[test_page_errors.html]
|
[test_page_errors.html]
|
||||||
[test_throw.html]
|
[test_throw.html]
|
||||||
|
[test_jsterm_cd_iframe.html]
|
||||||
|
154
toolkit/devtools/webconsole/test/test_jsterm_cd_iframe.html
Normal file
154
toolkit/devtools/webconsole/test/test_jsterm_cd_iframe.html
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf8">
|
||||||
|
<title>Test for the cd() function</title>
|
||||||
|
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="text/javascript;version=1.8" src="common.js"></script>
|
||||||
|
<!-- Any copyright is dedicated to the Public Domain.
|
||||||
|
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>Test for the cd() function</p>
|
||||||
|
|
||||||
|
<script class="testbody" type="text/javascript;version=1.8">
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
let gState;
|
||||||
|
|
||||||
|
function startTest()
|
||||||
|
{
|
||||||
|
removeEventListener("load", startTest);
|
||||||
|
|
||||||
|
attachConsole([], onAttach, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAttach(aState, aResponse)
|
||||||
|
{
|
||||||
|
top.foobarObject = Object.create(null);
|
||||||
|
top.foobarObject.bug609872 = "parent";
|
||||||
|
|
||||||
|
window.foobarObject = Object.create(null);
|
||||||
|
window.foobarObject.bug609872 = "child";
|
||||||
|
|
||||||
|
gState = aState;
|
||||||
|
|
||||||
|
let tests = [doCheckParent, doCdIframe, doCheckIframe, doCdParent,
|
||||||
|
doCheckParent2];
|
||||||
|
runTests(tests, testEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
function doCheckParent()
|
||||||
|
{
|
||||||
|
info("check parent window");
|
||||||
|
gState.client.evaluateJS("window.foobarObject.bug609872",
|
||||||
|
onFooObjectFromParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onFooObjectFromParent(aResponse)
|
||||||
|
{
|
||||||
|
checkObject(aResponse, {
|
||||||
|
from: gState.actor,
|
||||||
|
input: "window.foobarObject.bug609872",
|
||||||
|
result: "parent",
|
||||||
|
});
|
||||||
|
|
||||||
|
ok(!aResponse.exception, "no eval exception");
|
||||||
|
ok(!aResponse.helperResult, "no helper result");
|
||||||
|
|
||||||
|
nextTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
function doCdIframe()
|
||||||
|
{
|
||||||
|
info("test cd('iframe')");
|
||||||
|
gState.client.evaluateJS("cd('iframe')", onCdIframe);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCdIframe(aResponse)
|
||||||
|
{
|
||||||
|
checkObject(aResponse, {
|
||||||
|
from: gState.actor,
|
||||||
|
input: "cd('iframe')",
|
||||||
|
result: { type: "undefined" },
|
||||||
|
helperResult: { type: "cd" },
|
||||||
|
});
|
||||||
|
|
||||||
|
ok(!aResponse.exception, "no eval exception");
|
||||||
|
|
||||||
|
nextTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
function doCheckIframe()
|
||||||
|
{
|
||||||
|
info("check foobarObject from the iframe");
|
||||||
|
gState.client.evaluateJS("window.foobarObject.bug609872",
|
||||||
|
onFooObjectFromIframe);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onFooObjectFromIframe(aResponse)
|
||||||
|
{
|
||||||
|
checkObject(aResponse, {
|
||||||
|
from: gState.actor,
|
||||||
|
input: "window.foobarObject.bug609872",
|
||||||
|
result: "child",
|
||||||
|
});
|
||||||
|
|
||||||
|
ok(!aResponse.exception, "no js eval exception");
|
||||||
|
ok(!aResponse.helperResult, "no helper result");
|
||||||
|
|
||||||
|
nextTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
function doCdParent()
|
||||||
|
{
|
||||||
|
info("test cd() back to parent");
|
||||||
|
gState.client.evaluateJS("cd()", onCdParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCdParent(aResponse)
|
||||||
|
{
|
||||||
|
checkObject(aResponse, {
|
||||||
|
from: gState.actor,
|
||||||
|
input: "cd()",
|
||||||
|
result: { type: "undefined" },
|
||||||
|
helperResult: { type: "cd" },
|
||||||
|
});
|
||||||
|
|
||||||
|
ok(!aResponse.exception, "no eval exception");
|
||||||
|
|
||||||
|
nextTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
function doCheckParent2()
|
||||||
|
{
|
||||||
|
gState.client.evaluateJS("window.foobarObject.bug609872",
|
||||||
|
onFooObjectFromParent2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onFooObjectFromParent2(aResponse)
|
||||||
|
{
|
||||||
|
checkObject(aResponse, {
|
||||||
|
from: gState.actor,
|
||||||
|
input: "window.foobarObject.bug609872",
|
||||||
|
result: "parent",
|
||||||
|
});
|
||||||
|
|
||||||
|
ok(!aResponse.exception, "no eval exception");
|
||||||
|
ok(!aResponse.helperResult, "no helper result");
|
||||||
|
|
||||||
|
nextTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testEnd()
|
||||||
|
{
|
||||||
|
closeDebugger(gState, function() {
|
||||||
|
gState = null;
|
||||||
|
SimpleTest.finish();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addEventListener("load", startTest);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1512,6 +1512,40 @@ function JSTermHelpers(aOwner)
|
|||||||
aOwner.helperResult = { type: "help" };
|
aOwner.helperResult = { type: "help" };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the JS evaluation scope.
|
||||||
|
*
|
||||||
|
* @param DOMElement|string|window aWindow
|
||||||
|
* The window object to use for eval scope. This can be a string that
|
||||||
|
* is used to perform document.querySelector(), to find the iframe that
|
||||||
|
* you want to cd() to. A DOMElement can be given as well, the
|
||||||
|
* .contentWindow property is used. Lastly, you can directly pass
|
||||||
|
* a window object. If you call cd() with no arguments, the current
|
||||||
|
* eval scope is cleared back to its default (the top window).
|
||||||
|
*/
|
||||||
|
aOwner.sandbox.cd = function JSTH_cd(aWindow)
|
||||||
|
{
|
||||||
|
if (!aWindow) {
|
||||||
|
aOwner.consoleActor.evalWindow = null;
|
||||||
|
aOwner.helperResult = { type: "cd" };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof aWindow == "string") {
|
||||||
|
aWindow = aOwner.window.document.querySelector(aWindow);
|
||||||
|
}
|
||||||
|
if (aWindow instanceof Ci.nsIDOMElement && aWindow.contentWindow) {
|
||||||
|
aWindow = aWindow.contentWindow;
|
||||||
|
}
|
||||||
|
if (!(aWindow instanceof Ci.nsIDOMWindow)) {
|
||||||
|
aOwner.helperResult = { type: "error", message: "cdFunctionInvalidArgument" };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
aOwner.consoleActor.evalWindow = aWindow;
|
||||||
|
aOwner.helperResult = { type: "cd" };
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inspects the passed aObject. This is done by opening the PropertyPanel.
|
* Inspects the passed aObject. This is done by opening the PropertyPanel.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user