зеркало из https://github.com/mozilla/pjs.git
Merge backout; a=me
This commit is contained in:
Коммит
f8e1d233a4
|
@ -92,13 +92,17 @@
|
||||||
<field name="tabs" readonly="true">
|
<field name="tabs" readonly="true">
|
||||||
this.tabContainer.childNodes;
|
this.tabContainer.childNodes;
|
||||||
</field>
|
</field>
|
||||||
|
|
||||||
<property name="visibleTabs" readonly="true">
|
<property name="visibleTabs" readonly="true">
|
||||||
<getter><![CDATA[
|
<getter><![CDATA[
|
||||||
return Array.filter(this.tabs, function(tab) {
|
if (!this._visibleTabs)
|
||||||
return !tab.hidden && !tab.closing;
|
this._visibleTabs = Array.filter(this.tabs,
|
||||||
});
|
function (tab) !tab.hidden && !tab.closing);
|
||||||
|
return this._visibleTabs;
|
||||||
]]></getter>
|
]]></getter>
|
||||||
</property>
|
</property>
|
||||||
|
<field name="_visibleTabs">null</field>
|
||||||
|
|
||||||
<field name="mURIFixup" readonly="true">
|
<field name="mURIFixup" readonly="true">
|
||||||
Components.classes["@mozilla.org/docshell/urifixup;1"]
|
Components.classes["@mozilla.org/docshell/urifixup;1"]
|
||||||
.getService(Components.interfaces.nsIURIFixup);
|
.getService(Components.interfaces.nsIURIFixup);
|
||||||
|
@ -151,9 +155,6 @@
|
||||||
false
|
false
|
||||||
#endif
|
#endif
|
||||||
</field>
|
</field>
|
||||||
<field name="_browsers">
|
|
||||||
null
|
|
||||||
</field>
|
|
||||||
|
|
||||||
<field name="_autoScrollPopup">
|
<field name="_autoScrollPopup">
|
||||||
null
|
null
|
||||||
|
@ -1240,8 +1241,6 @@
|
||||||
aIsUTF8 = params.isUTF8;
|
aIsUTF8 = params.isUTF8;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._browsers = null; // invalidate cache
|
|
||||||
|
|
||||||
// if we're adding tabs, we're past interrupt mode, ditch the owner
|
// if we're adding tabs, we're past interrupt mode, ditch the owner
|
||||||
if (this.mCurrentTab.owner)
|
if (this.mCurrentTab.owner)
|
||||||
this.mCurrentTab.owner = null;
|
this.mCurrentTab.owner = null;
|
||||||
|
@ -1291,10 +1290,11 @@
|
||||||
}, 0, this.tabContainer);
|
}, 0, this.tabContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tabContainer.appendChild(t);
|
// invalidate caches
|
||||||
|
|
||||||
// invalidate cache, because tabContainer is about to change
|
|
||||||
this._browsers = null;
|
this._browsers = null;
|
||||||
|
this._visibleTabs = null;
|
||||||
|
|
||||||
|
this.tabContainer.appendChild(t);
|
||||||
|
|
||||||
// If this new tab is owned by another, assert that relationship
|
// If this new tab is owned by another, assert that relationship
|
||||||
if (aOwner)
|
if (aOwner)
|
||||||
|
@ -1625,6 +1625,7 @@
|
||||||
|
|
||||||
aTab.closing = true;
|
aTab.closing = true;
|
||||||
this._removingTabs.push(aTab);
|
this._removingTabs.push(aTab);
|
||||||
|
this._visibleTabs = null; // invalidate cache
|
||||||
if (newTab)
|
if (newTab)
|
||||||
this.addTab(BROWSER_NEW_TAB_URL, {skipAnimation: true});
|
this.addTab(BROWSER_NEW_TAB_URL, {skipAnimation: true});
|
||||||
else
|
else
|
||||||
|
@ -2009,7 +2010,10 @@
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
if (aTab.hidden) {
|
if (aTab.hidden) {
|
||||||
aTab.removeAttribute("hidden");
|
aTab.removeAttribute("hidden");
|
||||||
|
this._visibleTabs = null; // invalidate cache
|
||||||
|
|
||||||
this.tabContainer.adjustTabstrip();
|
this.tabContainer.adjustTabstrip();
|
||||||
|
|
||||||
let event = document.createEvent("Events");
|
let event = document.createEvent("Events");
|
||||||
event.initEvent("TabShow", true, false);
|
event.initEvent("TabShow", true, false);
|
||||||
aTab.dispatchEvent(event);
|
aTab.dispatchEvent(event);
|
||||||
|
@ -2025,7 +2029,10 @@
|
||||||
if (!aTab.hidden && !aTab.pinned && !aTab.selected &&
|
if (!aTab.hidden && !aTab.pinned && !aTab.selected &&
|
||||||
!aTab.closing) {
|
!aTab.closing) {
|
||||||
aTab.setAttribute("hidden", "true");
|
aTab.setAttribute("hidden", "true");
|
||||||
|
this._visibleTabs = null; // invalidate cache
|
||||||
|
|
||||||
this.tabContainer.adjustTabstrip();
|
this.tabContainer.adjustTabstrip();
|
||||||
|
|
||||||
let event = document.createEvent("Events");
|
let event = document.createEvent("Events");
|
||||||
event.initEvent("TabHide", true, false);
|
event.initEvent("TabHide", true, false);
|
||||||
aTab.dispatchEvent(event);
|
aTab.dispatchEvent(event);
|
||||||
|
@ -2081,6 +2088,7 @@
|
||||||
]]>
|
]]>
|
||||||
</getter>
|
</getter>
|
||||||
</property>
|
</property>
|
||||||
|
<field name="_browsers">null</field>
|
||||||
|
|
||||||
<!-- Moves a tab to a new browser window, unless it's already the only tab
|
<!-- Moves a tab to a new browser window, unless it's already the only tab
|
||||||
in the current window, in which case this will do nothing. -->
|
in the current window, in which case this will do nothing. -->
|
||||||
|
@ -2126,11 +2134,14 @@
|
||||||
|
|
||||||
aIndex = aIndex < aTab._tPos ? aIndex: aIndex+1;
|
aIndex = aIndex < aTab._tPos ? aIndex: aIndex+1;
|
||||||
this.mCurrentTab._selected = false;
|
this.mCurrentTab._selected = false;
|
||||||
|
|
||||||
|
// invalidate caches
|
||||||
|
this._browsers = null;
|
||||||
|
this._visibleTabs = null;
|
||||||
|
|
||||||
// use .item() instead of [] because dragging to the end of the strip goes out of
|
// use .item() instead of [] because dragging to the end of the strip goes out of
|
||||||
// bounds: .item() returns null (so it acts like appendChild), but [] throws
|
// bounds: .item() returns null (so it acts like appendChild), but [] throws
|
||||||
this.tabContainer.insertBefore(aTab, this.tabs.item(aIndex));
|
this.tabContainer.insertBefore(aTab, this.tabs.item(aIndex));
|
||||||
// invalidate cache, because tabContainer is about to change
|
|
||||||
this._browsers = null;
|
|
||||||
|
|
||||||
for (let i = 0; i < this.tabs.length; i++) {
|
for (let i = 0; i < this.tabs.length; i++) {
|
||||||
this.tabs[i]._tPos = i;
|
this.tabs[i]._tPos = i;
|
||||||
|
|
|
@ -60,6 +60,7 @@ import android.widget.Button;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.RelativeLayout.LayoutParams;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.TextSwitcher;
|
import android.widget.TextSwitcher;
|
||||||
import android.widget.ViewSwitcher.ViewFactory;
|
import android.widget.ViewSwitcher.ViewFactory;
|
||||||
|
@ -172,6 +173,18 @@ public class BrowserToolbar {
|
||||||
|
|
||||||
mFavicon = (ImageButton) mLayout.findViewById(R.id.favicon);
|
mFavicon = (ImageButton) mLayout.findViewById(R.id.favicon);
|
||||||
mSiteSecurity = (ImageButton) mLayout.findViewById(R.id.site_security);
|
mSiteSecurity = (ImageButton) mLayout.findViewById(R.id.site_security);
|
||||||
|
mSiteSecurity.setOnClickListener(new Button.OnClickListener() {
|
||||||
|
public void onClick(View view) {
|
||||||
|
int[] lockLocation = new int[2];
|
||||||
|
view.getLocationOnScreen(lockLocation);
|
||||||
|
LayoutParams lockLayoutParams = (LayoutParams) view.getLayoutParams();
|
||||||
|
|
||||||
|
// Calculate the left margin for the arrow based on the position of the lock icon.
|
||||||
|
int leftMargin = lockLocation[0] - lockLayoutParams.rightMargin;
|
||||||
|
GeckoApp.mSiteIdentityPopup.show(leftMargin);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
mProgressSpinner = (AnimationDrawable) resources.getDrawable(R.drawable.progress_spinner);
|
mProgressSpinner = (AnimationDrawable) resources.getDrawable(R.drawable.progress_spinner);
|
||||||
|
|
||||||
mStop = (ImageButton) mLayout.findViewById(R.id.stop);
|
mStop = (ImageButton) mLayout.findViewById(R.id.stop);
|
||||||
|
@ -322,9 +335,9 @@ public class BrowserToolbar {
|
||||||
public void setSecurityMode(String mode) {
|
public void setSecurityMode(String mode) {
|
||||||
mTitleCanExpand = false;
|
mTitleCanExpand = false;
|
||||||
|
|
||||||
if (mode.equals("identified")) {
|
if (mode.equals(SiteIdentityPopup.IDENTIFIED)) {
|
||||||
mSiteSecurity.setImageLevel(1);
|
mSiteSecurity.setImageLevel(1);
|
||||||
} else if (mode.equals("verified")) {
|
} else if (mode.equals(SiteIdentityPopup.VERIFIED)) {
|
||||||
mSiteSecurity.setImageLevel(2);
|
mSiteSecurity.setImageLevel(2);
|
||||||
} else {
|
} else {
|
||||||
mSiteSecurity.setImageLevel(0);
|
mSiteSecurity.setImageLevel(0);
|
||||||
|
|
|
@ -138,6 +138,7 @@ abstract public class GeckoApp
|
||||||
|
|
||||||
public static BrowserToolbar mBrowserToolbar;
|
public static BrowserToolbar mBrowserToolbar;
|
||||||
public static DoorHangerPopup mDoorHangerPopup;
|
public static DoorHangerPopup mDoorHangerPopup;
|
||||||
|
public static SiteIdentityPopup mSiteIdentityPopup;
|
||||||
public static FormAssistPopup mFormAssistPopup;
|
public static FormAssistPopup mFormAssistPopup;
|
||||||
public Favicons mFavicons;
|
public Favicons mFavicons;
|
||||||
|
|
||||||
|
@ -665,7 +666,7 @@ abstract public class GeckoApp
|
||||||
tab.setContentType(contentType);
|
tab.setContentType(contentType);
|
||||||
tab.updateFavicon(null);
|
tab.updateFavicon(null);
|
||||||
tab.updateFaviconURL(null);
|
tab.updateFaviconURL(null);
|
||||||
tab.updateSecurityMode("unknown");
|
tab.updateIdentityData(null);
|
||||||
tab.removeTransientDoorHangers();
|
tab.removeTransientDoorHangers();
|
||||||
tab.setHasTouchListeners(false);
|
tab.setHasTouchListeners(false);
|
||||||
tab.setCheckerboardColor(Color.WHITE);
|
tab.setCheckerboardColor(Color.WHITE);
|
||||||
|
@ -677,7 +678,7 @@ abstract public class GeckoApp
|
||||||
if (Tabs.getInstance().isSelectedTab(tab)) {
|
if (Tabs.getInstance().isSelectedTab(tab)) {
|
||||||
mBrowserToolbar.setTitle(uri);
|
mBrowserToolbar.setTitle(uri);
|
||||||
mBrowserToolbar.setFavicon(null);
|
mBrowserToolbar.setFavicon(null);
|
||||||
mBrowserToolbar.setSecurityMode("unknown");
|
mBrowserToolbar.setSecurityMode(tab.getSecurityMode());
|
||||||
mDoorHangerPopup.updatePopup();
|
mDoorHangerPopup.updatePopup();
|
||||||
mBrowserToolbar.setShadowVisibility(!(tab.getURL().startsWith("about:")));
|
mBrowserToolbar.setShadowVisibility(!(tab.getURL().startsWith("about:")));
|
||||||
|
|
||||||
|
@ -688,17 +689,17 @@ abstract public class GeckoApp
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleSecurityChange(final int tabId, final String mode) {
|
void handleSecurityChange(final int tabId, final JSONObject identityData) {
|
||||||
final Tab tab = Tabs.getInstance().getTab(tabId);
|
final Tab tab = Tabs.getInstance().getTab(tabId);
|
||||||
if (tab == null)
|
if (tab == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tab.updateSecurityMode(mode);
|
tab.updateIdentityData(identityData);
|
||||||
|
|
||||||
mMainHandler.post(new Runnable() {
|
mMainHandler.post(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (Tabs.getInstance().isSelectedTab(tab))
|
if (Tabs.getInstance().isSelectedTab(tab))
|
||||||
mBrowserToolbar.setSecurityMode(mode);
|
mBrowserToolbar.setSecurityMode(tab.getSecurityMode());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -871,9 +872,9 @@ abstract public class GeckoApp
|
||||||
handleLocationChange(tabId, uri, documentURI, contentType, sameDocument);
|
handleLocationChange(tabId, uri, documentURI, contentType, sameDocument);
|
||||||
} else if (event.equals("Content:SecurityChange")) {
|
} else if (event.equals("Content:SecurityChange")) {
|
||||||
final int tabId = message.getInt("tabID");
|
final int tabId = message.getInt("tabID");
|
||||||
final String mode = message.getString("mode");
|
final JSONObject identity = message.getJSONObject("identity");
|
||||||
Log.i(LOGTAG, "Security Mode - " + mode);
|
Log.i(LOGTAG, "Security Mode - " + identity.getString("mode"));
|
||||||
handleSecurityChange(tabId, mode);
|
handleSecurityChange(tabId, identity);
|
||||||
} else if (event.equals("Content:StateChange")) {
|
} else if (event.equals("Content:StateChange")) {
|
||||||
final int tabId = message.getInt("tabID");
|
final int tabId = message.getInt("tabID");
|
||||||
final String uri = message.getString("uri");
|
final String uri = message.getString("uri");
|
||||||
|
@ -1204,7 +1205,7 @@ abstract public class GeckoApp
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tab.setState("about:home".equals(uri) ? Tab.STATE_SUCCESS : Tab.STATE_LOADING);
|
tab.setState("about:home".equals(uri) ? Tab.STATE_SUCCESS : Tab.STATE_LOADING);
|
||||||
tab.updateSecurityMode("unknown");
|
tab.updateIdentityData(null);
|
||||||
if (Tabs.getInstance().isSelectedTab(tab))
|
if (Tabs.getInstance().isSelectedTab(tab))
|
||||||
getLayerController().getView().getRenderer().resetCheckerboard();
|
getLayerController().getView().getRenderer().resetCheckerboard();
|
||||||
mMainHandler.post(new Runnable() {
|
mMainHandler.post(new Runnable() {
|
||||||
|
@ -1665,6 +1666,7 @@ abstract public class GeckoApp
|
||||||
mPluginContainer = (AbsoluteLayout) findViewById(R.id.plugin_container);
|
mPluginContainer = (AbsoluteLayout) findViewById(R.id.plugin_container);
|
||||||
|
|
||||||
mDoorHangerPopup = new DoorHangerPopup(this);
|
mDoorHangerPopup = new DoorHangerPopup(this);
|
||||||
|
mSiteIdentityPopup = new SiteIdentityPopup(this);
|
||||||
mFormAssistPopup = (FormAssistPopup) findViewById(R.id.form_assist_popup);
|
mFormAssistPopup = (FormAssistPopup) findViewById(R.id.form_assist_popup);
|
||||||
|
|
||||||
Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - UI almost up");
|
Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - UI almost up");
|
||||||
|
@ -1955,6 +1957,9 @@ abstract public class GeckoApp
|
||||||
// Undo whatever we did in onPause.
|
// Undo whatever we did in onPause.
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
|
if (mSiteIdentityPopup != null)
|
||||||
|
mSiteIdentityPopup.dismiss();
|
||||||
|
|
||||||
int newOrientation = getResources().getConfiguration().orientation;
|
int newOrientation = getResources().getConfiguration().orientation;
|
||||||
|
|
||||||
if (mOrientation != newOrientation) {
|
if (mOrientation != newOrientation) {
|
||||||
|
@ -2081,6 +2086,8 @@ abstract public class GeckoApp
|
||||||
mOrientation = newConfig.orientation;
|
mOrientation = newConfig.orientation;
|
||||||
if (mFormAssistPopup != null)
|
if (mFormAssistPopup != null)
|
||||||
mFormAssistPopup.hide();
|
mFormAssistPopup.hide();
|
||||||
|
if (mSiteIdentityPopup != null)
|
||||||
|
mSiteIdentityPopup.dismiss();
|
||||||
refreshActionBar();
|
refreshActionBar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2551,6 +2558,11 @@ abstract public class GeckoApp
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mSiteIdentityPopup.isShowing()) {
|
||||||
|
mSiteIdentityPopup.dismiss();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mDOMFullScreen) {
|
if (mDOMFullScreen) {
|
||||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("FullScreen:Exit", null));
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("FullScreen:Exit", null));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -45,6 +45,7 @@ import java.lang.ref.SoftReference;
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
@ -115,12 +116,49 @@ class GlobalHistory {
|
||||||
GeckoAppShell.notifyUriVisited(uri);
|
GeckoAppShell.notifyUriVisited(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Logic ported from nsNavHistory::CanAddURI.
|
||||||
|
// http://mxr.mozilla.org/mozilla-central/source/toolkit/components/places/nsNavHistory.cpp#1272
|
||||||
|
private boolean canAddURI(String uri) {
|
||||||
|
if (uri == null || uri.length() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// First, heck the most common cases (HTTP, HTTPS) to avoid most of the work.
|
||||||
|
if (uri.startsWith("http:") || uri.startsWith("https:"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
String scheme = Uri.parse(uri).getScheme();
|
||||||
|
if (scheme == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Now check for all bad things.
|
||||||
|
if (scheme.equals("about") ||
|
||||||
|
scheme.equals("imap") ||
|
||||||
|
scheme.equals("news") ||
|
||||||
|
scheme.equals("mailbox") ||
|
||||||
|
scheme.equals("moz-anno") ||
|
||||||
|
scheme.equals("view-source") ||
|
||||||
|
scheme.equals("chrome") ||
|
||||||
|
scheme.equals("resource") ||
|
||||||
|
scheme.equals("data") ||
|
||||||
|
scheme.equals("wyciwyg") ||
|
||||||
|
scheme.equals("javascript"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public void add(String uri) {
|
public void add(String uri) {
|
||||||
|
if (!canAddURI(uri))
|
||||||
|
return;
|
||||||
|
|
||||||
BrowserDB.updateVisitedHistory(GeckoApp.mAppContext.getContentResolver(), uri);
|
BrowserDB.updateVisitedHistory(GeckoApp.mAppContext.getContentResolver(), uri);
|
||||||
addToGeckoOnly(uri);
|
addToGeckoOnly(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(String uri, String title) {
|
public void update(String uri, String title) {
|
||||||
|
if (!canAddURI(uri))
|
||||||
|
return;
|
||||||
|
|
||||||
ContentResolver resolver = GeckoApp.mAppContext.getContentResolver();
|
ContentResolver resolver = GeckoApp.mAppContext.getContentResolver();
|
||||||
BrowserDB.updateHistoryTitle(resolver, uri, title);
|
BrowserDB.updateHistoryTitle(resolver, uri, title);
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,7 @@ FENNEC_JAVA_FILES = \
|
||||||
sqlite/SQLiteBridgeException.java \
|
sqlite/SQLiteBridgeException.java \
|
||||||
RemoteTabs.java \
|
RemoteTabs.java \
|
||||||
SetupScreen.java \
|
SetupScreen.java \
|
||||||
|
SiteIdentityPopup.java \
|
||||||
SurfaceBits.java \
|
SurfaceBits.java \
|
||||||
Tab.java \
|
Tab.java \
|
||||||
Tabs.java \
|
Tabs.java \
|
||||||
|
@ -272,6 +273,7 @@ RES_LAYOUT = \
|
||||||
res/layout/notification_progress_text.xml \
|
res/layout/notification_progress_text.xml \
|
||||||
res/layout/site_setting_title.xml \
|
res/layout/site_setting_title.xml \
|
||||||
res/layout/setup_screen.xml \
|
res/layout/setup_screen.xml \
|
||||||
|
res/layout/site_identity_popup.xml \
|
||||||
res/layout/remote_tabs.xml \
|
res/layout/remote_tabs.xml \
|
||||||
res/layout/remote_tabs_child.xml \
|
res/layout/remote_tabs_child.xml \
|
||||||
res/layout/remote_tabs_group.xml \
|
res/layout/remote_tabs_group.xml \
|
||||||
|
@ -366,6 +368,8 @@ RES_DRAWABLE_BASE = \
|
||||||
res/drawable/doorhanger_bg.9.png \
|
res/drawable/doorhanger_bg.9.png \
|
||||||
res/drawable/doorhanger_shadow_bg.9.png \
|
res/drawable/doorhanger_shadow_bg.9.png \
|
||||||
res/drawable/doorhanger_popup_bg.9.png \
|
res/drawable/doorhanger_popup_bg.9.png \
|
||||||
|
res/drawable/larry_blue.png \
|
||||||
|
res/drawable/larry_green.png \
|
||||||
res/drawable/site_security_identified.png \
|
res/drawable/site_security_identified.png \
|
||||||
res/drawable/site_security_verified.png \
|
res/drawable/site_security_verified.png \
|
||||||
res/drawable/urlbar_stop.png \
|
res/drawable/urlbar_stop.png \
|
||||||
|
@ -423,6 +427,8 @@ RES_DRAWABLE_HDPI = \
|
||||||
res/drawable-hdpi/doorhanger_bg.9.png \
|
res/drawable-hdpi/doorhanger_bg.9.png \
|
||||||
res/drawable-hdpi/doorhanger_shadow_bg.9.png \
|
res/drawable-hdpi/doorhanger_shadow_bg.9.png \
|
||||||
res/drawable-hdpi/doorhanger_popup_bg.9.png \
|
res/drawable-hdpi/doorhanger_popup_bg.9.png \
|
||||||
|
res/drawable-hdpi/larry_blue.png \
|
||||||
|
res/drawable-hdpi/larry_green.png \
|
||||||
res/drawable-hdpi/site_security_identified.png \
|
res/drawable-hdpi/site_security_identified.png \
|
||||||
res/drawable-hdpi/site_security_verified.png \
|
res/drawable-hdpi/site_security_verified.png \
|
||||||
res/drawable-hdpi/urlbar_stop.png \
|
res/drawable-hdpi/urlbar_stop.png \
|
||||||
|
@ -492,6 +498,8 @@ RES_DRAWABLE_XHDPI_V11 = \
|
||||||
res/drawable-xhdpi-v11/doorhanger_shadow_bg.9.png \
|
res/drawable-xhdpi-v11/doorhanger_shadow_bg.9.png \
|
||||||
res/drawable-xhdpi-v11/doorhanger_popup_bg.9.png \
|
res/drawable-xhdpi-v11/doorhanger_popup_bg.9.png \
|
||||||
res/drawable-xhdpi-v11/urlbar_stop.png \
|
res/drawable-xhdpi-v11/urlbar_stop.png \
|
||||||
|
res/drawable-xhdpi-v11/larry_blue.png \
|
||||||
|
res/drawable-xhdpi-v11/larry_green.png \
|
||||||
res/drawable-xhdpi-v11/site_security_identified.png \
|
res/drawable-xhdpi-v11/site_security_identified.png \
|
||||||
res/drawable-xhdpi-v11/site_security_verified.png \
|
res/drawable-xhdpi-v11/site_security_verified.png \
|
||||||
res/drawable-xhdpi-v11/tabs_button_tail.9.png \
|
res/drawable-xhdpi-v11/tabs_button_tail.9.png \
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.PopupWindow;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.RelativeLayout;
|
||||||
|
import android.widget.RelativeLayout.LayoutParams;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.json.JSONException;
|
||||||
|
|
||||||
|
public class SiteIdentityPopup extends PopupWindow {
|
||||||
|
private static final String LOGTAG = "GeckoSiteIdentityPopup";
|
||||||
|
|
||||||
|
public static final String UNKNOWN = "unknown";
|
||||||
|
public static final String VERIFIED = "verified";
|
||||||
|
public static final String IDENTIFIED = "identified";
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private Resources mResources;
|
||||||
|
private boolean mInflated;
|
||||||
|
|
||||||
|
private TextView mHost;
|
||||||
|
private TextView mOwner;
|
||||||
|
private TextView mSupplemental;
|
||||||
|
private TextView mVerifier;
|
||||||
|
private TextView mEncrypted;
|
||||||
|
|
||||||
|
private ImageView mLarry;
|
||||||
|
private ImageView mArrow;
|
||||||
|
|
||||||
|
public SiteIdentityPopup(Context aContext) {
|
||||||
|
super(aContext);
|
||||||
|
mContext = aContext;
|
||||||
|
mResources = aContext.getResources();
|
||||||
|
mInflated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
setBackgroundDrawable(new BitmapDrawable());
|
||||||
|
setOutsideTouchable(true);
|
||||||
|
setWindowLayoutMode(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
|
||||||
|
|
||||||
|
LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||||
|
RelativeLayout layout = (RelativeLayout) inflater.inflate(R.layout.site_identity_popup, null);
|
||||||
|
setContentView(layout);
|
||||||
|
|
||||||
|
mHost = (TextView) layout.findViewById(R.id.host);
|
||||||
|
mOwner = (TextView) layout.findViewById(R.id.owner);
|
||||||
|
mSupplemental = (TextView) layout.findViewById(R.id.supplemental);
|
||||||
|
mVerifier = (TextView) layout.findViewById(R.id.verifier);
|
||||||
|
mEncrypted = (TextView) layout.findViewById(R.id.encrypted);
|
||||||
|
|
||||||
|
mLarry = (ImageView) layout.findViewById(R.id.larry);
|
||||||
|
mArrow = (ImageView) layout.findViewById(R.id.arrow);
|
||||||
|
|
||||||
|
mInflated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show(int leftMargin) {
|
||||||
|
JSONObject identityData = Tabs.getInstance().getSelectedTab().getIdentityData();
|
||||||
|
if (identityData == null) {
|
||||||
|
Log.e(LOGTAG, "Tab has no identity data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String mode;
|
||||||
|
try {
|
||||||
|
mode = identityData.getString("mode");
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.e(LOGTAG, "Exception trying to get identity mode: " + e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mode.equals(VERIFIED) && !mode.equals(IDENTIFIED)) {
|
||||||
|
Log.e(LOGTAG, "Can't show site identity popup in non-identified state");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mInflated)
|
||||||
|
init();
|
||||||
|
|
||||||
|
try {
|
||||||
|
String host = identityData.getString("host");
|
||||||
|
mHost.setText(host);
|
||||||
|
|
||||||
|
String owner = identityData.getString("owner");
|
||||||
|
mOwner.setText(owner);
|
||||||
|
|
||||||
|
String verifier = identityData.getString("verifier");
|
||||||
|
mVerifier.setText(verifier);
|
||||||
|
|
||||||
|
String encrypted = identityData.getString("encrypted");
|
||||||
|
mEncrypted.setText(encrypted);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.e(LOGTAG, "Exception trying to get identity data: " + e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String supplemental = identityData.getString("supplemental");
|
||||||
|
mSupplemental.setText(supplemental);
|
||||||
|
mSupplemental.setVisibility(View.VISIBLE);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
mSupplemental.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode.equals(VERIFIED)) {
|
||||||
|
// Use a blue theme for SSL
|
||||||
|
mLarry.setImageResource(R.drawable.larry_blue);
|
||||||
|
mHost.setTextColor(mResources.getColor(R.color.identity_verified));
|
||||||
|
mOwner.setTextColor(mResources.getColor(R.color.identity_verified));
|
||||||
|
mSupplemental.setTextColor(mResources.getColor(R.color.identity_verified));
|
||||||
|
} else {
|
||||||
|
// Use a green theme for EV
|
||||||
|
mLarry.setImageResource(R.drawable.larry_green);
|
||||||
|
mHost.setTextColor(mResources.getColor(R.color.identity_identified));
|
||||||
|
mOwner.setTextColor(mResources.getColor(R.color.identity_identified));
|
||||||
|
mSupplemental.setTextColor(mResources.getColor(R.color.identity_identified));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Position the mArrow according to lock position
|
||||||
|
LayoutParams layoutParams = (LayoutParams) mArrow.getLayoutParams();
|
||||||
|
LayoutParams newLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||||
|
newLayoutParams.setMargins(leftMargin, layoutParams.topMargin, 0, 0);
|
||||||
|
mArrow.setLayoutParams(newLayoutParams);
|
||||||
|
|
||||||
|
// This will place the popup at the correct vertical position
|
||||||
|
showAsDropDown(GeckoApp.mBrowserToolbar.mSiteSecurity);
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,7 +77,7 @@ public final class Tab {
|
||||||
private String mTitle;
|
private String mTitle;
|
||||||
private Drawable mFavicon;
|
private Drawable mFavicon;
|
||||||
private String mFaviconUrl;
|
private String mFaviconUrl;
|
||||||
private String mSecurityMode;
|
private JSONObject mIdentityData;
|
||||||
private Drawable mThumbnail;
|
private Drawable mThumbnail;
|
||||||
private List<HistoryEntry> mHistory;
|
private List<HistoryEntry> mHistory;
|
||||||
private int mHistoryIndex;
|
private int mHistoryIndex;
|
||||||
|
@ -119,7 +119,7 @@ public final class Tab {
|
||||||
mTitle = title;
|
mTitle = title;
|
||||||
mFavicon = null;
|
mFavicon = null;
|
||||||
mFaviconUrl = null;
|
mFaviconUrl = null;
|
||||||
mSecurityMode = "unknown";
|
mIdentityData = null;
|
||||||
mThumbnail = null;
|
mThumbnail = null;
|
||||||
mHistory = new ArrayList<HistoryEntry>();
|
mHistory = new ArrayList<HistoryEntry>();
|
||||||
mHistoryIndex = -1;
|
mHistoryIndex = -1;
|
||||||
|
@ -270,7 +270,16 @@ public final class Tab {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSecurityMode() {
|
public String getSecurityMode() {
|
||||||
return mSecurityMode;
|
try {
|
||||||
|
return mIdentityData.getString("mode");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// If mIdentityData is null, or we get a JSONException
|
||||||
|
return SiteIdentityPopup.UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONObject getIdentityData() {
|
||||||
|
return mIdentityData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBookmark() {
|
public boolean isBookmark() {
|
||||||
|
@ -368,8 +377,9 @@ public final class Tab {
|
||||||
Log.i(LOGTAG, "Updated favicon URL for tab with id: " + mId);
|
Log.i(LOGTAG, "Updated favicon URL for tab with id: " + mId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateSecurityMode(String mode) {
|
|
||||||
mSecurityMode = mode;
|
public void updateIdentityData(JSONObject identityData) {
|
||||||
|
mIdentityData = identityData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateBookmark() {
|
private void updateBookmark() {
|
||||||
|
|
|
@ -167,8 +167,10 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
|
||||||
// approximation using the Cauchy distribution: multiplier = 15^2 / (age^2 + 15^2).
|
// approximation using the Cauchy distribution: multiplier = 15^2 / (age^2 + 15^2).
|
||||||
// Using 15 as our scale parameter, we get a constant 15^2 = 225. Following this math,
|
// Using 15 as our scale parameter, we get a constant 15^2 = 225. Following this math,
|
||||||
// frecencyScore = numVisits * max(1, 100 * 225 / (age*age + 225)). (See bug 704977)
|
// frecencyScore = numVisits * max(1, 100 * 225 / (age*age + 225)). (See bug 704977)
|
||||||
|
// We also give bookmarks an extra bonus boost by adding 100 points to their frecency score.
|
||||||
final String age = "(" + Combined.DATE_LAST_VISITED + " - " + System.currentTimeMillis() + ") / 86400000";
|
final String age = "(" + Combined.DATE_LAST_VISITED + " - " + System.currentTimeMillis() + ") / 86400000";
|
||||||
final String sortOrder = Combined.VISITS + " * MAX(1, 100 * 225 / (" + age + "*" + age + " + 225)) DESC";
|
final String sortOrder = "(CASE WHEN " + Combined.BOOKMARK_ID + " > -1 THEN 100 ELSE 0 END) + " +
|
||||||
|
Combined.VISITS + " * MAX(1, 100 * 225 / (" + age + "*" + age + " + 225)) DESC";
|
||||||
|
|
||||||
Cursor c = cr.query(combinedUriWithLimit(limit),
|
Cursor c = cr.query(combinedUriWithLimit(limit),
|
||||||
projection,
|
projection,
|
||||||
|
|
|
@ -126,3 +126,18 @@
|
||||||
<!ENTITY filepicker_audio_title "Choose or record a sound">
|
<!ENTITY filepicker_audio_title "Choose or record a sound">
|
||||||
<!ENTITY filepicker_image_title "Choose or take a picture">
|
<!ENTITY filepicker_image_title "Choose or take a picture">
|
||||||
<!ENTITY filepicker_video_title "Choose or record a video">
|
<!ENTITY filepicker_video_title "Choose or record a video">
|
||||||
|
|
||||||
|
<!-- Site identity popup -->
|
||||||
|
<!ENTITY identity_connected_to "You are connected to">
|
||||||
|
<!-- Localization note (identity_run_by) : This string appears between a
|
||||||
|
domain name (above) and an organization name (below). E.g.
|
||||||
|
|
||||||
|
example.com
|
||||||
|
which is run by
|
||||||
|
Example Enterprises, Inc.
|
||||||
|
|
||||||
|
The layout of the identity dialog prevents combining this into a single string with
|
||||||
|
substitution variables. If it is difficult to translate the sense of the string
|
||||||
|
with that structure, consider a translation which ignores the preceding domain and
|
||||||
|
just addresses the organization to follow, e.g. "This site is run by " -->
|
||||||
|
<!ENTITY identity_run_by "which is run by">
|
||||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 5.1 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 5.1 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 7.3 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 7.3 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 3.0 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 3.1 KiB |
|
@ -0,0 +1,82 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<RelativeLayout android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dip"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:background="@drawable/doorhanger_popup_bg">
|
||||||
|
|
||||||
|
<LinearLayout android:id="@+id/identity_info"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="12dip"
|
||||||
|
android:background="@drawable/doorhanger_bg"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:text="@string/identity_connected_to"/>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/host"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textStyle="bold"/>
|
||||||
|
|
||||||
|
<TextView android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:text="@string/identity_run_by"/>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/owner"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textStyle="bold"/>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/supplemental"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"/>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/verifier"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView android:id="@+id/larry"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="12dip"
|
||||||
|
android:layout_alignParentRight="true"/>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/encrypted"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignBottom="@id/identity_info"
|
||||||
|
android:padding="12dip"
|
||||||
|
android:gravity="right"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<ImageView android:id="@+id/arrow"
|
||||||
|
android:layout_width="44dip"
|
||||||
|
android:layout_height="16dip"
|
||||||
|
android:layout_marginTop="9dip"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:src="@drawable/doorhanger_arrow"
|
||||||
|
android:scaleType="fitXY"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
|
@ -6,5 +6,7 @@
|
||||||
<color name="splash_content">#ffffff</color>
|
<color name="splash_content">#ffffff</color>
|
||||||
<color name="doorhanger_link">#ACC4D5</color>
|
<color name="doorhanger_link">#ACC4D5</color>
|
||||||
<color name="validation_message_text">#ffffff</color>
|
<color name="validation_message_text">#ffffff</color>
|
||||||
|
<color name="identity_verified">#77BAFF</color>
|
||||||
|
<color name="identity_identified">#B7D46A</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
|
|
|
@ -148,4 +148,8 @@
|
||||||
|
|
||||||
<string name="bookmarkdefaults_title_abouthome">@bookmarks_aboutHome@</string>
|
<string name="bookmarkdefaults_title_abouthome">@bookmarks_aboutHome@</string>
|
||||||
<string name="bookmarkdefaults_url_abouthome">about:home</string>
|
<string name="bookmarkdefaults_url_abouthome">about:home</string>
|
||||||
|
|
||||||
|
<!-- Site identity popup -->
|
||||||
|
<string name="identity_connected_to">&identity_connected_to;</string>
|
||||||
|
<string name="identity_run_by">&identity_run_by;</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -227,8 +227,14 @@ abstract class Axis {
|
||||||
* possible and this axis has not been scroll locked while panning. Otherwise, returns false.
|
* possible and this axis has not been scroll locked while panning. Otherwise, returns false.
|
||||||
*/
|
*/
|
||||||
private boolean scrollable() {
|
private boolean scrollable() {
|
||||||
return getViewportLength() <= getPageLength() - MIN_SCROLLABLE_DISTANCE &&
|
// If we're scrolling a subdocument, ignore the viewport length restrictions (since those
|
||||||
!mScrollingDisabled;
|
// apply to the top-level document) and only take into account axis locking.
|
||||||
|
if (mSubscroller.scrolling()) {
|
||||||
|
return !mScrollingDisabled;
|
||||||
|
} else {
|
||||||
|
return getViewportLength() <= getPageLength() - MIN_SCROLLABLE_DISTANCE &&
|
||||||
|
!mScrollingDisabled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -305,8 +311,9 @@ abstract class Axis {
|
||||||
|
|
||||||
// Performs displacement of the viewport position according to the current velocity.
|
// Performs displacement of the viewport position according to the current velocity.
|
||||||
void displace() {
|
void displace() {
|
||||||
if (!mSubscroller.scrolling() && !scrollable())
|
if (!scrollable()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mFlingState == FlingStates.PANNING)
|
if (mFlingState == FlingStates.PANNING)
|
||||||
mDisplacement += (mLastTouchPos - mTouchPos) * getEdgeResistance();
|
mDisplacement += (mLastTouchPos - mTouchPos) * getEdgeResistance();
|
||||||
|
|
|
@ -597,14 +597,14 @@ public class PanZoomController
|
||||||
return getVelocity() < STOPPED_THRESHOLD;
|
return getVelocity() < STOPPED_THRESHOLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
PointF getDisplacement() {
|
PointF resetDisplacement() {
|
||||||
return new PointF(mX.resetDisplacement(), mY.resetDisplacement());
|
return new PointF(mX.resetDisplacement(), mY.resetDisplacement());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePosition() {
|
private void updatePosition() {
|
||||||
mX.displace();
|
mX.displace();
|
||||||
mY.displace();
|
mY.displace();
|
||||||
PointF displacement = getDisplacement();
|
PointF displacement = resetDisplacement();
|
||||||
if (FloatUtils.fuzzyEquals(displacement.x, 0.0f) && FloatUtils.fuzzyEquals(displacement.y, 0.0f)) {
|
if (FloatUtils.fuzzyEquals(displacement.x, 0.0f) && FloatUtils.fuzzyEquals(displacement.y, 0.0f)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -947,12 +947,6 @@ public class PanZoomController
|
||||||
sendPointToGecko("Gesture:LongPress", motionEvent);
|
sendPointToGecko("Gesture:LongPress", motionEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onDown(MotionEvent motionEvent) {
|
|
||||||
sendPointToGecko("Gesture:ShowPress", motionEvent);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onSingleTapConfirmed(MotionEvent motionEvent) {
|
public boolean onSingleTapConfirmed(MotionEvent motionEvent) {
|
||||||
GeckoApp.mFormAssistPopup.hide();
|
GeckoApp.mFormAssistPopup.hide();
|
||||||
|
|
|
@ -57,15 +57,31 @@ class SubdocumentScrollHelper implements GeckoEventListener {
|
||||||
private final PanZoomController mPanZoomController;
|
private final PanZoomController mPanZoomController;
|
||||||
private final Handler mUiHandler;
|
private final Handler mUiHandler;
|
||||||
|
|
||||||
|
/* This is the amount of displacement we have accepted but not yet sent to JS; this is
|
||||||
|
* only valid when mOverrideScrollPending is true. */
|
||||||
|
private final PointF mPendingDisplacement;
|
||||||
|
|
||||||
|
/* When this is true, we're sending scroll events to JS to scroll the active subdocument. */
|
||||||
private boolean mOverridePanning;
|
private boolean mOverridePanning;
|
||||||
|
|
||||||
|
/* When this is true, we have received an ack for the last scroll event we sent to JS, and
|
||||||
|
* are ready to send the next scroll event. Note we only ever have one scroll event inflight
|
||||||
|
* at a time. */
|
||||||
private boolean mOverrideScrollAck;
|
private boolean mOverrideScrollAck;
|
||||||
|
|
||||||
|
/* When this is true, we have a pending scroll that we need to send to JS; we were unable
|
||||||
|
* to send it when it was initially requested because mOverrideScrollAck was not true. */
|
||||||
private boolean mOverrideScrollPending;
|
private boolean mOverrideScrollPending;
|
||||||
|
|
||||||
|
/* When this is true, the last scroll event we sent actually did some amount of scrolling on
|
||||||
|
* the subdocument; we use this to decide when we have reached the end of the subdocument. */
|
||||||
private boolean mScrollSucceeded;
|
private boolean mScrollSucceeded;
|
||||||
|
|
||||||
SubdocumentScrollHelper(PanZoomController controller) {
|
SubdocumentScrollHelper(PanZoomController controller) {
|
||||||
mPanZoomController = controller;
|
mPanZoomController = controller;
|
||||||
// mUiHandler will be bound to the UI thread since that's where this constructor runs
|
// mUiHandler will be bound to the UI thread since that's where this constructor runs
|
||||||
mUiHandler = new Handler();
|
mUiHandler = new Handler();
|
||||||
|
mPendingDisplacement = new PointF();
|
||||||
|
|
||||||
GeckoAppShell.registerGeckoEventListener(MESSAGE_PANNING_OVERRIDE, this);
|
GeckoAppShell.registerGeckoEventListener(MESSAGE_PANNING_OVERRIDE, this);
|
||||||
GeckoAppShell.registerGeckoEventListener(MESSAGE_CANCEL_OVERRIDE, this);
|
GeckoAppShell.registerGeckoEventListener(MESSAGE_CANCEL_OVERRIDE, this);
|
||||||
|
@ -79,12 +95,11 @@ class SubdocumentScrollHelper implements GeckoEventListener {
|
||||||
|
|
||||||
if (! mOverrideScrollAck) {
|
if (! mOverrideScrollAck) {
|
||||||
mOverrideScrollPending = true;
|
mOverrideScrollPending = true;
|
||||||
|
mPendingDisplacement.x += displacement.x;
|
||||||
|
mPendingDisplacement.y += displacement.y;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mOverrideScrollAck = false;
|
|
||||||
mOverrideScrollPending = false;
|
|
||||||
|
|
||||||
JSONObject json = new JSONObject();
|
JSONObject json = new JSONObject();
|
||||||
try {
|
try {
|
||||||
json.put("x", displacement.x);
|
json.put("x", displacement.x);
|
||||||
|
@ -94,6 +109,13 @@ class SubdocumentScrollHelper implements GeckoEventListener {
|
||||||
}
|
}
|
||||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(MESSAGE_SCROLL, json.toString()));
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(MESSAGE_SCROLL, json.toString()));
|
||||||
|
|
||||||
|
mOverrideScrollAck = false;
|
||||||
|
mOverrideScrollPending = false;
|
||||||
|
// clear the |mPendingDisplacement| after serializing |displacement| to
|
||||||
|
// JSON because they might be the same object
|
||||||
|
mPendingDisplacement.x = 0;
|
||||||
|
mPendingDisplacement.y = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +150,7 @@ class SubdocumentScrollHelper implements GeckoEventListener {
|
||||||
mOverrideScrollAck = true;
|
mOverrideScrollAck = true;
|
||||||
mScrollSucceeded = message.getBoolean("scrolled");
|
mScrollSucceeded = message.getBoolean("scrolled");
|
||||||
if (mOverridePanning && mOverrideScrollPending) {
|
if (mOverridePanning && mOverrideScrollPending) {
|
||||||
scrollBy(mPanZoomController.getDisplacement());
|
scrollBy(mPendingDisplacement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
|
@ -81,6 +81,7 @@ let Downloads = {
|
||||||
switch (aTopic) {
|
switch (aTopic) {
|
||||||
case "dl-failed":
|
case "dl-failed":
|
||||||
case "dl-cancel":
|
case "dl-cancel":
|
||||||
|
break;
|
||||||
case "dl-done":
|
case "dl-done":
|
||||||
if (!this._getElementForDownload(download.id)) {
|
if (!this._getElementForDownload(download.id)) {
|
||||||
let item = this._createItem(downloadTemplate, {
|
let item = this._createItem(downloadTemplate, {
|
||||||
|
@ -102,10 +103,10 @@ let Downloads = {
|
||||||
this._stmt.finalize();
|
this._stmt.finalize();
|
||||||
|
|
||||||
this._stmt = this._dlmgr.DBConnection.createStatement(
|
this._stmt = this._dlmgr.DBConnection.createStatement(
|
||||||
"SELECT id, name, source, state, startTime, endTime, referrer, " +
|
"SELECT id, name, source, startTime, endTime, referrer, " +
|
||||||
"currBytes, maxBytes, state IN (?1, ?2, ?3, ?4, ?5) isActive " +
|
"currBytes, maxBytes " +
|
||||||
"FROM moz_downloads " +
|
"FROM moz_downloads " +
|
||||||
"WHERE NOT isActive " +
|
"WHERE state = :download_state " +
|
||||||
"ORDER BY endTime DESC");
|
"ORDER BY endTime DESC");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -177,11 +178,7 @@ let Downloads = {
|
||||||
clearTimeout(this._timeoutID);
|
clearTimeout(this._timeoutID);
|
||||||
|
|
||||||
this._stmt.reset();
|
this._stmt.reset();
|
||||||
this._stmt.bindInt32Parameter(0, Ci.nsIDownloadManager.DOWNLOAD_NOTSTARTED);
|
this._stmt.params.download_state = Ci.nsIDownloadManager.DOWNLOAD_FINISHED;
|
||||||
this._stmt.bindInt32Parameter(1, Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING);
|
|
||||||
this._stmt.bindInt32Parameter(2, Ci.nsIDownloadManager.DOWNLOAD_PAUSED);
|
|
||||||
this._stmt.bindInt32Parameter(3, Ci.nsIDownloadManager.DOWNLOAD_QUEUED);
|
|
||||||
this._stmt.bindInt32Parameter(4, Ci.nsIDownloadManager.DOWNLOAD_SCANNING);
|
|
||||||
|
|
||||||
// Take a quick break before we actually start building the list
|
// Take a quick break before we actually start building the list
|
||||||
let self = this;
|
let self = this;
|
||||||
|
|
|
@ -2213,6 +2213,8 @@ Tab.prototype = {
|
||||||
if (contentWin != contentWin.top)
|
if (contentWin != contentWin.top)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
this._hostChanged = true;
|
||||||
|
|
||||||
let browser = BrowserApp.getBrowserForWindow(contentWin);
|
let browser = BrowserApp.getBrowserForWindow(contentWin);
|
||||||
let uri = browser.currentURI.spec;
|
let uri = browser.currentURI.spec;
|
||||||
let documentURI = "";
|
let documentURI = "";
|
||||||
|
@ -2249,26 +2251,29 @@ Tab.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Properties used to cache security state used to update the UI
|
||||||
|
_state: null,
|
||||||
|
_hostChanged: false, // onLocationChange will flip this bit
|
||||||
|
|
||||||
onSecurityChange: function(aWebProgress, aRequest, aState) {
|
onSecurityChange: function(aWebProgress, aRequest, aState) {
|
||||||
let mode = "unknown";
|
// Don't need to do anything if the data we use to update the UI hasn't changed
|
||||||
if (aState & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL)
|
if (this._state == aState && !this._hostChanged)
|
||||||
mode = "identified";
|
return;
|
||||||
else if (aState & Ci.nsIWebProgressListener.STATE_SECURE_HIGH)
|
|
||||||
mode = "verified";
|
this._state = aState;
|
||||||
else if (aState & Ci.nsIWebProgressListener.STATE_IS_BROKEN)
|
this._hostChanged = false;
|
||||||
mode = "mixed";
|
|
||||||
else
|
let identity = IdentityHandler.checkIdentity(aState, this.browser);
|
||||||
mode = "unknown";
|
|
||||||
|
|
||||||
let message = {
|
let message = {
|
||||||
gecko: {
|
gecko: {
|
||||||
type: "Content:SecurityChange",
|
type: "Content:SecurityChange",
|
||||||
tabID: this.id,
|
tabID: this.id,
|
||||||
mode: mode
|
identity: identity
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
sendMessageToJava(message);
|
sendMessageToJava(message);
|
||||||
},
|
},
|
||||||
|
|
||||||
onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {
|
onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {
|
||||||
|
@ -2521,13 +2526,44 @@ Tab.prototype = {
|
||||||
var BrowserEventHandler = {
|
var BrowserEventHandler = {
|
||||||
init: function init() {
|
init: function init() {
|
||||||
Services.obs.addObserver(this, "Gesture:SingleTap", false);
|
Services.obs.addObserver(this, "Gesture:SingleTap", false);
|
||||||
Services.obs.addObserver(this, "Gesture:ShowPress", false);
|
|
||||||
Services.obs.addObserver(this, "Gesture:CancelTouch", false);
|
Services.obs.addObserver(this, "Gesture:CancelTouch", false);
|
||||||
Services.obs.addObserver(this, "Gesture:DoubleTap", false);
|
Services.obs.addObserver(this, "Gesture:DoubleTap", false);
|
||||||
Services.obs.addObserver(this, "Gesture:Scroll", false);
|
Services.obs.addObserver(this, "Gesture:Scroll", false);
|
||||||
Services.obs.addObserver(this, "dom-touch-listener-added", false);
|
Services.obs.addObserver(this, "dom-touch-listener-added", false);
|
||||||
|
|
||||||
BrowserApp.deck.addEventListener("DOMUpdatePageReport", PopupBlockerObserver.onUpdatePageReport, false);
|
BrowserApp.deck.addEventListener("DOMUpdatePageReport", PopupBlockerObserver.onUpdatePageReport, false);
|
||||||
|
BrowserApp.deck.addEventListener("touchstart", this, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleEvent: function(aEvent) {
|
||||||
|
if (!BrowserApp.isBrowserContentDocumentDisplayed() || aEvent.touches.length > 1 || aEvent.defaultPrevented)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let closest = aEvent.target;
|
||||||
|
|
||||||
|
if (closest) {
|
||||||
|
// If we've pressed a scrollable element, let Java know that we may
|
||||||
|
// want to override the scroll behaviour (for document sub-frames)
|
||||||
|
this._scrollableElement = this._findScrollableElement(closest, true);
|
||||||
|
this._firstScrollEvent = true;
|
||||||
|
|
||||||
|
if (this._scrollableElement != null) {
|
||||||
|
// Discard if it's the top-level scrollable, we let Java handle this
|
||||||
|
let doc = BrowserApp.selectedBrowser.contentDocument;
|
||||||
|
if (this._scrollableElement != doc.body && this._scrollableElement != doc.documentElement)
|
||||||
|
sendMessageToJava({ gecko: { type: "Panning:Override" } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ElementTouchHelper.isElementClickable(closest))
|
||||||
|
closest = ElementTouchHelper.elementFromPoint(BrowserApp.selectedBrowser.contentWindow,
|
||||||
|
aEvent.changedTouches[0].screenX,
|
||||||
|
aEvent.changedTouches[0].screenY);
|
||||||
|
if (!closest)
|
||||||
|
closest = aEvent.target;
|
||||||
|
|
||||||
|
if (closest)
|
||||||
|
this._doTapHighlight(closest);
|
||||||
},
|
},
|
||||||
|
|
||||||
observe: function(aSubject, aTopic, aData) {
|
observe: function(aSubject, aTopic, aData) {
|
||||||
|
@ -2562,12 +2598,19 @@ var BrowserEventHandler = {
|
||||||
// the user wanted, and neither can any non-root sub-frame, cancel the
|
// the user wanted, and neither can any non-root sub-frame, cancel the
|
||||||
// override so that Java can handle panning the main document.
|
// override so that Java can handle panning the main document.
|
||||||
let data = JSON.parse(aData);
|
let data = JSON.parse(aData);
|
||||||
|
|
||||||
|
// round the scroll amounts because they come in as floats and might be
|
||||||
|
// subject to minor rounding errors because of zoom values. I've seen values
|
||||||
|
// like 0.99 come in here and get truncated to 0; this avoids that problem.
|
||||||
|
data.x = Math.round(data.x);
|
||||||
|
data.y = Math.round(data.y);
|
||||||
|
|
||||||
if (this._firstScrollEvent) {
|
if (this._firstScrollEvent) {
|
||||||
while (this._scrollableElement != null && !this._elementCanScroll(this._scrollableElement, data.x, data.y))
|
while (this._scrollableElement != null && !this._elementCanScroll(this._scrollableElement, data.x, data.y))
|
||||||
this._scrollableElement = this._findScrollableElement(this._scrollableElement, false);
|
this._scrollableElement = this._findScrollableElement(this._scrollableElement, false);
|
||||||
|
|
||||||
let doc = BrowserApp.selectedBrowser.contentDocument;
|
let doc = BrowserApp.selectedBrowser.contentDocument;
|
||||||
if (this._scrollableElement == doc.body || this._scrollableElement == doc.documentElement) {
|
if (this._scrollableElement == null || this._scrollableElement == doc.body || this._scrollableElement == doc.documentElement) {
|
||||||
sendMessageToJava({ gecko: { type: "Panning:CancelOverride" } });
|
sendMessageToJava({ gecko: { type: "Panning:CancelOverride" } });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2584,32 +2627,12 @@ var BrowserEventHandler = {
|
||||||
}
|
}
|
||||||
} else if (aTopic == "Gesture:CancelTouch") {
|
} else if (aTopic == "Gesture:CancelTouch") {
|
||||||
this._cancelTapHighlight();
|
this._cancelTapHighlight();
|
||||||
} else if (aTopic == "Gesture:ShowPress") {
|
|
||||||
let data = JSON.parse(aData);
|
|
||||||
let closest = ElementTouchHelper.elementFromPoint(BrowserApp.selectedBrowser.contentWindow, data.x, data.y);
|
|
||||||
if (!closest)
|
|
||||||
closest = ElementTouchHelper.anyElementFromPoint(BrowserApp.selectedBrowser.contentWindow, data.x, data.y);
|
|
||||||
if (closest) {
|
|
||||||
this._doTapHighlight(closest);
|
|
||||||
|
|
||||||
// If we've pressed a scrollable element, let Java know that we may
|
|
||||||
// want to override the scroll behaviour (for document sub-frames)
|
|
||||||
this._scrollableElement = this._findScrollableElement(closest, true);
|
|
||||||
this._firstScrollEvent = true;
|
|
||||||
|
|
||||||
if (this._scrollableElement != null) {
|
|
||||||
// Discard if it's the top-level scrollable, we let Java handle this
|
|
||||||
let doc = BrowserApp.selectedBrowser.contentDocument;
|
|
||||||
if (this._scrollableElement != doc.body && this._scrollableElement != doc.documentElement)
|
|
||||||
sendMessageToJava({ gecko: { type: "Panning:Override" } });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (aTopic == "Gesture:SingleTap") {
|
} else if (aTopic == "Gesture:SingleTap") {
|
||||||
let element = this._highlightElement;
|
let element = this._highlightElement;
|
||||||
if (element && !SelectHelper.handleClick(element)) {
|
if (element && !SelectHelper.handleClick(element)) {
|
||||||
try {
|
try {
|
||||||
let data = JSON.parse(aData);
|
let data = JSON.parse(aData);
|
||||||
|
|
||||||
this._sendMouseEvent("mousemove", element, data.x, data.y);
|
this._sendMouseEvent("mousemove", element, data.x, data.y);
|
||||||
this._sendMouseEvent("mousedown", element, data.x, data.y);
|
this._sendMouseEvent("mousedown", element, data.x, data.y);
|
||||||
this._sendMouseEvent("mouseup", element, data.x, data.y);
|
this._sendMouseEvent("mouseup", element, data.x, data.y);
|
||||||
|
@ -2824,24 +2847,11 @@ var BrowserEventHandler = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_elementCanScroll: function(elem, x, y) {
|
_elementCanScroll: function(elem, x, y) {
|
||||||
let scrollX = true;
|
let scrollX = (x < 0 && elem.scrollLeft > 0)
|
||||||
let scrollY = true;
|
|| (x > 0 && elem.scrollLeft < (elem.scrollWidth - elem.clientWidth));
|
||||||
|
|
||||||
if (x < 0) {
|
let scrollY = (y < 0 && elem.scrollTop > 0)
|
||||||
if (elem.scrollLeft <= 0) {
|
|| (y > 0 && elem.scrollTop < (elem.scrollHeight - elem.clientHeight));
|
||||||
scrollX = false;
|
|
||||||
}
|
|
||||||
} else if (elem.scrollLeft >= (elem.scrollWidth - elem.clientWidth)) {
|
|
||||||
scrollX = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (y < 0) {
|
|
||||||
if (elem.scrollTop <= 0) {
|
|
||||||
scrollY = false;
|
|
||||||
}
|
|
||||||
} else if (elem.scrollTop >= (elem.scrollHeight - elem.clientHeight)) {
|
|
||||||
scrollY = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return scrollX || scrollY;
|
return scrollX || scrollY;
|
||||||
}
|
}
|
||||||
|
@ -3593,14 +3603,11 @@ var ViewportHandler = {
|
||||||
if (doctype && /(WAP|WML|Mobile)/.test(doctype.publicId))
|
if (doctype && /(WAP|WML|Mobile)/.test(doctype.publicId))
|
||||||
return { defaultZoom: 1, autoSize: true, allowZoom: true, autoScale: true };
|
return { defaultZoom: 1, autoSize: true, allowZoom: true, autoScale: true };
|
||||||
|
|
||||||
let windowUtils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
|
||||||
let handheldFriendly = windowUtils.getDocumentMetadata("HandheldFriendly");
|
|
||||||
if (handheldFriendly == "true")
|
|
||||||
return { defaultZoom: 1, autoSize: true, allowZoom: true, autoScale: true };
|
|
||||||
|
|
||||||
if (aWindow.document instanceof XULDocument)
|
if (aWindow.document instanceof XULDocument)
|
||||||
return { defaultZoom: 1, autoSize: true, allowZoom: false, autoScale: false };
|
return { defaultZoom: 1, autoSize: true, allowZoom: false, autoScale: false };
|
||||||
|
|
||||||
|
let windowUtils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||||
|
|
||||||
// viewport details found here
|
// viewport details found here
|
||||||
// http://developer.apple.com/safari/library/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html
|
// http://developer.apple.com/safari/library/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html
|
||||||
// http://developer.apple.com/safari/library/documentation/AppleApplications/Reference/SafariWebContent/UsingtheViewport/UsingtheViewport.html
|
// http://developer.apple.com/safari/library/documentation/AppleApplications/Reference/SafariWebContent/UsingtheViewport/UsingtheViewport.html
|
||||||
|
@ -3619,6 +3626,15 @@ var ViewportHandler = {
|
||||||
let allowZoomStr = windowUtils.getDocumentMetadata("viewport-user-scalable");
|
let allowZoomStr = windowUtils.getDocumentMetadata("viewport-user-scalable");
|
||||||
let allowZoom = !/^(0|no|false)$/.test(allowZoomStr); // WebKit allows 0, "no", or "false"
|
let allowZoom = !/^(0|no|false)$/.test(allowZoomStr); // WebKit allows 0, "no", or "false"
|
||||||
|
|
||||||
|
|
||||||
|
if (scale == NaN && minScale == NaN && maxScale == NaN && allowZoomStr == "" && widthStr == "" && heightStr == "") {
|
||||||
|
// Only check for HandheldFriendly if we don't have a viewport meta tag
|
||||||
|
let handheldFriendly = windowUtils.getDocumentMetadata("HandheldFriendly");
|
||||||
|
|
||||||
|
if (handheldFriendly == "true")
|
||||||
|
return { defaultZoom: 1, autoSize: true, allowZoom: true, autoScale: true };
|
||||||
|
}
|
||||||
|
|
||||||
scale = this.clamp(scale, kViewportMinScale, kViewportMaxScale);
|
scale = this.clamp(scale, kViewportMinScale, kViewportMaxScale);
|
||||||
minScale = this.clamp(minScale, kViewportMinScale, kViewportMaxScale);
|
minScale = this.clamp(minScale, kViewportMinScale, kViewportMaxScale);
|
||||||
maxScale = this.clamp(maxScale, kViewportMinScale, kViewportMaxScale);
|
maxScale = this.clamp(maxScale, kViewportMinScale, kViewportMaxScale);
|
||||||
|
@ -4605,6 +4621,159 @@ var CharacterEncoding = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var IdentityHandler = {
|
||||||
|
// Mode strings used to control CSS display
|
||||||
|
IDENTITY_MODE_IDENTIFIED : "identified", // High-quality identity information
|
||||||
|
IDENTITY_MODE_DOMAIN_VERIFIED : "verified", // Minimal SSL CA-signed domain verification
|
||||||
|
IDENTITY_MODE_UNKNOWN : "unknown", // No trusted identity information
|
||||||
|
|
||||||
|
// Cache the most recent SSLStatus and Location seen in getIdentityStrings
|
||||||
|
_lastStatus : null,
|
||||||
|
_lastLocation : null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to parse out the important parts of _lastStatus (of the SSL cert in
|
||||||
|
* particular) for use in constructing identity UI strings
|
||||||
|
*/
|
||||||
|
getIdentityData : function() {
|
||||||
|
let result = {};
|
||||||
|
let status = this._lastStatus.QueryInterface(Components.interfaces.nsISSLStatus);
|
||||||
|
let cert = status.serverCert;
|
||||||
|
|
||||||
|
// Human readable name of Subject
|
||||||
|
result.subjectOrg = cert.organization;
|
||||||
|
|
||||||
|
// SubjectName fields, broken up for individual access
|
||||||
|
if (cert.subjectName) {
|
||||||
|
result.subjectNameFields = {};
|
||||||
|
cert.subjectName.split(",").forEach(function(v) {
|
||||||
|
let field = v.split("=");
|
||||||
|
this[field[0]] = field[1];
|
||||||
|
}, result.subjectNameFields);
|
||||||
|
|
||||||
|
// Call out city, state, and country specifically
|
||||||
|
result.city = result.subjectNameFields.L;
|
||||||
|
result.state = result.subjectNameFields.ST;
|
||||||
|
result.country = result.subjectNameFields.C;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Human readable name of Certificate Authority
|
||||||
|
result.caOrg = cert.issuerOrganization || cert.issuerCommonName;
|
||||||
|
result.cert = cert;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
getIdentityMode: function getIdentityMode(aState) {
|
||||||
|
if (aState & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL)
|
||||||
|
return this.IDENTITY_MODE_IDENTIFIED;
|
||||||
|
|
||||||
|
if (aState & Ci.nsIWebProgressListener.STATE_SECURE_HIGH)
|
||||||
|
return this.IDENTITY_MODE_DOMAIN_VERIFIED;
|
||||||
|
|
||||||
|
return this.IDENTITY_MODE_UNKNOWN;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the identity of the page being displayed by examining its SSL cert
|
||||||
|
* (if available). Return the data needed to update the UI.
|
||||||
|
*/
|
||||||
|
checkIdentity: function checkIdentity(aState, aBrowser) {
|
||||||
|
this._lastStatus = aBrowser.securityUI
|
||||||
|
.QueryInterface(Components.interfaces.nsISSLStatusProvider)
|
||||||
|
.SSLStatus;
|
||||||
|
|
||||||
|
// Don't pass in the actual location object, since it can cause us to
|
||||||
|
// hold on to the window object too long. Just pass in the fields we
|
||||||
|
// care about. (bug 424829)
|
||||||
|
let locationObj = {};
|
||||||
|
try {
|
||||||
|
let location = aBrowser.contentWindow.location;
|
||||||
|
locationObj.host = location.host;
|
||||||
|
locationObj.hostname = location.hostname;
|
||||||
|
locationObj.port = location.port;
|
||||||
|
} catch (ex) {
|
||||||
|
// Can sometimes throw if the URL being visited has no host/hostname,
|
||||||
|
// e.g. about:blank. The _state for these pages means we won't need these
|
||||||
|
// properties anyways, though.
|
||||||
|
}
|
||||||
|
this._lastLocation = locationObj;
|
||||||
|
|
||||||
|
let mode = this.getIdentityMode(aState);
|
||||||
|
let result = { mode: mode };
|
||||||
|
|
||||||
|
// We can't to do anything else for pages without identity data
|
||||||
|
if (mode == this.IDENTITY_MODE_UNKNOWN)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
// Ideally we'd just make this a Java string
|
||||||
|
result.encrypted = Strings.browser.GetStringFromName("identity.encrypted2");
|
||||||
|
result.host = this.getEffectiveHost();
|
||||||
|
|
||||||
|
let iData = this.getIdentityData();
|
||||||
|
result.verifier = Strings.browser.formatStringFromName("identity.identified.verifier", [iData.caOrg], 1);
|
||||||
|
|
||||||
|
// If the cert is identified, then we can populate the results with credentials
|
||||||
|
if (mode == this.IDENTITY_MODE_IDENTIFIED) {
|
||||||
|
result.owner = iData.subjectOrg;
|
||||||
|
|
||||||
|
// Build an appropriate supplemental block out of whatever location data we have
|
||||||
|
let supplemental = "";
|
||||||
|
if (iData.city)
|
||||||
|
supplemental += iData.city + "\n";
|
||||||
|
if (iData.state && iData.country)
|
||||||
|
supplemental += Strings.browser.formatStringFromName("identity.identified.state_and_country", [iData.state, iData.country], 2);
|
||||||
|
else if (iData.state) // State only
|
||||||
|
supplemental += iData.state;
|
||||||
|
else if (iData.country) // Country only
|
||||||
|
supplemental += iData.country;
|
||||||
|
result.supplemental = supplemental;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we don't know the cert owner
|
||||||
|
result.owner = Strings.browser.GetStringFromName("identity.ownerUnknown2");
|
||||||
|
|
||||||
|
// Cache the override service the first time we need to check it
|
||||||
|
if (!this._overrideService)
|
||||||
|
this._overrideService = Cc["@mozilla.org/security/certoverride;1"].getService(Ci.nsICertOverrideService);
|
||||||
|
|
||||||
|
// Check whether this site is a security exception. XPConnect does the right
|
||||||
|
// thing here in terms of converting _lastLocation.port from string to int, but
|
||||||
|
// the overrideService doesn't like undefined ports, so make sure we have
|
||||||
|
// something in the default case (bug 432241).
|
||||||
|
// .hostname can return an empty string in some exceptional cases -
|
||||||
|
// hasMatchingOverride does not handle that, so avoid calling it.
|
||||||
|
// Updating the tooltip value in those cases isn't critical.
|
||||||
|
// FIXME: Fixing bug 646690 would probably makes this check unnecessary
|
||||||
|
if (this._lastLocation.hostname &&
|
||||||
|
this._overrideService.hasMatchingOverride(this._lastLocation.hostname,
|
||||||
|
(this._lastLocation.port || 443),
|
||||||
|
iData.cert, {}, {}))
|
||||||
|
result.verifier = Strings.browser.GetStringFromName("identity.identified.verified_by_you");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the eTLD+1 version of the current hostname
|
||||||
|
*/
|
||||||
|
getEffectiveHost: function getEffectiveHost() {
|
||||||
|
if (!this._IDNService)
|
||||||
|
this._IDNService = Cc["@mozilla.org/network/idn-service;1"]
|
||||||
|
.getService(Ci.nsIIDNService);
|
||||||
|
try {
|
||||||
|
let baseDomain = Services.eTLD.getBaseDomainFromHost(this._lastLocation.hostname);
|
||||||
|
return this._IDNService.convertToDisplayIDN(baseDomain, {});
|
||||||
|
} catch (e) {
|
||||||
|
// If something goes wrong (e.g. hostname is an IP address) just fail back
|
||||||
|
// to the full domain.
|
||||||
|
return this._lastLocation.hostname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function OverscrollController(aTab) {
|
function OverscrollController(aTab) {
|
||||||
this.tab = aTab;
|
this.tab = aTab;
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,8 +75,6 @@ identity.identified.verified_by_you=You have added a security exception for this
|
||||||
identity.identified.state_and_country=%S, %S
|
identity.identified.state_and_country=%S, %S
|
||||||
identity.identified.title_with_country=%S (%S)
|
identity.identified.title_with_country=%S (%S)
|
||||||
identity.encrypted2=Encrypted
|
identity.encrypted2=Encrypted
|
||||||
identity.unencrypted2=Not encrypted
|
|
||||||
identity.unknown.tooltip=This website does not supply identity information.
|
|
||||||
identity.ownerUnknown2=(unknown)
|
identity.ownerUnknown2=(unknown)
|
||||||
|
|
||||||
# Geolocation UI
|
# Geolocation UI
|
||||||
|
|
|
@ -46,3 +46,55 @@ class TestSwitchFrame(MarionetteTestCase):
|
||||||
self.assertEqual("Marionette IFrame Test", self.marionette.execute_script("return window.document.title;"))
|
self.assertEqual("Marionette IFrame Test", self.marionette.execute_script("return window.document.title;"))
|
||||||
self.marionette.switch_to_frame("test_iframe")
|
self.marionette.switch_to_frame("test_iframe")
|
||||||
self.assertTrue("test.html" in self.marionette.get_url())
|
self.assertTrue("test.html" in self.marionette.get_url())
|
||||||
|
|
||||||
|
def test_switch_nested(self):
|
||||||
|
self.assertTrue(self.marionette.execute_script("window.location.href = 'about:blank'; return true;"))
|
||||||
|
self.assertEqual("about:blank", self.marionette.execute_script("return window.location.href;"))
|
||||||
|
test_html = self.marionette.absolute_url("test_nested_iframe.html")
|
||||||
|
self.marionette.navigate(test_html)
|
||||||
|
self.assertNotEqual("about:blank", self.marionette.execute_script("return window.location.href;"))
|
||||||
|
self.assertEqual("Marionette IFrame Test", self.marionette.execute_script("return window.document.title;"))
|
||||||
|
self.marionette.switch_to_frame("test_iframe")
|
||||||
|
self.assertTrue("test_inner_iframe.html" in self.marionette.get_url())
|
||||||
|
self.marionette.switch_to_frame("inner_frame")
|
||||||
|
self.assertTrue("test.html" in self.marionette.get_url())
|
||||||
|
self.marionette.switch_to_frame() # go back to main frame
|
||||||
|
self.assertTrue("test_nested_iframe.html" in self.marionette.get_url())
|
||||||
|
#test that we're using the right window object server-side
|
||||||
|
self.assertTrue("test_nested_iframe.html" in self.marionette.execute_script("return window.location.href;"))
|
||||||
|
|
||||||
|
class TestSwitchFrameChrome(MarionetteTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
MarionetteTestCase.setUp(self)
|
||||||
|
self.marionette.set_context("chrome")
|
||||||
|
self.win = self.marionette.get_window()
|
||||||
|
#need to get the file:// path for xul
|
||||||
|
unit = os.path.abspath(os.path.join(os.path.realpath(__file__), os.path.pardir))
|
||||||
|
tests = os.path.abspath(os.path.join(unit, os.path.pardir))
|
||||||
|
mpath = os.path.abspath(os.path.join(tests, os.path.pardir))
|
||||||
|
xul = "file://" + os.path.join(mpath, "www", "test.xul")
|
||||||
|
self.marionette.execute_script("window.open('" + xul +"', '_blank', 'chrome,centerscreen');")
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.marionette.execute_script("window.close();")
|
||||||
|
self.marionette.switch_to_window(self.win)
|
||||||
|
MarionetteTestCase.tearDown(self)
|
||||||
|
|
||||||
|
def test_switch_simple(self):
|
||||||
|
self.assertTrue("test.xul" in self.marionette.get_url())
|
||||||
|
self.marionette.switch_to_frame(0)
|
||||||
|
self.assertTrue("test2.xul" in self.marionette.get_url())
|
||||||
|
self.marionette.switch_to_frame()
|
||||||
|
self.assertTrue("test.xul" in self.marionette.get_url())
|
||||||
|
self.marionette.switch_to_frame("iframe")
|
||||||
|
self.assertTrue("test2.xul" in self.marionette.get_url())
|
||||||
|
self.marionette.switch_to_frame()
|
||||||
|
self.assertTrue("test.xul" in self.marionette.get_url())
|
||||||
|
self.marionette.switch_to_frame("iframename")
|
||||||
|
self.assertTrue("test2.xul" in self.marionette.get_url())
|
||||||
|
self.marionette.switch_to_frame()
|
||||||
|
self.assertTrue("test.xul" in self.marionette.get_url())
|
||||||
|
|
||||||
|
#I can't seem to access a xul iframe within a xul iframe
|
||||||
|
def test_switch_nested(self):
|
||||||
|
pass
|
||||||
|
|
|
@ -12,4 +12,6 @@
|
||||||
<textbox id="textInput3" class="asdf" size="6" value="test" label="input" />
|
<textbox id="textInput3" class="asdf" size="6" value="test" label="input" />
|
||||||
</vbox>
|
</vbox>
|
||||||
|
|
||||||
|
<iframe id="iframe" name="iframename" src="test2.xul"/>
|
||||||
|
<iframe id="iframe" name="iframename" src="test_nested_iframe.xul"/>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE window [
|
||||||
|
]>
|
||||||
|
|
||||||
|
<dialog id="dia"
|
||||||
|
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||||
|
|
||||||
|
<vbox id="things">
|
||||||
|
<checkbox id="testBox" label="box" />
|
||||||
|
<textbox id="textInput" size="6" value="test" label="input" />
|
||||||
|
<textbox id="textInput2" size="6" value="test" label="input" />
|
||||||
|
<textbox id="textInput3" class="asdf" size="6" value="test" label="input" />
|
||||||
|
</vbox>
|
||||||
|
|
||||||
|
</dialog>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Inner Iframe</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<iframe src="test.html" id="inner_frame"></iframe>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Marionette IFrame Test</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<iframe src="test_inner_iframe.html" id="test_iframe"></iframe>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE window [
|
||||||
|
]>
|
||||||
|
|
||||||
|
<iframe id="iframe" name="iframename" src="test2.xul"/>
|
||||||
|
</dialog>
|
|
@ -119,6 +119,8 @@ function MarionetteDriverActor(aConnection)
|
||||||
this.timer = null;
|
this.timer = null;
|
||||||
this.marionetteLog = new MarionetteLogObj();
|
this.marionetteLog = new MarionetteLogObj();
|
||||||
this.command_id = null;
|
this.command_id = null;
|
||||||
|
this.mainFrame = null; //topmost chrome frame
|
||||||
|
this.curFrame = null; //subframe that currently has focus
|
||||||
|
|
||||||
//register all message listeners
|
//register all message listeners
|
||||||
this.messageManager.addMessageListener("Marionette:ok", this);
|
this.messageManager.addMessageListener("Marionette:ok", this);
|
||||||
|
@ -219,10 +221,15 @@ MarionetteDriverActor.prototype = {
|
||||||
*/
|
*/
|
||||||
getCurrentWindow: function MDA_getCurrentWindow() {
|
getCurrentWindow: function MDA_getCurrentWindow() {
|
||||||
let type = null;
|
let type = null;
|
||||||
if (appName != "B2G" && this.context == "content") {
|
if (this.curFrame == null) {
|
||||||
type = 'navigator:browser';
|
if (appName != "B2G" && this.context == "content") {
|
||||||
|
type = 'navigator:browser';
|
||||||
|
}
|
||||||
|
return this.windowMediator.getMostRecentWindow(type);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return this.curFrame;
|
||||||
}
|
}
|
||||||
return this.windowMediator.getMostRecentWindow(type);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -275,6 +282,8 @@ MarionetteDriverActor.prototype = {
|
||||||
* True if this is the first time we're talking to this browser
|
* True if this is the first time we're talking to this browser
|
||||||
*/
|
*/
|
||||||
startBrowser: function MDA_startBrowser(win, newSession) {
|
startBrowser: function MDA_startBrowser(win, newSession) {
|
||||||
|
this.mainFrame = win;
|
||||||
|
this.curFrame = null;
|
||||||
this.addBrowser(win);
|
this.addBrowser(win);
|
||||||
this.curBrowser.newSession = newSession;
|
this.curBrowser.newSession = newSession;
|
||||||
this.curBrowser.startSession(newSession);
|
this.curBrowser.startSession(newSession);
|
||||||
|
@ -711,7 +720,7 @@ MarionetteDriverActor.prototype = {
|
||||||
* Searches based on name, then id.
|
* Searches based on name, then id.
|
||||||
*
|
*
|
||||||
* @param object aRequest
|
* @param object aRequest
|
||||||
* 'value' member holds the id of the window to switch to
|
* 'value' member holds the name or id of the window to switch to
|
||||||
*/
|
*/
|
||||||
switchToWindow: function MDA_switchToWindow(aRequest) {
|
switchToWindow: function MDA_switchToWindow(aRequest) {
|
||||||
let winEn = this.getWinEnumerator();
|
let winEn = this.getWinEnumerator();
|
||||||
|
@ -738,10 +747,73 @@ MarionetteDriverActor.prototype = {
|
||||||
* Switch to a given frame within the current window
|
* Switch to a given frame within the current window
|
||||||
*
|
*
|
||||||
* @param object aRequest
|
* @param object aRequest
|
||||||
* 'value' holds the id of the frame to switch to
|
* 'element' is the element to switch to
|
||||||
|
* 'value' if element is not set, then this
|
||||||
|
* holds either the id, name or index
|
||||||
|
* of the frame to switch to
|
||||||
*/
|
*/
|
||||||
switchToFrame: function MDA_switchToFrame(aRequest) {
|
switchToFrame: function MDA_switchToFrame(aRequest) {
|
||||||
this.sendAsync("switchToFrame", aRequest);
|
let curWindow = this.getCurrentWindow();
|
||||||
|
if (this.context == "chrome") {
|
||||||
|
let foundFrame = null;
|
||||||
|
if ((aRequest.value == null) && (aRequest.element == null)) {
|
||||||
|
this.curFrame = null;
|
||||||
|
this.mainFrame.focus();
|
||||||
|
this.sendOk();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (aRequest.element != undefined) {
|
||||||
|
if (this.curBrowser.elementManager.seenItems[aRequest.element] != undefined) {
|
||||||
|
let wantedFrame = this.curBrowser.elementManager.getKnownElement(aRequest.element, curWindow); //HTMLIFrameElement
|
||||||
|
let numFrames = curWindow.frames.length;
|
||||||
|
for (let i = 0; i < numFrames; i++) {
|
||||||
|
if (curWindow.frames[i].frameElement == wantedFrame) {
|
||||||
|
curWindow = curWindow.frames[i];
|
||||||
|
this.curFrame = curWindow;
|
||||||
|
this.curFrame.focus();
|
||||||
|
this.sendOk();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch(typeof(aRequest.value)) {
|
||||||
|
case "string" :
|
||||||
|
let foundById = null;
|
||||||
|
let numFrames = curWindow.frames.length;
|
||||||
|
for (let i = 0; i < numFrames; i++) {
|
||||||
|
//give precedence to name
|
||||||
|
let frame = curWindow.frames[i];
|
||||||
|
let frameElement = frame.frameElement;
|
||||||
|
if (frame.name == aRequest.value) {
|
||||||
|
foundFrame = i;
|
||||||
|
break;
|
||||||
|
} else if ((foundById == null) && (frameElement.id == aRequest.value)) {
|
||||||
|
foundById = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((foundFrame == null) && (foundById != null)) {
|
||||||
|
foundFrame = foundById;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "number":
|
||||||
|
if (curWindow.frames[aRequest.value] != undefined) {
|
||||||
|
foundFrame = aRequest.value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (foundFrame != null) {
|
||||||
|
curWindow = curWindow.frames[foundFrame];
|
||||||
|
this.curFrame = curWindow;
|
||||||
|
this.curFrame.focus();
|
||||||
|
this.sendOk();
|
||||||
|
} else {
|
||||||
|
this.sendError("Unable to locate frame: " + aRequest.value, 8, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.sendAsync("switchToFrame", aRequest);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1106,11 +1178,6 @@ MarionetteDriverActor.prototype = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return reg;
|
return reg;
|
||||||
case "Marionette:goUrl":
|
|
||||||
// if content determines that the goUrl call is directed at a top level window (not an iframe)
|
|
||||||
// it calls back into chrome to load the uri.
|
|
||||||
this.curBrowser.loadURI(message.json.value, this);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
@ -1243,25 +1310,6 @@ BrowserObj.prototype = {
|
||||||
this.tab = this.browser.addTab(uri, true);
|
this.tab = this.browser.addTab(uri, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Load a uri in the current tab
|
|
||||||
*
|
|
||||||
* @param string uri
|
|
||||||
* URI to load
|
|
||||||
* @param EventListener listener
|
|
||||||
* event listener fired on load
|
|
||||||
*/
|
|
||||||
loadURI: function BO_openURI(uri, listener) {
|
|
||||||
if (appName != "B2G") {
|
|
||||||
this.browser.addEventListener("DOMContentLoaded", listener, false);
|
|
||||||
this.browser.loadURI(uri);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.messageManager.addMessageListener("DOMContentLoaded", listener, true);
|
|
||||||
this.browser.selectedBrowser.loadURI(uri);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads content listeners if we don't already have them
|
* Loads content listeners if we don't already have them
|
||||||
*
|
*
|
||||||
|
|
|
@ -26,7 +26,7 @@ let marionetteTimeout = null;
|
||||||
let winUtil = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowUtils);
|
let winUtil = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||||
let listenerId = null; //unique ID of this listener
|
let listenerId = null; //unique ID of this listener
|
||||||
let activeFrame = null;
|
let activeFrame = null;
|
||||||
let win = content;
|
let curWindow = content;
|
||||||
let elementManager = new ElementManager([]);
|
let elementManager = new ElementManager([]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -179,6 +179,7 @@ function sendError(message, status, trace, command_id) {
|
||||||
*/
|
*/
|
||||||
function resetValues() {
|
function resetValues() {
|
||||||
marionetteTimeout = null;
|
marionetteTimeout = null;
|
||||||
|
curWin = content;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -227,9 +228,9 @@ function createExecuteContentSandbox(aWindow, marionette, args) {
|
||||||
*/
|
*/
|
||||||
function executeScript(msg, directInject) {
|
function executeScript(msg, directInject) {
|
||||||
let script = msg.json.value;
|
let script = msg.json.value;
|
||||||
let marionette = new Marionette(false, win, "content", marionetteLogObj);
|
let marionette = new Marionette(false, curWindow, "content", marionetteLogObj);
|
||||||
|
|
||||||
let sandbox = createExecuteContentSandbox(win, marionette, msg.json.args);
|
let sandbox = createExecuteContentSandbox(curWindow, marionette, msg.json.args);
|
||||||
if (!sandbox)
|
if (!sandbox)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -299,7 +300,7 @@ function executeJSScript(msg) {
|
||||||
* method is called, or if it times out.
|
* method is called, or if it times out.
|
||||||
*/
|
*/
|
||||||
function executeWithCallback(msg, timeout) {
|
function executeWithCallback(msg, timeout) {
|
||||||
win.addEventListener("unload", errUnload, false);
|
curWindow.addEventListener("unload", errUnload, false);
|
||||||
let script = msg.json.value;
|
let script = msg.json.value;
|
||||||
let command_id = msg.json.id;
|
let command_id = msg.json.id;
|
||||||
|
|
||||||
|
@ -308,21 +309,21 @@ function executeWithCallback(msg, timeout) {
|
||||||
// However Selenium code returns 28, see
|
// However Selenium code returns 28, see
|
||||||
// http://code.google.com/p/selenium/source/browse/trunk/javascript/firefox-driver/js/evaluate.js.
|
// http://code.google.com/p/selenium/source/browse/trunk/javascript/firefox-driver/js/evaluate.js.
|
||||||
// We'll stay compatible with the Selenium code.
|
// We'll stay compatible with the Selenium code.
|
||||||
let timeoutId = win.setTimeout(function() {
|
let timeoutId = curWindow.setTimeout(function() {
|
||||||
contentAsyncReturnFunc('timed out', 28);
|
contentAsyncReturnFunc('timed out', 28);
|
||||||
}, marionetteTimeout);
|
}, marionetteTimeout);
|
||||||
win.addEventListener('error', function win__onerror(evt) {
|
curWindow.addEventListener('error', function win__onerror(evt) {
|
||||||
win.removeEventListener('error', win__onerror, true);
|
curWindow.removeEventListener('error', win__onerror, true);
|
||||||
contentAsyncReturnFunc(evt, 17);
|
contentAsyncReturnFunc(evt, 17);
|
||||||
return true;
|
return true;
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
function contentAsyncReturnFunc(value, status) {
|
function contentAsyncReturnFunc(value, status) {
|
||||||
win.removeEventListener("unload", errUnload, false);
|
curWindow.removeEventListener("unload", errUnload, false);
|
||||||
|
|
||||||
/* clear all timeouts potentially generated by the script*/
|
/* clear all timeouts potentially generated by the script*/
|
||||||
for(let i=0; i<=timeoutId; i++) {
|
for(let i=0; i<=timeoutId; i++) {
|
||||||
win.clearTimeout(i);
|
curWindow.clearTimeout(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendSyncMessage("Marionette:testLog", {value: elementManager.wrapValue(marionetteLogObj.getLogs())});
|
sendSyncMessage("Marionette:testLog", {value: elementManager.wrapValue(marionetteLogObj.getLogs())});
|
||||||
|
@ -349,9 +350,9 @@ function executeWithCallback(msg, timeout) {
|
||||||
"__marionetteFunc.apply(null, __marionetteParams); ";
|
"__marionetteFunc.apply(null, __marionetteParams); ";
|
||||||
}
|
}
|
||||||
|
|
||||||
let marionette = new Marionette(true, win, "content", marionetteLogObj);
|
let marionette = new Marionette(true, curWindow, "content", marionetteLogObj);
|
||||||
|
|
||||||
let sandbox = createExecuteContentSandbox(win, marionette, msg.json.args);
|
let sandbox = createExecuteContentSandbox(curWindow, marionette, msg.json.args);
|
||||||
if (!sandbox)
|
if (!sandbox)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -387,37 +388,32 @@ function setSearchTimeout(msg) {
|
||||||
* All other navigation is handled by the server (in chrome space).
|
* All other navigation is handled by the server (in chrome space).
|
||||||
*/
|
*/
|
||||||
function goUrl(msg) {
|
function goUrl(msg) {
|
||||||
if (activeFrame != null) {
|
curWindow.location = msg.json.value;
|
||||||
win.document.location = msg.json.value;
|
//TODO: replace this with DOMContentLoaded event listening when Bug 720714 is resolved
|
||||||
//TODO: replace this with event firing when Bug 720714 is resolved
|
let checkTimer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
|
||||||
let checkTimer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
|
let checkLoad = function () {
|
||||||
let checkLoad = function () {
|
if (curWindow.document.readyState == "complete") {
|
||||||
if (win.document.readyState == "complete") {
|
sendOk();
|
||||||
sendOk();
|
}
|
||||||
}
|
else {
|
||||||
else {
|
checkTimer.initWithCallback(checkLoad, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
||||||
checkTimer.initWithCallback(checkLoad, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
}
|
||||||
}
|
};
|
||||||
};
|
checkTimer.initWithCallback(checkLoad, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
||||||
checkLoad();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sendAsyncMessage("Marionette:goUrl", {value: msg.json.value});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current URI
|
* Get the current URI
|
||||||
*/
|
*/
|
||||||
function getUrl(msg) {
|
function getUrl(msg) {
|
||||||
sendResponse({value: win.location.href});
|
sendResponse({value: curWindow.location.href});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Go back in history
|
* Go back in history
|
||||||
*/
|
*/
|
||||||
function goBack(msg) {
|
function goBack(msg) {
|
||||||
win.history.back();
|
curWindow.history.back();
|
||||||
sendOk();
|
sendOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,7 +421,7 @@ function goBack(msg) {
|
||||||
* Go forward in history
|
* Go forward in history
|
||||||
*/
|
*/
|
||||||
function goForward(msg) {
|
function goForward(msg) {
|
||||||
win.history.forward();
|
curWindow.history.forward();
|
||||||
sendOk();
|
sendOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,7 +429,7 @@ function goForward(msg) {
|
||||||
* Refresh the page
|
* Refresh the page
|
||||||
*/
|
*/
|
||||||
function refresh(msg) {
|
function refresh(msg) {
|
||||||
win.location.reload(true);
|
curWindow.location.reload(true);
|
||||||
let listen = function() { removeEventListener("DOMContentLoaded", arguments.callee, false); sendOk() } ;
|
let listen = function() { removeEventListener("DOMContentLoaded", arguments.callee, false); sendOk() } ;
|
||||||
addEventListener("DOMContentLoaded", listen, false);
|
addEventListener("DOMContentLoaded", listen, false);
|
||||||
}
|
}
|
||||||
|
@ -445,8 +441,7 @@ function findElementContent(msg) {
|
||||||
let id;
|
let id;
|
||||||
try {
|
try {
|
||||||
let notify = function(id) { sendResponse({value:id});};
|
let notify = function(id) { sendResponse({value:id});};
|
||||||
let curWin = activeFrame ? win.frames[activeFrame] : win;
|
id = elementManager.find(curWindow, msg.json, notify, false);
|
||||||
id = elementManager.find(curWin, msg.json, notify, false);
|
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.num, e.stack);
|
sendError(e.message, e.num, e.stack);
|
||||||
|
@ -460,8 +455,7 @@ function findElementsContent(msg) {
|
||||||
let id;
|
let id;
|
||||||
try {
|
try {
|
||||||
let notify = function(id) { sendResponse({value:id});};
|
let notify = function(id) { sendResponse({value:id});};
|
||||||
let curWin = activeFrame ? win.frames[activeFrame] : win;
|
id = elementManager.find(curWindow, msg.json, notify, true);
|
||||||
id = elementManager.find(curWin, msg.json, notify, true);
|
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
sendError(e.message, e.num, e.stack);
|
sendError(e.message, e.num, e.stack);
|
||||||
|
@ -474,8 +468,7 @@ function findElementsContent(msg) {
|
||||||
function clickElement(msg) {
|
function clickElement(msg) {
|
||||||
let el;
|
let el;
|
||||||
try {
|
try {
|
||||||
//el = elementManager.click(msg.json.element, win);
|
el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
el = elementManager.getKnownElement(msg.json.element, win);
|
|
||||||
utils.click(el);
|
utils.click(el);
|
||||||
sendOk();
|
sendOk();
|
||||||
}
|
}
|
||||||
|
@ -489,7 +482,7 @@ function clickElement(msg) {
|
||||||
*/
|
*/
|
||||||
function getElementAttribute(msg) {
|
function getElementAttribute(msg) {
|
||||||
try {
|
try {
|
||||||
let el = elementManager.getKnownElement(msg.json.element, win);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
sendResponse({value: utils.getElementAttribute(el, msg.json.name)});
|
sendResponse({value: utils.getElementAttribute(el, msg.json.name)});
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
|
@ -502,7 +495,7 @@ function getElementAttribute(msg) {
|
||||||
*/
|
*/
|
||||||
function getElementText(msg) {
|
function getElementText(msg) {
|
||||||
try {
|
try {
|
||||||
let el = elementManager.getKnownElement(msg.json.element, win);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
sendResponse({value: utils.getElementText(el)});
|
sendResponse({value: utils.getElementText(el)});
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
|
@ -515,7 +508,7 @@ function getElementText(msg) {
|
||||||
*/
|
*/
|
||||||
function isElementDisplayed(msg) {
|
function isElementDisplayed(msg) {
|
||||||
try {
|
try {
|
||||||
let el = elementManager.getKnownElement(msg.json.element, win);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
sendResponse({value: utils.isElementDisplayed(el)});
|
sendResponse({value: utils.isElementDisplayed(el)});
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
|
@ -528,7 +521,7 @@ function isElementDisplayed(msg) {
|
||||||
*/
|
*/
|
||||||
function isElementEnabled(msg) {
|
function isElementEnabled(msg) {
|
||||||
try {
|
try {
|
||||||
let el = elementManager.getKnownElement(msg.json.element, win);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
sendResponse({value: utils.isElementEnabled(el)});
|
sendResponse({value: utils.isElementEnabled(el)});
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
|
@ -541,7 +534,7 @@ function isElementEnabled(msg) {
|
||||||
*/
|
*/
|
||||||
function isElementSelected(msg) {
|
function isElementSelected(msg) {
|
||||||
try {
|
try {
|
||||||
let el = elementManager.getKnownElement(msg.json.element, win);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
sendResponse({value: utils.isElementSelected(el)});
|
sendResponse({value: utils.isElementSelected(el)});
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
|
@ -554,7 +547,7 @@ function isElementSelected(msg) {
|
||||||
*/
|
*/
|
||||||
function sendKeysToElement(msg) {
|
function sendKeysToElement(msg) {
|
||||||
try {
|
try {
|
||||||
let el = elementManager.getKnownElement(msg.json.element, win);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
utils.sendKeysToElement(el, msg.json.value);
|
utils.sendKeysToElement(el, msg.json.value);
|
||||||
sendOk();
|
sendOk();
|
||||||
}
|
}
|
||||||
|
@ -568,7 +561,7 @@ function sendKeysToElement(msg) {
|
||||||
*/
|
*/
|
||||||
function clearElement(msg) {
|
function clearElement(msg) {
|
||||||
try {
|
try {
|
||||||
let el = elementManager.getKnownElement(msg.json.element, win);
|
let el = elementManager.getKnownElement(msg.json.element, curWindow);
|
||||||
utils.clearElement(el);
|
utils.clearElement(el);
|
||||||
sendOk();
|
sendOk();
|
||||||
}
|
}
|
||||||
|
@ -584,21 +577,19 @@ function clearElement(msg) {
|
||||||
function switchToFrame(msg) {
|
function switchToFrame(msg) {
|
||||||
let foundFrame = null;
|
let foundFrame = null;
|
||||||
if ((msg.json.value == null) && (msg.json.element == null)) {
|
if ((msg.json.value == null) && (msg.json.element == null)) {
|
||||||
win = content;
|
curWindow = content;
|
||||||
activeFrame = null;
|
curWindow.focus();
|
||||||
content.focus();
|
|
||||||
sendOk();
|
sendOk();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (msg.json.element != undefined) {
|
if (msg.json.element != undefined) {
|
||||||
if (elementManager.seenItems[msg.json.element] != undefined) {
|
if (elementManager.seenItems[msg.json.element] != undefined) {
|
||||||
let wantedFrame = elementManager.getKnownElement(msg.json.element, win);//HTMLIFrameElement
|
let wantedFrame = elementManager.getKnownElement(msg.json.element, curWindow); //HTMLIFrameElement
|
||||||
let numFrames = win.frames.length;
|
let numFrames = curWindow.frames.length;
|
||||||
for (let i = 0; i < numFrames; i++) {
|
for (let i = 0; i < numFrames; i++) {
|
||||||
if (win.frames[i].frameElement == wantedFrame) {
|
if (curWindow.frames[i].frameElement == wantedFrame) {
|
||||||
win = win.frames[i];
|
curWindow = curWindow.frames[i];
|
||||||
activeFrame = i;
|
curWindow.focus();
|
||||||
win.focus();
|
|
||||||
sendOk();
|
sendOk();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -608,10 +599,10 @@ function switchToFrame(msg) {
|
||||||
switch(typeof(msg.json.value)) {
|
switch(typeof(msg.json.value)) {
|
||||||
case "string" :
|
case "string" :
|
||||||
let foundById = null;
|
let foundById = null;
|
||||||
let numFrames = win.frames.length;
|
let numFrames = curWindow.frames.length;
|
||||||
for (let i = 0; i < numFrames; i++) {
|
for (let i = 0; i < numFrames; i++) {
|
||||||
//give precedence to name
|
//give precedence to name
|
||||||
let frame = win.frames[i];
|
let frame = curWindow.frames[i];
|
||||||
let frameElement = frame.frameElement;
|
let frameElement = frame.frameElement;
|
||||||
if (frameElement.name == msg.json.value) {
|
if (frameElement.name == msg.json.value) {
|
||||||
foundFrame = i;
|
foundFrame = i;
|
||||||
|
@ -625,17 +616,14 @@ function switchToFrame(msg) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "number":
|
case "number":
|
||||||
if (win.frames[msg.json.value] != undefined) {
|
if (curWindow.frames[msg.json.value] != undefined) {
|
||||||
foundFrame = msg.json.value;
|
foundFrame = msg.json.value;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//TODO: implement index
|
|
||||||
if (foundFrame != null) {
|
if (foundFrame != null) {
|
||||||
let frameWindow = win.frames[foundFrame];
|
curWindow = curWindow.frames[foundFrame];
|
||||||
activeFrame = foundFrame;
|
curWindow.focus();
|
||||||
win = frameWindow;
|
|
||||||
win.focus();
|
|
||||||
sendOk();
|
sendOk();
|
||||||
} else {
|
} else {
|
||||||
sendError("Unable to locate frame: " + msg.json.value, 8, null);
|
sendError("Unable to locate frame: " + msg.json.value, 8, null);
|
||||||
|
|
|
@ -48,8 +48,8 @@ def main():
|
||||||
entity = get_value(jsonFilename, key)
|
entity = get_value(jsonFilename, key)
|
||||||
if passesRestrictions(options.talos_json_url, entity["url"]):
|
if passesRestrictions(options.talos_json_url, entity["url"]):
|
||||||
# the key is at the same time the filename e.g. talos.zip
|
# the key is at the same time the filename e.g. talos.zip
|
||||||
|
print "INFO: Downloading %s as %s" % (entity["url"], os.path.join(entity["path"], key))
|
||||||
download_file(entity["url"], entity["path"], key)
|
download_file(entity["url"], entity["path"], key)
|
||||||
print "INFO: %s -> %s" % (entity["url"], os.path.join(entity["path"], key))
|
|
||||||
else:
|
else:
|
||||||
print "ERROR: You have tried to download a file " + \
|
print "ERROR: You have tried to download a file " + \
|
||||||
"from: %s " % fileUrl + \
|
"from: %s " % fileUrl + \
|
||||||
|
|
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -87,11 +87,14 @@ const APPLY_TO_DIR_SUFFIX = "_applyToDir/";
|
||||||
const HELPER_BIN_FILE = "TestAUSHelper" + BIN_SUFFIX;
|
const HELPER_BIN_FILE = "TestAUSHelper" + BIN_SUFFIX;
|
||||||
const MAR_COMPLETE_FILE = "data/complete.mar";
|
const MAR_COMPLETE_FILE = "data/complete.mar";
|
||||||
const MAR_PARTIAL_FILE = "data/partial.mar";
|
const MAR_PARTIAL_FILE = "data/partial.mar";
|
||||||
|
const MAR_OLD_VERSION_FILE = "data/old_version_mar.mar";
|
||||||
|
const MAR_WRONG_CHANNEL_FILE = "data/wrong_product_channel_mar.mar";
|
||||||
const UPDATER_BIN_FILE = "updater" + BIN_SUFFIX;
|
const UPDATER_BIN_FILE = "updater" + BIN_SUFFIX;
|
||||||
const MAINTENANCE_SERVICE_BIN_FILE = "maintenanceservice.exe";
|
const MAINTENANCE_SERVICE_BIN_FILE = "maintenanceservice.exe";
|
||||||
const MAINTENANCE_SERVICE_INSTALLER_BIN_FILE = "maintenanceservice_installer.exe";
|
const MAINTENANCE_SERVICE_INSTALLER_BIN_FILE = "maintenanceservice_installer.exe";
|
||||||
const UPDATE_SETTINGS_INI_FILE = "update-settings.ini";
|
const UPDATE_SETTINGS_INI_FILE = "update-settings.ini";
|
||||||
const UPDATE_SETTINGS_CONTENTS = "[Settings]\nMAR_CHANNEL_ID=xpcshell-test\n"
|
const UPDATE_SETTINGS_CONTENTS = "[Settings]\n" +
|
||||||
|
"ACCEPTED_MAR_CHANNEL_IDS=xpcshell-test\n"
|
||||||
const UPDATES_DIR_SUFFIX = "_mar";
|
const UPDATES_DIR_SUFFIX = "_mar";
|
||||||
|
|
||||||
const LOG_COMPLETE_SUCCESS = "data/complete_log_success";
|
const LOG_COMPLETE_SUCCESS = "data/complete_log_success";
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is mozilla.org code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* the Mozilla Foundation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2012
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Brian R. Bondy <netzen@gmail.com> (Original Author)
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Test version downgrade MAR security check */
|
||||||
|
|
||||||
|
const TEST_ID = "0113";
|
||||||
|
|
||||||
|
// We don't actually care if the MAR has any data, we only care about the
|
||||||
|
// application return code and update.status result.
|
||||||
|
const TEST_FILES = [];
|
||||||
|
|
||||||
|
const VERSION_DOWNGRADE_ERROR = "23";
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
// Setup an old version MAR file
|
||||||
|
do_register_cleanup(cleanupUpdaterTest);
|
||||||
|
setupUpdaterTest(MAR_OLD_VERSION_FILE);
|
||||||
|
|
||||||
|
// Apply the MAR
|
||||||
|
let exitValue = runUpdate();
|
||||||
|
logTestInfo("testing updater binary process exitValue for failure when " +
|
||||||
|
"applying a version downgrade MAR");
|
||||||
|
// Make sure the updater executed successfully
|
||||||
|
do_check_eq(exitValue, 0);
|
||||||
|
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
|
||||||
|
|
||||||
|
//Make sure we get a version downgrade error
|
||||||
|
let updateStatus = readStatusFile(updatesDir);
|
||||||
|
do_check_eq(updateStatus.split(": ")[1], VERSION_DOWNGRADE_ERROR);
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is mozilla.org code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* the Mozilla Foundation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2012
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Brian R. Bondy <netzen@gmail.com> (Original Author)
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Test product/channel MAR security check */
|
||||||
|
|
||||||
|
const TEST_ID = "0114";
|
||||||
|
|
||||||
|
// We don't actually care if the MAR has any data, we only care about the
|
||||||
|
// application return code and update.status result.
|
||||||
|
const TEST_FILES = [];
|
||||||
|
|
||||||
|
const MAR_CHANNEL_MISMATCH_ERROR = "22";
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
// Setup a wrong channel MAR file
|
||||||
|
do_register_cleanup(cleanupUpdaterTest);
|
||||||
|
setupUpdaterTest(MAR_WRONG_CHANNEL_FILE);
|
||||||
|
|
||||||
|
// Apply the MAR
|
||||||
|
let exitValue = runUpdate();
|
||||||
|
logTestInfo("testing updater binary process exitValue for failure when " +
|
||||||
|
"applying a wrong product and channel MAR file");
|
||||||
|
// Make sure the updater executed successfully
|
||||||
|
do_check_eq(exitValue, 0);
|
||||||
|
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
|
||||||
|
|
||||||
|
//Make sure we get a version downgrade error
|
||||||
|
let updateStatus = readStatusFile(updatesDir);
|
||||||
|
do_check_eq(updateStatus.split(": ")[1], MAR_CHANNEL_MISMATCH_ERROR);
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
[test_0113_versionDowngradeCheck.js]
|
||||||
|
[test_0114_productChannelCheck.js]
|
||||||
[test_0150_appBinReplaced_xp_win_complete.js]
|
[test_0150_appBinReplaced_xp_win_complete.js]
|
||||||
[test_0151_appBinPatched_xp_win_partial.js]
|
[test_0151_appBinPatched_xp_win_partial.js]
|
||||||
[test_0160_appInUse_xp_win_complete.js]
|
[test_0160_appInUse_xp_win_complete.js]
|
||||||
|
|
|
@ -16,6 +16,7 @@ const allowedOrigins = [
|
||||||
"https://www.facebook.com",
|
"https://www.facebook.com",
|
||||||
"https://accounts.google.com",
|
"https://accounts.google.com",
|
||||||
"https://www.google.com",
|
"https://www.google.com",
|
||||||
|
"https://twitter.com",
|
||||||
"https://api.twitter.com",
|
"https://api.twitter.com",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -139,6 +139,10 @@
|
||||||
onset="this.setAttribute('timeout', val); return val;"
|
onset="this.setAttribute('timeout', val); return val;"
|
||||||
onget="return parseInt(this.getAttribute('timeout')) || 0;"/>
|
onget="return parseInt(this.getAttribute('timeout')) || 0;"/>
|
||||||
|
|
||||||
|
<property name="searchParam"
|
||||||
|
onget="return this.getAttribute('autocompletesearchparam') || '';"
|
||||||
|
onset="this.setAttribute('autocompletesearchparam', val); return val;"/>
|
||||||
|
|
||||||
<method name="onSearchBegin">
|
<method name="onSearchBegin">
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
this._fireEvent("searchbegin");
|
this._fireEvent("searchbegin");
|
||||||
|
@ -378,7 +382,7 @@
|
||||||
param: this,
|
param: this,
|
||||||
onStartLookup: function(aSearchString, aPreviousSearchResult, aListener) {
|
onStartLookup: function(aSearchString, aPreviousSearchResult, aListener) {
|
||||||
this.session.startSearch(aSearchString,
|
this.session.startSearch(aSearchString,
|
||||||
this.param.getAttribute("autocompletesearchparam") || "",
|
this.param.searchParam,
|
||||||
aPreviousSearchResult && aPreviousSearchResult.lastResult,
|
aPreviousSearchResult && aPreviousSearchResult.lastResult,
|
||||||
aListener);
|
aListener);
|
||||||
},
|
},
|
||||||
|
|
Загрузка…
Ссылка в новой задаче