feat: add app.getApplicationNameForProtocol API (#20399)

* Add GetApplicationNameForProtocol.

* Fix Windows implementation.

* Fix up test.

* Add documentation.

* Implement for real on Linux using xdg-mime.

Also ensure we allow blocking calls here to avoid errant DCHECKing.

* Improve docs for Linux.

* Clean up tests.

* Add a note about not relying on the precise format.

* Update docs/api/app.md

Co-Authored-By: Shelley Vohr <codebytere@github.com>

* Remove needless `done()`s from tests.

* Use vector list initialization.

* Add a simple test for isDefaultProtocolClient.

* Remove unneeded include and skip a test on Linux CI.

* We no longer differentiate between CI and non-CI test runs.
This commit is contained in:
Andrew MacDonald 2019-11-06 17:50:33 -08:00 committed by Shelley Vohr
parent 24939e8fa4
commit 9b01bb00d2
7 changed files with 183 additions and 20 deletions

View file

@ -25,6 +25,14 @@ namespace electron {
const char kXdgSettings[] = "xdg-settings";
const char kXdgSettingsDefaultSchemeHandler[] = "default-url-scheme-handler";
// The use of the ForTesting flavors is a hack workaround to avoid having to
// patch these as friends into the associated guard classes.
class LaunchXdgUtilityScopedAllowBaseSyncPrimitives
: public base::ScopedAllowBaseSyncPrimitivesForTesting {};
class GetXdgAppOutputScopedAllowBlocking
: public base::ScopedAllowBlockingForTesting {};
bool LaunchXdgUtility(const std::vector<std::string>& argv, int* exit_code) {
*exit_code = EXIT_FAILURE;
int devnull = open("/dev/null", O_RDONLY);
@ -39,24 +47,37 @@ bool LaunchXdgUtility(const std::vector<std::string>& argv, int* exit_code) {
if (!process.IsValid())
return false;
LaunchXdgUtilityScopedAllowBaseSyncPrimitives allow_base_sync_primitives;
return process.WaitForExit(exit_code);
}
base::Optional<std::string> GetXdgAppOutput(
const std::vector<std::string>& argv) {
std::string reply;
int success_code;
GetXdgAppOutputScopedAllowBlocking allow_blocking;
bool ran_ok = base::GetAppOutputWithExitCode(base::CommandLine(argv), &reply,
&success_code);
if (!ran_ok || success_code != EXIT_SUCCESS)
return base::Optional<std::string>();
return base::make_optional(reply);
}
bool SetDefaultWebClient(const std::string& protocol) {
std::unique_ptr<base::Environment> env(base::Environment::Create());
std::vector<std::string> argv;
argv.emplace_back(kXdgSettings);
argv.emplace_back("set");
std::vector<std::string> argv = {kXdgSettings, "set"};
if (!protocol.empty()) {
argv.emplace_back(kXdgSettingsDefaultSchemeHandler);
argv.push_back(protocol);
argv.emplace_back(protocol);
}
std::string desktop_name;
if (!env->GetVar("CHROME_DESKTOP", &desktop_name)) {
return false;
}
argv.push_back(desktop_name);
argv.emplace_back(desktop_name);
int exit_code;
bool ran_ok = LaunchXdgUtility(argv, &exit_code);
@ -91,27 +112,18 @@ bool Browser::IsDefaultProtocolClient(const std::string& protocol,
if (protocol.empty())
return false;
std::vector<std::string> argv;
argv.emplace_back(kXdgSettings);
argv.emplace_back("check");
argv.emplace_back(kXdgSettingsDefaultSchemeHandler);
argv.push_back(protocol);
std::string desktop_name;
if (!env->GetVar("CHROME_DESKTOP", &desktop_name))
return false;
argv.push_back(desktop_name);
std::string reply;
int success_code;
bool ran_ok = base::GetAppOutputWithExitCode(base::CommandLine(argv), &reply,
&success_code);
if (!ran_ok || success_code != EXIT_SUCCESS)
const std::vector<std::string> argv = {kXdgSettings, "check",
kXdgSettingsDefaultSchemeHandler,
protocol, desktop_name};
const auto output = GetXdgAppOutput(argv);
if (!output)
return false;
// Allow any reply that starts with "yes".
return base::StartsWith(reply, "yes", base::CompareCase::SENSITIVE) ? true
: false;
return base::StartsWith(output.value(), "yes", base::CompareCase::SENSITIVE);
}
// Todo implement
@ -120,6 +132,14 @@ bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol,
return false;
}
base::string16 Browser::GetApplicationNameForProtocol(const GURL& url) {
const std::vector<std::string> argv = {
"xdg-mime", "query", "default",
std::string("x-scheme-handler/") + url.scheme()};
return base::ASCIIToUTF16(GetXdgAppOutput(argv).value_or(std::string()));
}
bool Browser::SetBadgeCount(int count) {
if (IsUnityRunning()) {
unity::SetDownloadCount(count);