chromium/services/device/geolocation/win/fake_geolocator_winrt.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "services/device/geolocation/win/fake_geolocator_winrt.h"

#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/task/sequenced_task_runner.h"
#include "services/device/geolocation/win/fake_geocoordinate_winrt.h"
#include "services/device/geolocation/win/fake_position_changed_event_args_winrt.h"
#include "services/device/geolocation/win/fake_status_changed_event_args_winrt.h"

namespace device {
namespace {
using ABI::Windows::Devices::Geolocation::Geolocator;
using ABI::Windows::Devices::Geolocation::Geoposition;
using ABI::Windows::Devices::Geolocation::PositionAccuracy;
using ABI::Windows::Devices::Geolocation::PositionChangedEventArgs;
using ABI::Windows::Devices::Geolocation::PositionStatus;
using ABI::Windows::Devices::Geolocation::StatusChangedEventArgs;
using ABI::Windows::Foundation::IAsyncOperation;
using ABI::Windows::Foundation::ITypedEventHandler;
using ABI::Windows::Foundation::TimeSpan;
using Microsoft::WRL::ComPtr;
using Microsoft::WRL::Make;
}  // namespace

FakeGeolocatorWinrt::FakeGeolocatorWinrt(
    std::unique_ptr<FakeGeocoordinateData> position_data,
    PositionStatus position_status)
    : position_data_(std::move(position_data)),
      position_status_(position_status) {}

FakeGeolocatorWinrt::~FakeGeolocatorWinrt() = default;

IFACEMETHODIMP FakeGeolocatorWinrt::get_DesiredAccuracy(
    PositionAccuracy* value) {
  *value = accuracy_;
  return S_OK;
}

IFACEMETHODIMP FakeGeolocatorWinrt::put_DesiredAccuracy(
    PositionAccuracy value) {
  accuracy_ = value;
  return S_OK;
}

IFACEMETHODIMP FakeGeolocatorWinrt::get_MovementThreshold(DOUBLE* value) {
  *value = movement_threshold_;
  return S_OK;
}

IFACEMETHODIMP FakeGeolocatorWinrt::put_MovementThreshold(DOUBLE value) {
  movement_threshold_ = value;
  return S_OK;
}

IFACEMETHODIMP FakeGeolocatorWinrt::get_ReportInterval(UINT32* value) {
  return E_NOTIMPL;
}

IFACEMETHODIMP FakeGeolocatorWinrt::put_ReportInterval(UINT32 value) {
  return E_NOTIMPL;
}

IFACEMETHODIMP FakeGeolocatorWinrt::get_LocationStatus(PositionStatus* value) {
  return E_NOTIMPL;
}

IFACEMETHODIMP FakeGeolocatorWinrt::GetGeopositionAsync(
    IAsyncOperation<Geoposition*>** value) {
  return E_NOTIMPL;
}

IFACEMETHODIMP FakeGeolocatorWinrt::GetGeopositionAsyncWithAgeAndTimeout(
    TimeSpan maximumAge,
    TimeSpan timeout,
    IAsyncOperation<Geoposition*>** value) {
  return E_NOTIMPL;
}

void FakeGeolocatorWinrt::RunPositionChangedHandler(
    ITypedEventHandler<Geolocator*, PositionChangedEventArgs*>* handler) {
  if (!position_changed_token_.has_value() ||
      position_status_ != PositionStatus::PositionStatus_Ready) {
    return;
  }

  auto event_args =
      Make<FakePositionChangedEventArgs>(std::move(position_data_));
  handler->Invoke(this, event_args.Detach());
}

IFACEMETHODIMP FakeGeolocatorWinrt::add_PositionChanged(
    ITypedEventHandler<Geolocator*, PositionChangedEventArgs*>* handler,
    EventRegistrationToken* token) {
  position_changed_token_ = EventRegistrationToken();
  *token = position_changed_token_.value();
  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(
          &FakeGeolocatorWinrt::RunPositionChangedHandler,
          weak_ptr_factory_.GetWeakPtr(),
          ComPtr<ITypedEventHandler<Geolocator*, PositionChangedEventArgs*>>(
              handler)));
  return S_OK;
}

IFACEMETHODIMP FakeGeolocatorWinrt::remove_PositionChanged(
    EventRegistrationToken token) {
  DCHECK(position_changed_token_.has_value());
  DCHECK_EQ(token.value, position_changed_token_->value);
  position_changed_token_.reset();
  return S_OK;
}

void FakeGeolocatorWinrt::RunStatusChangedHandler(
    ITypedEventHandler<Geolocator*, StatusChangedEventArgs*>* handler) {
  if (!status_changed_token_.has_value())
    return;

  auto event_args = Make<FakeStatusChangedEventArgs>(position_status_);
  handler->Invoke(this, event_args.Detach());
}

IFACEMETHODIMP FakeGeolocatorWinrt::add_StatusChanged(
    ITypedEventHandler<Geolocator*, StatusChangedEventArgs*>* handler,
    EventRegistrationToken* token) {
  status_changed_token_ = EventRegistrationToken();
  *token = status_changed_token_.value();
  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(
          &FakeGeolocatorWinrt::RunStatusChangedHandler,
          weak_ptr_factory_.GetWeakPtr(),
          ComPtr<ITypedEventHandler<Geolocator*, StatusChangedEventArgs*>>(
              handler)));
  return S_OK;
}

IFACEMETHODIMP FakeGeolocatorWinrt::remove_StatusChanged(
    EventRegistrationToken token) {
  DCHECK(status_changed_token_.has_value());
  DCHECK_EQ(token.value, status_changed_token_->value);
  status_changed_token_.reset();
  return S_OK;
}

}  // namespace device