Bug 1363169 - Add support for native windows share. r=gijs, r=aklotz

MozReview-Commit-ID: 7quON7Somvr
This commit is contained in:
Dale Harvey 2018-09-26 21:09:00 +01:00
parent 4590e9df52
commit ce7a7296b3
10 changed files with 234 additions and 5 deletions

View File

@ -1203,6 +1203,12 @@ BrowserPageActions.addSearchEngine = {
// share URL
BrowserPageActions.shareURL = {
onCommand(event, buttonNode) {
let browser = gBrowser.selectedBrowser;
let currentURI = gURLBar.makeURIReadable(browser.currentURI).displaySpec;
this._windowsUIUtils.shareUrl(currentURI, browser.contentTitle);
},
onShowingInPanel(buttonNode) {
this._cached = false;
},
@ -1264,7 +1270,7 @@ BrowserPageActions.shareURL = {
};
// Attach sharingService here so tests can override the implementation
XPCOMUtils.defineLazyServiceGetter(BrowserPageActions.shareURL,
"_sharingService",
"@mozilla.org/widget/macsharingservice;1",
"nsIMacSharingService");
XPCOMUtils.defineLazyServiceGetters(BrowserPageActions.shareURL, {
_sharingService: ["@mozilla.org/widget/macsharingservice;1", "nsIMacSharingService"],
_windowsUIUtils: ["@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils"],
});

View File

@ -57,6 +57,10 @@ support-files =
subsuite = clipboard
[browser_page_action_menu_share_mac.js]
skip-if = os != "mac" # Mac only feature
[browser_page_action_menu_share_win.js]
support-files =
browser_page_action_menu_share_win.html
skip-if = os != "win" # Windows only feature
[browser_pasteAndGo.js]
subsuite = clipboard
[browser_populateAfterPushState.js]

View File

@ -0,0 +1,2 @@
<!doctype html>
<title>Windows Sharing</title>

View File

@ -0,0 +1,49 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/* global sinon */
Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js");
const TEST_URL = getRootDirectory(gTestPath) + "browser_page_action_menu_share_win.html";
// Keep track of site details we are sharing
let sharedUrl, sharedTitle;
let stub = sinon.stub(BrowserPageActions.shareURL, "_windowsUIUtils").get(() => {
return {
shareUrl(url, title) {
sharedUrl = url;
sharedTitle = title;
},
};
});
registerCleanupFunction(async function() {
stub.restore();
delete window.sinon;
});
add_task(async function shareURL() {
if (!AppConstants.isPlatformAndVersionAtLeast("win", "6.4")) {
Assert.ok(true, "We only expose share on windows 10 and above");
return;
}
await BrowserTestUtils.withNewTab(TEST_URL, async () => {
// Open the panel.
await promisePageActionPanelOpen();
// Click Share URL.
let shareURLButton = document.getElementById("pageAction-panel-shareURL");
let hiddenPromise = promisePageActionPanelHidden();
EventUtils.synthesizeMouseAtCenter(shareURLButton, {});
await hiddenPromise;
Assert.equal(sharedUrl, TEST_URL, "Shared correct URL");
Assert.equal(sharedTitle, "Windows Sharing", "Shared with the correct title");
});
});

View File

@ -1185,6 +1185,21 @@ if (AppConstants.platform == "macosx") {
});
}
if (AppConstants.isPlatformAndVersionAtLeast("win", "6.4")) {
gBuiltInActions.push(
// Share URL
{
id: "shareURL",
title: "shareURL-title",
onBeforePlacedInWindow(buttonNode) {
browserPageActions(buttonNode).shareURL.onBeforePlacedInWindow(buttonNode);
},
onCommand(event, buttonNode) {
browserPageActions(buttonNode).shareURL.onCommand(event, buttonNode);
},
});
}
/**
* Gets a BrowserPageActions object in a browser window.
*

View File

@ -597,6 +597,10 @@ html|*.urlbar-input:-moz-lwtheme::placeholder,
color: GrayText;
}
#pageAction-panel-shareURL {
list-style-image: url("chrome://browser/skin/share.svg");
}
%include ../shared/urlbarSearchSuggestionsNotification.inc.css
#search-container {

View File

@ -41,6 +41,7 @@ browser.jar:
* skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
* skin/classic/browser/preferences/in-content/dialog.css (preferences/in-content/dialog.css)
skin/classic/browser/preferences/applications.css (preferences/applications.css)
skin/classic/browser/share.svg (share.svg)
skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png)
skin/classic/browser/window-controls/close.svg (window-controls/close.svg)
skin/classic/browser/window-controls/close-highcontrast.svg (window-controls/close-highcontrast.svg)

View File

@ -0,0 +1,7 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path fill="context-fill" d="M 15.707 4.293 l -4 -4 a 1 1 0 0 0 -1.414 1.414 L 12.585 4 H 11 a 7.008 7.008 0 0 0 -7 7 a 1 1 0 0 0 2 0 a 5.006 5.006 0 0 1 5 -5 h 1.585 l -2.293 2.293 a 1 1 0 1 0 1.414 1.414 l 4 -4 a 1 1 0 0 0 0.001 -1.414 Z" />
<path fill="context-fill" d="M 13 11 a 1 1 0 0 0 -1 1 v 1 a 1 1 0 0 1 -1 1 H 3 a 1 1 0 0 1 -1 -1 V 6 a 1 1 0 0 1 1 -1 h 1 a 1 1 0 0 0 0 -2 H 3 a 3 3 0 0 0 -3 3 v 7 a 3 3 0 0 0 3 3 h 8 a 3 3 0 0 0 3 -3 v -1 a 1 1 0 0 0 -1 -1 Z" />
</svg>

After

Width:  |  Height:  |  Size: 781 B

View File

@ -20,5 +20,9 @@ interface nsIWindowsUIUtils : nsISupports
* Update the tablet mode state
*/
void updateTabletModeState();
};
/**
* Share URL
*/
void shareUrl(in AString shareTitle, in AString urlToShare);
};

View File

@ -35,6 +35,7 @@ using namespace ABI::Windows::UI::ViewManagement;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::ApplicationModel::DataTransfer;
/* All of this is win10 stuff and we're compiling against win81 headers
* for now, so we may need to do some legwork: */
@ -90,6 +91,21 @@ public:
};
#endif
#ifndef __IDataTransferManagerInterop_INTERFACE_DEFINED__
#define __IDataTransferManagerInterop_INTERFACE_DEFINED__
typedef interface IDataTransferManagerInterop IDataTransferManagerInterop;
MIDL_INTERFACE("3A3DCD6C-3EAB-43DC-BCDE-45671CE800C8")
IDataTransferManagerInterop : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE GetForWindow(HWND appWindow, REFIID riid, void **dataTransferManager) = 0;
virtual HRESULT STDMETHODCALLTYPE ShowShareUIForWindow(HWND appWindow) = 0;
};
#endif
#endif
WindowsUIUtils::WindowsUIUtils() :
@ -178,3 +194,124 @@ WindowsUIUtils::UpdateTabletModeState()
return NS_OK;
}
struct HStringDeleter
{
typedef HSTRING pointer;
void operator()(pointer aString)
{
WindowsDeleteString(aString);
}
};
typedef mozilla::UniquePtr<HSTRING, HStringDeleter> HStringUniquePtr;
NS_IMETHODIMP
WindowsUIUtils::ShareUrl(const nsAString& aUrlToShare,
const nsAString& aShareTitle)
{
#ifndef __MINGW32__
if (!IsWin10OrLater()) {
return NS_OK;
}
HSTRING rawTitle;
HRESULT hr = WindowsCreateString(PromiseFlatString(aShareTitle).get(), aShareTitle.Length(), &rawTitle);
if (FAILED(hr)) {
return NS_OK;
}
HStringUniquePtr title(rawTitle);
HSTRING rawUrl;
hr = WindowsCreateString(PromiseFlatString(aUrlToShare).get(), aUrlToShare.Length(), &rawUrl);
if (FAILED(hr)) {
return NS_OK;
}
HStringUniquePtr url(rawUrl);
ComPtr<IUriRuntimeClassFactory> uriFactory;
hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_Uri).Get(), &uriFactory);
if (FAILED(hr)) {
return NS_OK;
}
ComPtr<IUriRuntimeClass> uri;
hr = uriFactory->CreateUri(url.get(), &uri);
if (FAILED(hr)) {
return NS_OK;
}
HWND hwnd = GetForegroundWindow();
if (!hwnd) {
return NS_OK;
}
ComPtr<IDataTransferManagerInterop> dtmInterop;
hr = RoGetActivationFactory(HStringReference(
RuntimeClass_Windows_ApplicationModel_DataTransfer_DataTransferManager)
.Get(), IID_PPV_ARGS(&dtmInterop));
if (FAILED(hr)) {
return NS_OK;
}
ComPtr<IDataTransferManager> dtm;
hr = dtmInterop->GetForWindow(hwnd, IID_PPV_ARGS(&dtm));
if (FAILED(hr)) {
return NS_OK;
}
auto callback = Callback < ITypedEventHandler<DataTransferManager*, DataRequestedEventArgs* >> (
[uri = std::move(uri), title = std::move(title)](IDataTransferManager*, IDataRequestedEventArgs* pArgs) -> HRESULT
{
ComPtr<IDataRequest> spDataRequest;
HRESULT hr = pArgs->get_Request(&spDataRequest);
if (FAILED(hr)) {
return hr;
}
ComPtr<IDataPackage> spDataPackage;
hr = spDataRequest->get_Data(&spDataPackage);
if (FAILED(hr)) {
return hr;
}
ComPtr<IDataPackage2> spDataPackage2;
hr = spDataPackage->QueryInterface(IID_PPV_ARGS(&spDataPackage2));
if (FAILED(hr)) {
return hr;
}
ComPtr<IDataPackagePropertySet> spDataPackageProperties;
hr = spDataPackage->get_Properties(&spDataPackageProperties);
if (FAILED(hr)) {
return hr;
}
hr = spDataPackageProperties->put_Title(title.get());
if (FAILED(hr)) {
return hr;
}
hr = spDataPackage2->SetWebLink(uri.Get());
if (FAILED(hr)) {
return hr;
}
return S_OK;
});
EventRegistrationToken dataRequestedToken;
hr = dtm->add_DataRequested(callback.Get(), &dataRequestedToken);
if (FAILED(hr)) {
return NS_OK;
}
hr = dtmInterop->ShowShareUIForWindow(hwnd);
if (FAILED(hr)) {
return NS_OK;
}
#endif
return NS_OK;
}