blob: 66a7ab4fd9baf803324ddcd3f89c2269fe0ae894 [file] [log] [blame]
// Copyright 2016 The Fuchsia 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 <memory>
#include <fuchsia/cpp/modular.h>
#include <fuchsia/cpp/modular_calculator_example.h>
#include <fuchsia/cpp/images.h>
#include <fuchsia/cpp/views_v1.h>
#include <fuchsia/cpp/views_v1_token.h>
#include <lib/async/cpp/task.h>
#include <lib/async/default.h>
#include "lib/app/cpp/application_context.h"
#include "lib/app/cpp/connect.h"
#include "lib/app_driver/cpp/app_driver.h"
#include "lib/fidl/cpp/interface_request.h"
#include "lib/fsl/tasks/message_loop.h"
#include "lib/fxl/functional/make_copyable.h"
#include "lib/fxl/logging.h"
#include "lib/fxl/memory/weak_ptr.h"
#include "lib/fxl/time/time_delta.h"
#include "lib/ui/view_framework/base_view.h"
#include "peridot/examples/counter_cpp/store.h"
#include "peridot/lib/fidl/single_service_app.h"
namespace {
constexpr float kBackgroundElevation = 0.f;
constexpr float kSquareElevation = 8.f;
constexpr int kTickRotationDegrees = 45;
constexpr int kAnimationDelayInMs = 50;
constexpr char kModuleName[] = "Module1Impl";
class Module1View : public mozart::BaseView {
public:
explicit Module1View(
modular_example::Store* const store,
views_v1::ViewManagerPtr view_manager,
fidl::InterfaceRequest<views_v1_token::ViewOwner> view_owner_request)
: BaseView(std::move(view_manager),
std::move(view_owner_request),
kModuleName),
store_(store),
background_node_(session()),
square_node_(session()) {
scenic_lib::Material background_material(session());
background_material.SetColor(0x67, 0x3a, 0xb7, 0xff); // Deep Purple 500
background_node_.SetMaterial(background_material);
parent_node().AddChild(background_node_);
scenic_lib::Material square_material(session());
square_material.SetColor(0x00, 0xe6, 0x76, 0xff); // Green A400
square_node_.SetMaterial(square_material);
parent_node().AddChild(square_node_);
}
~Module1View() override = default;
private:
// Copied from
// https://fuchsia.googlesource.com/garnet/+/master/examples/ui/spinning_square/spinning_square_view.cc
// |BaseView|:
void OnSceneInvalidated(
images::PresentationInfo /*presentation_info*/) override {
if (!has_logical_size()) {
return;
}
const float center_x = logical_size().width * .5f;
const float center_y = logical_size().height * .5f;
const float square_size =
std::min(logical_size().width, logical_size().height) * .6f;
const float angle =
kTickRotationDegrees * store_->counter.counter * M_PI * 2;
scenic_lib::Rectangle background_shape(session(), logical_size().width,
logical_size().height);
background_node_.SetShape(background_shape);
background_node_.SetTranslation(
(float[]){center_x, center_y, kBackgroundElevation});
scenic_lib::Rectangle square_shape(session(), square_size, square_size);
square_node_.SetShape(square_shape);
square_node_.SetTranslation(
(float[]){center_x, center_y, kSquareElevation});
square_node_.SetRotation(
(float[]){0.f, 0.f, sinf(angle * .5f), cosf(angle * .5f)});
}
modular_example::Store* const store_;
scenic_lib::ShapeNode background_node_;
scenic_lib::ShapeNode square_node_;
FXL_DISALLOW_COPY_AND_ASSIGN(Module1View);
};
class MultiplierImpl : public modular_calculator_example::Multiplier {
public:
MultiplierImpl() = default;
private:
// |Multiplier|
void Multiply(int32_t a, int32_t b, MultiplyCallback result) override {
result(a * b);
}
FXL_DISALLOW_COPY_AND_ASSIGN(MultiplierImpl);
};
// Module implementation that acts as a leaf module. It implements Module.
class Module1App : modular::SingleServiceApp<modular::Module> {
public:
explicit Module1App(component::ApplicationContext* const application_context)
: SingleServiceApp(application_context),
store_(kModuleName),
weak_ptr_factory_(this) {
// TODO(mesch): The callbacks seem to have a sequential relationship.
// It seems to me there should be a single callback that does all three
// things in a sequence. Since the result InvalidateScene() happens only
// (asynchonously) later, the order here really doesn't matter, but it's
// only accidentally so.
store_.AddCallback([this] {
if (view_) {
view_->InvalidateScene();
}
});
store_.AddCallback([this] { IncrementCounterAction(); });
store_.AddCallback([this] { CheckForDone(); });
}
~Module1App() override = default;
// |SingleServiceApp|
void Terminate(std::function<void()> done) override {
store_.Stop();
done();
}
private:
// |SingleServiceApp|
void CreateView(
fidl::InterfaceRequest<views_v1_token::ViewOwner> view_owner_request,
fidl::InterfaceRequest<component::ServiceProvider> /*services*/)
override {
view_ = std::make_unique<Module1View>(
&store_,
application_context()
->ConnectToEnvironmentService<views_v1::ViewManager>(),
std::move(view_owner_request));
}
// |Module|
void Initialize(fidl::InterfaceHandle<modular::ModuleContext> module_context,
fidl::InterfaceRequest<component::ServiceProvider>
outgoing_services) override {
FXL_CHECK(outgoing_services.is_valid());
module_context_.Bind(std::move(module_context));
modular::LinkPtr link;
module_context_->GetLink("theOneLink", link.NewRequest());
store_.Initialize(std::move(link));
// Provide services to the recipe module.
outgoing_services_.AddBinding(std::move(outgoing_services));
outgoing_services_.AddService<modular_calculator_example::Multiplier>(
[this](fidl::InterfaceRequest<modular_calculator_example::Multiplier> req) {
multiplier_clients_.AddBinding(&multiplier_service_, std::move(req));
});
module_context_->Ready();
}
void CheckForDone() {
if (store_.counter.counter > 10) {
module_context_->Done();
}
}
void IncrementCounterAction() {
if (store_.counter.sender == kModuleName || store_.counter.counter > 10) {
return;
}
fxl::WeakPtr<Module1App> module_ptr = weak_ptr_factory_.GetWeakPtr();
async::PostDelayedTask(
async_get_default(),
[this, module_ptr] {
if (!module_ptr.get() || store_.terminating()) {
return;
}
store_.counter.sender = kModuleName;
store_.counter.counter += 1;
FXL_LOG(INFO) << "Module1Impl COUNT " << store_.counter.counter;
store_.MarkDirty();
store_.ModelChanged();
},
zx::msec(kAnimationDelayInMs));
}
// This is a ServiceProvider we expose to our parent (recipe) module, to
// demonstrate the use of a service exchange.
fidl::BindingSet<modular_calculator_example::Multiplier> multiplier_clients_;
MultiplierImpl multiplier_service_;
component::ServiceNamespace outgoing_services_;
std::unique_ptr<Module1View> view_;
modular::ModuleContextPtr module_context_;
modular_example::Store store_;
// Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed.
fxl::WeakPtrFactory<Module1App> weak_ptr_factory_;
FXL_DISALLOW_COPY_AND_ASSIGN(Module1App);
};
} // namespace
int main(int /*argc*/, const char** /*argv*/) {
fsl::MessageLoop loop;
auto app_context = component::ApplicationContext::CreateFromStartupInfo();
modular::AppDriver<Module1App> driver(
app_context->outgoing_services(),
std::make_unique<Module1App>(app_context.get()),
[&loop] { loop.QuitNow(); });
loop.Run();
return 0;
}