// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/installedapp/native_win_app_fetcher_impl.h"
#include <windows.foundation.h>
#include <string>
#include <vector>
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/types/expected.h"
#include "base/win/async_operation.h"
#include "base/win/core_winrt_util.h"
#include "base/win/post_async_results.h"
#include "base/win/vector.h"
#include "third_party/blink/public/mojom/installedapp/related_application.mojom.h"
namespace content {
namespace {
constexpr char kWindowsPlatformName[] = "windows";
using ABI::Windows::ApplicationModel::AppInfo;
using ABI::Windows::ApplicationModel::IAppInfo;
using ABI::Windows::Foundation::IAsyncOperation;
using ABI::Windows::Foundation::IAsyncOperationCompletedHandler;
using ABI::Windows::Foundation::IUriRuntimeClass;
using ABI::Windows::Foundation::IUriRuntimeClassFactory;
using ABI::Windows::Foundation::Collections::IVectorView;
using ABI::Windows::System::ILauncherStatics4;
using Microsoft::WRL::Callback;
using Microsoft::WRL::ComPtr;
} // namespace
NativeWinAppFetcherImpl::NativeWinAppFetcherImpl() = default;
NativeWinAppFetcherImpl::~NativeWinAppFetcherImpl() = default;
void NativeWinAppFetcherImpl::FetchAppsForUrl(
const GURL& url,
base::OnceCallback<void(std::vector<blink::mojom::RelatedApplicationPtr>)>
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
callback_ = std::move(callback);
ComPtr<IUriRuntimeClassFactory> url_factory;
HRESULT hr =
base::win::GetActivationFactory<IUriRuntimeClassFactory,
RuntimeClass_Windows_Foundation_Uri>(
&url_factory);
if (FAILED(hr)) {
return OnFailure();
}
ComPtr<IUriRuntimeClass> url_win;
hr = url_factory->CreateUri(
base::win::ScopedHString::Create(url.spec()).get(), &url_win);
if (FAILED(hr)) {
return OnFailure();
}
ComPtr<ILauncherStatics4> launcher;
hr = base::win::GetActivationFactory<ILauncherStatics4,
RuntimeClass_Windows_System_Launcher>(
&launcher);
if (FAILED(hr)) {
return OnFailure();
}
// FindAppUriHandlersAsync API returns list of apps that is validated
// by the sites.
// https://docs.microsoft.com/en-us/windows/uwp/
// launch-resume/web-to-app-linking
hr = launcher->FindAppUriHandlersAsync(url_win.Get(), &enum_operation_);
if (FAILED(hr)) {
return OnFailure();
}
base::win::PostAsyncHandlers(
enum_operation_.Get(),
base::BindOnce(&NativeWinAppFetcherImpl::OnGetAppUriHandlers,
weak_ptr_factory_.GetWeakPtr())),
base::BindOnce(&NativeWinAppFetcherImpl::OnFailure,
weak_ptr_factory_.GetWeakPtr());
}
void NativeWinAppFetcherImpl::OnGetAppUriHandlers(
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVectorView<
ABI::Windows::ApplicationModel::AppInfo*>> found_app_list) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::vector<blink::mojom::RelatedApplicationPtr> found_related_apps;
if (!found_app_list) {
return OnFailure();
}
UINT found_app_url_size = 0;
HRESULT hr = found_app_list->get_Size(&found_app_url_size);
if (FAILED(hr) || found_app_url_size == 0) {
return OnFailure();
}
for (size_t i = 0; i < found_app_url_size; ++i) {
ComPtr<IAppInfo> app_info;
hr = found_app_list->GetAt(i, &app_info);
if (FAILED(hr)) {
continue;
}
HSTRING app_user_model_id_native;
hr = app_info->get_AppUserModelId(&app_user_model_id_native);
if (FAILED(hr)) {
continue;
}
std::wstring app_user_model_id(
base::win::ScopedHString(app_user_model_id_native).Get());
auto application = blink::mojom::RelatedApplication::New();
application->platform = kWindowsPlatformName;
application->id = base::WideToASCII(app_user_model_id);
found_related_apps.push_back(std::move(application));
}
CHECK(callback_);
return std::move(callback_).Run(std::move(found_related_apps));
}
void NativeWinAppFetcherImpl::OnFailure() {
return std::move(callback_).Run(
std::vector<blink::mojom::RelatedApplicationPtr>());
}
} // namespace content