Add support for terminateUponInput option.

See https://chromium-review.googlesource.com/c/chromium/src/+/1619801
for the CL that introduces this flag and passes it to the IT2Me host.

Bug: 965039
Change-Id: Ib2c29816da6d8f96a9d2ed5de03b675d5e3cfa16
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1621370
Reviewed-by: Jamie Walch <jamiewalch@chromium.org>
Reviewed-by: Joe Downing <joedow@chromium.org>
Commit-Queue: Jamie Walch <jamiewalch@chromium.org>
Cr-Commit-Position: refs/heads/master@{#661892}
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc
index b7dbe0e..3eb3b9d 100644
--- a/remoting/host/client_session.cc
+++ b/remoting/host/client_session.cc
@@ -441,7 +441,9 @@
 void ClientSession::OnLocalPointerMoved(const webrtc::DesktopVector& position,
                                         ui::EventType type) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  remote_input_filter_.LocalPointerMoved(position, type);
+  bool is_local = remote_input_filter_.LocalPointerMoved(position, type);
+  if (is_local && desktop_environment_options_.terminate_upon_input())
+    DisconnectSession(protocol::OK);
 }
 
 void ClientSession::SetDisableInputs(bool disable_inputs) {
diff --git a/remoting/host/client_session_unittest.cc b/remoting/host/client_session_unittest.cc
index d98940d..43d9e7a 100644
--- a/remoting/host/client_session_unittest.cc
+++ b/remoting/host/client_session_unittest.cc
@@ -186,6 +186,8 @@
   protocol::FakeConnectionToClient* connection_;
 
   std::unique_ptr<FakeDesktopEnvironmentFactory> desktop_environment_factory_;
+
+  DesktopEnvironmentOptions desktop_environment_options_;
 };
 
 void ClientSessionTest::SetUp() {
@@ -195,11 +197,13 @@
 
   desktop_environment_factory_.reset(
       new FakeDesktopEnvironmentFactory(message_loop_.task_runner()));
+  desktop_environment_options_ = DesktopEnvironmentOptions::CreateDefault();
 }
 
 void ClientSessionTest::TearDown() {
   if (client_session_) {
-    client_session_->DisconnectSession(protocol::OK);
+    if (connection_->is_connected())
+      client_session_->DisconnectSession(protocol::OK);
     client_session_.reset();
     desktop_environment_factory_.reset();
   }
@@ -223,9 +227,8 @@
 
   client_session_.reset(new ClientSession(
       &session_event_handler_, std::move(connection),
-      desktop_environment_factory_.get(),
-      DesktopEnvironmentOptions::CreateDefault(), base::TimeDelta(), nullptr,
-      extensions_));
+      desktop_environment_factory_.get(), desktop_environment_options_,
+      base::TimeDelta(), nullptr, extensions_));
 }
 
 void ClientSessionTest::CreateClientSession() {
@@ -470,10 +473,24 @@
   EXPECT_THAT(mouse_events[0], EqualsMouseMoveEvent(100, 101));
   EXPECT_THAT(mouse_events[1], EqualsMouseMoveEvent(200, 201));
 
+  // Verify that we're still connected.
+  EXPECT_TRUE(connection_->is_connected());
+
   // TODO(jamiewalch): Verify that remote inputs are re-enabled
   // eventually (via dependency injection, not sleep!)
 }
 
+TEST_F(ClientSessionTest, DisconnectOnLocalInputTest) {
+  desktop_environment_options_.set_terminate_upon_input(true);
+  CreateClientSession();
+  ConnectClientSession();
+  SetupSingleDisplay();
+
+  client_session_->OnLocalPointerMoved(webrtc::DesktopVector(100, 101),
+                                       ui::ET_MOUSE_MOVED);
+  EXPECT_FALSE(connection_->is_connected());
+}
+
 TEST_F(ClientSessionTest, RestoreEventState) {
   CreateClientSession();
   ConnectClientSession();
diff --git a/remoting/host/desktop_environment_options.cc b/remoting/host/desktop_environment_options.cc
index 5eef6c9..0b08dfa 100644
--- a/remoting/host/desktop_environment_options.cc
+++ b/remoting/host/desktop_environment_options.cc
@@ -79,6 +79,14 @@
   enable_user_interface_ = enabled;
 }
 
+bool DesktopEnvironmentOptions::terminate_upon_input() const {
+  return terminate_upon_input_;
+}
+
+void DesktopEnvironmentOptions::set_terminate_upon_input(bool enabled) {
+  terminate_upon_input_ = enabled;
+}
+
 bool DesktopEnvironmentOptions::enable_file_transfer() const {
   return enable_file_transfer_;
 }
diff --git a/remoting/host/desktop_environment_options.h b/remoting/host/desktop_environment_options.h
index ab978ee..bc12703 100644
--- a/remoting/host/desktop_environment_options.h
+++ b/remoting/host/desktop_environment_options.h
@@ -36,6 +36,9 @@
   bool enable_user_interface() const;
   void set_enable_user_interface(bool enabled);
 
+  bool terminate_upon_input() const;
+  void set_terminate_upon_input(bool enabled);
+
   bool enable_file_transfer() const;
   void set_enable_file_transfer(bool enabled);
 
@@ -56,6 +59,9 @@
   // True if a user-interactive window is showing up in it2me scenario.
   bool enable_user_interface_ = true;
 
+  // True if the session should be terminated when local input is detected.
+  bool terminate_upon_input_ = false;
+
   // True if this host has file transfer enabled.
   bool enable_file_transfer_ = false;
 
diff --git a/remoting/host/it2me/it2me_host.cc b/remoting/host/it2me/it2me_host.cc
index 4b93df3..959e407 100644
--- a/remoting/host/it2me/it2me_host.cc
+++ b/remoting/host/it2me/it2me_host.cc
@@ -73,6 +73,15 @@
 #endif
 }
 
+void It2MeHost::set_terminate_upon_input(bool terminate_upon_input) {
+#if defined(OS_CHROMEOS) || !defined(NDEBUG)
+  terminate_upon_input_ = terminate_upon_input;
+#else
+  NOTREACHED()
+      << "It2MeHost::set_terminate_upon_input is only supported on ChromeOS";
+#endif
+}
+
 void It2MeHost::Connect(
     std::unique_ptr<ChromotingHostContext> host_context,
     std::unique_ptr<base::DictionaryValue> policies,
@@ -190,6 +199,7 @@
   // Create the host.
   DesktopEnvironmentOptions options(DesktopEnvironmentOptions::CreateDefault());
   options.set_enable_user_interface(enable_dialogs_);
+  options.set_terminate_upon_input(terminate_upon_input_);
   host_.reset(new ChromotingHost(
       desktop_environment_factory_.get(), std::move(session_manager),
       transport_context, host_context_->audio_task_runner(),
diff --git a/remoting/host/it2me/it2me_host.h b/remoting/host/it2me/it2me_host.h
index c16ccaf..420a0e1 100644
--- a/remoting/host/it2me/it2me_host.h
+++ b/remoting/host/it2me/it2me_host.h
@@ -74,6 +74,10 @@
   void set_enable_dialogs(bool enable);
   bool enable_dialogs() const { return enable_dialogs_; }
 
+  // Enable or disable whether or not the session should be terminated if local
+  // input is detected.
+  void set_terminate_upon_input(bool terminate_upon_input);
+
   // Methods called by the script object, from the plugin thread.
 
   // Creates It2Me host structures and starts the host.
@@ -192,6 +196,7 @@
   std::string connecting_jid_;
 
   bool enable_dialogs_ = true;
+  bool terminate_upon_input_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(It2MeHost);
 };
diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc
index 382520d..6022a64 100644
--- a/remoting/host/it2me/it2me_native_messaging_host.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host.cc
@@ -270,6 +270,9 @@
   bool no_dialogs = false;
   message->GetBoolean("noDialogs", &no_dialogs);
 
+  bool terminate_upon_input = false;
+  message->GetBoolean("terminateUponInput", &terminate_upon_input);
+
   std::string directory_bot_jid =
       ServiceUrls::GetInstance()->directory_bot_jid();
 
@@ -327,6 +330,7 @@
   it2me_host_ = factory_->CreateIt2MeHost();
 #if defined(OS_CHROMEOS) || !defined(NDEBUG)
   it2me_host_->set_enable_dialogs(!no_dialogs);
+  it2me_host_->set_terminate_upon_input(terminate_upon_input);
 #endif
   it2me_host_->Connect(host_context_->Copy(), std::move(policies),
                        std::make_unique<It2MeConfirmationDialogFactory>(),
diff --git a/remoting/host/remote_input_filter.cc b/remoting/host/remote_input_filter.cc
index 4eface7..388ce13 100644
--- a/remoting/host/remote_input_filter.cc
+++ b/remoting/host/remote_input_filter.cc
@@ -32,7 +32,7 @@
 
 RemoteInputFilter::~RemoteInputFilter() = default;
 
-void RemoteInputFilter::LocalPointerMoved(const webrtc::DesktopVector& pos,
+bool RemoteInputFilter::LocalPointerMoved(const webrtc::DesktopVector& pos,
                                           ui::EventType type) {
   // If this is a genuine local input event (rather than an echo of a remote
   // input event that we've just injected), then ignore remote inputs for a
@@ -57,13 +57,14 @@
       // These spurious positions should therefore be discarded.
       injected_mouse_positions_.erase(injected_mouse_positions_.begin(),
                                       ++found_position);
-      return;
+      return false;
     }
   }
 
   // Release all pressed buttons or keys, disable inputs, and note the time.
   event_tracker_->ReleaseAll();
   latest_local_input_time_ = base::TimeTicks::Now();
+  return true;
 }
 
 void RemoteInputFilter::SetExpectLocalEcho(bool expect_local_echo) {
diff --git a/remoting/host/remote_input_filter.h b/remoting/host/remote_input_filter.h
index 13a22f4..99592b2 100644
--- a/remoting/host/remote_input_filter.h
+++ b/remoting/host/remote_input_filter.h
@@ -27,8 +27,9 @@
 
   // Informs the filter that local mouse or touch activity has been detected.
   // If the activity does not match events we injected then we assume that it
-  // is local, and block remote input for a short while.
-  void LocalPointerMoved(const webrtc::DesktopVector& pos, ui::EventType type);
+  // is local, and block remote input for a short while. Returns true if the
+  // input was local, or false if it was rejected as an echo.
+  bool LocalPointerMoved(const webrtc::DesktopVector& pos, ui::EventType type);
 
   // Informs the filter that injecting input causes an echo.
   void SetExpectLocalEcho(bool expect_local_echo);