geolocation_impl.cc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "services/device/geolocation/geolocation_impl.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/metrics/histogram_macros.h"
  8. #include "services/device/geolocation/geolocation_context.h"
  9. #include "services/device/public/cpp/geolocation/geoposition.h"
  10. namespace device {
  11. namespace {
  12. // Geoposition error codes for reporting in UMA.
  13. enum GeopositionErrorCode {
  14. // NOTE: Do not renumber these as that would confuse interpretation of
  15. // previously logged data. When making changes, also update the enum list
  16. // in tools/metrics/histograms/histograms.xml to keep it in sync.
  17. // There was no error.
  18. GEOPOSITION_ERROR_CODE_NONE = 0,
  19. // User denied use of geolocation.
  20. GEOPOSITION_ERROR_CODE_PERMISSION_DENIED = 1,
  21. // Geoposition could not be determined.
  22. GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE = 2,
  23. // Timeout.
  24. GEOPOSITION_ERROR_CODE_TIMEOUT = 3,
  25. // NOTE: Add entries only immediately above this line.
  26. GEOPOSITION_ERROR_CODE_COUNT = 4
  27. };
  28. void RecordGeopositionErrorCode(mojom::Geoposition::ErrorCode error_code) {
  29. GeopositionErrorCode code = GEOPOSITION_ERROR_CODE_NONE;
  30. switch (error_code) {
  31. case mojom::Geoposition::ErrorCode::NONE:
  32. code = GEOPOSITION_ERROR_CODE_NONE;
  33. break;
  34. case mojom::Geoposition::ErrorCode::PERMISSION_DENIED:
  35. code = GEOPOSITION_ERROR_CODE_PERMISSION_DENIED;
  36. break;
  37. case mojom::Geoposition::ErrorCode::POSITION_UNAVAILABLE:
  38. code = GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE;
  39. break;
  40. case mojom::Geoposition::ErrorCode::TIMEOUT:
  41. code = GEOPOSITION_ERROR_CODE_TIMEOUT;
  42. break;
  43. }
  44. UMA_HISTOGRAM_ENUMERATION("Geolocation.LocationUpdate.ErrorCode", code,
  45. GEOPOSITION_ERROR_CODE_COUNT);
  46. }
  47. } // namespace
  48. GeolocationImpl::GeolocationImpl(mojo::PendingReceiver<Geolocation> receiver,
  49. GeolocationContext* context)
  50. : receiver_(this, std::move(receiver)),
  51. context_(context),
  52. high_accuracy_(false),
  53. has_position_to_report_(false) {
  54. DCHECK(context_);
  55. receiver_.set_disconnect_handler(base::BindOnce(
  56. &GeolocationImpl::OnConnectionError, base::Unretained(this)));
  57. }
  58. GeolocationImpl::~GeolocationImpl() {
  59. // Make sure to respond to any pending callback even without a valid position.
  60. if (!position_callback_.is_null()) {
  61. if (ValidateGeoposition(current_position_)) {
  62. current_position_.error_code = mojom::Geoposition::ErrorCode(
  63. GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE);
  64. current_position_.error_message.clear();
  65. }
  66. ReportCurrentPosition();
  67. }
  68. }
  69. void GeolocationImpl::PauseUpdates() {
  70. geolocation_subscription_ = {};
  71. }
  72. void GeolocationImpl::ResumeUpdates() {
  73. if (ValidateGeoposition(position_override_)) {
  74. OnLocationUpdate(position_override_);
  75. return;
  76. }
  77. StartListeningForUpdates();
  78. }
  79. void GeolocationImpl::StartListeningForUpdates() {
  80. geolocation_subscription_ =
  81. GeolocationProvider::GetInstance()->AddLocationUpdateCallback(
  82. base::BindRepeating(&GeolocationImpl::OnLocationUpdate,
  83. base::Unretained(this)),
  84. high_accuracy_);
  85. }
  86. void GeolocationImpl::SetHighAccuracy(bool high_accuracy) {
  87. high_accuracy_ = high_accuracy;
  88. if (ValidateGeoposition(position_override_)) {
  89. OnLocationUpdate(position_override_);
  90. return;
  91. }
  92. StartListeningForUpdates();
  93. }
  94. void GeolocationImpl::QueryNextPosition(QueryNextPositionCallback callback) {
  95. if (!position_callback_.is_null()) {
  96. DVLOG(1) << "Overlapped call to QueryNextPosition!";
  97. OnConnectionError(); // Simulate a connection error.
  98. return;
  99. }
  100. position_callback_ = std::move(callback);
  101. if (has_position_to_report_)
  102. ReportCurrentPosition();
  103. }
  104. void GeolocationImpl::SetOverride(const mojom::Geoposition& position) {
  105. if (!position_callback_.is_null())
  106. ReportCurrentPosition();
  107. position_override_ = position;
  108. if (!ValidateGeoposition(position_override_))
  109. ResumeUpdates();
  110. geolocation_subscription_ = {};
  111. OnLocationUpdate(position_override_);
  112. }
  113. void GeolocationImpl::ClearOverride() {
  114. position_override_ = mojom::Geoposition();
  115. StartListeningForUpdates();
  116. }
  117. void GeolocationImpl::OnConnectionError() {
  118. context_->OnConnectionError(this);
  119. // The above call deleted this instance, so the only safe thing to do is
  120. // return.
  121. }
  122. void GeolocationImpl::OnLocationUpdate(const mojom::Geoposition& position) {
  123. RecordGeopositionErrorCode(position.error_code);
  124. DCHECK(context_);
  125. current_position_ = position;
  126. current_position_.valid = ValidateGeoposition(position);
  127. has_position_to_report_ = true;
  128. if (!position_callback_.is_null())
  129. ReportCurrentPosition();
  130. }
  131. void GeolocationImpl::ReportCurrentPosition() {
  132. std::move(position_callback_).Run(current_position_.Clone());
  133. has_position_to_report_ = false;
  134. }
  135. } // namespace device