Fix indicator crash
[platform/core/uifw/dali-adaptor.git] / adaptors / ecore / common / ecore-indicator-impl.cpp
index a3e7b5f..574e0bd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include "ecore-indicator-impl.h"
 
 // EXTERNAL INCLUDES
+// Ecore is littered with C style cast
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
 #include <Ecore.h>
 #include <Evas.h>
+#ifdef WAYLAND
+#include <Ecore_Wayland.h>
+#else
+#include <Ecore_X.h>
+#endif
 
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <iomanip>
+#include <fstream>
 
 #include <dali/public-api/images/native-image.h>
 #include <dali/public-api/events/touch-event.h>
 #include <dali/public-api/events/touch-point.h>
 #include <dali/public-api/common/stage.h>
-#include <dali/public-api/actors/blending.h>
-#include <dali/public-api/shader-effects/shader-effect.h>
 #include <dali/public-api/images/buffer-image.h>
+#include <dali/public-api/images/pixel.h>
 
 #include <dali/integration-api/debug.h>
 
@@ -95,6 +104,50 @@ const char* BACKGROUND_FRAGMENT_SHADER = MAKE_SHADER(
   }
 );
 
+const char* FOREGROUND_VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  varying mediump vec2 vTexCoord;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump vec4 sTextureRect;\n
+  \n
+  void main()\n
+  {\n
+    gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);\n
+    vTexCoord = aPosition + vec2(0.5);\n
+  }\n
+);
+
+const char* FOREGROUND_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  \n
+  void main()\n
+  {\n
+    gl_FragColor = texture2D( sTexture, vTexCoord );\n // the foreground does not apply actor color
+  }\n
+);
+
+Dali::Geometry CreateQuadGeometry()
+{
+  Dali::Property::Map quadVertexFormat;
+  quadVertexFormat["aPosition"] = Dali::Property::VECTOR2;
+  Dali::PropertyBuffer vertexData = Dali::PropertyBuffer::New( quadVertexFormat );
+
+  const float halfQuadSize = .5f;
+  struct QuadVertex { Dali::Vector2 position; };
+  QuadVertex quadVertexData[4] = {
+      { Dali::Vector2(-halfQuadSize, -halfQuadSize) },
+      { Dali::Vector2(-halfQuadSize, halfQuadSize) },
+      { Dali::Vector2( halfQuadSize, -halfQuadSize) },
+      { Dali::Vector2( halfQuadSize, halfQuadSize) } };
+  vertexData.SetData(quadVertexData, 4);
+
+  Dali::Geometry quad = Dali::Geometry::New();
+  quad.AddVertexBuffer( vertexData );
+  quad.SetType( Dali::Geometry::TRIANGLE_STRIP );
+  return quad;
+}
 
 const float OPAQUE_THRESHOLD(0.99f);
 const float TRANSPARENT_THRESHOLD(0.05f);
@@ -104,6 +157,8 @@ const char* INDICATOR_SERVICE_NAME("elm_indicator");
 
 // Copied from ecore_evas_extn_engine.h
 
+#define NBUF 2
+
 enum // opcodes
 {
    OP_RESIZE,
@@ -131,7 +186,8 @@ enum // opcodes
    OP_EV_KEY_DOWN,
    OP_EV_HOLD,
    OP_MSG_PARENT,
-   OP_MSG
+   OP_MSG,
+   OP_PIXMAP_REF,
 };
 
 // Copied from elm_conform.c
@@ -203,9 +259,9 @@ struct IpcDataEvMouseMove
   unsigned int       timestamp;
   Evas_Event_Flags   event_flags;
 
-  IpcDataEvMouseMove(const Dali::TouchPoint& touchPoint, unsigned long timestamp)
-  : x(static_cast<Evas_Coord>(touchPoint.local.x)),
-    y(static_cast<Evas_Coord>(touchPoint.local.y)),
+  IpcDataEvMouseMove(const Dali::Vector2& touchPoint, unsigned long timestamp)
+  : x(static_cast<Evas_Coord>(touchPoint.x)),
+    y(static_cast<Evas_Coord>(touchPoint.y)),
     flags(EVAS_BUTTON_NONE),
     mask(0),
     timestamp(static_cast<unsigned int>(timestamp)),
@@ -228,6 +284,59 @@ struct IpcDataEvMouseOut
   }
 };
 
+#ifdef ENABLE_INDICATOR_IMAGE_SAVING
+
+void SaveIndicatorImage( Dali::NativeImageSourcePtr nativeImageSource )
+{
+  // Save image data to disk in BMP form.
+  static int gFilenameCounter = 0;
+  static const char bmpHeader[] = {
+      0x42, 0x4d, 0x0a, 0xcb, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x7c, 0x00,
+      0x00, 0x00,
+      0xe0, 0x01, 0x00, 0x00, // Width  (480)
+      0x1b, 0x00, 0x00, 0x00, // Height ( 27)
+      0x01, 0x00, 0x20, 0x00, 0x03, 0x00,
+      0x00, 0x00, 0x80, 0xca, 0x00, 0x00, 0x13, 0x0b,  0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+      0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x42, 0x47,  0x52, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00
+    };
+
+  // This is a BMP header with width & height hard-coded in.
+  // The data was first determined by dumping the raw data and inspecting in GIMP, before creating this header data.
+  std::vector<unsigned char> buffer;
+  unsigned int w = 0;
+  unsigned int h = 0;
+  Dali::Pixel::Format pixelFormat;
+  if( nativeImageSource->GetPixels( buffer, w, h, pixelFormat ) )
+  {
+    int imageSize = w * h * 4;
+    std::stringstream fileName;
+    // Give each file an incremental filename.
+    fileName << "/opt/usr/media/Images/out-" << std::setfill( '0' ) << std::setw( 5 ) << gFilenameCounter << ".bmp";
+
+    std::ofstream outfile( fileName.str().c_str(), std::ofstream::binary );
+    if( outfile.is_open() )
+    {
+      DALI_LOG_WARNING( "Saving Indicator Image w:%d, h:%d, %s\n", w, h, fileName.str().c_str() );
+
+      outfile.write( bmpHeader, sizeof( bmpHeader ) / sizeof( bmpHeader[0] ) ); // Size of the BMP header.
+      outfile.write( (const char*)buffer.data(), imageSize );
+      outfile.close();
+      gFilenameCounter++;
+    }
+    else
+    {
+      DALI_LOG_ERROR( "COULD NOT OPEN FOR SAVING: %s\n", fileName.str().c_str() );
+    }
+  }
+}
+
+#endif
+
 } // anonymous namespace
 
 
@@ -241,6 +350,107 @@ namespace Adaptor
 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
 #endif
 
+// Impl to hide EFL implementation.
+
+struct Indicator::Impl
+{
+  enum // operation mode
+  {
+    INDICATOR_HIDE,
+    INDICATOR_STAY_WITH_DURATION
+  };
+
+  /**
+   * Constructor
+   */
+  Impl(Indicator* indicator)
+  : mIndicator(indicator),
+    mEcoreEventHandler(NULL)
+  {
+#if defined(DALI_PROFILE_MOBILE)
+#if defined(WAYLAND)
+    mEcoreEventHandler = ecore_event_handler_add(ECORE_WL_EVENT_INDICATOR_FLICK,  EcoreEventIndicator, this);
+#else
+    mEcoreEventHandler = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE,  EcoreEventClientMessage, this);
+#endif
+#endif // WAYLAND && DALI_PROFILE_MOBILE
+  }
+
+  /**
+   * Destructor
+   */
+  ~Impl()
+  {
+    if ( mEcoreEventHandler )
+    {
+      ecore_event_handler_del(mEcoreEventHandler);
+    }
+  }
+
+  static void SetIndicatorVisibility( void* data, int operation )
+  {
+    Indicator::Impl* indicatorImpl((Indicator::Impl*)data);
+
+    if ( indicatorImpl == NULL || indicatorImpl->mIndicator == NULL)
+    {
+      return;
+    }
+    if ( operation == INDICATOR_STAY_WITH_DURATION )
+    {
+      // if indicator is not showing, INDICATOR_FLICK_DONE is given
+      if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
+          !indicatorImpl->mIndicator->mIsShowing )
+      {
+        indicatorImpl->mIndicator->ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
+      }
+    }
+    else if( operation == INDICATOR_HIDE )
+    {
+      if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
+          indicatorImpl->mIndicator->mIsShowing )
+      {
+        indicatorImpl->mIndicator->ShowIndicator( HIDE_NOW );
+      }
+    }
+  }
+#if defined(DALI_PROFILE_MOBILE)
+#if defined(WAYLAND)
+  /**
+   * Called when the Ecore indicator event is received.
+   */
+  static Eina_Bool EcoreEventIndicator( void* data, int type, void* event )
+  {
+    SetIndicatorVisibility( data, INDICATOR_STAY_WITH_DURATION );
+    return ECORE_CALLBACK_PASS_ON;
+  }
+#else
+  /**
+   * Called when the client messages (i.e. quick panel state) are received.
+   */
+  static Eina_Bool EcoreEventClientMessage( void* data, int type, void* event )
+  {
+    Ecore_X_Event_Client_Message* clientMessageEvent((Ecore_X_Event_Client_Message*)event);
+
+    if ( clientMessageEvent != NULL )
+    {
+      if (clientMessageEvent->message_type == ECORE_X_ATOM_E_INDICATOR_FLICK_DONE)
+      {
+        SetIndicatorVisibility( data, INDICATOR_STAY_WITH_DURATION );
+      }
+      else if ( clientMessageEvent->message_type == ECORE_X_ATOM_E_MOVE_QUICKPANEL_STATE )
+      {
+        SetIndicatorVisibility( data, INDICATOR_HIDE );
+      }
+    }
+    return ECORE_CALLBACK_PASS_ON;
+  }
+#endif
+#endif // WAYLAND && DALI_PROFILE_MOBILE
+
+  // Data
+  Indicator*           mIndicator;
+  Ecore_Event_Handler* mEcoreEventHandler;
+};
 
 Indicator::LockFile::LockFile(const std::string filename)
 : mFilename(filename),
@@ -258,7 +468,10 @@ Indicator::LockFile::LockFile(const std::string filename)
 Indicator::LockFile::~LockFile()
 {
   // Closing file descriptor also unlocks file.
-  close( mFileDescriptor );
+  if( mFileDescriptor > 0 )
+  {
+    close( mFileDescriptor );
+  }
 }
 
 bool Indicator::LockFile::Lock()
@@ -268,21 +481,27 @@ bool Indicator::LockFile::Lock()
   bool locked = false;
   if( mFileDescriptor > 0 )
   {
-    if( lockf( mFileDescriptor, F_LOCK, 0 ) == 0 ) // Note, operation may block.
+    struct flock filelock;
+
+    filelock.l_type = F_RDLCK;
+    filelock.l_whence = SEEK_SET;
+    filelock.l_start = 0;
+    filelock.l_len = 0;
+    if( fcntl( mFileDescriptor, F_SETLKW, &filelock ) == -1 )
     {
-      locked = true;
+      mErrorThrown = true;
+      DALI_LOG_ERROR( "### Failed to lock with fd : %s ###\n", mFilename.c_str() );
     }
     else
     {
-      if( errno == EBADF )
-      {
-        // file descriptor is no longer valid or not writable
-        mFileDescriptor = 0;
-        mErrorThrown = true;
-        DALI_LOG_ERROR( "### Cannot lock indicator: bad file descriptor for %s ###\n", mFilename.c_str() );
-      }
+      locked = true;
     }
   }
+  else
+  {
+    mErrorThrown = true;
+    DALI_LOG_ERROR( "### Invalid fd ###\n" );
+  }
 
   return locked;
 }
@@ -290,14 +509,19 @@ bool Indicator::LockFile::Lock()
 void Indicator::LockFile::Unlock()
 {
   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
-  if( lockf( mFileDescriptor, F_ULOCK, 0 ) != 0 )
+
+  if( mFileDescriptor > 0 )
   {
-    if( errno == EBADF )
+    struct flock filelock;
+
+    filelock.l_type = F_UNLCK;
+    filelock.l_whence = SEEK_SET;
+    filelock.l_start = 0;
+    filelock.l_len = 0;
+    if (fcntl(mFileDescriptor, F_SETLKW, &filelock) == -1)
     {
-      // file descriptor is no longer valid or not writable
-      mFileDescriptor = 0;
       mErrorThrown = true;
-      DALI_LOG_ERROR( "### Cannot unlock indicator: bad file descriptor for %s\n", mFilename.c_str() );
+      DALI_LOG_ERROR( "### Failed to lock with fd : %s ###\n", mFilename.c_str() );
     }
   }
 }
@@ -334,6 +558,7 @@ bool Indicator::ScopedLock::IsLocked()
 
 Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, IndicatorInterface::Observer* observer )
 : mPixmap( 0 ),
+  mGestureDeltaY( 0.0f ),
   mGestureDetected( false ),
   mConnection( this ),
   mOpacityMode( Dali::Window::OPAQUE ),
@@ -347,38 +572,23 @@ Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientat
   mVisible( Dali::Window::INVISIBLE ),
   mIsShowing( true ),
   mIsAnimationPlaying( false ),
-  mCurrentSharedFile( 0 )
+  mCurrentSharedFile( 0 ),
+  mSharedBufferType( BUFFER_TYPE_SHM ),
+  mImpl( NULL ),
+  mBackgroundVisible( false ),
+  mTopMargin( 0 )
 {
-  mIndicatorImageActor = Dali::ImageActor::New();
-  mIndicatorImageActor.SetBlendFunc( Dali::BlendingFactor::ONE, Dali::BlendingFactor::ONE_MINUS_SRC_ALPHA,
-                                    Dali::BlendingFactor::ONE, Dali::BlendingFactor::ONE );
-
-  mIndicatorImageActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
-  mIndicatorImageActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
-  mIndicatorImageActor.SetSortModifier( 1.0f );
+  mIndicatorContentActor = Dali::Actor::New();
+  mIndicatorContentActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
+  mIndicatorContentActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
 
   // Indicator image handles the touch event including "leave"
-  mIndicatorImageActor.SetLeaveRequired( true );
-  mIndicatorImageActor.TouchedSignal().Connect( this, &Indicator::OnTouched );
-
-  mBackgroundActor = Dali::Actor::New();
-  mBackgroundActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
-  mBackgroundActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
-  mBackgroundActor.SetColor( Color::BLACK );
-
-  mIndicatorImageContainerActor = Dali::Actor::New();
-  mIndicatorImageContainerActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
-  mIndicatorImageContainerActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
-  mIndicatorImageContainerActor.Add( mBackgroundActor );
-  mIndicatorImageContainerActor.Add( mIndicatorImageActor );
+  mIndicatorContentActor.SetLeaveRequired( true );
+  mIndicatorContentActor.TouchSignal().Connect( this, &Indicator::OnTouch );
+  mIndicatorContentActor.SetColor( Color::BLACK );
 
   mIndicatorActor = Dali::Actor::New();
-  mIndicatorActor.Add( mIndicatorImageContainerActor );
-
-  if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
-  {
-    mBackgroundActor.SetVisible( false );
-  }
+  mIndicatorActor.Add( mIndicatorContentActor );
 
   // Event handler to find out flick down gesture
   mEventActor = Dali::Actor::New();
@@ -403,13 +613,22 @@ Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientat
   }
   // hide the indicator by default
   mIndicatorActor.SetVisible( false );
+
+  // create impl to handle ecore event
+  mImpl = new Impl(this);
 }
 
 Indicator::~Indicator()
 {
+  if(mImpl)
+  {
+    delete mImpl;
+    mImpl = NULL;
+  }
+
   if(mEventActor)
   {
-    mEventActor.TouchedSignal().Disconnect( this, &Indicator::OnTouched );
+    mEventActor.TouchSignal().Disconnect( this, &Indicator::OnTouch );
   }
   Disconnect();
 }
@@ -438,9 +657,13 @@ void Indicator::Open( Dali::Window::WindowOrientation orientation )
   Connect();
 
   // Change background visibility depending on orientation
-  if(mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE  )
+  if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE  )
   {
-    mBackgroundActor.SetVisible( false );
+    if( mBackgroundRenderer )
+    {
+      mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
+      mBackgroundVisible = false;
+    }
   }
   else
   {
@@ -461,52 +684,46 @@ void Indicator::Close()
     }
   }
 
-  Dali::Image emptyImage;
-  mIndicatorImageActor.SetImage(emptyImage);
+  Dali::Texture emptyTexture;
+  SetForegroundImage( emptyTexture );
 }
 
 void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
 {
   mOpacityMode = mode;
 
-  //@todo replace with a gradient renderer when that is implemented
   Dali::Geometry geometry = CreateBackgroundGeometry();
   if( geometry )
   {
-    mBackgroundActor.SetVisible( true );
-
-    if( mBackgroundActor.GetRendererCount() > 0 )
+    if( mBackgroundRenderer )
     {
-      Dali::Renderer renderer = mBackgroundActor.GetRendererAt( 0 );
-      if( renderer )
+      if( mBackgroundRenderer.GetGeometry() != geometry )
       {
-        if( renderer.GetGeometry() == geometry )
-        {
-          return;
-        }
-        else
-        {
-          renderer.SetGeometry( geometry );
-        }
+        mBackgroundRenderer.SetGeometry( geometry );
       }
     }
     else
     {
-      if( !mBackgroundMaterial )
+      if( !mBackgroundShader )
       {
-        Dali::Shader shader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::HINT_OUTPUT_IS_TRANSPARENT );
-        mBackgroundMaterial = Dali::Material::New( shader );
+        mBackgroundShader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT );
       }
 
-      Dali::Renderer renderer = Dali::Renderer::New( geometry, mBackgroundMaterial );
+      mBackgroundRenderer = Dali::Renderer::New( geometry, mBackgroundShader );
+    }
 
-      mBackgroundActor.AddRenderer( renderer );
+    if( !mBackgroundVisible )
+    {
+      mIndicatorContentActor.AddRenderer( mBackgroundRenderer );
+      mBackgroundVisible = true;
     }
   }
-  else
+  else if( mBackgroundRenderer )
   {
-    mBackgroundActor.SetVisible( false );
+    mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
+    mBackgroundVisible = false;
   }
+  UpdateTopMargin();
 }
 
 void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
@@ -518,14 +735,28 @@ void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool
     {
       UpdateImageData( mCurrentSharedFile );
     }
-    if ( visibleMode != Dali::Window::INVISIBLE )
+
+    if ( visibleMode == Dali::Window::INVISIBLE )
+    {
+      if (mServerConnection)
+      {
+        mServerConnection->SendEvent( OP_HIDE, NULL, 0 );
+      }
+    }
+    else
     {
       mIndicatorActor.SetVisible( true );
+
+      if( mServerConnection )
+      {
+         mServerConnection->SendEvent( OP_SHOW, NULL, 0 );
+      }
     }
 
     mVisible = visibleMode;
+    UpdateTopMargin();
 
-    if( mIndicatorImageActor.GetImage() )
+    if( mForegroundRenderer && mForegroundRenderer.GetTextures().GetTexture( 0u ) )
     {
       if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
       {
@@ -543,6 +774,10 @@ void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool
         ShowIndicator( HIDE_NOW );
       }
     }
+    else
+    {
+      mIsShowing = false;
+    }
   }
 }
 
@@ -563,21 +798,19 @@ bool Indicator::SendMessage( int messageDomain, int messageId, const void *data,
  }
 }
 
-bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEvent)
+bool Indicator::OnTouch(Dali::Actor indicator, const Dali::TouchData& touchData)
 {
   if( mServerConnection )
   {
-    const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
-
     // Send touch event to indicator server when indicator is showing
     if( CheckVisibleState() || mIsShowing )
     {
-      switch( touchPoint.state )
+      switch( touchData.GetState(0) )
       {
-        case Dali::TouchPoint::Down:
+        case Dali::PointState::DOWN:
         {
-          IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
-          IpcDataEvMouseDown ipcDown( touchEvent.time );
+          IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
+          IpcDataEvMouseDown ipcDown( touchData.GetTime() );
           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
           mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
 
@@ -589,16 +822,17 @@ bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEv
         }
         break;
 
-        case Dali::TouchPoint::Motion:
+        case Dali::PointState::MOTION:
         {
-          IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
+          IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
         }
         break;
 
-        case Dali::TouchPoint::Up:
+        case Dali::PointState::UP:
+        case Dali::PointState::INTERRUPTED:
         {
-          IpcDataEvMouseUp ipcUp( touchEvent.time );
+          IpcDataEvMouseUp ipcUp( touchData.GetTime() );
           mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
 
           if( mVisible == Dali::Window::AUTO )
@@ -611,9 +845,9 @@ bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEv
 
         case Dali::TouchPoint::Leave:
         {
-          IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
+          IpcDataEvMouseMove ipcMove( touchData.GetLocalPosition(0), touchData.GetTime() );
           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
-          IpcDataEvMouseUp ipcOut( touchEvent.time );
+          IpcDataEvMouseUp ipcOut( touchData.GetTime() );
           mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
         }
         break;
@@ -714,11 +948,10 @@ void Indicator::Resize( int width, int height )
     mImageWidth = width;
     mImageHeight = height;
 
-    mIndicatorImageActor.SetSize( mImageWidth, mImageHeight );
+    mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
     mIndicatorActor.SetSize( mImageWidth, mImageHeight );
     mEventActor.SetSize(mImageWidth, mImageHeight);
-    mBackgroundActor.SetSize( mImageWidth, mImageHeight );
-    mIndicatorImageContainerActor.SetSize( mImageWidth, mImageHeight );
+    UpdateTopMargin();
   }
 }
 
@@ -793,6 +1026,11 @@ void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
   // epcEvent->ref_to == sys
   // epcEvent->response == buffer num
 
+  if ( mSharedBufferType != BUFFER_TYPE_SHM )
+  {
+    return ;
+  }
+
   int n = epcEvent->response;
 
   if( n >= 0 && n < SHARED_FILE_NUMBER )
@@ -823,21 +1061,11 @@ void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
       {
         DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
       }
-
-      CreateNewImage( n );
-
-      if( CheckVisibleState() )
-      {
-        // set default indicator type (enable the quick panel)
-        OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
-      }
       else
       {
-        // set default indicator type (disable the quick panel)
-        OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
+        CreateNewImage( n );
+        UpdateVisibility();
       }
-
-      SetVisible(mVisible, true);
     }
   }
 }
@@ -846,38 +1074,53 @@ void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
 {
   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
 
-  // epcEvent->ref == w
-  // epcEvent->ref_to == h
-  // epcEvent->response == alpha
-  // epcEvent->data = pixmap id
+  // epcEvent->ref == pixmap id
+  // epcEvent->ref_to == type
+  // epcEvent->response == buffer num
 
-  if( ( epcEvent->data ) &&
-      (epcEvent->size >= (int)sizeof(PixmapId)) )
+  if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
   {
+    mSharedBufferType = (BufferType)(epcEvent->ref_to);
+
     ClearSharedFileInfo();
 
-    if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
-    {
-      mImageWidth  = epcEvent->ref;
-      mImageHeight = epcEvent->ref_to;
+    mPixmap = static_cast<PixmapId>(epcEvent->ref);
+    DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "mPixmap [%x]", mPixmap);
 
-      mPixmap = *(static_cast<PixmapId*>(epcEvent->data));
-      CreateNewPixmapImage();
+    CreateNewPixmapImage();
+    UpdateVisibility();
+  }
+}
 
-      if( CheckVisibleState() )
-      {
-        // set default indicator type (enable the quick panel)
-        OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
-      }
-      else
-      {
-        // set default indicator type (disable the quick panel)
-        OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
-      }
+void Indicator::UpdateTopMargin()
+{
+  int newMargin = (mVisible == Dali::Window::VISIBLE && mOpacityMode == Dali::Window::OPAQUE) ? mImageHeight : 0;
+  if (mTopMargin != newMargin)
+  {
+    mTopMargin = newMargin;
+    mAdaptor->IndicatorSizeChanged( mTopMargin );
+  }
+}
 
-      SetVisible(mVisible, true);
-    }
+void Indicator::UpdateVisibility()
+{
+  if( CheckVisibleState() )
+  {
+    // set default indicator type (enable the quick panel)
+    OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
+  }
+  else
+  {
+    // set default indicator type (disable the quick panel)
+    OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
   }
+
+  if( !mIsShowing )
+  {
+    mIndicatorContentActor.SetPosition( 0.0f, -mImageHeight, 0.0f );
+  }
+
+  SetVisible(mVisible, true);
 }
 
 void Indicator::UpdateImageData( int bufferNumber )
@@ -915,7 +1158,7 @@ bool Indicator::CopyToBuffer( int bufferNumber )
     else if( scopedLock.IsLocked() )
     {
       unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
-      size_t size = mSharedFileInfo[bufferNumber].mImageWidth * mSharedFileInfo[bufferNumber].mImageHeight * 4;
+      size_t size = static_cast< size_t >( mSharedFileInfo[bufferNumber].mImageWidth ) * mSharedFileInfo[bufferNumber].mImageHeight * 4;
 
       if( mIndicatorBuffer->UpdatePixels( src, size ) )
       {
@@ -933,14 +1176,18 @@ void Indicator::CreateNewPixmapImage()
   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mImageWidth, mImageHeight );
   Dali::NativeImageSourcePtr nativeImageSource = Dali::NativeImageSource::New( mPixmap );
 
+#ifdef ENABLE_INDICATOR_IMAGE_SAVING
+  SaveIndicatorImage( nativeImageSource );
+#endif
+
   if( nativeImageSource )
   {
-    mIndicatorImageActor.SetImage( Dali::NativeImage::New(*nativeImageSource) );
-    mIndicatorImageActor.SetSize( mImageWidth, mImageHeight );
+    Dali::Texture texture = Dali::Texture::New( *nativeImageSource );
+    SetForegroundImage( texture );
+    mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
     mIndicatorActor.SetSize( mImageWidth, mImageHeight );
-    mEventActor.SetSize(mImageWidth, mImageHeight);
-    mBackgroundActor.SetSize( mImageWidth, mImageHeight );
-    mIndicatorImageContainerActor.SetSize( mImageWidth, mImageHeight );
+    mEventActor.SetSize( mImageWidth, mImageHeight );
+    UpdateTopMargin();
   }
   else
   {
@@ -959,26 +1206,24 @@ void Indicator::CreateNewImage( int bufferNumber )
 {
   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
   mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
-  Dali::Image image = Dali::NativeImage::New( mIndicatorBuffer->GetNativeImage() );
+  bool success = false;
 
   if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
   {
-    mIndicatorImageActor.SetImage( image );
-  }
-  else
-  {
-    DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
-    Disconnect();
-    if( mObserver != NULL )
+    Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() );
+    if( texture )
     {
-      mObserver->IndicatorClosed( this );
+      SetForegroundImage( texture );
+      success = true;
     }
-    // Don't do connection in this callback - strange things happen!
-    StartReconnectionTimer();
+  }
+
+  if( !success )
+  {
+    DALI_LOG_WARNING("### Cannot create indicator image ###\n");
   }
 }
 
-//@todo replace with a gradient renderer when that is implemented
 Dali::Geometry Indicator::CreateBackgroundGeometry()
 {
   switch( mOpacityMode )
@@ -1025,9 +1270,9 @@ Dali::Geometry Indicator::CreateBackgroundGeometry()
 
         // Create indices
         unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
-        unsigned int indices[ numIndices ];
+        unsigned short indices[ numIndices ];
 
-        unsigned int* currentIndex = indices;
+        unsigned short* currentIndex = indices;
         for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
         {
           *currentIndex++ = (2 * y);
@@ -1045,15 +1290,10 @@ Dali::Geometry Indicator::CreateBackgroundGeometry()
         Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
         vertexPropertyBuffer.SetData( vertices, numVertices );
 
-        Dali::Property::Map indexFormat;
-        indexFormat[ "indices" ] = Dali::Property::INTEGER;
-        Dali::PropertyBuffer indexPropertyBuffer = Dali::PropertyBuffer::New( indexFormat );
-        indexPropertyBuffer.SetData( indices, numIndices );
-
         // Create the geometry object
         mTranslucentGeometry = Dali::Geometry::New();
         mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
-        mTranslucentGeometry.SetIndexBuffer( indexPropertyBuffer );
+        mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices );
       }
 
       return mTranslucentGeometry;
@@ -1072,7 +1312,7 @@ Dali::Geometry Indicator::CreateBackgroundGeometry()
                                            { Vector2( -0.5f,  0.5f ), 1.0f }, { Vector2( 0.5f,  0.5f ), 1.0f } };
 
         // Create indices
-        unsigned int indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
+        unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
 
         Dali::Property::Map vertexFormat;
         vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
@@ -1080,15 +1320,11 @@ Dali::Geometry Indicator::CreateBackgroundGeometry()
         Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
         vertexPropertyBuffer.SetData( vertices, 4 );
 
-        Dali::Property::Map indexFormat;
-        indexFormat[ "indices" ] = Dali::Property::INTEGER;
-        Dali::PropertyBuffer indexPropertyBuffer = Dali::PropertyBuffer::New( indexFormat );
-        indexPropertyBuffer.SetData( indices, 6 );
 
         // Create the geometry object
         mSolidGeometry = Dali::Geometry::New();
         mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
-        mSolidGeometry.SetIndexBuffer( indexPropertyBuffer );
+        mSolidGeometry.SetIndexBuffer( &indices[0], 6 );
       }
 
       return mSolidGeometry;
@@ -1099,6 +1335,45 @@ Dali::Geometry Indicator::CreateBackgroundGeometry()
   return Dali::Geometry();
 }
 
+void Indicator::SetForegroundImage( Dali::Texture texture )
+{
+  if( !mForegroundRenderer && texture )
+  {
+    // Create Shader
+    Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER );
+
+    // Create renderer from geometry and material
+    Dali::Geometry quad = CreateQuadGeometry();
+    mForegroundRenderer = Dali::Renderer::New( quad, shader );
+    // Make sure the foreground stays in front of the background
+    mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
+
+    // Set blend function
+    mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB,    Dali::BlendFactor::ONE );
+    mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB,   Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
+    mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA,  Dali::BlendFactor::ONE );
+    mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
+
+    // Create a texture-set and add to renderer
+
+    Dali::TextureSet textureSet = Dali::TextureSet::New();
+    textureSet.SetTexture( 0u, texture );
+    mForegroundRenderer.SetTextures( textureSet );
+
+    mIndicatorContentActor.AddRenderer( mForegroundRenderer );
+  }
+  else if( mForegroundRenderer )
+  {
+    Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
+    textureSet.SetTexture( 0u, texture );
+  }
+
+  if( mImageWidth == 0 && mImageHeight == 0  && texture)
+  {
+    Resize( texture.GetWidth(), texture.GetHeight() );
+  }
+}
+
 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
 {
   if( mObserver != NULL )
@@ -1148,6 +1423,12 @@ void Indicator::DataReceived( void* event )
       LoadSharedImage( epcEvent );
       break;
     }
+    case OP_PIXMAP_REF:
+    {
+      DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_PIXMAP_REF\n" );
+      LoadPixmapImage( epcEvent );
+      break;
+    }
     case OP_RESIZE:
     {
       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
@@ -1189,7 +1470,7 @@ void Indicator::DataReceived( void* event )
 
             if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
             {
-              DALI_LOG_ERROR("Message data is incorrect");
+              DALI_LOG_ERROR("Message data is incorrect\n");
               break;
             }
 
@@ -1201,7 +1482,6 @@ void Indicator::DataReceived( void* event )
             }
             break;
           }
-
         }
       }
       break;
@@ -1226,7 +1506,8 @@ bool Indicator::CheckVisibleState()
 {
   if( mOrientation == Dali::Window::LANDSCAPE
     || mOrientation == Dali::Window::LANDSCAPE_INVERSE
-    || (mVisible != Dali::Window::VISIBLE) )
+    || (mVisible == Dali::Window::INVISIBLE)
+    || (mVisible == Dali::Window::AUTO && !mIsShowing) )
   {
     return false;
   }
@@ -1277,9 +1558,11 @@ void Indicator::ShowIndicator(float duration)
   }
   else
   {
+    mIndicatorAnimation.Clear();
+
     if( EqualsZero(duration) )
     {
-      mIndicatorAnimation.AnimateTo( Property( mIndicatorImageContainerActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
+      mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
 
       mIsShowing = false;
 
@@ -1287,7 +1570,7 @@ void Indicator::ShowIndicator(float duration)
     }
     else
     {
-      mIndicatorAnimation.AnimateTo( Property( mIndicatorImageContainerActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
+      mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
 
       mIsShowing = true;
 
@@ -1311,7 +1594,7 @@ void Indicator::ShowIndicator(float duration)
     if( mVisible == Dali::Window::AUTO )
     {
       // check the stage touch
-      Dali::Stage::GetCurrent().TouchedSignal().Connect( this, &Indicator::OnStageTouched );
+      Dali::Stage::GetCurrent().TouchSignal().Connect( this, &Indicator::OnStageTouch );
     }
   }
   else
@@ -1324,7 +1607,7 @@ void Indicator::ShowIndicator(float duration)
     if( mVisible == Dali::Window::AUTO )
     {
       // check the stage touch
-      Dali::Stage::GetCurrent().TouchedSignal().Disconnect( this, &Indicator::OnStageTouched );
+      Dali::Stage::GetCurrent().TouchSignal().Disconnect( this, &Indicator::OnStageTouch );
     }
   }
 }
@@ -1341,81 +1624,31 @@ void Indicator::OnAnimationFinished(Dali::Animation& animation)
 {
   mIsAnimationPlaying = false;
   // once animation is finished and indicator is hidden, take it off stage
-  if( !mIsShowing )
+  if( mObserver != NULL )
   {
-    if( mObserver != NULL )
-    {
-      mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
-    }
+    mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
   }
 }
 
 void Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
 {
-  if( mServerConnection )
-  {
-    switch( gesture.state )
-    {
-      case Gesture::Started:
-      {
-        mGestureDetected = false;
-
-        // The gesture position is the current position after it has moved by the displacement.
-        // We want to reference the original position.
-        mGestureDeltaY = gesture.position.y - gesture.displacement.y;
-      }
-
-      // No break, Fall through
-      case Gesture::Continuing:
-      {
-        if( mVisible == Dali::Window::AUTO && !mIsShowing )
-        {
-          // Only take one touch point
-          if( gesture.numberOfTouches == 1 && mGestureDetected == false )
-          {
-            mGestureDeltaY += gesture.displacement.y;
-
-            if( mGestureDeltaY >= mImageHeight * SHOWING_DISTANCE_HEIGHT_RATE )
-            {
-              ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
-              mGestureDetected = true;
-            }
-          }
-        }
-
-        break;
-      }
-
-      case Gesture::Finished:
-      case Gesture::Cancelled:
-      {
-        // if indicator is showing, hide again when touching is finished (Since touch leave is activated, checking it in gesture::finish instead of touch::up)
-        if( mVisible == Dali::Window::AUTO && mIsShowing )
-        {
-          ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
-        }
-        break;
-      }
-
-
-      default:
-        break;
-    }
-  }
+  // Nothing to do, but we still want to consume pan
 }
 
-void Indicator::OnStageTouched(const Dali::TouchEvent& touchEvent)
+void Indicator::OnStageTouch(const Dali::TouchData& touchData)
 {
-  const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
-
   // when stage is touched while indicator is showing temporary, hide it
   if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
   {
-    switch( touchPoint.state )
+    switch( touchData.GetState(0) )
     {
-      case Dali::TouchPoint::Down:
+      case Dali::PointState::DOWN:
       {
-        ShowIndicator( HIDE_NOW );
+        // if touch point is inside the indicator, indicator is not hidden
+        if( mImageHeight < int( touchData.GetScreenPosition(0).y ) )
+        {
+          ShowIndicator( HIDE_NOW );
+        }
         break;
       }
 
@@ -1426,5 +1659,9 @@ void Indicator::OnStageTouched(const Dali::TouchEvent& touchEvent)
 }
 
 } // Adaptor
+
 } // Internal
+
 } // Dali
+
+#pragma GCC diagnostic pop