Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2013-12-19 12:36:43 +01:00
commit e4857a9228
68 changed files with 810 additions and 258 deletions

View File

@ -21,4 +21,7 @@ browser.jar:
content/branding/metro-about.css (metro-about.css)
content/branding/metro-about-footer.png (metro-about-footer.png)
content/branding/metro-about-wordmark.png (metro-about-wordmark.png)
content/branding/metro_firstrun_logo.png (metro_firstrun_logo.png)
content/branding/metro_firstrun_logo@1.4x.png (metro_firstrun_logo@1.4x.png)
content/branding/metro_firstrun_logo@1.8x.png (metro_firstrun_logo@1.8x.png)
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

View File

@ -21,4 +21,7 @@ browser.jar:
content/branding/metro-about.css (metro-about.css)
content/branding/metro-about-footer.png (metro-about-footer.png)
content/branding/metro-about-wordmark.png (metro-about-wordmark.png)
content/branding/metro_firstrun_logo.png (metro_firstrun_logo.png)
content/branding/metro_firstrun_logo@1.4x.png (metro_firstrun_logo@1.4x.png)
content/branding/metro_firstrun_logo@1.8x.png (metro_firstrun_logo@1.8x.png)
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

View File

@ -20,4 +20,7 @@ browser.jar:
content/branding/metro-about.css (metro-about.css)
content/branding/metro-about-footer.png (metro-about-footer.png)
content/branding/metro-about-wordmark.png (metro-about-wordmark.png)
content/branding/metro_firstrun_logo.png (metro_firstrun_logo.png)
content/branding/metro_firstrun_logo@1.4x.png (metro_firstrun_logo@1.4x.png)
content/branding/metro_firstrun_logo@1.8x.png (metro_firstrun_logo@1.8x.png)
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

View File

@ -21,4 +21,7 @@ browser.jar:
content/branding/metro-about.css (metro-about.css)
content/branding/metro-about-footer.png (metro-about-footer.png)
content/branding/metro-about-wordmark.png (metro-about-wordmark.png)
content/branding/metro_firstrun_logo.png (metro_firstrun_logo.png)
content/branding/metro_firstrun_logo@1.4x.png (metro_firstrun_logo@1.4x.png)
content/branding/metro_firstrun_logo@1.8x.png (metro_firstrun_logo@1.8x.png)
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

View File

@ -396,10 +396,6 @@
align="center"
pack="center">
<description value="&debuggerUI.tracingNotStarted.label;" />
<button id="start-tracing"
class="devtools-toolbarbutton"
command="startTracing"
label="&debuggerUI.startTracing;"/>
</vbox>
</deck>
</tabpanel>

View File

@ -213,7 +213,7 @@ let Util = {
aURL == "about:empty" ||
aURL == "about:home" ||
aURL == "about:newtab" ||
aURL == "about:start");
aURL.startsWith("about:newtab"));
},
// Title to use for emptyURL tabs.

View File

@ -308,7 +308,7 @@ var BrowserUI = {
isStartURI: function isStartURI(aURI) {
aURI = aURI || Browser.selectedBrowser.currentURI.spec;
return aURI == kStartURI || aURI == "about:start" || aURI == "about:home";
return aURI.startsWith(kStartURI) || aURI == "about:start" || aURI == "about:home";
},
updateStartURIAttributes: function (aURI) {

View File

@ -0,0 +1,69 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://browser/skin/firstrun.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/. -->
<!DOCTYPE window [
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
%browserDTD;
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
%brandDTD;
]>
<overlay id="firstrun"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<hbox id="start-container">
<box id="instruction-topsites-box" insertafter="start-topsites" class="firstrun">
<box id="instruction-topsites">
<vbox align="center">
<image class="instruction-arrow arrow-left" />
<label class="instruction-label" value="&firstRunTopSites.label;"/>
</vbox>
</box>
</box>
<vbox id="firstrun-welcome" insertafter="instruction-topsites-box" class="firstrun" align="center" pack="center">
<image class="welcome-image" />
<label class="welcome-title" value="&firstRunWelcome.label;"/>
<label class="welcome-subtitle" value="&firstRunDifferent.label;"/>
</vbox>
<box insertafter="start-bookmarks" class="firstrun">
<box id="instruction-bookmarks">
<vbox align="center">
<image class="instruction-arrow arrow-right" />
<label class="instruction-label" value="&firstRunBookmarks.label;"/>
</vbox>
</box>
</box>
<box id="instruction-history-container" insertafter="start-history" class="firstrun">
<box id="instruction-history">
<vbox align="center">
<image class="instruction-arrow arrow-right" />
<label class="instruction-label" value="&firstRunHistory.label;"/>
</vbox>
</box>
</box>
<box id="instruction-tabs" class="firstrun">
<vbox align="center">
<image class="instruction-arrow arrow-top" />
<label class="instruction-label" value="&firstRunTabs.label;"/>
</vbox>
</box>
<box id="instruction-menu" class="firstrun">
<hbox>
<label class="instruction-label" value="&firstRunMenu.label;"/>
<image class="instruction-arrow arrow-down" />
</hbox>
</box>
</hbox>
</overlay>

View File

@ -26,6 +26,11 @@ var StartUI = {
document.getElementById("bcast_preciseInput").setAttribute("input",
this.chromeWin.InputSourceHelper.isPrecise ? "precise" : "imprecise");
// NOTE: location.search doesn't work for about: pages
if (location.href.indexOf("?firstrun") > 0) {
document.loadOverlay("chrome://browser/content/FirstRunOverlay.xul", null);
}
this._adjustDOMforViewState(this.chromeWin.ContentAreaObserver.viewstate);
TopSitesStartView.init();

View File

@ -99,6 +99,7 @@ chrome.jar:
content/BookmarksView.js (content/startui/BookmarksView.js)
content/HistoryView.js (content/startui/HistoryView.js)
content/TopSitesView.js (content/startui/TopSitesView.js)
content/FirstRunOverlay.xul (content/startui/FirstRunOverlay.xul)
#ifdef MOZ_SERVICES_SYNC
content/RemoteTabsView.js (content/startui/RemoteTabsView.js)
#endif

View File

@ -61,7 +61,7 @@ function needHomepageOverride() {
if (savedmstone == "ignore")
return "none";
#expand let ourmstone = "__MOZ_APP_VERSION__";
let ourmstone = Services.appinfo.platformVersion;
if (ourmstone != savedmstone) {
Services.prefs.setCharPref("browser.startup.homepage_override.mstone", ourmstone);
@ -222,6 +222,11 @@ BrowserCLH.prototype = {
// Default to the saved homepage
let defaultURL = getHomePage();
// Show page for first run or upgrade.
if (needHomepageOverride() == "new profile") {
defaultURL = 'about:newtab?firstrun';
}
// Override the default if we have a URL passed on command line
if (uris.length > 0) {
defaultURL = uris[0].spec;

View File

@ -0,0 +1,188 @@
/* 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/. */
/* Rearrange about:start ---------------------- */
/* Disable all instructions in snapped mode */
#start-container[viewstate="snapped"] .firstrun {
display: none;
}
/* Keep only first column of tiles */
#start-container[viewstate="landscape"] #start-topsites-grid .richgrid-grid,
#start-container:not([viewstate="snapped"]) #start-bookmarks-grid .richgrid-grid,
#start-container:not([viewstate="snapped"]) #start-history-grid .richgrid-grid {
-moz-column-count: 1 !important;
}
/* Add some bottom padding to make sure bottom tile will not be
below instruction */
#start-container[viewstate="landscape"] #start-topsites-grid .richgrid-grid {
padding-bottom: 30px;
}
/* Keep only first few items */
#start-container:not([viewstate="snapped"]) #start-history-grid richgriditem:nth-child(n+3),
#start-container:not([viewstate="snapped"]) #start-bookmarks-grid richgriditem:nth-child(n+3),
#start-container[viewstate="portrait"] #start-topsites-grid richgriditem:nth-child(n+4) {
display: none;
}
/* Add some space for the instructions */
#start-container[viewstate="portrait"] {
padding-top: 120px;
padding-bottom: 120px;
}
/* Remove watermark */
.meta {
background-image: none;
}
/* Welcome pane ---------------------- */
/* Logo and welcome message */
#firstrun-welcome {
width: 550px;
font-family: "Segoe UI", sans-serif;
padding: 30px 0;
}
.welcome-image {
background-image: url("chrome://branding/content/metro_firstrun_logo.png");
width: 220px;
height: 220px;
}
#firstrun-welcome .welcome-title {
font-size: 25px;
color: #4d4e53;
line-height: 30px;
padding-top: 20px;
}
#firstrun-welcome .welcome-subtitle {
font-size: 16px;
color: #808080;
line-height: 22px;
padding-top: 10px;
}
/* Instructions ---------------------- */
.instruction-label {
font-size: 16px;
color: #808080;
line-height: 22px;
}
.instruction-arrow {
width: 76px;
height: 76px;
}
.instruction-arrow.arrow-top,
.instruction-arrow.arrow-down {
background-image: url("chrome://browser/skin/images/arrow-top.png");
}
.instruction-arrow.arrow-down {
transform: rotate(180deg);
}
.instruction-arrow.arrow-left,
.instruction-arrow.arrow-right {
background-image: url("chrome://browser/skin/images/arrow-left.png");
}
.instruction-arrow.arrow-right {
transform: rotate(180deg) scaleY(-1);
}
#instruction-tabs {
position: absolute;
top: 10px;
transform: translateX(calc(630px - 50%));
}
#start-container[viewstate="portrait"] #instruction-tabs {
transform: translateX(calc(50vw - 50%));
}
#start-container[viewstate="landscape"] #instruction-topsites {
position: absolute;
bottom: 20px;
transform: translateX(-50%);
margin-left: 20px;
}
#start-container[viewstate="portrait"] #instruction-topsites {
transform: translateX(calc(150px + 50%)) translateY(-60px);
}
#start-container[viewstate="landscape"] #instruction-history,
#start-container[viewstate="landscape"] #instruction-bookmarks {
position: absolute;
top: 310px;
transform: translateX(calc(-300px - 50%));
}
#start-container[viewstate="portrait"] #instruction-history,
#start-container[viewstate="portrait"] #instruction-bookmarks {
transform: translateX(-55px);
}
#start-container[viewstate="landscape"] #instruction-menu {
position: fixed;
bottom: 16px;
right: 37px;
}
#start-container[viewstate="portrait"] #instruction-menu {
position: absolute;
right: 37px;
transform: translateY(40px);
}
#start-container[viewstate="landscape"] #start-history {
padding-left: 50px;
}
/* Higher resolution images ---------------------- */
@media (min-resolution: @min_res_140pc@) {
/* Load 140% image when scaled by 140% */
.instruction-arrow.arrow-top,
.instruction-arrow.arrow-down {
background-image: url("chrome://browser/skin/images/arrow-top@1.4x.png");
}
.instruction-arrow.arrow-left,
.instruction-arrow.arrow-right {
background-image: url("chrome://browser/skin/images/arrow-left@1.4x.png");
}
.welcome-image {
background-image: url("chrome://branding/content/metro_firstrun_logo@1.4x.png");
}
}
@media (min-resolution: @min_res_180pc@) {
/* Load 180% image when scaled by 180% */
.instruction-arrow.arrow-top,
.instruction-arrow.arrow-down {
background-image: url("chrome://browser/skin/images/arrow-top@1.8x.png");
}
.instruction-arrow.arrow-left,
.instruction-arrow.arrow-right {
background-image: url("chrome://browser/skin/images/arrow-left@1.8x.png");
}
.welcome-image {
background-image: url("chrome://branding/content/metro_firstrun_logo@1.8x.png");
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -22,6 +22,7 @@ chrome.jar:
* skin/tiles.css (tiles.css)
skin/touchcontrols.css (touchcontrols.css)
skin/netError.css (netError.css)
skin/firstrun.css (firstrun.css)
% override chrome://global/skin/about.css chrome://browser/skin/about.css
% override chrome://global/skin/media/videocontrols.css chrome://browser/skin/touchcontrols.css
% override chrome://global/skin/netError.css chrome://browser/skin/netError.css
@ -135,3 +136,10 @@ chrome.jar:
skin/images/overlay-back.png (images/overlay-back.png)
skin/images/overlay-plus.png (images/overlay-plus.png)
skin/images/autoscroll.png (images/autoscroll.png)
skin/images/arrow-top.png (images/arrow-top.png)
skin/images/arrow-top@1.4x.png (images/arrow-top@1.4x.png)
skin/images/arrow-top@1.8x.png (images/arrow-top@1.8x.png)
skin/images/arrow-left.png (images/arrow-left.png)
skin/images/arrow-left@1.4x.png (images/arrow-left@1.4x.png)
skin/images/arrow-left@1.8x.png (images/arrow-left@1.8x.png)

View File

@ -333,23 +333,23 @@ richgriditem[bending] > .tile-content {
transform-origin: center center;
}
/* Empty/unused tiles */
richgriditem:not([value]) {
visibility: hidden;
}
richgriditem[tiletype="thumbnail"]:not([value]) {
visibility: visible;
}
richgriditem:not([value]) > .tile-content {
padding: 10px 14px;
}
richgriditem[tiletype="thumbnail"]:not([value]) > .tile-content {
/* Empty/unused tiles */
richgriditem:not([value]) > .tile-content {
box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.05);
background-image: url("chrome://browser/skin/images/firefox-watermark.png");
background-origin: content-box;
background-repeat: no-repeat;
background-color: rgba(255,255,255, 0.2);
background-position: center center;
background-size: @compactgrid_row_height@;
}
richgriditem[tiletype="thumbnail"]:not([value]) > .tile-content {
background-size: @grid_row_height@;
}

View File

@ -1408,7 +1408,15 @@ abstract public class BrowserApp extends GeckoApp
int flags = (tab.isPrivate() || tab.getErrorType() != Tab.ErrorType.NONE) ? 0 : LoadFaviconTask.FLAG_PERSIST;
int id = Favicons.getFaviconForSize(tab.getURL(), tab.getFaviconURL(), tabFaviconSize, flags, sFaviconLoadedListener);
tab.setFaviconLoadId(id);
if (id != Favicons.LOADED &&
Tabs.getInstance().isSelectedTab(tab)) {
// We're loading the current tab's favicon from somewhere
// other than the cache.
// Display the globe favicon until then.
mBrowserToolbar.showDefaultFavicon();
}
}
private void maybeCancelFaviconLoad(Tab tab) {
@ -2053,6 +2061,7 @@ abstract public class BrowserApp extends GeckoApp
Tab tab = Tabs.getInstance().getSelectedTab();
MenuItem bookmark = aMenu.findItem(R.id.bookmark);
MenuItem back = aMenu.findItem(R.id.back);
MenuItem forward = aMenu.findItem(R.id.forward);
MenuItem share = aMenu.findItem(R.id.share);
MenuItem saveAsPDF = aMenu.findItem(R.id.save_as_pdf);
@ -2068,6 +2077,7 @@ abstract public class BrowserApp extends GeckoApp
if (tab == null || tab.getURL() == null) {
bookmark.setEnabled(false);
back.setEnabled(false);
forward.setEnabled(false);
share.setEnabled(false);
saveAsPDF.setEnabled(false);
@ -2080,6 +2090,7 @@ abstract public class BrowserApp extends GeckoApp
bookmark.setChecked(tab.isBookmark());
bookmark.setIcon(tab.isBookmark() ? R.drawable.ic_menu_bookmark_remove : R.drawable.ic_menu_bookmark_add);
back.setEnabled(tab.canDoBack());
forward.setEnabled(tab.canDoForward());
desktopMode.setChecked(tab.getDesktopMode());
desktopMode.setIcon(tab.getDesktopMode() ? R.drawable.ic_menu_desktop_mode_on : R.drawable.ic_menu_desktop_mode_off);
@ -2209,6 +2220,13 @@ abstract public class BrowserApp extends GeckoApp
return true;
}
if (itemId == R.id.back) {
tab = Tabs.getInstance().getSelectedTab();
if (tab != null)
tab.doBack();
return true;
}
if (itemId == R.id.forward) {
tab = Tabs.getInstance().getSelectedTab();
if (tab != null)

View File

@ -246,7 +246,8 @@ class TextSelection extends Layer implements GeckoEventListener {
try {
final JSONObject obj = mItems.getJSONObject(i);
final GeckoMenuItem menuitem = (GeckoMenuItem) menu.add(0, i, 0, obj.optString("label"));
menuitem.setShowAsAction(obj.optBoolean("showAsAction") ? 1 : 0, R.attr.menuItemActionModeStyle);
final int actionEnum = obj.optBoolean("showAsAction") ? GeckoMenuItem.SHOW_AS_ACTION_ALWAYS : GeckoMenuItem.SHOW_AS_ACTION_NEVER;
menuitem.setShowAsAction(actionEnum, R.attr.menuItemActionModeStyle);
BitmapUtils.getDrawable(mStartHandle.getContext(), obj.optString("icon"), new BitmapLoader() {
public void onBitmapFound(Drawable d) {

View File

@ -78,8 +78,11 @@ public class GeckoMenu extends ListView
// List of all menu items.
private List<GeckoMenuItem> mItems;
// Map of items in action-bar and their views.
private Map<GeckoMenuItem, View> mActionItems;
// Map of "always" action-items in action-bar and their views.
private Map<GeckoMenuItem, View> mPrimaryActionItems;
// Map of "ifRoom" action-items in action-bar and their views.
private Map<GeckoMenuItem, View> mSecondaryActionItems;
// Reference to a callback for menu events.
private Callback mCallback;
@ -87,18 +90,24 @@ public class GeckoMenu extends ListView
// Reference to menu presenter.
private MenuPresenter mMenuPresenter;
// Reference to action-items bar in action-bar.
private ActionItemBarPresenter mActionItemBarPresenter;
// Reference to "always" action-items bar in action-bar.
private ActionItemBarPresenter mPrimaryActionItemBar;
// Reference to "ifRoom" action-items bar in action-bar.
private final ActionItemBarPresenter mSecondaryActionItemBar;
// Adapter to hold the list of menu items.
private MenuItemsAdapter mAdapter;
// Show/hide icons in the list.
private boolean mShowIcons;
public GeckoMenu(Context context) {
this(context, null);
}
public GeckoMenu(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.listViewStyle);
this(context, attrs, R.attr.geckoMenuListViewStyle);
}
public GeckoMenu(Context context, AttributeSet attrs, int defStyle) {
@ -112,10 +121,13 @@ public class GeckoMenu extends ListView
setAdapter(mAdapter);
setOnItemClickListener(this);
mShowIcons = false;
mItems = new ArrayList<GeckoMenuItem>();
mActionItems = new HashMap<GeckoMenuItem, View>();
mPrimaryActionItems = new HashMap<GeckoMenuItem, View>();
mSecondaryActionItems = new HashMap<GeckoMenuItem, View>();
mActionItemBarPresenter = (DefaultActionItemBar) LayoutInflater.from(context).inflate(R.layout.menu_action_bar, null);
mPrimaryActionItemBar = (DefaultActionItemBar) LayoutInflater.from(context).inflate(R.layout.menu_action_bar, null);
mSecondaryActionItemBar = (DefaultActionItemBar) LayoutInflater.from(context).inflate(R.layout.menu_secondary_action_bar, null);
}
@Override
@ -155,28 +167,55 @@ public class GeckoMenu extends ListView
private boolean addActionItem(final GeckoMenuItem menuItem) {
menuItem.setOnShowAsActionChangedListener(this);
if (mActionItems.size() == 0 &&
mActionItemBarPresenter instanceof DefaultActionItemBar) {
// Reset the adapter before adding the header view to a list.
setAdapter(null);
addHeaderView((DefaultActionItemBar) mActionItemBarPresenter);
setAdapter(mAdapter);
}
final View actionView = menuItem.getActionView();
final int actionEnum = menuItem.getActionEnum();
boolean added = false;
View actionView = menuItem.getActionView();
actionView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
handleMenuItemClick(menuItem);
if (actionEnum == GeckoMenuItem.SHOW_AS_ACTION_ALWAYS) {
if (mPrimaryActionItems.size() == 0 &&
mPrimaryActionItemBar instanceof DefaultActionItemBar) {
// Reset the adapter before adding the header view to a list.
setAdapter(null);
addHeaderView((DefaultActionItemBar) mPrimaryActionItemBar);
setAdapter(mAdapter);
}
});
if (mActionItemBarPresenter.addActionItem(actionView)) {
mActionItems.put(menuItem, actionView);
mItems.add(menuItem);
return true;
if (added = mPrimaryActionItemBar.addActionItem(actionView)) {
mPrimaryActionItems.put(menuItem, actionView);
mItems.add(menuItem);
}
} else if (actionEnum == GeckoMenuItem.SHOW_AS_ACTION_IF_ROOM) {
if (mSecondaryActionItems.size() == 0) {
// Reset the adapter before adding the header view to a list.
setAdapter(null);
addHeaderView((DefaultActionItemBar) mSecondaryActionItemBar);
setAdapter(mAdapter);
}
if (added = mSecondaryActionItemBar.addActionItem(actionView)) {
mSecondaryActionItems.put(menuItem, actionView);
mItems.add(menuItem);
}
}
return false;
// Set the listeners.
if (actionView instanceof MenuItemActionBar) {
((MenuItemActionBar) actionView).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
handleMenuItemClick(menuItem);
}
});
} else if (actionView instanceof MenuItemActionView) {
((MenuItemActionView) actionView).setMenuItemClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
handleMenuItemClick(menuItem);
}
});
}
return added;
}
@Override
@ -217,10 +256,17 @@ public class GeckoMenu extends ListView
return subMenu;
}
private void removeActionBarView() {
private void removePrimaryActionBarView() {
// Reset the adapter before removing the header view from a list.
setAdapter(null);
removeHeaderView((DefaultActionItemBar) mActionItemBarPresenter);
removeHeaderView((DefaultActionItemBar) mPrimaryActionItemBar);
setAdapter(mAdapter);
}
private void removeSecondaryActionBarView() {
// Reset the adapter before removing the header view from a list.
setAdapter(null);
removeHeaderView((DefaultActionItemBar) mSecondaryActionItemBar);
setAdapter(mAdapter);
}
@ -248,18 +294,27 @@ public class GeckoMenu extends ListView
* remove the old ones. This also ensures that any text associated with
* these is switched to the correct locale.
*/
if (mActionItemBarPresenter != null) {
for (View item : mActionItems.values()) {
mActionItemBarPresenter.removeActionItem(item);
if (mPrimaryActionItemBar != null) {
for (View item : mPrimaryActionItems.values()) {
mPrimaryActionItemBar.removeActionItem(item);
}
}
mActionItems.clear();
mPrimaryActionItems.clear();
if (mSecondaryActionItemBar != null) {
for (View item : mSecondaryActionItems.values()) {
mSecondaryActionItemBar.removeActionItem(item);
}
}
mSecondaryActionItems.clear();
// Remove the view, too -- the first addActionItem will re-add it,
// and this is simpler than changing that logic.
if (mActionItemBarPresenter instanceof DefaultActionItemBar) {
removeActionBarView();
if (mPrimaryActionItemBar instanceof DefaultActionItemBar) {
removePrimaryActionBarView();
}
removeSecondaryActionBarView();
}
@Override
@ -301,7 +356,9 @@ public class GeckoMenu extends ListView
@Override
public boolean hasVisibleItems() {
for (GeckoMenuItem menuItem : mItems) {
if (menuItem.isVisible() && !mActionItems.containsKey(menuItem))
if (menuItem.isVisible() &&
!mPrimaryActionItems.containsKey(menuItem) &&
!mSecondaryActionItems.containsKey(menuItem))
return true;
}
@ -345,16 +402,30 @@ public class GeckoMenu extends ListView
}
// Remove it from own menu.
if (mActionItems.containsKey(item)) {
if (mActionItemBarPresenter != null)
mActionItemBarPresenter.removeActionItem(mActionItems.get(item));
if (mPrimaryActionItems.containsKey(item)) {
if (mPrimaryActionItemBar != null)
mPrimaryActionItemBar.removeActionItem(mPrimaryActionItems.get(item));
mActionItems.remove(item);
mPrimaryActionItems.remove(item);
mItems.remove(item);
if (mActionItems.size() == 0 &&
mActionItemBarPresenter instanceof DefaultActionItemBar) {
removeActionBarView();
if (mPrimaryActionItems.size() == 0 &&
mPrimaryActionItemBar instanceof DefaultActionItemBar) {
removePrimaryActionBarView();
}
return;
}
if (mSecondaryActionItems.containsKey(item)) {
if (mSecondaryActionItemBar != null)
mSecondaryActionItemBar.removeActionItem(mSecondaryActionItems.get(item));
mSecondaryActionItems.remove(item);
mItems.remove(item);
if (mSecondaryActionItems.size() == 0) {
removeSecondaryActionBarView();
}
return;
@ -387,14 +458,14 @@ public class GeckoMenu extends ListView
@Override
public boolean hasActionItemBar() {
return (mActionItemBarPresenter != null);
return (mPrimaryActionItemBar != null) && (mSecondaryActionItemBar != null);
}
@Override
public void onShowAsActionChanged(GeckoMenuItem item, boolean isActionItem) {
public void onShowAsActionChanged(GeckoMenuItem item) {
removeItem(item.getItemId());
if (isActionItem && addActionItem(item)) {
if (item.isActionItem() && addActionItem(item)) {
return;
}
@ -403,23 +474,33 @@ public class GeckoMenu extends ListView
public void onItemChanged(GeckoMenuItem item) {
if (item.isActionItem()) {
final MenuItemActionBar actionView = (MenuItemActionBar) mActionItems.get(item);
if (actionView != null) {
// The update could be coming from the background thread.
// Post a runnable on the UI thread of the view for it to update.
final GeckoMenuItem menuItem = item;
actionView.post(new Runnable() {
@Override
public void run() {
if (menuItem.isVisible()) {
actionView.setVisibility(View.VISIBLE);
actionView.initialize(menuItem);
} else {
actionView.setVisibility(View.GONE);
}
}
});
}
final View actionView;
if (item.getActionEnum() == GeckoMenuItem.SHOW_AS_ACTION_ALWAYS) {
actionView = mPrimaryActionItems.get(item);
} else {
actionView = mSecondaryActionItems.get(item);
}
if (actionView != null) {
// The update could be coming from the background thread.
// Post a runnable on the UI thread of the view for it to update.
final GeckoMenuItem menuItem = item;
actionView.post(new Runnable() {
@Override
public void run() {
if (menuItem.isVisible()) {
actionView.setVisibility(View.VISIBLE);
if (actionView instanceof MenuItemActionBar) {
((MenuItemActionBar) actionView).initialize(menuItem);
} else {
((MenuItemActionView) actionView).initialize(menuItem);
}
} else {
actionView.setVisibility(View.GONE);
}
}
});
}
} else {
mAdapter.notifyDataSetChanged();
}
@ -445,6 +526,7 @@ public class GeckoMenu extends ListView
ActionProvider provider = item.getActionProvider();
if (provider != null) {
GeckoSubMenu subMenu = new GeckoSubMenu(getContext());
subMenu.setShowIcons(true);
provider.onPrepareSubMenu(subMenu);
item.setSubMenu(subMenu);
}
@ -491,13 +573,23 @@ public class GeckoMenu extends ListView
}
public void setActionItemBarPresenter(ActionItemBarPresenter presenter) {
mActionItemBarPresenter = presenter;
mPrimaryActionItemBar = presenter;
}
public void setShowIcons(boolean show) {
if (mShowIcons != show) {
mShowIcons = show;
mAdapter.notifyDataSetChanged();
}
}
// Action Items are added to the header view by default.
// URL bar can register itself as a presenter, in case it has a different place to show them.
public static class DefaultActionItemBar extends LinearLayout
implements ActionItemBarPresenter {
private final int mRowHeight;
private float mWeightSum;
public DefaultActionItemBar(Context context) {
this(context, null);
}
@ -505,21 +597,42 @@ public class GeckoMenu extends ListView
public DefaultActionItemBar(Context context, AttributeSet attrs) {
super(context, attrs);
setWeightSum(3.0f);
mRowHeight = getResources().getDimensionPixelSize(R.dimen.menu_item_row_height);
}
@Override
public boolean addActionItem(View actionItem) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(actionItem.getLayoutParams());
params.weight = 1.0f;
ViewGroup.LayoutParams actualParams = actionItem.getLayoutParams();
LinearLayout.LayoutParams params;
if (actualParams != null) {
params = new LinearLayout.LayoutParams(actionItem.getLayoutParams());
params.width = 0;
} else {
params = new LinearLayout.LayoutParams(0, mRowHeight);
}
if (actionItem instanceof MenuItemActionView) {
params.weight = ((MenuItemActionView) actionItem).getChildCount();
} else {
params.weight = 1.0f;
}
mWeightSum += params.weight;
actionItem.setLayoutParams(params);
addView(actionItem);
setWeightSum(mWeightSum);
return true;
}
@Override
public void removeActionItem(View actionItem) {
removeView(actionItem);
if (indexOfChild(actionItem) != -1) {
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) actionItem.getLayoutParams();
mWeightSum -= params.weight;
removeView(actionItem);
}
}
}
@ -599,6 +712,7 @@ public class GeckoMenu extends ListView
}
// Initialize the view.
view.setShowIcon(mShowIcons);
view.initialize(item);
return (View) view;
}

View File

@ -4,6 +4,7 @@
package org.mozilla.gecko.menu;
import org.mozilla.gecko.R;
import org.mozilla.gecko.widget.GeckoActionProvider;
import android.content.Intent;
@ -18,21 +19,26 @@ import android.view.View;
public class GeckoMenuItem implements MenuItem {
private static final String LOGTAG = "GeckoMenuItem";
public static final int SHOW_AS_ACTION_NEVER = 0;
public static final int SHOW_AS_ACTION_IF_ROOM = 1;
public static final int SHOW_AS_ACTION_ALWAYS = 2;
// A View that can show a MenuItem should be able to initialize from
// the properties of the MenuItem.
public static interface Layout {
public void initialize(GeckoMenuItem item);
public void setShowIcon(boolean show);
}
public static interface OnShowAsActionChangedListener {
public boolean hasActionItemBar();
public void onShowAsActionChanged(GeckoMenuItem item, boolean isActionItem);
public void onShowAsActionChanged(GeckoMenuItem item);
}
private int mId;
private int mOrder;
private View mActionView;
private boolean mActionItem = false;
private int mActionEnum;
private CharSequence mTitle;
private CharSequence mTitleCondensed;
private boolean mCheckable = false;
@ -79,6 +85,10 @@ public class GeckoMenuItem implements MenuItem {
return (mActionProvider != null);
}
public int getActionEnum() {
return mActionEnum;
}
@Override
public ActionProvider getActionProvider() {
return mActionProvider;
@ -164,7 +174,7 @@ public class GeckoMenuItem implements MenuItem {
}
public boolean isActionItem() {
return mActionItem;
return (mActionEnum > 0);
}
@Override
@ -201,10 +211,14 @@ public class GeckoMenuItem implements MenuItem {
@Override
public void onTargetSelected() {
mMenu.close();
// Refresh the menu item to show the high frequency apps.
mShowAsActionChangedListener.onShowAsActionChanged(GeckoMenuItem.this);
}
});
}
mShowAsActionChangedListener.onShowAsActionChanged(this);
return this;
}
@ -293,27 +307,34 @@ public class GeckoMenuItem implements MenuItem {
if (mShowAsActionChangedListener == null)
return;
if (mActionItem == (actionEnum > 0))
if (mActionEnum == actionEnum)
return;
if (actionEnum > 0) {
if (!mShowAsActionChangedListener.hasActionItemBar())
return;
// Change the type to just an icon
MenuItemActionBar actionView;
if (style != 0) {
actionView = new MenuItemActionBar(mMenu.getContext(), null, style);
} else {
actionView = new MenuItemActionBar(mMenu.getContext());
}
actionView.initialize(this);
mActionView = actionView;
if (!hasActionProvider()) {
// Change the type to just an icon
MenuItemActionBar actionView;
if (style != 0) {
actionView = new MenuItemActionBar(mMenu.getContext(), null, style);
} else {
if (actionEnum == SHOW_AS_ACTION_ALWAYS) {
actionView = new MenuItemActionBar(mMenu.getContext());
} else {
actionView = new MenuItemActionBar(mMenu.getContext(), null, R.attr.menuItemSecondaryActionBarStyle);
}
}
mActionItem = (actionEnum > 0);
actionView.initialize(this);
mActionView = actionView;
}
mActionEnum = actionEnum;
}
mShowAsActionChangedListener.onShowAsActionChanged(this, mActionItem);
mShowAsActionChangedListener.onShowAsActionChanged(this);
}
@Override

View File

@ -26,9 +26,6 @@ public class MenuItemActionBar extends ImageButton
public MenuItemActionBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
int size = (int) (context.getResources().getDimension(R.dimen.browser_toolbar_height));
setLayoutParams(new ViewGroup.LayoutParams(size, size));
}
@Override
@ -42,7 +39,7 @@ public class MenuItemActionBar extends ImageButton
setId(item.getItemId());
}
private void setIcon(Drawable icon) {
void setIcon(Drawable icon) {
if (icon != null) {
setImageDrawable(icon);
setVisibility(VISIBLE);
@ -51,7 +48,7 @@ public class MenuItemActionBar extends ImageButton
}
}
private void setIcon(int icon) {
void setIcon(int icon) {
if (icon != 0) {
setImageResource(icon);
setVisibility(VISIBLE);
@ -60,7 +57,7 @@ public class MenuItemActionBar extends ImageButton
}
}
private void setTitle(CharSequence title) {
void setTitle(CharSequence title) {
// set accessibility contentDescription here
setContentDescription(title);
}
@ -70,4 +67,9 @@ public class MenuItemActionBar extends ImageButton
super.setEnabled(enabled);
setColorFilter(enabled ? 0 : 0xFF999999);
}
@Override
public void setShowIcon(boolean show) {
// Do nothing.
}
}

View File

@ -25,7 +25,7 @@ public class MenuItemActionView extends LinearLayout
private static final String LOGTAG = "GeckoMenuItemActionView";
private MenuItemDefault mMenuItem;
private ImageButton mMenuButton;
private MenuItemActionBar mMenuButton;
private List<ImageButton> mActionButtons;
private View.OnClickListener mActionButtonListener;
@ -41,18 +41,28 @@ public class MenuItemActionView extends LinearLayout
public MenuItemActionView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
Resources res = context.getResources();
int width = res.getDimensionPixelSize(R.dimen.menu_item_row_width);
int height = res.getDimensionPixelSize(R.dimen.menu_item_row_height);
setMinimumWidth(width);
setMinimumHeight(height);
LayoutInflater.from(context).inflate(R.layout.menu_item_action_view, this);
mMenuItem = (MenuItemDefault) findViewById(R.id.menu_item);
mMenuButton = (ImageButton) findViewById(R.id.menu_item_button);
mMenuButton = (MenuItemActionBar) findViewById(R.id.menu_item_button);
mActionButtons = new ArrayList<ImageButton>();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
View parent = (View) getParent();
if ((right - left) < parent.getMeasuredWidth() || mActionButtons.size() != 0) {
// Use the icon.
mMenuItem.setVisibility(View.GONE);
mMenuButton.setVisibility(View.VISIBLE);
} else {
// Use the button.
mMenuItem.setVisibility(View.VISIBLE);
mMenuButton.setVisibility(View.GONE);
}
super.onLayout(changed, left, top, right, bottom);
}
@Override
public void initialize(GeckoMenuItem item) {
if (item == null)
@ -65,16 +75,17 @@ public class MenuItemActionView extends LinearLayout
private void setIcon(Drawable icon) {
mMenuItem.setIcon(icon);
mMenuButton.setImageDrawable(icon);
mMenuButton.setIcon(icon);
}
private void setIcon(int icon) {
mMenuItem.setIcon(icon);
mMenuButton.setImageResource(icon);
mMenuButton.setIcon(icon);
}
private void setTitle(CharSequence title) {
mMenuItem.setTitle(title);
mMenuButton.setTitle(title);
}
@Override
@ -82,7 +93,6 @@ public class MenuItemActionView extends LinearLayout
super.setEnabled(enabled);
mMenuItem.setEnabled(enabled);
mMenuButton.setEnabled(enabled);
mMenuButton.setAlpha(enabled ? 255 : 99);
for (ImageButton button : mActionButtons) {
button.setEnabled(enabled);
@ -103,17 +113,17 @@ public class MenuItemActionView extends LinearLayout
}
}
@Override
public void setShowIcon(boolean show) {
mMenuItem.setShowIcon(show);
}
public void addActionButton(Drawable drawable) {
// If this is the first icon, retain the text.
// If not, make the menu item an icon.
final int count = mActionButtons.size();
if (count == 0) {
mMenuItem.setVisibility(View.VISIBLE);
mMenuButton.setVisibility(View.GONE);
} else {
mMenuItem.setVisibility(View.GONE);
mMenuButton.setVisibility(View.VISIBLE);
}
mMenuItem.setVisibility(View.GONE);
mMenuButton.setVisibility(View.VISIBLE);
if (drawable != null) {
ImageButton button = new ImageButton(getContext(), null, R.attr.menuItemShareActionButtonStyle);
@ -126,8 +136,9 @@ public class MenuItemActionView extends LinearLayout
params.weight = 1.0f;
button.setLayoutParams(params);
// Fill in the action-buttons to the left of the actual menu button.
mActionButtons.add(button);
addView(button);
addView(button, count);
}
}
}

View File

@ -26,6 +26,7 @@ public class MenuItemDefault extends TextView
private boolean mCheckable = false;
private boolean mChecked = false;
private boolean mHasSubMenu = false;
private boolean mShowIcon = false;
public MenuItemDefault(Context context) {
this(context, null);
@ -85,6 +86,10 @@ public class MenuItemDefault extends TextView
setSubMenuIndicator(item.hasSubMenu());
}
private void refreshIcon() {
setCompoundDrawables(mShowIcon ? mIcon : null, null, mState, null);
}
void setIcon(Drawable icon) {
mIcon = icon;
@ -93,7 +98,7 @@ public class MenuItemDefault extends TextView
mIcon.setAlpha(isEnabled() ? 255 : 99);
}
setCompoundDrawables(mIcon, null, mState, null);
refreshIcon();
}
void setIcon(int icon) {
@ -134,6 +139,14 @@ public class MenuItemDefault extends TextView
}
}
@Override
public void setShowIcon(boolean show) {
if (mShowIcon != show) {
mShowIcon = show;
refreshIcon();
}
}
private void setSubMenuIndicator(boolean hasSubMenu) {
if (mHasSubMenu != hasSubMenu) {
mHasSubMenu = hasSubMenu;

View File

@ -8,41 +8,30 @@ package org.mozilla.gecko.menu;
import org.mozilla.gecko.R;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
/**
* A popup to show the inflated MenuPanel. This has an arrow pointing to the anchor.
* A popup to show the inflated MenuPanel.
*/
public class MenuPopup extends PopupWindow {
private Resources mResources;
private ImageView mArrowTop;
private ImageView mArrowBottom;
private RelativeLayout mPanel;
private LinearLayout mPanel;
private int mYOffset;
private int mArrowMargin;
private int mPopupWidth;
private boolean mShowArrow;
public MenuPopup(Context context) {
super(context);
mResources = context.getResources();
setFocusable(true);
mYOffset = mResources.getDimensionPixelSize(R.dimen.menu_popup_offset);
mArrowMargin = mResources.getDimensionPixelSize(R.dimen.menu_popup_arrow_margin);
mPopupWidth = mResources.getDimensionPixelSize(R.dimen.menu_popup_width);
mYOffset = context.getResources().getDimensionPixelSize(R.dimen.menu_popup_offset);
mPopupWidth = context.getResources().getDimensionPixelSize(R.dimen.menu_popup_width);
// Setting a null background makes the popup to not close on touching outside.
setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
@ -50,13 +39,9 @@ public class MenuPopup extends PopupWindow {
ViewGroup.LayoutParams.WRAP_CONTENT);
LayoutInflater inflater = LayoutInflater.from(context);
RelativeLayout layout = (RelativeLayout) inflater.inflate(R.layout.menu_popup, null);
setContentView(layout);
mPanel = (LinearLayout) inflater.inflate(R.layout.menu_popup, null);
setContentView(mPanel);
mArrowTop = (ImageView) layout.findViewById(R.id.menu_arrow_top);
mArrowBottom = (ImageView) layout.findViewById(R.id.menu_arrow_bottom);
mPanel = (RelativeLayout) layout.findViewById(R.id.menu_panel);
mShowArrow = true;
setAnimationStyle(R.style.PopupAnimation);
}
@ -66,52 +51,18 @@ public class MenuPopup extends PopupWindow {
* @param view The panel view with the menu to be shown.
*/
public void setPanelView(View view) {
view.setLayoutParams(new LinearLayout.LayoutParams(mPopupWidth,
LinearLayout.LayoutParams.WRAP_CONTENT));
mPanel.removeAllViews();
mPanel.addView(view);
mPanel.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
/**
* Show/hide the arrow pointing to the anchor.
*
* @param show Show/hide the arrow.
*/
public void showArrowToAnchor(boolean show) {
mShowArrow = show;
}
/**
* A small little offset for the arrow to overlap the anchor.
* A small little offset.
*/
@Override
public void showAsDropDown(View anchor) {
if (!mShowArrow) {
mArrowTop.setVisibility(View.GONE);
mArrowBottom.setVisibility(View.GONE);
showAsDropDown(anchor, 0, -mYOffset);
return;
}
int[] anchorLocation = new int[2];
anchor.getLocationOnScreen(anchorLocation);
int screenWidth = mResources.getDisplayMetrics().widthPixels;
int arrowWidth = mResources.getDimensionPixelSize(R.dimen.menu_popup_arrow_width);
int arrowOffset = (anchor.getWidth() - arrowWidth)/2;
if (anchorLocation[0] + mPopupWidth <= screenWidth) {
// left align
((LayoutParams) mArrowTop.getLayoutParams()).rightMargin = mPopupWidth - anchor.getWidth() + arrowOffset;
((LayoutParams) mArrowBottom.getLayoutParams()).rightMargin = mPopupWidth - anchor.getWidth() + arrowOffset;
} else {
// right align
((LayoutParams) mArrowTop.getLayoutParams()).rightMargin = screenWidth - anchorLocation[0] - anchor.getWidth()/2 - arrowWidth/2;
((LayoutParams) mArrowBottom.getLayoutParams()).rightMargin = mArrowMargin;
}
// shown below anchor
mArrowTop.setVisibility(View.VISIBLE);
mArrowBottom.setVisibility(View.GONE);
showAsDropDown(anchor, 0, -mYOffset);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 393 B

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 757 B

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 278 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 573 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -12,6 +12,4 @@
android:layout_width="@dimen/menu_item_row_width"
android:layout_height="@dimen/browser_toolbar_height"
android:orientation="horizontal"
android:divider="@drawable/divider_vertical"
android:showDividers="middle"
android:dividerPadding="0dip"/>
android:background="#FFD6DEE4"/>

View File

@ -5,23 +5,29 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<org.mozilla.gecko.menu.MenuItemDefault
android:id="@+id/menu_item"
android:layout_width="0dip"
android:layout_height="fill_parent"
android:layout_weight="2.0"
android:background="@drawable/action_bar_button"
android:clickable="true"
android:focusable="true"/>
<!-- Application icons will be added dynamically -->
<ImageButton android:id="@+id/menu_item_button"
android:layout_width="0dip"
<FrameLayout android:layout_width="0dip"
android:layout_height="@dimen/menu_item_row_height"
android:layout_weight="1.0"
android:padding="10dip"
android:scaleType="centerInside"
android:background="@drawable/action_bar_button"
android:layout_gravity="center_vertical"
android:visibility="gone"/>
android:layout_weight="1.0">
<org.mozilla.gecko.menu.MenuItemDefault
android:id="@+id/menu_item"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/action_bar_button"
android:clickable="true"
android:focusable="true"/>
<org.mozilla.gecko.menu.MenuItemActionBar
style="@style/Widget.MenuItemSecondaryActionBar"
android:id="@+id/menu_item_button"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/action_bar_button"
android:layout_gravity="center_vertical"
android:visibility="gone"/>
</FrameLayout>
</merge>

View File

@ -3,35 +3,14 @@
- 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/. -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/menu_panel"
android:layout_width="@dimen/menu_popup_width"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:minWidth="@dimen/menu_popup_width"
android:background="@drawable/menu_popup_bg">
<RelativeLayout android:id="@+id/menu_panel"
android:layout_width="@dimen/menu_popup_width"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:background="@drawable/menu_popup_bg">
<!-- MenuPanel will be added here dynamically -->
<!-- MenuPanel will be added here dynamically -->
</RelativeLayout>
<ImageView android:id="@+id/menu_arrow_top"
android:layout_width="@dimen/menu_popup_arrow_width"
android:layout_height="12dip"
android:layout_marginRight="@dimen/menu_popup_arrow_margin"
android:layout_alignRight="@id/menu_panel"
android:src="@drawable/menu_popup_arrow_top"
android:scaleType="fitXY"/>
<ImageView android:id="@+id/menu_arrow_bottom"
android:layout_width="@dimen/menu_popup_arrow_width"
android:layout_height="12dip"
android:layout_marginRight="@dimen/menu_popup_arrow_margin"
android:layout_alignRight="@id/menu_panel"
android:layout_alignBottom="@id/menu_panel"
android:src="@drawable/menu_popup_arrow_bottom"
android:scaleType="fitXY"/>
</RelativeLayout>
</LinearLayout>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!--
Note: This layout is intended to be used only above 11+.
android:showDividers are available only 11+
-->
<view xmlns:android="http://schemas.android.com/apk/res/android"
class="org.mozilla.gecko.menu.GeckoMenu$DefaultActionItemBar"
android:layout_width="@dimen/menu_item_row_width"
android:layout_height="@dimen/browser_toolbar_height"
android:orientation="horizontal"
android:divider="@drawable/divider_vertical"
android:showDividers="middle"
android:dividerPadding="0dip"/>

View File

@ -10,6 +10,11 @@
android:title="@string/reload"
android:showAsAction="always"/>
<item android:id="@+id/back"
android:icon="@drawable/ic_menu_back"
android:title="@string/back"
android:visible="false"/>
<item android:id="@+id/forward"
android:icon="@drawable/ic_menu_forward"
android:title="@string/forward"
@ -17,11 +22,13 @@
<item android:id="@+id/bookmark"
android:icon="@drawable/ic_menu_bookmark_add"
android:title="@string/bookmark"/>
android:title="@string/bookmark"
android:showAsAction="ifRoom"/>
<item android:id="@+id/share"
android:icon="@drawable/ic_menu_share"
android:title="@string/share" />
android:title="@string/share"
android:showAsAction="ifRoom"/>
<item android:id="@+id/new_tab"
android:icon="@drawable/ic_menu_new_tab"

View File

@ -5,6 +5,11 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/back"
android:icon="@drawable/ic_menu_back"
android:title="@string/back"
android:showAsAction="always"/>
<item android:id="@+id/forward"
android:icon="@drawable/ic_menu_forward"
android:title="@string/forward"
@ -18,11 +23,12 @@
<item android:id="@+id/bookmark"
android:icon="@drawable/ic_menu_bookmark_add"
android:title="@string/bookmark"
android:showAsAction="always"/>
android:showAsAction="ifRoom"/>
<item android:id="@+id/share"
android:icon="@drawable/ic_menu_share"
android:title="@string/share" />
android:title="@string/share"
android:showAsAction="ifRoom"/>
<item android:id="@+id/new_tab"
android:icon="@drawable/ic_menu_new_tab"

View File

@ -10,6 +10,11 @@
android:title="@string/reload"
android:showAsAction="always"/>
<item android:id="@+id/back"
android:icon="@drawable/ic_menu_back"
android:title="@string/back"
android:visible="false"/>
<item android:id="@+id/forward"
android:icon="@drawable/ic_menu_forward"
android:title="@string/forward"
@ -22,7 +27,8 @@
<item android:id="@+id/share"
android:icon="@drawable/ic_menu_share"
android:title="@string/share" />
android:title="@string/share"
android:showAsAction="ifRoom"/>
<item android:id="@+id/new_tab"
android:icon="@drawable/ic_menu_new_tab"

View File

@ -9,6 +9,11 @@
android:icon="@drawable/ic_menu_reload"
android:title="@string/reload"/>
<item android:id="@+id/back"
android:icon="@drawable/ic_menu_back"
android:title="@string/back"
android:visible="false"/>
<item android:id="@+id/forward"
android:icon="@drawable/ic_menu_forward"
android:title="@string/forward"/>

View File

@ -61,6 +61,14 @@
<item name="android:paddingRight">0dp</item>
</style>
<style name="Widget.MenuItemActionBar">
<item name="android:layout_width">@dimen/browser_toolbar_height</item>
<item name="android:layout_height">@dimen/browser_toolbar_height</item>
<item name="android:padding">@dimen/browser_toolbar_button_padding</item>
<item name="android:background">@drawable/action_bar_button</item>
<item name="android:scaleType">fitCenter</item>
</style>
<style name="Widget.BookmarksListView" parent="Widget.HomeListView">
<item name="android:paddingTop">30dp</item>
<item name="android:paddingLeft">32dp</item>

View File

@ -42,12 +42,14 @@
<item name="menuItemActionBarStyle">@style/Widget.MenuItemActionBar</item>
<item name="menuItemActionViewStyle">@style/Widget.MenuItemActionView</item>
<item name="menuItemDefaultStyle">@style/Widget.MenuItemDefault</item>
<item name="menuItemShareActionButtonStyle">@style/Widget.MenuItemShareActionButton</item>
<item name="menuItemSecondaryActionBarStyle">@style/Widget.MenuItemSecondaryActionBar</item>
<item name="menuItemShareActionButtonStyle">@style/Widget.MenuItemSecondaryActionBar</item>
<item name="bookmarksListViewStyle">@style/Widget.BookmarksListView</item>
<item name="topSitesGridItemViewStyle">@style/Widget.TopSitesGridItemView</item>
<item name="topSitesGridViewStyle">@style/Widget.TopSitesGridView</item>
<item name="topSitesThumbnailViewStyle">@style/Widget.TopSitesThumbnailView</item>
<item name="homeListViewStyle">@style/Widget.HomeListView</item>
<item name="geckoMenuListViewStyle">@style/Widget.GeckoMenuListView</item>
<item name="menuItemActionModeStyle">@style/GeckoActionBar.Button</item>
<item name="android:actionModeStyle">@style/GeckoActionBar</item>
<item name="android:actionButtonStyle">@style/GeckoActionBar.Button</item>

View File

@ -8,6 +8,9 @@
<!-- Theme level attributes -->
<declare-styleable name="GeckoTheme">
<!-- Style for GeckoMenu ListView -->
<attr name="geckoMenuListViewStyle" format="reference"/>
<!-- Style for MenuItemActionBar -->
<attr name="menuItemActionBarStyle" format="reference"/>
@ -20,6 +23,9 @@
<!-- Style for MenuItemDefault -->
<attr name="menuItemDefaultStyle" format="reference"/>
<!-- Style for MenuItemActionBar when shown in SecondaryActionBar -->
<attr name="menuItemSecondaryActionBarStyle" format="reference"/>
<!-- Style for MenuItemActionView's ShareActionButton -->
<attr name="menuItemShareActionButtonStyle" format="reference"/>

View File

@ -74,25 +74,29 @@
<item name="android:minWidth">@dimen/doorhanger_input_width</item>
</style>
<style name="Widget.GeckoMenuListView" parent="Widget.ListView">
<item name="android:divider">#FFC9D3DC</item>
</style>
<style name="Widget.MenuItemActionBar">
<item name="android:padding">@dimen/browser_toolbar_button_padding</item>
<item name="android:padding">8dip</item>
<item name="android:background">@drawable/action_bar_button</item>
<item name="android:scaleType">fitCenter</item>
</style>
<style name="Widget.MenuItemSecondaryActionBar">
<item name="android:padding">8dip</item>
<item name="android:background">@drawable/action_bar_button</item>
<item name="android:scaleType">centerInside</item>
</style>
<style name="Widget.MenuItemActionView">
<item name="android:divider">@drawable/divider_vertical</item>
<item name="android:showDividers">middle</item>
<item name="android:dividerPadding">12dip</item>
<item name="android:dividerPadding">0dip</item>
<item name="android:gravity">left</item>
</style>
<style name="Widget.MenuItemShareActionButton">
<item name="android:padding">10dip</item>
<item name="android:background">@drawable/action_bar_button</item>
<item name="android:scaleType">centerInside</item>
</style>
<style name="Widget.MenuItemDefault">
<item name="android:paddingLeft">10dip</item>
<item name="android:paddingRight">10dip</item>

View File

@ -82,6 +82,7 @@
<item name="topSitesGridViewStyle">@style/Widget.TopSitesGridView</item>
<item name="topSitesThumbnailViewStyle">@style/Widget.TopSitesThumbnailView</item>
<item name="homeListViewStyle">@style/Widget.HomeListView</item>
<item name="geckoMenuListViewStyle">@style/Widget.GeckoMenuListView</item>
<item name="menuItemDefaultStyle">@style/Widget.MenuItemDefault</item>
<item name="menuItemActionBarStyle">@style/Widget.MenuItemActionBar</item>
<item name="menuItemActionModeStyle">@style/GeckoActionBar.Button</item>

View File

@ -962,6 +962,11 @@ public class BrowserToolbar extends GeckoRelativeLayout
setTitle(title);
}
public void showDefaultFavicon() {
mFavicon.setImageResource(R.drawable.favicon);
mLastFavicon = null;
}
private void setFavicon(Bitmap image) {
Log.d(LOGTAG, "setFavicon(" + image + ")");
if (Tabs.getInstance().getSelectedTab().getState() == Tab.STATE_LOADING) {

View File

@ -59,6 +59,14 @@ public class GeckoActionProvider extends ActionProvider {
historySize = 2;
}
// Historical data is dependent on past selection of activities.
// Activity count is determined by the number of activities that can handle
// the particular intent. When no intent is set, the activity count is 0,
// while the history count can be a valid number.
if (historySize > dataModel.getActivityCount()) {
return view;
}
for (int i = 0; i < historySize; i++) {
view.addActionButton(dataModel.getActivity(i).loadIcon(packageManager));
}
@ -105,6 +113,11 @@ public class GeckoActionProvider extends ActionProvider {
public void setIntent(Intent intent) {
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName);
dataModel.setIntent(intent);
// Inform the target listener to refresh it's UI, if needed.
if (mOnTargetListener != null) {
mOnTargetListener.onTargetSelected();
}
}
public void setOnTargetSelectedListener(OnTargetSelectedListener listener) {
@ -117,15 +130,16 @@ public class GeckoActionProvider extends ActionProvider {
private class Callbacks implements OnMenuItemClickListener,
OnClickListener {
private void chooseActivity(int index) {
if (mOnTargetListener != null)
mOnTargetListener.onTargetSelected();
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName);
Intent launchIntent = dataModel.chooseActivity(index);
if (launchIntent != null) {
launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
mContext.startActivity(launchIntent);
}
if (mOnTargetListener != null) {
mOnTargetListener.onTargetSelected();
}
}
@Override

View File

@ -137,15 +137,6 @@ public class GeckoPopupMenu implements GeckoMenu.Callback,
}
}
/**
* Show/hide the arrow pointing to the anchor.
*
* @param show Show/hide the arrow.
*/
public void showArrowToAnchor(boolean show) {
mMenuPopup.showArrowToAnchor(show);
}
@Override
public boolean onMenuItemSelected(MenuItem item) {
if (mClickListener != null)

View File

@ -6,6 +6,13 @@
const Cu = Components.utils;
const PREF_BRANCH = "toolkit.telemetry.";
#ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
const PREF_ENABLED = PREF_BRANCH + "enabledPreRelease";
#else
const PREF_ENABLED = PREF_BRANCH + "enabled";
#endif
this.EXPORTED_SYMBOLS = [
"UITelemetry",
];
@ -17,10 +24,55 @@ Cu.import("resource://gre/modules/Services.jsm");
*
* It implements nsIUITelemetryObserver, defined in nsIAndroidBridge.idl.
*/
this.UITelemetry = Object.freeze({
this.UITelemetry = {
_enabled: undefined,
_activeSessions: {},
_measurements: [],
// Lazily decide whether telemetry is enabled.
get enabled() {
if (this._enabled !== undefined) {
return this._enabled;
}
// Set an observer to watch for changes at runtime.
Services.prefs.addObserver(PREF_ENABLED, this, false);
Services.obs.addObserver(this, "profile-before-change", false);
// Pick up the current value.
try {
this._enabled = Services.prefs.getBoolPref(PREF_ENABLED);
} catch (e) {
this._enabled = false;
}
return this._enabled;
},
observe: function(aSubject, aTopic, aData) {
if (aTopic == "profile-before-change") {
Services.obs.removeObserver(this, "profile-before-change");
Services.prefs.removeObserver(PREF_ENABLED, this);
this._enabled = undefined;
return;
}
if (aTopic == "nsPref:changed") {
switch (aData) {
case PREF_ENABLED:
let on = Services.prefs.getBoolPref(PREF_ENABLED);
this._enabled = on;
// Wipe ourselves if we were just disabled.
if (!on) {
this._activeSessions = {};
this._measurements = [];
}
break;
}
}
},
/**
* This exists exclusively for testing -- our events are not intended to
* be retrieved via an XPCOM interface.
@ -46,6 +98,10 @@ this.UITelemetry = Object.freeze({
* All extant sessions will be recorded by name for each event.
*/
addEvent: function(aAction, aMethod, aTimestamp, aExtras) {
if (!this.enabled) {
return;
}
let sessions = Object.keys(this._activeSessions);
let aEvent = {
type: "event",
@ -66,6 +122,10 @@ this.UITelemetry = Object.freeze({
* Begins tracking a session by storing a timestamp for session start.
*/
startSession: function(aName, aTimestamp) {
if (!this.enabled) {
return;
}
if (this._activeSessions[aName]) {
// Do not overwrite a previous event start if it already exists.
return;
@ -77,6 +137,10 @@ this.UITelemetry = Object.freeze({
* Tracks the end of a session with a timestamp.
*/
stopSession: function(aName, aReason, aTimestamp) {
if (!this.enabled) {
return;
}
let sessionStart = this._activeSessions[aName];
delete this._activeSessions[aName];
@ -107,6 +171,10 @@ this.UITelemetry = Object.freeze({
* results of those functions.
*/
getSimpleMeasures: function() {
if (!this.enabled) {
return {};
}
let result = {};
for (let name in this._simpleMeasureFunctions) {
result[name] = this._simpleMeasureFunctions[name]();
@ -124,6 +192,10 @@ this.UITelemetry = Object.freeze({
* registered for it.
*/
addSimpleMeasureFunction: function(aName, aFunction) {
if (!this.enabled) {
return;
}
if (aName in this._simpleMeasureFunctions) {
throw new Error("A simple measurement function is already registered for " + aName);
}
@ -139,7 +211,11 @@ this.UITelemetry = Object.freeze({
delete this._simpleMeasureFunctions[aName];
},
getUIMeasurements: function getUIMeasurements() {
getUIMeasurements: function() {
if (!this.enabled) {
return [];
}
return this._measurements.slice();
}
});
};

View File

@ -35,6 +35,9 @@ EXTRA_JS_MODULES += [
'TelemetryFile.jsm',
'TelemetryStopwatch.jsm',
'ThirdPartyCookieProbe.jsm',
]
EXTRA_PP_JS_MODULES += [
'UITelemetry.jsm',
]

View File

@ -778,6 +778,9 @@ this.AddonRepository = {
getService(Ci.nsIAppStartup).
getStartupInfo();
params.TIME_MAIN = "";
params.TIME_FIRST_PAINT = "";
params.TIME_SESSION_RESTORED = "";
if (startupInfo.process) {
if (startupInfo.main) {
params.TIME_MAIN = startupInfo.main - startupInfo.process;