chromium/content/browser/installedapp/native_win_app_fetcher_impl.cc

// 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