зеркало из https://github.com/mozilla/gecko-dev.git
merge fx-team to mozilla-central
This commit is contained in:
Коммит
43960220d1
|
@ -52,11 +52,12 @@ function init(aEvent)
|
|||
#ifdef MOZ_UPDATER
|
||||
gAppUpdater = new appUpdater();
|
||||
|
||||
#if MOZ_UPDATE_CHANNEL != release
|
||||
let defaults = Services.prefs.getDefaultBranch("");
|
||||
let channelLabel = document.getElementById("currentChannel");
|
||||
let currentChannelText = document.getElementById("currentChannelText");
|
||||
channelLabel.value = defaults.getCharPref("app.update.channel");
|
||||
#endif
|
||||
if (channelLabel.value == "release")
|
||||
currentChannelText.hidden = true;
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
|
|
|
@ -108,12 +108,10 @@
|
|||
#endif
|
||||
</vbox>
|
||||
|
||||
#if MOZ_UPDATE_CHANNEL != release
|
||||
#ifdef MOZ_UPDATER
|
||||
<description class="text-blurb" id="currentChannelText">
|
||||
&channel.description.start;<label id="currentChannel"/>&channel.description.end;
|
||||
</description>
|
||||
#endif
|
||||
#endif
|
||||
<vbox id="experimental" hidden="true">
|
||||
<description class="text-blurb" id="warningDesc">
|
||||
|
|
|
@ -18,6 +18,8 @@ import org.mozilla.gecko.AndroidGamepadManager;
|
|||
import org.mozilla.gecko.DynamicToolbar.PinReason;
|
||||
import org.mozilla.gecko.DynamicToolbar.VisibilityTransition;
|
||||
import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.animation.PropertyAnimator;
|
||||
import org.mozilla.gecko.animation.ViewHelper;
|
||||
import org.mozilla.gecko.db.BrowserContract.Combined;
|
||||
|
@ -485,6 +487,8 @@ abstract public class BrowserApp extends GeckoApp
|
|||
if (Intent.ACTION_VIEW.equals(intent.getAction())) {
|
||||
// Show the target URL immediately in the toolbar.
|
||||
mBrowserToolbar.setTitle(intent.getDataString());
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT);
|
||||
}
|
||||
|
||||
((GeckoApp.MainLayout) mMainLayout).setTouchEventInterceptor(new HideTabsTouchListener());
|
||||
|
@ -643,6 +647,12 @@ abstract public class BrowserApp extends GeckoApp
|
|||
if (isHomePagerVisible()) {
|
||||
mHomePager.onToolbarFocusChange(hasFocus);
|
||||
}
|
||||
|
||||
if (hasFocus) {
|
||||
Telemetry.startUISession(TelemetryContract.Session.URLBAR_FOCUSED);
|
||||
} else {
|
||||
Telemetry.stopUISession(TelemetryContract.Session.URLBAR_FOCUSED);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -751,6 +761,7 @@ abstract public class BrowserApp extends GeckoApp
|
|||
String text = Clipboard.getText();
|
||||
if (!TextUtils.isEmpty(text)) {
|
||||
Tabs.getInstance().loadUrl(text);
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.CONTEXT_MENU);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -942,6 +953,9 @@ abstract public class BrowserApp extends GeckoApp
|
|||
|
||||
GeckoAppShell.openUriExternal(url, "text/plain", "", "",
|
||||
Intent.ACTION_SEND, tab.getDisplayTitle());
|
||||
|
||||
// Context: Sharing via chrome list (no explicit session is active)
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1613,6 +1627,8 @@ abstract public class BrowserApp extends GeckoApp
|
|||
// If the URL doesn't look like a search query, just load it.
|
||||
if (!StringUtils.isSearchQuery(url, true)) {
|
||||
Tabs.getInstance().loadUrl(url, Tabs.LOADURL_USER_ENTERED);
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1638,6 +1654,7 @@ abstract public class BrowserApp extends GeckoApp
|
|||
// using the default search engine.
|
||||
if (TextUtils.isEmpty(keywordUrl)) {
|
||||
Tabs.getInstance().loadUrl(url, Tabs.LOADURL_USER_ENTERED);
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1646,6 +1663,7 @@ abstract public class BrowserApp extends GeckoApp
|
|||
// Otherwise, construct a search query from the bookmark keyword.
|
||||
final String searchUrl = keywordUrl.replace("%s", URLEncoder.encode(keywordSearch));
|
||||
Tabs.getInstance().loadUrl(searchUrl, Tabs.LOADURL_USER_ENTERED);
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, "", "keyword");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -2538,9 +2556,11 @@ abstract public class BrowserApp extends GeckoApp
|
|||
return;
|
||||
}
|
||||
|
||||
// Dismiss editing mode if the user is loading a URL from an external app.
|
||||
if (Intent.ACTION_VIEW.equals(action)) {
|
||||
// Dismiss editing mode if the user is loading a URL from an external app.
|
||||
mBrowserToolbar.cancelEdit();
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -607,6 +607,9 @@ public abstract class GeckoApp
|
|||
} else if (event.equals("Share:Text")) {
|
||||
String text = message.getString("text");
|
||||
GeckoAppShell.openUriExternal(text, "text/plain", "", "", Intent.ACTION_SEND, "");
|
||||
|
||||
// Context: Sharing via chrome list (no explicit session is active)
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST);
|
||||
} else if (event.equals("Image:SetAs")) {
|
||||
String src = message.getString("url");
|
||||
setImageAs(src);
|
||||
|
|
|
@ -30,8 +30,22 @@ public interface TelemetryContract {
|
|||
// Set default panel.
|
||||
public static final String PANEL_SET_DEFAULT = "setdefault.1";
|
||||
|
||||
// Sharing content.
|
||||
public static final String SHARE = "share.1";
|
||||
|
||||
// Sanitizing private data.
|
||||
public static final String SANITIZE = "sanitize.1";
|
||||
|
||||
// Saving a resource (reader, bookmark, etc) for viewing later.
|
||||
// Note: Only used in JavaScript for now, but here for completeness.
|
||||
public static final String SAVE = "save.1";
|
||||
|
||||
// Stop holding a resource (reader, bookmark, etc) for viewing later.
|
||||
// Note: Only used in JavaScript for now, but here for completeness.
|
||||
public static final String UNSAVE = "unsave.1";
|
||||
|
||||
// Loading a URL.
|
||||
public static final String LOAD_URL = "loadurl.1";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -39,8 +53,29 @@ public interface TelemetryContract {
|
|||
* Telemetry.sendUIEvent() as the "method" parameter.
|
||||
*/
|
||||
public interface Method {
|
||||
// Action triggered from a list.
|
||||
public static final String LIST = "list";
|
||||
|
||||
// Action triggered from a button.
|
||||
public static final String BUTTON = "button";
|
||||
|
||||
// Action triggered from a dialog.
|
||||
public static final String DIALOG = "dialog";
|
||||
|
||||
// Action occurred via an intent.
|
||||
public static final String INTENT = "intent";
|
||||
|
||||
// Action occurred via a context menu.
|
||||
public static final String CONTEXT_MENU = "contextmenu";
|
||||
|
||||
// Action triggered from a view grid item, like a thumbnail.
|
||||
public static final String GRID_ITEM = "griditem";
|
||||
|
||||
// Action triggered from a view list item, like a row of a list.
|
||||
public static final String LIST_ITEM = "listitem";
|
||||
|
||||
// Action triggered from a suggestion provided to the user.
|
||||
public static final String SUGGESTION = "suggestion";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -54,6 +89,16 @@ public interface TelemetryContract {
|
|||
// Started when a user enters a given home panel.
|
||||
// Session name is dynamic, encoded as "homepanel.1:<panel_id>"
|
||||
public static final String HOME_PANEL = "homepanel.1:";
|
||||
|
||||
// Started when a Reader viewer becomes active in the foreground.
|
||||
// Note: Only used in JavaScript for now, but here for completeness.
|
||||
public static final String READER = "reader.1";
|
||||
|
||||
// URL bar focused.
|
||||
public static final String URLBAR_FOCUSED = "urlbar.1:";
|
||||
|
||||
// Awesomescreen frecency search is active.
|
||||
public static final String FRECENCY = "frecency.1:";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,6 +8,8 @@ package org.mozilla.gecko.home;
|
|||
import java.util.EnumSet;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.db.BrowserContract.Bookmarks;
|
||||
import org.mozilla.gecko.db.BrowserDB.URLColumns;
|
||||
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
|
||||
|
@ -91,6 +93,8 @@ public class BookmarksListView extends HomeListView
|
|||
// Otherwise, just open the URL
|
||||
final String url = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.URL));
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL);
|
||||
|
||||
// This item is a TwoLinePageRow, so we allow switch-to-tab.
|
||||
getOnUrlOpenListener().onUrlOpen(url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ import org.mozilla.gecko.PrefsHelper;
|
|||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.Tab;
|
||||
import org.mozilla.gecko.Tabs;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.db.BrowserDB.URLColumns;
|
||||
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
|
||||
import org.mozilla.gecko.home.SearchEngine;
|
||||
|
@ -220,6 +222,20 @@ public class BrowserSearch extends HomeFragment
|
|||
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
Telemetry.startUISession(TelemetryContract.Session.FRECENCY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
Telemetry.stopUISession(TelemetryContract.Session.FRECENCY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// All list views are styled to look the same with a global activity theme.
|
||||
|
@ -264,6 +280,11 @@ public class BrowserSearch extends HomeFragment
|
|||
final Cursor c = mAdapter.getCursor(position);
|
||||
final String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL));
|
||||
|
||||
// The "urlbar" and "frecency" sessions can be open at the same time. Use the LIST_ITEM
|
||||
// method to set this LOAD_URL event apart from the case where the user commits what's in
|
||||
// the url bar.
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.LIST_ITEM);
|
||||
|
||||
// This item is a TwoLinePageRow, so we allow switch-to-tab.
|
||||
mUrlOpenListener.onUrlOpen(url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ import org.mozilla.gecko.GeckoProfile;
|
|||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.ReaderModeUtils;
|
||||
import org.mozilla.gecko.Tabs;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.db.BrowserContract.Combined;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.favicons.Favicons;
|
||||
|
@ -132,6 +134,9 @@ abstract class HomeFragment extends Fragment {
|
|||
} else {
|
||||
GeckoAppShell.openUriExternal(info.url, SHARE_MIME_TYPE, "", "",
|
||||
Intent.ACTION_SEND, info.getDisplayTitle());
|
||||
|
||||
// Context: Sharing via chrome homepage contextmenu list (home session should be active)
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -157,6 +162,8 @@ abstract class HomeFragment extends Fragment {
|
|||
if (item.getItemId() == R.id.home_open_private_tab)
|
||||
flags |= Tabs.LOADURL_PRIVATE;
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.CONTEXT_MENU);
|
||||
|
||||
final String url = (info.isInReadingList() ? ReaderModeUtils.getAboutReaderForUrl(info.url) : info.url);
|
||||
|
||||
// Some pinned site items have "user-entered" urls. URLs entered in the PinSiteDialog are wrapped in
|
||||
|
|
|
@ -9,6 +9,8 @@ import org.mozilla.gecko.AboutPages;
|
|||
import org.mozilla.gecko.GeckoProfile;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.SessionParser;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.db.BrowserContract.Combined;
|
||||
import org.mozilla.gecko.home.HomePager.OnNewTabsListener;
|
||||
|
||||
|
@ -110,6 +112,8 @@ public class LastTabsPanel extends HomeFragment {
|
|||
return;
|
||||
}
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL);
|
||||
|
||||
final String url = c.getString(c.getColumnIndexOrThrow(Combined.URL));
|
||||
mNewTabsListener.onNewTabs(new String[] { url });
|
||||
}
|
||||
|
@ -206,6 +210,8 @@ public class LastTabsPanel extends HomeFragment {
|
|||
urls[c.getPosition()] = c.getString(c.getColumnIndexOrThrow(Combined.URL));
|
||||
} while (c.moveToNext());
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.BUTTON);
|
||||
|
||||
mNewTabsListener.onNewTabs(urls);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ import java.util.Date;
|
|||
import java.util.EnumSet;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.db.BrowserContract.Combined;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.db.BrowserDB.URLColumns;
|
||||
|
@ -98,6 +100,8 @@ public class MostRecentPanel extends HomeFragment {
|
|||
final Cursor c = mAdapter.getCursor(position);
|
||||
final String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL));
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL);
|
||||
|
||||
// This item is a TwoLinePageRow, so we allow switch-to-tab.
|
||||
mUrlOpenListener.onUrlOpen(url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ import java.util.EnumSet;
|
|||
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.ReaderModeUtils;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.db.BrowserContract.ReadingListItems;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.db.BrowserDB.URLColumns;
|
||||
|
@ -105,6 +107,8 @@ public class ReadingListPanel extends HomeFragment {
|
|||
String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL));
|
||||
url = ReaderModeUtils.getAboutReaderForUrl(url);
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL);
|
||||
|
||||
// This item is a TwoLinePageRow, so we allow switch-to-tab.
|
||||
mUrlOpenListener.onUrlOpen(url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
package org.mozilla.gecko.home;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.home.BrowserSearch.OnEditSuggestionListener;
|
||||
import org.mozilla.gecko.home.BrowserSearch.OnSearchListener;
|
||||
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
|
||||
|
@ -79,9 +81,16 @@ class SearchEngineRow extends AnimatedHeightLayout {
|
|||
// search for the term.
|
||||
if (v != mUserEnteredView && !StringUtils.isSearchQuery(suggestion, false)) {
|
||||
if (mUrlOpenListener != null) {
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.SUGGESTION, "url");
|
||||
|
||||
mUrlOpenListener.onUrlOpen(suggestion, EnumSet.noneOf(OnUrlOpenListener.Flags.class));
|
||||
}
|
||||
} else if (mSearchListener != null) {
|
||||
if (v == mUserEnteredView) {
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.SUGGESTION, "user");
|
||||
} else {
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.SUGGESTION, "engine");
|
||||
}
|
||||
mSearchListener.onSearch(mSearchEngine, suggestion);
|
||||
}
|
||||
}
|
||||
|
@ -135,6 +144,7 @@ class SearchEngineRow extends AnimatedHeightLayout {
|
|||
public void performUserEnteredSearch() {
|
||||
String searchTerm = getSuggestionTextFromView(mUserEnteredView);
|
||||
if (mSearchListener != null) {
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.SUGGESTION, "user");
|
||||
mSearchListener.onSearch(mSearchEngine, searchTerm);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ package org.mozilla.gecko.home;
|
|||
import java.util.EnumSet;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.ThumbnailHelper;
|
||||
import org.mozilla.gecko.db.BrowserDB.URLColumns;
|
||||
import org.mozilla.gecko.db.TopSitesCursorWrapper;
|
||||
|
@ -110,6 +112,8 @@ public class TopSitesGridView extends GridView {
|
|||
// If not, navigate to the page given by the url.
|
||||
if (!TextUtils.isEmpty(url)) {
|
||||
if (mUrlOpenListener != null) {
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.GRID_ITEM);
|
||||
|
||||
mUrlOpenListener.onUrlOpen(url, EnumSet.noneOf(OnUrlOpenListener.Flags.class));
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -181,6 +181,8 @@ public class TopSitesPanel extends HomeFragment {
|
|||
|
||||
final String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL));
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.LIST_ITEM);
|
||||
|
||||
// This item is a TwoLinePageRow, so we allow switch-to-tab.
|
||||
mUrlOpenListener.onUrlOpen(url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package org.mozilla.gecko.prompts;
|
||||
|
||||
import org.mozilla.gecko.menu.MenuItemActionView;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.gfx.BitmapUtils;
|
||||
import org.mozilla.gecko.menu.MenuItemActionView;
|
||||
import org.mozilla.gecko.widget.GeckoActionProvider;
|
||||
|
||||
import org.json.JSONArray;
|
||||
|
@ -197,6 +199,9 @@ public class PromptListAdapter extends ArrayAdapter<PromptListItem> {
|
|||
@Override
|
||||
public void onIntentSelected(final Intent intent, final int p) {
|
||||
provider.chooseActivity(p);
|
||||
|
||||
// Context: Sharing via content contextmenu list (no explicit session is active)
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,6 +19,8 @@ import java.util.List;
|
|||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.Tabs;
|
||||
import org.mozilla.gecko.TabsAccessor;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
|
||||
/**
|
||||
* The actual list of synced tabs. This serves as the only child view of {@link RemoteTabsContainer}
|
||||
|
@ -68,6 +70,8 @@ class RemoteTabsList extends ExpandableListView
|
|||
return true;
|
||||
}
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, "", "remote");
|
||||
|
||||
Tabs.getInstance().loadUrl(tab.get("url"), Tabs.LOADURL_NEW_TAB);
|
||||
autoHidePanel();
|
||||
return true;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
package org.mozilla.gecko.widget;
|
||||
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.menu.MenuItemActionView;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -194,6 +196,9 @@ public class GeckoActionProvider {
|
|||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
chooseActivity(item.getItemId());
|
||||
|
||||
// Context: Sharing via chrome mainmenu list (no explicit session is active)
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -201,6 +206,9 @@ public class GeckoActionProvider {
|
|||
public void onClick(View view) {
|
||||
Integer index = (Integer) view.getTag();
|
||||
chooseActivity(index);
|
||||
|
||||
// Context: Sharing via chrome mainmenu and content contextmenu quickshare (no explicit session is active)
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.BUTTON);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,9 @@ let Ci = Components.interfaces, Cc = Components.classes, Cu = Components.utils;
|
|||
Cu.import("resource://gre/modules/Services.jsm")
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "UITelemetry",
|
||||
"resource://gre/modules/UITelemetry.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(window, "gChromeWin", function ()
|
||||
window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
|
@ -286,12 +289,18 @@ AboutReader.prototype = {
|
|||
this._isReadingListItem = (this._isReadingListItem == 1) ? 0 : 1;
|
||||
this._updateToggleButton();
|
||||
|
||||
// Create a relative timestamp for telemetry
|
||||
let uptime = Date.now() - Services.startup.getStartupInfo().linkerInitialized;
|
||||
|
||||
if (this._isReadingListItem == 1) {
|
||||
gChromeWin.Reader.storeArticleInCache(this._article, function(success) {
|
||||
dump("Reader:Add (in reader) success=" + success);
|
||||
|
||||
let result = (success ? gChromeWin.Reader.READER_ADD_SUCCESS :
|
||||
gChromeWin.Reader.READER_ADD_FAILED);
|
||||
let result = gChromeWin.Reader.READER_ADD_FAILED;
|
||||
if (success) {
|
||||
result = gChromeWin.Reader.READER_ADD_SUCCESS;
|
||||
UITelemetry.addEvent("save.1", "button", uptime, "reader");
|
||||
}
|
||||
|
||||
let json = JSON.stringify({ fromAboutReader: true, url: this._article.url });
|
||||
Services.obs.notifyObservers(null, "Reader:Add", json);
|
||||
|
@ -310,6 +319,8 @@ AboutReader.prototype = {
|
|||
// browser.js), sending this message will cause the toggle button to be
|
||||
// updated (handled in this file).
|
||||
Services.obs.notifyObservers(null, "Reader:Remove", this._article.url);
|
||||
|
||||
UITelemetry.addEvent("unsave.1", "button", uptime, "reader");
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -322,6 +333,10 @@ AboutReader.prototype = {
|
|||
url: this._article.url,
|
||||
title: this._article.title
|
||||
});
|
||||
|
||||
// Create a relative timestamp for telemetry
|
||||
let uptime = Date.now() - Services.startup.getStartupInfo().linkerInitialized;
|
||||
UITelemetry.addEvent("share.1", "list", uptime);
|
||||
},
|
||||
|
||||
_setFontSize: function Reader_setFontSize(newFontSize) {
|
||||
|
|
|
@ -7483,15 +7483,22 @@ let Reader = {
|
|||
sendMessageToJava({
|
||||
type: "Reader:LongClick",
|
||||
});
|
||||
|
||||
// Create a relative timestamp for telemetry
|
||||
let uptime = Date.now() - Services.startup.getStartupInfo().linkerInitialized;
|
||||
UITelemetry.addEvent("save.1", "pageaction", uptime, "reader");
|
||||
},
|
||||
},
|
||||
|
||||
updatePageAction: function(tab) {
|
||||
if(this.pageAction.id) {
|
||||
if (this.pageAction.id) {
|
||||
NativeWindow.pageactions.remove(this.pageAction.id);
|
||||
delete this.pageAction.id;
|
||||
}
|
||||
|
||||
// Create a relative timestamp for telemetry
|
||||
let uptime = Date.now() - Services.startup.getStartupInfo().linkerInitialized;
|
||||
|
||||
if (tab.readerActive) {
|
||||
this.pageAction.id = NativeWindow.pageactions.add({
|
||||
title: Strings.browser.GetStringFromName("readerMode.exit"),
|
||||
|
@ -7499,7 +7506,17 @@ let Reader = {
|
|||
clickCallback: this.pageAction.readerModeCallback,
|
||||
important: true
|
||||
});
|
||||
} else if (tab.readerEnabled) {
|
||||
|
||||
// Only start a reader session if the viewer is in the foreground. We do
|
||||
// not track background reader viewers.
|
||||
UITelemetry.startSession("reader.1", uptime);
|
||||
return;
|
||||
}
|
||||
|
||||
// Only stop a reader session if the foreground viewer is not visible.
|
||||
UITelemetry.stopSession("reader.1", "", uptime);
|
||||
|
||||
if (tab.readerEnabled) {
|
||||
this.pageAction.id = NativeWindow.pageactions.add({
|
||||
title: Strings.browser.GetStringFromName("readerMode.enter"),
|
||||
icon: "drawable://reader",
|
||||
|
|
|
@ -39,3 +39,4 @@
|
|||
[include:js/xpconnect/tests/unit/xpcshell.ini]
|
||||
[include:js/jsd/test/xpcshell.ini]
|
||||
[include:security/manager/ssl/tests/unit/xpcshell.ini]
|
||||
[include:toolkit/devtools/qrcode/tests/unit/xpcshell.ini]
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
[include:dom/wappush/tests/xpcshell.ini]
|
||||
[include:toolkit/devtools/apps/tests/unit/xpcshell.ini]
|
||||
[include:toolkit/devtools/debugger/tests/unit/xpcshell.ini]
|
||||
[include:toolkit/devtools/qrcode/tests/unit/xpcshell.ini]
|
||||
[include:toolkit/devtools/sourcemap/tests/unit/xpcshell.ini]
|
||||
[include:toolkit/mozapps/downloads/tests/unit/xpcshell.ini]
|
||||
[include:toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini]
|
||||
|
|
|
@ -141,7 +141,6 @@ this.UITelemetry = {
|
|||
delete this._activeSessions[aName];
|
||||
|
||||
if (!sessionStart) {
|
||||
Services.console.logStringMessage("UITelemetry error: no session [" + aName + "] to stop!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -113,6 +113,7 @@
|
|||
<li><a href="about:license#pbkdf2-sha256">pbkdf2_sha256 License</a></li>
|
||||
<li><a href="about:license#praton">praton License</a></li>
|
||||
<li><a href="about:license#qcms">qcms License</a></li>
|
||||
<li><a href="about:license#qrcode-generator">QR Code Generator License</a></li>
|
||||
<li><a href="about:license#xdg">Red Hat xdg_user_dir_lookup License</a></li>
|
||||
<li><a href="about:license#hunspell-ru">Russian Spellchecking Dictionary License</a></li>
|
||||
<li><a href="about:license#sctp">SCTP Licenses</a></li>
|
||||
|
@ -3574,6 +3575,35 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
</pre>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a id="qrcode-generator"></a>QR Code Generator License</h1>
|
||||
|
||||
<p>This license applies to certain files in the directory
|
||||
<span class="path">toolkit/devtools/qrcode/encoder/</span>.</p>
|
||||
<pre>
|
||||
Copyright (c) 2009 Kazuhiko Arase
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
</pre>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a id="xdg"></a>Red Hat xdg_user_dir_lookup License</h1>
|
||||
|
|
|
@ -130,6 +130,8 @@ skip-if = os == "win" # Intermittent failures, bug 919016
|
|||
[test_preferences.xul]
|
||||
[test_preferences_beforeaccept.xul]
|
||||
support-files = window_preferences_beforeaccept.xul
|
||||
[test_preferences_onsyncfrompreference.xul]
|
||||
support-files = window_preferences_onsyncfrompreference.xul
|
||||
[test_progressmeter.xul]
|
||||
[test_props.xul]
|
||||
[test_radio.xul]
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
||||
<!-- 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/. -->
|
||||
<window title="Preferences Window beforeaccept Tests"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
const PREFS = ['tests.onsyncfrompreference.pref1',
|
||||
'tests.onsyncfrompreference.pref2',
|
||||
'tests.onsyncfrompreference.pref3'];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
for (let pref of PREFS) {
|
||||
SpecialPowers.setIntPref(pref, 1);
|
||||
}
|
||||
|
||||
let counter = 0;
|
||||
let prefWindow = openDialog("window_preferences_onsyncfrompreference.xul", "", "", onSync);
|
||||
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
for (let pref of PREFS) {
|
||||
SpecialPowers.clearUserPref(pref);
|
||||
}
|
||||
prefWindow.close();
|
||||
});
|
||||
|
||||
// Onsyncfrompreference handler for the prefs
|
||||
function onSync() {
|
||||
for (let pref of PREFS) {
|
||||
// The `value` field of each <preference> element should be initialized by now.
|
||||
|
||||
is(SpecialPowers.getIntPref(pref), prefWindow.document.getElementById(pref).value,
|
||||
"Pref constructor was called correctly")
|
||||
}
|
||||
|
||||
counter++;
|
||||
|
||||
if (counter == PREFS.length) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
|
||||
</window>
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<!-- 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/. -->
|
||||
<!--
|
||||
XUL Widget Test for preferences window with onsyncfrompreference
|
||||
This test ensures that onsyncfrompreference handlers are called after all the
|
||||
values of the corresponding preference element have been set correctly
|
||||
-->
|
||||
<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="preferences window"
|
||||
width="300" height="300"
|
||||
windowtype="test:preferences">
|
||||
|
||||
<prefpane id="sample_pane" label="Sample Prefpane">
|
||||
<preferences id="sample_preferences">
|
||||
<preference id="tests.onsyncfrompreference.pref1"
|
||||
name="tests.onsyncfrompreference.pref1"
|
||||
type="int"/>
|
||||
<preference id="tests.onsyncfrompreference.pref2"
|
||||
name="tests.onsyncfrompreference.pref2"
|
||||
type="int"/>
|
||||
<preference id="tests.onsyncfrompreference.pref3"
|
||||
name="tests.onsyncfrompreference.pref3"
|
||||
type="int"/>
|
||||
</preferences>
|
||||
</prefpane>
|
||||
<label>Test Prefpane</label>
|
||||
<checkbox id="check1" label="Label1"
|
||||
preference="tests.onsyncfrompreference.pref1"
|
||||
onsyncfrompreference="return window.arguments[0]();"
|
||||
onsynctopreference="return 1;"/>
|
||||
<checkbox id="check2" label="Label2"
|
||||
preference="tests.onsyncfrompreference.pref2"
|
||||
onsyncfrompreference="return window.arguments[0]();"
|
||||
onsynctopreference="return 1;"/>
|
||||
<checkbox id="check3" label="Label3"
|
||||
preference="tests.onsyncfrompreference.pref3"
|
||||
onsyncfrompreference="return window.arguments[0]();"
|
||||
onsynctopreference="return 1;"/>
|
||||
</prefwindow>
|
|
@ -30,6 +30,25 @@
|
|||
|
||||
<binding id="preferences">
|
||||
<implementation implements="nsIObserver">
|
||||
<method name="_constructAfterChildren">
|
||||
<body>
|
||||
<![CDATA[
|
||||
// This method will be called after each one of the child
|
||||
// <preference> elements is constructed. Its purpose is to propagate
|
||||
// the values to the associated form elements
|
||||
|
||||
var elements = this.getElementsByTagName("preference");
|
||||
for (let element of elements) {
|
||||
if (!element._constructed) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (let element of elements) {
|
||||
element.updateElements();
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
<method name="observe">
|
||||
<parameter name="aSubject"/>
|
||||
<parameter name="aTopic"/>
|
||||
|
@ -101,6 +120,8 @@
|
|||
<implementation>
|
||||
<constructor>
|
||||
<![CDATA[
|
||||
this._constructed = true;
|
||||
|
||||
// if the element has been inserted without the name attribute set,
|
||||
// we have nothing to do here
|
||||
if (!this.name)
|
||||
|
@ -126,18 +147,20 @@
|
|||
preference = parentPrefs[l];
|
||||
}
|
||||
}
|
||||
this._setValue(preference ? preference.value
|
||||
: this.valueFromPreferences, false);
|
||||
|
||||
// Don't use the value setter here, we don't want updateElements to be prematurely fired.
|
||||
this._value = preference ? preference.value : this.valueFromPreferences;
|
||||
}
|
||||
else
|
||||
this._setValue(this.valueFromPreferences, false);
|
||||
this._value = this.valueFromPreferences;
|
||||
this.preferences._constructAfterChildren();
|
||||
]]>
|
||||
</constructor>
|
||||
<destructor>
|
||||
this.preferences.rootBranchInternal
|
||||
.removeObserver(this.name, this.preferences);
|
||||
</destructor>
|
||||
|
||||
<field name="_constructed">false</field>
|
||||
<property name="instantApply">
|
||||
<getter>
|
||||
return this.getAttribute("instantApply") == "true" || this.preferences.instantApply;
|
||||
|
@ -169,24 +192,19 @@
|
|||
<field name="_value">null</field>
|
||||
<method name="_setValue">
|
||||
<parameter name="aValue"/>
|
||||
<parameter name="aUpdate"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
if (aUpdate && this.value !== aValue) {
|
||||
if (this.value !== aValue) {
|
||||
this._value = aValue;
|
||||
if (this.instantApply)
|
||||
this.valueFromPreferences = aValue;
|
||||
this.preferences.fireChangedEvent(this);
|
||||
}
|
||||
else if (!aUpdate) {
|
||||
this._value = aValue;
|
||||
this.updateElements();
|
||||
}
|
||||
return aValue;
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
<property name="value" onget="return this._value" onset="return this._setValue(val, true);"/>
|
||||
<property name="value" onget="return this._value" onset="return this._setValue(val);"/>
|
||||
|
||||
<property name="locked">
|
||||
<getter>
|
||||
|
|
|
@ -13,7 +13,8 @@ PARALLEL_DIRS += [
|
|||
'apps',
|
||||
'styleinspector',
|
||||
'acorn',
|
||||
'pretty-fast'
|
||||
'pretty-fast',
|
||||
'qrcode'
|
||||
]
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += ['tests/mochitest/chrome.ini']
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2009 Kazuhiko Arase
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,11 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
JS_MODULES_PATH = 'modules/devtools/qrcode/encoder'
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'index.js',
|
||||
]
|
|
@ -0,0 +1,17 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
PARALLEL_DIRS += [
|
||||
'encoder'
|
||||
]
|
||||
|
||||
JS_MODULES_PATH = 'modules/devtools/qrcode'
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'qrcode.js',
|
||||
]
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
|
|
@ -0,0 +1,62 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
let { Encoder, QRRSBlock, QRErrorCorrectLevel } = require("./encoder/index");
|
||||
|
||||
/**
|
||||
* There are many "versions" of QR codes, which describes how many dots appear
|
||||
* in the resulting image, thus limiting the amount of data that can be
|
||||
* represented.
|
||||
*
|
||||
* The encoder used here allows for versions 1 - 10 (more dots for larger
|
||||
* versions).
|
||||
*
|
||||
* It expects you to pick a version large enough to contain your message. Here
|
||||
* we search for the mimimum version based on the message length.
|
||||
* @param string message
|
||||
* Text to encode
|
||||
* @param string quality
|
||||
* Quality level: L, M, Q, H
|
||||
* @return integer
|
||||
*/
|
||||
exports.findMinimumVersion = function(message, quality) {
|
||||
let msgLength = message.length;
|
||||
let qualityLevel = QRErrorCorrectLevel[quality];
|
||||
for (let version = 1; version <= 10; version++) {
|
||||
let rsBlocks = QRRSBlock.getRSBlocks(version, qualityLevel);
|
||||
let maxLength = rsBlocks.reduce((prev, block) => {
|
||||
return prev + block.dataCount;
|
||||
}, 0);
|
||||
// Remove two bytes to fit header info
|
||||
maxLength -= 2;
|
||||
if (msgLength <= maxLength) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
throw new Error("Message too large");
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple wrapper around the underlying encoder's API.
|
||||
* @param string message
|
||||
* Text to encode
|
||||
* @param string quality (optional)
|
||||
Quality level: L, M, Q, H
|
||||
* @param integer version (optional)
|
||||
* QR code "version" large enough to contain the message
|
||||
* @return object with the following fields:
|
||||
* * src: an image encoded a data URI
|
||||
* * height: image height
|
||||
* * width: image width
|
||||
*/
|
||||
exports.encodeToDataURI = function(message, quality, version) {
|
||||
quality = quality || "H";
|
||||
version = version || exports.findMinimumVersion(message, quality);
|
||||
let encoder = new Encoder(version, quality);
|
||||
encoder.addData(message);
|
||||
encoder.make();
|
||||
return encoder.createImgData();
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Test encoding a simple message.
|
||||
*/
|
||||
|
||||
const { utils: Cu } = Components;
|
||||
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
const { require } = devtools;
|
||||
|
||||
const QR = require("devtools/toolkit/qrcode/qrcode");
|
||||
|
||||
function run_test() {
|
||||
let imgData = QR.encodeToDataURI("HELLO", "L");
|
||||
do_check_eq(imgData.src,
|
||||
"data:image/gif;base64,R0lGODdhOgA6AIAAAAAAAP///ywAAAAAOgA6AAAC" +
|
||||
"/4yPqcvtD6OctNqLs968+w+G4gKU5nkaKKquLuW+QVy2tAkDTj3rfQts8CRDko" +
|
||||
"+HPPoYRUgy9YsyldDm44mLWhHYZM6W7WaDqyCRGkZDySxpRGw2sqvLt1q5w/fo" +
|
||||
"XyE6vnUQOJUHBlinMGh046V1F5PDqNcoqcgBOWKBKbK2N+aY+Ih49VkmqMcl2l" +
|
||||
"dkhZUK1umE6jZXJ2ZJaujZaRqH4bpb2uZrJxvIt4Ebe9qoYYrJOsw8apz2bCut" +
|
||||
"m9kqDcw52uuImyr5Oh1KXH1jrn2anuunywtODU/o2c6teceW39ZcLFg/fNMo1b" +
|
||||
"t3jVw2dwTPwJq1KYG3gAklCgu37yGxeScYKyiCc+7DR34hPVQiuQ7UhJMagyEb" +
|
||||
"lymmzJk0a9q8iTOnzp0NCgAAOw==");
|
||||
do_check_eq(imgData.width, 58);
|
||||
do_check_eq(imgData.height, 58);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
[DEFAULT]
|
||||
head =
|
||||
tail =
|
||||
|
||||
[test_encode.js]
|
|
@ -147,6 +147,12 @@ function log_exceptions(aCallback, ...aArgs) {
|
|||
}
|
||||
}
|
||||
|
||||
function log_callback(aPromise, aCallback) {
|
||||
aPromise.then(aCallback)
|
||||
.then(null, e => info("Exception thrown: " + e));
|
||||
return aPromise;
|
||||
}
|
||||
|
||||
function add_test(test) {
|
||||
gPendingTests.push(test);
|
||||
}
|
||||
|
@ -283,87 +289,82 @@ function wait_for_manager_load(aManagerWindow, aCallback) {
|
|||
}
|
||||
|
||||
function open_manager(aView, aCallback, aLoadCallback, aLongerTimeout) {
|
||||
let deferred = Promise.defer();
|
||||
let p = new Promise((resolve, reject) => {
|
||||
|
||||
function setup_manager(aManagerWindow) {
|
||||
if (aLoadCallback)
|
||||
log_exceptions(aLoadCallback, aManagerWindow);
|
||||
function setup_manager(aManagerWindow) {
|
||||
if (aLoadCallback)
|
||||
log_exceptions(aLoadCallback, aManagerWindow);
|
||||
|
||||
if (aView)
|
||||
aManagerWindow.loadView(aView);
|
||||
if (aView)
|
||||
aManagerWindow.loadView(aView);
|
||||
|
||||
ok(aManagerWindow != null, "Should have an add-ons manager window");
|
||||
is(aManagerWindow.location, MANAGER_URI, "Should be displaying the correct UI");
|
||||
ok(aManagerWindow != null, "Should have an add-ons manager window");
|
||||
is(aManagerWindow.location, MANAGER_URI, "Should be displaying the correct UI");
|
||||
|
||||
waitForFocus(function() {
|
||||
wait_for_manager_load(aManagerWindow, function() {
|
||||
wait_for_view_load(aManagerWindow, function() {
|
||||
// Some functions like synthesizeMouse don't like to be called during
|
||||
// the load event so ensure that has completed
|
||||
executeSoon(function() {
|
||||
if (aCallback) {
|
||||
log_exceptions(aCallback, aManagerWindow);
|
||||
}
|
||||
deferred.resolve(aManagerWindow);
|
||||
});
|
||||
}, null, aLongerTimeout);
|
||||
});
|
||||
}, aManagerWindow);
|
||||
}
|
||||
waitForFocus(function() {
|
||||
info("window has focus, waiting for manager load");
|
||||
wait_for_manager_load(aManagerWindow, function() {
|
||||
info("Manager waiting for view load");
|
||||
wait_for_view_load(aManagerWindow, function() {
|
||||
resolve(aManagerWindow);
|
||||
}, null, aLongerTimeout);
|
||||
});
|
||||
}, aManagerWindow);
|
||||
}
|
||||
|
||||
if (gUseInContentUI) {
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
switchToTabHavingURI(MANAGER_URI, true);
|
||||
if (gUseInContentUI) {
|
||||
info("Loading manager window in tab");
|
||||
Services.obs.addObserver(function (aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(arguments.callee, aTopic);
|
||||
if (aSubject.location.href != MANAGER_URI) {
|
||||
info("Ignoring load event for " + aSubject.location.href);
|
||||
return;
|
||||
}
|
||||
setup_manager(aSubject);
|
||||
}, "EM-loaded", false);
|
||||
|
||||
// This must be a new load, else the ping/pong would have
|
||||
// found the window above.
|
||||
Services.obs.addObserver(function (aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(arguments.callee, aTopic);
|
||||
if (aSubject.location.href != MANAGER_URI)
|
||||
return;
|
||||
setup_manager(aSubject);
|
||||
}, "EM-loaded", false);
|
||||
return deferred.promise;
|
||||
}
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
switchToTabHavingURI(MANAGER_URI, true);
|
||||
} else {
|
||||
info("Loading manager window in dialog");
|
||||
Services.obs.addObserver(function (aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(arguments.callee, aTopic);
|
||||
setup_manager(aSubject);
|
||||
}, "EM-loaded", false);
|
||||
|
||||
openDialog(MANAGER_URI);
|
||||
Services.obs.addObserver(function (aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(arguments.callee, aTopic);
|
||||
setup_manager(aSubject);
|
||||
}, "EM-loaded", false);
|
||||
openDialog(MANAGER_URI);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
return log_callback(p, aCallback);
|
||||
}
|
||||
|
||||
function close_manager(aManagerWindow, aCallback, aLongerTimeout) {
|
||||
let deferred = Promise.defer();
|
||||
requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2);
|
||||
let p = new Promise((resolve, reject) => {
|
||||
requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2);
|
||||
|
||||
ok(aManagerWindow != null, "Should have an add-ons manager window to close");
|
||||
is(aManagerWindow.location, MANAGER_URI, "Should be closing window with correct URI");
|
||||
ok(aManagerWindow != null, "Should have an add-ons manager window to close");
|
||||
is(aManagerWindow.location, MANAGER_URI, "Should be closing window with correct URI");
|
||||
|
||||
aManagerWindow.addEventListener("unload", function() {
|
||||
this.removeEventListener("unload", arguments.callee, false);
|
||||
if (aCallback) {
|
||||
log_exceptions(aCallback);
|
||||
}
|
||||
deferred.resolve();
|
||||
}, false);
|
||||
aManagerWindow.addEventListener("unload", function() {
|
||||
info("Manager window unloaded");
|
||||
this.removeEventListener("unload", arguments.callee, false);
|
||||
resolve();
|
||||
}, false);
|
||||
});
|
||||
|
||||
aManagerWindow.close();
|
||||
|
||||
return deferred.promise;
|
||||
return log_callback(p, aCallback);
|
||||
}
|
||||
|
||||
function restart_manager(aManagerWindow, aView, aCallback, aLoadCallback) {
|
||||
if (!aManagerWindow) {
|
||||
open_manager(aView, aCallback, aLoadCallback);
|
||||
return;
|
||||
return open_manager(aView, aCallback, aLoadCallback);
|
||||
}
|
||||
|
||||
close_manager(aManagerWindow, function() {
|
||||
open_manager(aView, aCallback, aLoadCallback);
|
||||
});
|
||||
return close_manager(aManagerWindow)
|
||||
.then(() => open_manager(aView, aCallback, aLoadCallback));
|
||||
}
|
||||
|
||||
function wait_for_window_open(aCallback) {
|
||||
|
@ -437,25 +438,17 @@ function is_element_hidden(aElement, aMsg) {
|
|||
* The callback will receive the Addon for the installed add-on.
|
||||
*/
|
||||
function install_addon(path, cb, pathPrefix=TESTROOT) {
|
||||
let deferred = Promise.defer();
|
||||
let p = new Promise((resolve, reject) => {
|
||||
AddonManager.getInstallForURL(pathPrefix + path, (install) => {
|
||||
install.addListener({
|
||||
onInstallEnded: () => resolve(install.addon),
|
||||
});
|
||||
|
||||
AddonManager.getInstallForURL(pathPrefix + path, (install) => {
|
||||
install.addListener({
|
||||
onInstallEnded: () => {
|
||||
executeSoon(() => {
|
||||
if (cb) {
|
||||
cb(install.addon);
|
||||
}
|
||||
install.install();
|
||||
}, "application/x-xpinstall");
|
||||
});
|
||||
|
||||
deferred.resolve(install.addon);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
install.install();
|
||||
}, "application/x-xpinstall");
|
||||
|
||||
return deferred.promise;
|
||||
return log_callback(p, cb);
|
||||
}
|
||||
|
||||
function CategoryUtilities(aManagerWindow) {
|
||||
|
@ -517,22 +510,14 @@ CategoryUtilities.prototype = {
|
|||
},
|
||||
|
||||
open: function(aCategory, aCallback) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
isnot(this.window, null, "Should not open category when manager window is not loaded");
|
||||
ok(this.isVisible(aCategory), "Category should be visible if attempting to open it");
|
||||
|
||||
EventUtils.synthesizeMouse(aCategory, 2, 2, { }, this.window);
|
||||
let p = new Promise((resolve, reject) => wait_for_view_load(this.window, resolve));
|
||||
|
||||
wait_for_view_load(this.window, (win) => {
|
||||
if (aCallback) {
|
||||
log_exceptions(aCallback, win);
|
||||
}
|
||||
|
||||
deferred.resolve(win);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
return log_callback(p, aCallback);
|
||||
},
|
||||
|
||||
openType: function(aCategoryType, aCallback) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче