Commit b6136a85 authored by Kyle Horimoto's avatar Kyle Horimoto Committed by Commit Bot

[CrOS PhoneHub] Create PhoneModel and MutablePhoneModel

PhoneModel stores an in-memory model of the phone during a Phone Hub
session. Currently, it only holds a PhoneStatusModel, but future CLs
will add support for other parts of the model (e.g., notifications,
Chrome tabs, and quick action button status).

PhoneModel also provides an observer interface for clients to use to be
notified when the model changes. This CL also creates the
MutablePhoneModel class, which provides setters which can cause the
model's data to change.

PhoneHubManager instantiates a MutablePhoneModel when it is created and
exposes it publicly via a PhoneModel*, which ensures that clients of the
model cannot edit its contents.

Bug: 1106937
Change-Id: I011c4f62916b158b291eb4abb0f38ab91fef7ac5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2365225
Commit-Queue: Kyle Horimoto <khorimoto@chromium.org>
Reviewed-by: default avatarRegan Hsu <hsuregan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799975}
parent 9f17ae81
...@@ -14,6 +14,8 @@ static_library("phonehub") { ...@@ -14,6 +14,8 @@ static_library("phonehub") {
"feature_status_provider.h", "feature_status_provider.h",
"feature_status_provider_impl.cc", "feature_status_provider_impl.cc",
"feature_status_provider_impl.h", "feature_status_provider_impl.h",
"mutable_phone_model.cc",
"mutable_phone_model.h",
"notification_access_manager.cc", "notification_access_manager.cc",
"notification_access_manager.h", "notification_access_manager.h",
"notification_access_manager_impl.cc", "notification_access_manager_impl.cc",
...@@ -22,6 +24,8 @@ static_library("phonehub") { ...@@ -22,6 +24,8 @@ static_library("phonehub") {
"notification_access_setup_operation.h", "notification_access_setup_operation.h",
"phone_hub_manager.cc", "phone_hub_manager.cc",
"phone_hub_manager.h", "phone_hub_manager.h",
"phone_model.cc",
"phone_model.h",
"phone_status_model.cc", "phone_status_model.cc",
"phone_status_model.h", "phone_status_model.h",
"pref_names.cc", "pref_names.cc",
...@@ -62,6 +66,7 @@ source_set("unit_tests") { ...@@ -62,6 +66,7 @@ source_set("unit_tests") {
sources = [ sources = [
"feature_status_provider_impl_unittest.cc", "feature_status_provider_impl_unittest.cc",
"mutable_phone_model_unittest.cc",
"notification_access_manager_impl_unittest.cc", "notification_access_manager_impl_unittest.cc",
"phone_status_model_unittest.cc", "phone_status_model_unittest.cc",
] ]
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/components/phonehub/mutable_phone_model.h"
namespace chromeos {
namespace phonehub {
MutablePhoneModel::MutablePhoneModel() = default;
MutablePhoneModel::~MutablePhoneModel() = default;
void MutablePhoneModel::SetPhoneStatusModel(
const base::Optional<PhoneStatusModel>& phone_status_model) {
if (phone_status_model_ == phone_status_model)
return;
phone_status_model_ = phone_status_model;
NotifyModelChanged();
}
} // namespace phonehub
} // namespace chromeos
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_COMPONENTS_PHONEHUB_MUTABLE_PHONE_MODEL_H_
#define CHROMEOS_COMPONENTS_PHONEHUB_MUTABLE_PHONE_MODEL_H_
#include "chromeos/components/phonehub/phone_model.h"
namespace chromeos {
namespace phonehub {
// Phone model which provides public API functions allowing the model to be
// updated.
class MutablePhoneModel : public PhoneModel {
public:
MutablePhoneModel();
~MutablePhoneModel() override;
void SetPhoneStatusModel(
const base::Optional<PhoneStatusModel>& phone_status_model);
};
} // namespace phonehub
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_PHONEHUB_MUTABLE_PHONE_MODEL_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/components/phonehub/mutable_phone_model.h"
#include "chromeos/components/phonehub/phone_model_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace phonehub {
namespace {
class FakeObserver : public PhoneModel::Observer {
public:
FakeObserver() = default;
~FakeObserver() override = default;
size_t num_calls() const { return num_calls_; }
// PhoneModel::Observer:
void OnModelChanged() override { ++num_calls_; }
private:
size_t num_calls_ = 0;
};
} // namespace
class MutablePhoneModelTest : public testing::Test {
protected:
MutablePhoneModelTest() = default;
MutablePhoneModelTest(const MutablePhoneModelTest&) = delete;
MutablePhoneModelTest& operator=(const MutablePhoneModelTest&) = delete;
~MutablePhoneModelTest() override = default;
// testing::Test:
void SetUp() override { model_.AddObserver(&fake_observer_); }
void TearDown() override { model_.RemoveObserver(&fake_observer_); }
size_t GetNumObserverCalls() const { return fake_observer_.num_calls(); }
protected:
MutablePhoneModel model_;
private:
FakeObserver fake_observer_;
};
TEST_F(MutablePhoneModelTest, PhoneStatusModel) {
// Set the PhoneStatusModel to be null (the default value); observers should
// not be notified, since this is not a change.
model_.SetPhoneStatusModel(/*phone_status_model=*/base::nullopt);
EXPECT_FALSE(model_.phone_status_model().has_value());
EXPECT_EQ(0u, GetNumObserverCalls());
// Set the PhoneStatusModel; observers should be notified.
model_.SetPhoneStatusModel(CreateFakePhoneStatusModel());
EXPECT_EQ(CreateFakePhoneStatusModel(), model_.phone_status_model());
EXPECT_EQ(1u, GetNumObserverCalls());
// Set the same PhoneStatusModel; observers should not be notified.
model_.SetPhoneStatusModel(CreateFakePhoneStatusModel());
EXPECT_EQ(CreateFakePhoneStatusModel(), model_.phone_status_model());
EXPECT_EQ(1u, GetNumObserverCalls());
// Set the PhoneStatusModel back to null; observers should be notified.
model_.SetPhoneStatusModel(/*phone_status_model=*/base::nullopt);
EXPECT_FALSE(model_.phone_status_model().has_value());
EXPECT_EQ(2u, GetNumObserverCalls());
}
} // namespace phonehub
} // namespace chromeos
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/no_destructor.h" #include "base/no_destructor.h"
#include "chromeos/components/phonehub/feature_status_provider_impl.h" #include "chromeos/components/phonehub/feature_status_provider_impl.h"
#include "chromeos/components/phonehub/mutable_phone_model.h"
#include "chromeos/components/phonehub/notification_access_manager_impl.h" #include "chromeos/components/phonehub/notification_access_manager_impl.h"
namespace chromeos { namespace chromeos {
...@@ -28,7 +29,8 @@ PhoneHubManager::PhoneHubManager( ...@@ -28,7 +29,8 @@ PhoneHubManager::PhoneHubManager(
device_sync_client, device_sync_client,
multidevice_setup_client)), multidevice_setup_client)),
notification_access_manager_( notification_access_manager_(
std::make_unique<NotificationAccessManagerImpl>(pref_service)) { std::make_unique<NotificationAccessManagerImpl>(pref_service)),
phone_model_(std::make_unique<MutablePhoneModel>()) {
DCHECK(!g_instance); DCHECK(!g_instance);
g_instance = this; g_instance = this;
} }
...@@ -39,6 +41,7 @@ void PhoneHubManager::Shutdown() { ...@@ -39,6 +41,7 @@ void PhoneHubManager::Shutdown() {
DCHECK(g_instance); DCHECK(g_instance);
g_instance = nullptr; g_instance = nullptr;
phone_model_.reset();
notification_access_manager_.reset(); notification_access_manager_.reset();
feature_status_provider_.reset(); feature_status_provider_.reset();
} }
......
...@@ -26,6 +26,7 @@ namespace phonehub { ...@@ -26,6 +26,7 @@ namespace phonehub {
class FeatureStatusProvider; class FeatureStatusProvider;
class NotificationAccessManager; class NotificationAccessManager;
class PhoneModel;
// Implements the core logic of the Phone Hub feature and exposes interfaces via // Implements the core logic of the Phone Hub feature and exposes interfaces via
// its public API. Implemented as a KeyedService which is keyed by the primary // its public API. Implemented as a KeyedService which is keyed by the primary
...@@ -55,12 +56,15 @@ class PhoneHubManager : public KeyedService { ...@@ -55,12 +56,15 @@ class PhoneHubManager : public KeyedService {
return notification_access_manager_.get(); return notification_access_manager_.get();
} }
PhoneModel* phone_model() { return phone_model_.get(); }
private: private:
// KeyedService: // KeyedService:
void Shutdown() override; void Shutdown() override;
std::unique_ptr<FeatureStatusProvider> feature_status_provider_; std::unique_ptr<FeatureStatusProvider> feature_status_provider_;
std::unique_ptr<NotificationAccessManager> notification_access_manager_; std::unique_ptr<NotificationAccessManager> notification_access_manager_;
std::unique_ptr<PhoneModel> phone_model_;
}; };
} // namespace phonehub } // namespace phonehub
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/components/phonehub/phone_model.h"
namespace chromeos {
namespace phonehub {
PhoneModel::PhoneModel() = default;
PhoneModel::~PhoneModel() = default;
void PhoneModel::AddObserver(Observer* observer) {
observer_list_.AddObserver(observer);
}
void PhoneModel::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
void PhoneModel::NotifyModelChanged() {
for (auto& observer : observer_list_)
observer.OnModelChanged();
}
} // namespace phonehub
} // namespace chromeos
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_COMPONENTS_PHONEHUB_PHONE_MODEL_H_
#define CHROMEOS_COMPONENTS_PHONEHUB_PHONE_MODEL_H_
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/optional.h"
#include "chromeos/components/phonehub/phone_status_model.h"
namespace chromeos {
namespace phonehub {
// Model representing the phone used for Phone Hub. Provides getters which
// return the state of the phone when connected, or null if disconnected. Also
// exposes an observer interface so that clients can be notified of changes to
// the model.
// TODO(khorimoto): Add additional metadata to this model.
class PhoneModel {
public:
class Observer : public base::CheckedObserver {
public:
~Observer() override = default;
// Called when some part of the model has changed.
virtual void OnModelChanged() = 0;
};
PhoneModel(const PhoneModel&) = delete;
PhoneModel& operator=(const PhoneModel&) = delete;
virtual ~PhoneModel();
const base::Optional<PhoneStatusModel>& phone_status_model() const {
return phone_status_model_;
}
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
protected:
PhoneModel();
void NotifyModelChanged();
base::Optional<PhoneStatusModel> phone_status_model_;
private:
base::ObserverList<Observer> observer_list_;
};
} // namespace phonehub
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_PHONEHUB_PHONE_MODEL_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment