ledflasher: Implement base.identify and pairing session confirmation

Added a handler for base.identify command that would flash LEDs on the
board for 2 seconds. Also when the device goes into pairing mode, its
LEDs will flash as well to confirm that the client is connected to the
right physical device.

BUG: 26467076
Change-Id: I7ef31e9d2694c46b6d9c61b209f3e50b99fc3258
diff --git a/src/ledflasher/animation.cpp b/src/ledflasher/animation.cpp
index f58c8e9..34513d2 100644
--- a/src/ledflasher/animation.cpp
+++ b/src/ledflasher/animation.cpp
@@ -27,6 +27,10 @@
   : led_service_{led_service}, step_duration_{step_duration} {
 }
 
+Animation::~Animation() {
+  SetAllLEDs(false);
+}
+
 void Animation::Start() {
   DoAnimationStep();
   base::MessageLoop::current()->PostDelayedTask(
diff --git a/src/ledflasher/animation.h b/src/ledflasher/animation.h
index 0627f16..190e9a6 100644
--- a/src/ledflasher/animation.h
+++ b/src/ledflasher/animation.h
@@ -29,7 +29,7 @@
  public:
   Animation(android::sp<brillo::examples::ledflasher::ILEDService> led_service,
             const base::TimeDelta& step_duration);
-  virtual ~Animation() = default;
+  virtual ~Animation();
 
   void Start();
   void Stop();
diff --git a/src/ledflasher/ledflasher.cpp b/src/ledflasher/ledflasher.cpp
index f39dbf2..269c5be 100644
--- a/src/ledflasher/ledflasher.cpp
+++ b/src/ledflasher/ledflasher.cpp
@@ -34,6 +34,8 @@
 namespace {
 const char kWeaveComponent[] = "ledflasher";
 const char kWeaveTrait[] = "_ledflasher";
+const char kBaseComponent[] = "base";
+const char kBaseTrait[] = "base";
 }  // anonymous namespace
 
 using brillo::examples::ledflasher::ILEDService;
@@ -49,16 +51,21 @@
   void OnWeaveServiceConnected(const std::weak_ptr<weaved::Service>& service);
   void ConnectToLEDService();
   void OnLEDServiceDisconnected();
+  void OnPairingInfoChanged(const weaved::Service::PairingInfo* pairing_info);
 
   // Particular command handlers for various commands.
   void OnSet(std::unique_ptr<weaved::Command> command);
   void OnToggle(std::unique_ptr<weaved::Command> command);
   void OnAnimate(std::unique_ptr<weaved::Command> command);
+  void OnIdentify(std::unique_ptr<weaved::Command> command);
 
   // Helper methods to propagate device state changes to Buffet and hence to
   // the cloud server or local clients.
   void UpdateDeviceState();
 
+  void StartAnimation(const std::string& type, base::TimeDelta duration);
+  void StopAnimation();
+
   std::weak_ptr<weaved::Service> weave_service_;
 
   // Device state variables.
@@ -114,6 +121,13 @@
   weave_service->AddCommandHandler(
       kWeaveComponent, kWeaveTrait, "animate",
       base::Bind(&Daemon::OnAnimate, weak_ptr_factory_.GetWeakPtr()));
+  weave_service->AddCommandHandler(
+      kBaseComponent, kBaseTrait, "identify",
+      base::Bind(&Daemon::OnIdentify, weak_ptr_factory_.GetWeakPtr()));
+
+  weave_service->SetPairingInfoListener(
+      base::Bind(&Daemon::OnPairingInfoChanged,
+                 weak_ptr_factory_.GetWeakPtr()));
 
   UpdateDeviceState();
 }
@@ -203,8 +217,33 @@
     return;
   }
   std::string type = command->GetParameter<std::string>("type");
-  animation_ = Animation::Create(led_service_, type,
-                                 base::TimeDelta::FromSecondsD(duration));
+  StartAnimation(type, base::TimeDelta::FromSecondsD(duration));
+  command->Complete({}, nullptr);
+}
+
+void Daemon::OnIdentify(std::unique_ptr<weaved::Command> command) {
+  if (!led_service_.get()) {
+    command->Abort("_system_error", "ledservice unavailable", nullptr);
+    return;
+  }
+  StartAnimation("blink", base::TimeDelta::FromMilliseconds(500));
+  command->Complete({}, nullptr);
+
+  brillo::MessageLoop::current()->PostDelayedTask(
+      base::Bind(&Daemon::StopAnimation, weak_ptr_factory_.GetWeakPtr()),
+      base::TimeDelta::FromSeconds(2));
+}
+
+void Daemon::OnPairingInfoChanged(
+    const weaved::Service::PairingInfo* pairing_info) {
+  LOG(INFO) << "Daemon::OnPairingInfoChanged: " << pairing_info;
+  if (!pairing_info)
+    return StopAnimation();
+  StartAnimation("blink", base::TimeDelta::FromMilliseconds(500));
+}
+
+void Daemon::StartAnimation(const std::string& type, base::TimeDelta duration) {
+  animation_ = Animation::Create(led_service_, type, duration);
   if (animation_) {
     status_ = "animating";
     animation_->Start();
@@ -212,7 +251,15 @@
     status_ = "idle";
   }
   UpdateDeviceState();
-  command->Complete({}, nullptr);
+}
+
+void Daemon::StopAnimation() {
+  if (!animation_)
+    return;
+
+  animation_.reset();
+  status_ = "idle";
+  UpdateDeviceState();
 }
 
 void Daemon::UpdateDeviceState() {