media_perception: Adds smart_framing.mojom and output handling for proto.

smart_framing.mojom pushes a proto serialized as a uint8 array to the
client as per security approval in go/mps-serialized-protos

BUG=chromium:1059006

Change-Id: I03920799002f4a4853b86fea69d720352eddb214
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2090240
Reviewed-by: Mustafa Emre Acer <meacer@chromium.org>
Reviewed-by: Toni Baržić <tbarzic@chromium.org>
Commit-Queue: Luke Sorenson <lasoren@chromium.org>
Tested-by: Luke Sorenson <lasoren@chromium.org>
(cherry picked from commit 8c57e7f7372a003aece7eea68c3fe5f1b6309b42)
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2115746
Reviewed-by: Greg Kerr <kerrnel@chromium.org>
diff --git a/media_perception/BUILD.gn b/media_perception/BUILD.gn
index 9608400..1c9e670 100644
--- a/media_perception/BUILD.gn
+++ b/media_perception/BUILD.gn
@@ -61,6 +61,7 @@
     "mojom/producer.mojom",
     "mojom/scoped_access_permission.mojom",
     "mojom/shared_memory.mojom",
+    "mojom/one_touch_autozoom.mojom",
     "mojom/sync_token.mojom",
     "mojom/time.mojom",
     "mojom/unguessable_token.mojom",
diff --git a/media_perception/mojom/media_perception.mojom b/media_perception/mojom/media_perception.mojom
index 9a0fc30..8139ec1 100644
--- a/media_perception/mojom/media_perception.mojom
+++ b/media_perception/mojom/media_perception.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Next MinVersion: 2
+// Next MinVersion: 3
 
 module chromeos.media_perception.mojom;
 
@@ -13,6 +13,7 @@
 import "mojom/occupancy_trigger.mojom";
 import "mojom/pipeline.mojom";
 import "mojom/presence_perception.mojom";
+import "mojom/one_touch_autozoom.mojom";
 
 struct SuccessStatus {
   // Whether or not the action succeeded.
@@ -27,6 +28,7 @@
   PresencePerceptionHandler&? presence_perception_handler_request@2;
   OccupancyTriggerHandler&? occupancy_trigger_handler_request@3;
   [MinVersion=1] AppearancesHandler&? appearances_handler_request@4;
+  [MinVersion=2] OneTouchAutozoomHandler&? one_touch_autozoom_handler_request@5;
 };
 
 interface MediaPerception {
diff --git a/media_perception/mojom/one_touch_autozoom.mojom b/media_perception/mojom/one_touch_autozoom.mojom
new file mode 100644
index 0000000..c4c1484
--- /dev/null
+++ b/media_perception/mojom/one_touch_autozoom.mojom
@@ -0,0 +1,13 @@
+// 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.
+//
+// Next MinVersion: 1
+
+module chromeos.media_perception.mojom;
+
+interface OneTouchAutozoomHandler {
+  // Callback for smart framing proto that comes out of the pipeline.
+  OnSmartFraming(array<uint8> smart_framing);
+};
+
diff --git a/media_perception/output_manager.cc b/media_perception/output_manager.cc
index 604b218..8695daf 100644
--- a/media_perception/output_manager.cc
+++ b/media_perception/output_manager.cc
@@ -179,6 +179,36 @@
       }
       continue;
     }
+
+    // One touch Autozoom interface setup.
+    if (interface.interface_type() ==
+        PerceptionInterfaceType::INTERFACE_ONE_TOUCH_AUTOZOOM) {
+      (*interfaces_ptr)->one_touch_autozoom_handler_request =
+          mojo::MakeRequest(&one_touch_autozoom_handler_ptr_);
+      one_touch_autozoom_handler_ptr_.set_connection_error_handler(
+          base::Bind(&OnConnectionClosedOrError,
+          "ONE_TOUCH_AUTOZOOM"));
+
+      // One touch Autozoom outputs setup.
+      for (const PipelineOutput& output : interface.output()) {
+        if (output.output_type() ==
+            PipelineOutputType::OUTPUT_SMART_FRAMING) {
+          SerializedSuccessStatus serialized_status =
+              rtanalytics->SetPipelineOutputHandler(
+                  configuration_name, output.stream_name(),
+                  std::bind(&OutputManager::HandleSmartFraming,
+                            this, std::placeholders::_1));
+          SuccessStatus status = Serialized<SuccessStatus>(
+              serialized_status).Deserialize();
+          if (!status.success()) {
+            LOG(ERROR) << "Failed to set output handler for "
+                       << configuration_name << " with output "
+                       << output.stream_name();
+          }
+        }
+      }
+      continue;
+    }
   }
 }
 
@@ -271,4 +301,20 @@
   appearances_handler_ptr_->OnAppearances(bytes);
 }
 
+void OutputManager::HandleSmartFraming(
+    const std::vector<uint8_t>& bytes) {
+  if (!one_touch_autozoom_handler_ptr_.is_bound()) {
+    LOG(WARNING)
+        << "Got smart framing proto but handler ptr is not bound.";
+    return;
+  }
+
+  if (one_touch_autozoom_handler_ptr_.get() == nullptr) {
+    LOG(ERROR) << "Handler ptr is null.";
+    return;
+  }
+
+  one_touch_autozoom_handler_ptr_->OnSmartFraming(bytes);
+}
+
 }  // namespace mri
diff --git a/media_perception/output_manager.h b/media_perception/output_manager.h
index dfe6870..ff80cf5 100644
--- a/media_perception/output_manager.h
+++ b/media_perception/output_manager.h
@@ -40,6 +40,8 @@
 
   void HandleAppearances(const std::vector<uint8_t>& bytes);
 
+  void HandleSmartFraming(const std::vector<uint8_t>& bytes);
+
  private:
   chromeos::media_perception::mojom::FramePerceptionHandlerPtr
       frame_perception_handler_ptr_;
@@ -55,6 +57,9 @@
 
   chromeos::media_perception::mojom::AppearancesHandlerPtr
       appearances_handler_ptr_;
+
+  chromeos::media_perception::mojom::OneTouchAutozoomHandlerPtr
+      one_touch_autozoom_handler_ptr_;
 };
 
 }  // namespace mri
diff --git a/media_perception/output_manager_test.cc b/media_perception/output_manager_test.cc
index 1b9a178..e71f67e 100644
--- a/media_perception/output_manager_test.cc
+++ b/media_perception/output_manager_test.cc
@@ -27,7 +27,7 @@
   FramePerceptionHandlerImpl(
       chromeos::media_perception::mojom::FramePerceptionHandlerRequest
       request) : binding_(this, std::move(request)) {
-    LOG(INFO) << "Binding is bound: " << binding_.is_bound();
+    EXPECT_TRUE(binding_.is_bound());
   }
 
   void OnFramePerception(
@@ -48,7 +48,7 @@
   HotwordDetectionHandlerImpl(
       chromeos::media_perception::mojom::HotwordDetectionHandlerRequest
       request) : binding_(this, std::move(request)) {
-    LOG(INFO) << "Binding is bound: " << binding_.is_bound();
+    EXPECT_TRUE(binding_.is_bound());
   }
 
   void OnHotwordDetection(
@@ -69,7 +69,7 @@
   PresencePerceptionHandlerImpl(
       chromeos::media_perception::mojom::PresencePerceptionHandlerRequest
       request) : binding_(this, std::move(request)) {
-    LOG(INFO) << "Binding is bound: " << binding_.is_bound();
+    EXPECT_TRUE(binding_.is_bound());
   }
 
   void OnPresencePerception(
@@ -90,7 +90,7 @@
   OccupancyTriggerHandlerImpl(
       chromeos::media_perception::mojom::OccupancyTriggerHandlerRequest
       request) : binding_(this, std::move(request)) {
-    LOG(INFO) << "Binding is bound: " << binding_.is_bound();
+    EXPECT_TRUE(binding_.is_bound());
   }
 
   void OnOccupancyTrigger(
@@ -111,7 +111,7 @@
   AppearancesHandlerImpl(
       chromeos::media_perception::mojom::AppearancesHandlerRequest
       request) : binding_(this, std::move(request)) {
-    LOG(INFO) << "Binding is bound: " << binding_.is_bound();
+    EXPECT_TRUE(binding_.is_bound());
   }
 
   void OnAppearances(
@@ -125,6 +125,26 @@
       binding_;
 };
 
+class OneTouchAutozoomHandlerImpl :
+  public chromeos::media_perception::mojom::OneTouchAutozoomHandler {
+ public:
+  OneTouchAutozoomHandlerImpl(
+      chromeos::media_perception::mojom::OneTouchAutozoomHandlerRequest
+      request) : binding_(this, std::move(request)) {
+    EXPECT_TRUE(binding_.is_bound());
+  }
+
+  void OnSmartFraming(
+      const std::vector<uint8_t> & smart_framing) override {
+    smart_framing_ = smart_framing;
+  }
+
+  std::vector<uint8_t> smart_framing_;
+
+  mojo::Binding<chromeos::media_perception::mojom::OneTouchAutozoomHandler>
+      binding_;
+};
+
 class OutputManagerTest : public testing::Test {
  protected:
   void SetUp() override {
@@ -322,5 +342,47 @@
   }
 }
 
+TEST_F(OutputManagerTest, OneTouchAutozoomOutputManagerTest) {
+  PerceptionInterfaces perception_interfaces;
+  PerceptionInterface* interface = perception_interfaces.add_interface();
+  interface->set_interface_type(
+      PerceptionInterfaceType::INTERFACE_ONE_TOUCH_AUTOZOOM);
+  PipelineOutput* output = interface->add_output();
+  output->set_output_type(
+      PipelineOutputType::OUTPUT_SMART_FRAMING);
+  output->set_stream_name("fake_stream_name");
+
+  chromeos::media_perception::mojom::PerceptionInterfacesPtr interfaces_ptr =
+      chromeos::media_perception::mojom::PerceptionInterfaces::New();
+
+  OutputManager output_manager(
+      "fake_one_touch_autozoom_configuration",
+      rtanalytics_,
+      perception_interfaces,
+      &interfaces_ptr);
+
+  EXPECT_TRUE(interfaces_ptr->one_touch_autozoom_handler_request.is_pending());
+  EXPECT_EQ(fake_rtanalytics_->GetMostRecentOutputStreamName(),
+            "fake_stream_name");
+
+  OneTouchAutozoomHandlerImpl one_touch_autozoom_handler_impl(
+      std::move(interfaces_ptr->one_touch_autozoom_handler_request));
+  base::RunLoop().RunUntilIdle();
+
+  std::vector<uint8_t> bytes {0, 1, 2, 3, 1, 2, 3, 2, 1};
+
+  output_manager.HandleSmartFraming(bytes);
+  base::RunLoop().RunUntilIdle();
+
+  ASSERT_EQ(one_touch_autozoom_handler_impl.smart_framing_.size(), bytes.size())
+      << "Vectors are of unequal length.";
+
+  for (int i = 0; i < bytes.size(); ++i) {
+    EXPECT_EQ(one_touch_autozoom_handler_impl.smart_framing_[i], bytes[i])
+        << "Bytes and Output Appearances Vector differ at index "<< i;
+  }
+}
+
+
 }  // namespace
 }  // namespace mri
diff --git a/media_perception/proto/perception_interface.proto b/media_perception/proto/perception_interface.proto
index 335d728..d0377d9 100644
--- a/media_perception/proto/perception_interface.proto
+++ b/media_perception/proto/perception_interface.proto
@@ -9,6 +9,7 @@
   OUTPUT_PRESENCE_PERCEPTION = 3;
   OUTPUT_OCCUPANCY_TRIGGER = 4;
   OUTPUT_APPEARANCES = 5;
+  OUTPUT_SMART_FRAMING = 6;
 }
 
 message PipelineOutput {
@@ -23,6 +24,7 @@
   INTERFACE_PRESENCE_PERCEPTION = 3;
   INTERFACE_OCCUPANCY_TRIGGER = 4;
   INTERFACE_APPEARANCES = 5;
+  INTERFACE_ONE_TOUCH_AUTOZOOM = 6;
 }
 
 message PerceptionInterface {