Implement IFocus iface

Change-Id: Ifd8418b029d28c189285df5091c18e009abd78b7
Signed-off-by: Eugene Mutavchi <Ievgen_Mutavchi@comcast.com>
diff --git a/plugin/Cobalt.h b/plugin/Cobalt.h
index d7b09b0..c9b5188 100644
--- a/plugin/Cobalt.h
+++ b/plugin/Cobalt.h
@@ -20,6 +20,7 @@
 #include "Module.h"
 #include <interfaces/IBrowser.h>
 #include <interfaces/IMemory.h>
+#include <interfaces/IFocus.h>
 #include <interfaces/json/JsonData_Browser.h>
 #include <interfaces/json/JsonData_StateControl.h>
 
@@ -123,6 +124,7 @@
     INTERFACE_AGGREGATE(PluginHost::IStateControl, _cobalt)
     INTERFACE_AGGREGATE(Exchange::IBrowser, _cobalt)
     INTERFACE_AGGREGATE(Exchange::IMemory, _memory)
+    INTERFACE_AGGREGATE(Exchange::IFocus, _cobalt)
   END_INTERFACE_MAP
 
 public:
diff --git a/plugin/CobaltImplementation.cpp b/plugin/CobaltImplementation.cpp
index 72c3932..1280d1f 100644
--- a/plugin/CobaltImplementation.cpp
+++ b/plugin/CobaltImplementation.cpp
@@ -19,6 +19,7 @@
 #include <interfaces/IMemory.h>
 #include <interfaces/IBrowser.h>
 #include <interfaces/IDictionary.h>
+#include <interfaces/IFocus.h>
 
 extern "C" {
 
@@ -26,6 +27,8 @@
 void SbRdkHandleDeepLink(const char* link);
 void SbRdkSuspend();
 void SbRdkResume();
+void SbRdkPause();
+void SbRdkUnpause();
 void SbRdkQuit();
 void SbRdkSetSetting(const char* key, const char* json);
 int  SbRdkGetSetting(const char* key, char** out_json);
@@ -63,10 +66,17 @@
   file.Close();
 }
 
+enum StateChangeCommand : uint16_t {
+  SUSPEND = PluginHost::IStateControl::SUSPEND,
+  RESUME = PluginHost::IStateControl::RESUME,
+  BACKGROUND
+};
+
 class CobaltImplementation:
     public Exchange::IBrowser,
     public PluginHost::IStateControl,
-    public Exchange::IDictionary {
+    public Exchange::IDictionary,
+    public Exchange::IFocus {
 private:
   class Config: public Core::JSON::Container {
   private:
@@ -113,7 +123,7 @@
   public:
     NotificationSink(CobaltImplementation &parent) :
       _parent(parent), _command(
-        PluginHost::IStateControl::SUSPEND) {
+        StateChangeCommand::SUSPEND) {
     }
     virtual ~NotificationSink() {
       Stop();
@@ -122,7 +132,7 @@
 
   public:
     void RequestForStateChange(
-      const PluginHost::IStateControl::command command) {
+      const StateChangeCommand command) {
       _lock.Lock();
       _command = command;
       _lock.Unlock();
@@ -134,7 +144,7 @@
       bool success = false;
 
       _lock.Lock();
-      const PluginHost::IStateControl::command command = _command;
+      const StateChangeCommand command = _command;
       _lock.Unlock();
 
       if ((IsRunning() == true) && (success == false)) {
@@ -157,7 +167,7 @@
 
   private:
     CobaltImplementation &_parent;
-    PluginHost::IStateControl::command _command;
+    StateChangeCommand _command;
     mutable Core::CriticalSection _lock;
   };
 
@@ -307,6 +317,17 @@
       return (true);
     }
 
+    bool Pause(const bool paused)
+    {
+      if (paused == true) {
+        SbRdkPause();
+      }
+      else {
+        SbRdkUnpause();
+      }
+      return (true);
+    }
+
     string Url() const { return _url; }
 
     bool IsPreloadEnabled() const { return _preloadEnabled; }
@@ -480,34 +501,28 @@
 
     _adminLock.Lock();
 
-    if (_state == PluginHost::IStateControl::UNINITIALIZED) {
-      // Seems we are passing state changes before we reached an operational Cobalt.
-      // Just move the state to what we would like it to be :-)
-      _state = (
-        command == PluginHost::IStateControl::SUSPEND ?
-        PluginHost::IStateControl::SUSPENDED :
-        PluginHost::IStateControl::RESUMED);
-      result = Core::ERROR_NONE;
+    if (_state == PluginHost::IStateControl::UNINITIALIZED || _state == PluginHost::IStateControl::EXITED) {
+      ASSERT(false);
     } else {
       switch (command) {
         case PluginHost::IStateControl::SUSPEND:
-          if (_state == PluginHost::IStateControl::RESUMED || _statePending == PluginHost::IStateControl::RESUMED) {
+          if (_state != PluginHost::IStateControl::SUSPENDED && _statePending != PluginHost::IStateControl::SUSPENDED) {
             _statePending = PluginHost::IStateControl::SUSPENDED;
             _sink.RequestForStateChange(
-              PluginHost::IStateControl::SUSPEND);
-            result = Core::ERROR_NONE;
+              StateChangeCommand::SUSPEND);
           }
+          result = Core::ERROR_NONE;
           break;
         case PluginHost::IStateControl::RESUME:
-          if (_state == PluginHost::IStateControl::SUSPENDED || _statePending == PluginHost::IStateControl::SUSPENDED) {
+          if (_state != PluginHost::IStateControl::RESUMED && _statePending != PluginHost::IStateControl::RESUMED) {
             _statePending = PluginHost::IStateControl::RESUMED;
             _sink.RequestForStateChange(
-              PluginHost::IStateControl::RESUME);
-            result = Core::ERROR_NONE;
+              StateChangeCommand::RESUME);
           }
           if (_delayedSuspend.IsScheduled()) {
             _delayedSuspend.Cancel();
           }
+          result = Core::ERROR_NONE;
           break;
         default:
           break;
@@ -520,10 +535,10 @@
   }
 
   void StateChangeCompleted(bool success,
-                            const PluginHost::IStateControl::command request) {
+                            const StateChangeCommand request) {
     if (success) {
       switch (request) {
-        case PluginHost::IStateControl::RESUME:
+        case StateChangeCommand::RESUME:
 
           _adminLock.Lock();
 
@@ -533,7 +548,7 @@
 
           _adminLock.Unlock();
           break;
-        case PluginHost::IStateControl::SUSPEND:
+        case StateChangeCommand::SUSPEND:
 
           _adminLock.Lock();
 
@@ -543,6 +558,8 @@
 
           _adminLock.Unlock();
           break;
+        case StateChangeCommand::BACKGROUND:
+          break;
         default:
           ASSERT(false);
           break;
@@ -555,11 +572,24 @@
   void RequestDelayedSuspend() {
     _adminLock.Lock();
     if (_state == PluginHost::IStateControl::SUSPENDED && _statePending == PluginHost::IStateControl::SUSPENDED) {
-      _sink.RequestForStateChange(PluginHost::IStateControl::SUSPEND);
+      _sink.RequestForStateChange(StateChangeCommand::SUSPEND);
     }
     _adminLock.Unlock();
   }
 
+  // IFocus
+  uint32_t Focused(const bool focused) override {
+    _adminLock.Lock();
+    if (_state == PluginHost::IStateControl::RESUMED || _statePending == PluginHost::IStateControl::RESUMED) {
+      if (focused)
+        _sink.RequestForStateChange(StateChangeCommand::RESUMED);
+      else
+        _sink.RequestForStateChange(StateChangeCommand::BACKGROUND);
+    }
+    _adminLock.Unlock();
+    return Core::ERROR_NONE;
+  };
+
   // IDictionary iface
   void Register(const string& nameSpace, struct IDictionary::INotification* sink) override  {  }
   void Unregister(const string& nameSpace, struct IDictionary::INotification* sink) override  {  }
@@ -591,28 +621,50 @@
   INTERFACE_ENTRY (Exchange::IBrowser)
   INTERFACE_ENTRY (PluginHost::IStateControl)
   INTERFACE_ENTRY (Exchange::IDictionary)
+  INTERFACE_ENTRY (Exchange::IFocus)
   END_INTERFACE_MAP
 
 private:
+  static const char* ToString(const StateChangeCommand command) {
+    switch(command) {
+      case StateChangeCommand::SUSPEND:
+        return "suspend";
+      case StateChangeCommand::RESUME:
+        return "resume";
+      case StateChangeCommand::BACKGROUND:
+        return "background";
+      default:
+        break;
+    }
+    return "unknown";
+  }
+
   inline bool RequestForStateChange(
-    const PluginHost::IStateControl::command command) {
+    const StateChangeCommand command) {
     bool result = false;
 
-    SYSLOG(Logging::Notification, (_T("Cobalt request state change -> %s\n"), command == PluginHost::IStateControl::SUSPEND ? "suspend" : "resume"));
+    SYSLOG(Logging::Notification, (_T("Cobalt request state change -> %s\n"), ToString(command)));
 
     switch (command) {
-      case PluginHost::IStateControl::SUSPEND: {
+      case StateChangeCommand::SUSPEND: {
         if (_window.Suspend(true) == true) {
           result = true;
         }
         break;
       }
-      case PluginHost::IStateControl::RESUME: {
+      case StateChangeCommand::RESUME: {
+        // implies unpause
         if (_window.Suspend(false) == true) {
           result = true;
         }
         break;
       }
+      case StateChangeCommand::BACKGROUND: {
+        if (_window.Pause(true) == true) {
+          result = true;
+        }
+        break;
+      }
       default:
         ASSERT(false);
         break;
diff --git a/plugin/CobaltJsonRpc.cpp b/plugin/CobaltJsonRpc.cpp
index 01fd14a..b9466a4 100644
--- a/plugin/CobaltJsonRpc.cpp
+++ b/plugin/CobaltJsonRpc.cpp
@@ -18,6 +18,7 @@
 #include <interfaces/json/JsonData_Browser.h>
 #include <interfaces/json/JsonData_StateControl.h>
 #include <interfaces/IDictionary.h>
+#include <core/Optional.h>
 
 #include "Cobalt.h"
 #include "Module.h"
@@ -134,16 +135,26 @@
 uint32_t Cobalt::get_state(Core::JSON::EnumType<StateType> &response) const /* StateControl */
 {
   ASSERT(_cobalt != nullptr);
+
+  response.Clear();
+
   PluginHost::IStateControl *stateControl(_cobalt->QueryInterface<PluginHost::IStateControl>());
   if (stateControl != nullptr) {
     PluginHost::IStateControl::state currentState = stateControl->State();
-    response = (
-      currentState == PluginHost::IStateControl::SUSPENDED ?
-      StateType::SUSPENDED : StateType::RESUMED);
+    switch (currentState) {
+      case PluginHost::IStateControl::SUSPENDED:
+        response = StateType::SUSPENDED;
+        break;
+      case PluginHost::IStateControl::RESUMED:
+        response = StateType::RESUMED;
+        break;
+      default:
+        break;
+    };
     stateControl->Release();
   }
 
-  return Core::ERROR_NONE;
+  return response.IsSet() ? Core::ERROR_NONE : Core::ERROR_ILLEGAL_STATE;
 }
 
 // Property: state - Running state of the service
@@ -158,14 +169,27 @@
     PluginHost::IStateControl *stateControl(
       _cobalt->QueryInterface<PluginHost::IStateControl>());
     if (stateControl != nullptr) {
-      stateControl->Request(
-        param == StateType::SUSPENDED ?
-        PluginHost::IStateControl::SUSPEND :
-        PluginHost::IStateControl::RESUME);
+      Core::OptionalType<PluginHost::IStateControl::command> cmd;
+
+      switch(param.Value()) {
+        case StateType::SUSPENDED:
+          cmd = PluginHost::IStateControl::SUSPEND;
+          break;
+        case StateType::RESUMED:
+          cmd = PluginHost::IStateControl::RESUME;
+          break;
+        default:
+          break;
+      }
+
+      if (cmd.IsSet())
+        result = stateControl->Request(cmd.Value());
 
       stateControl->Release();
     }
-    result = Core::ERROR_NONE;
+    else {
+      result = Core::ERROR_ILLEGAL_STATE;
+    }
   }
   return result;
 }