PropertyBuffer SetData clean-up
[platform/core/uifw/dali-adaptor.git] / adaptors / ecore / common / ecore-indicator-impl.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include "ecore-indicator-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <Ecore.h>
23 #include <Evas.h>
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <errno.h>
30
31 #include <dali/public-api/images/native-image.h>
32 #include <dali/public-api/events/touch-event.h>
33 #include <dali/public-api/events/touch-point.h>
34 #include <dali/public-api/common/stage.h>
35 #include <dali/public-api/actors/blending.h>
36 #include <dali/public-api/shader-effects/shader-effect.h>
37 #include <dali/public-api/images/buffer-image.h>
38
39 #include <dali/integration-api/debug.h>
40
41 // INTERNAL INCLUDES
42 #include <adaptor-impl.h>
43 #include <accessibility-adaptor-impl.h>
44 #include <native-image-source.h>
45
46 using Dali::Vector4;
47
48 #if defined(DEBUG_ENABLED)
49 #define STATE_DEBUG_STRING(state) (state==DISCONNECTED?"DISCONNECTED":state==CONNECTED?"CONNECTED":"UNKNOWN")
50 #endif
51
52 namespace
53 {
54
55 const float SLIDING_ANIMATION_DURATION( 0.2f ); // 200 milli seconds
56 const float AUTO_INDICATOR_STAY_DURATION(3.0f); // 3 seconds
57 const float SHOWING_DISTANCE_HEIGHT_RATE(0.34f); // 20 pixels
58
59 enum
60 {
61   KEEP_SHOWING = -1,
62   HIDE_NOW = 0
63 };
64
65 const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals
66 const float GRADIENT_ALPHA[NUM_GRADIENT_INTERVALS+1] = { 0.6f, 0.38f, 0.20f, 0.08f, 0.0f, 0.0f };
67
68 #define MAKE_SHADER(A)#A
69
70 const char* BACKGROUND_VERTEX_SHADER = MAKE_SHADER(
71   attribute mediump vec2 aPosition;
72   attribute mediump float aAlpha;
73   varying mediump float vAlpha;
74   uniform mediump mat4 uMvpMatrix;
75   uniform mediump vec3 uSize;
76
77   void main()
78   {
79     mediump vec4 vertexPosition = vec4( aPosition * uSize.xy, 0.0, 1.0 );
80     vertexPosition = uMvpMatrix * vertexPosition;
81
82     vAlpha = aAlpha;
83     gl_Position = vertexPosition;
84   }
85 );
86
87 const char* BACKGROUND_FRAGMENT_SHADER = MAKE_SHADER(
88   uniform lowp vec4 uColor;
89   varying mediump float vAlpha;
90
91   void main()
92   {
93     gl_FragColor = uColor;
94     gl_FragColor.a *= vAlpha;
95   }
96 );
97
98
99 const float OPAQUE_THRESHOLD(0.99f);
100 const float TRANSPARENT_THRESHOLD(0.05f);
101
102 // indicator service name
103 const char* INDICATOR_SERVICE_NAME("elm_indicator");
104
105 // Copied from ecore_evas_extn_engine.h
106
107 enum // opcodes
108 {
109    OP_RESIZE,
110    OP_SHOW,
111    OP_HIDE,
112    OP_FOCUS,
113    OP_UNFOCUS,
114    OP_UPDATE,
115    OP_UPDATE_DONE,
116    OP_SHM_REF0,
117    OP_SHM_REF1,
118    OP_SHM_REF2,
119    OP_PROFILE_CHANGE_REQUEST,
120    OP_PROFILE_CHANGE_DONE,
121    OP_EV_MOUSE_IN,
122    OP_EV_MOUSE_OUT,
123    OP_EV_MOUSE_UP,
124    OP_EV_MOUSE_DOWN,
125    OP_EV_MOUSE_MOVE,
126    OP_EV_MOUSE_WHEEL,
127    OP_EV_MULTI_UP,
128    OP_EV_MULTI_DOWN,
129    OP_EV_MULTI_MOVE,
130    OP_EV_KEY_UP,
131    OP_EV_KEY_DOWN,
132    OP_EV_HOLD,
133    OP_MSG_PARENT,
134    OP_MSG
135 };
136
137 // Copied from elm_conform.c
138
139 const int MSG_DOMAIN_CONTROL_INDICATOR( 0x10001 );
140 const int MSG_ID_INDICATOR_REPEAT_EVENT( 0x10002 );
141 const int MSG_ID_INDICATOR_ROTATION( 0x10003 );
142 const int MSG_ID_INDICATOR_OPACITY( 0X1004 );
143 const int MSG_ID_INDICATOR_TYPE( 0X1005 );
144 const int MSG_ID_INDICATOR_START_ANIMATION( 0X10006 );
145
146 struct IpcDataUpdate
147 {
148    int x, w, y, h;
149 };
150
151 struct IpcDataResize
152 {
153   int w, h;
154 };
155
156 struct IpcIndicatorDataAnimation
157 {
158   unsigned int xwin;
159   double       duration;
160 };
161
162 struct IpcDataEvMouseUp
163 {
164   int               b;
165   Evas_Button_Flags flags;
166   int               mask;
167   unsigned int      timestamp;
168   Evas_Event_Flags  event_flags;
169
170   IpcDataEvMouseUp(unsigned long timestamp)
171   : b(1),
172     flags(EVAS_BUTTON_NONE),
173     mask(0),
174     timestamp(static_cast<unsigned int>(timestamp)),
175     event_flags(EVAS_EVENT_FLAG_NONE)
176   {
177   }
178 };
179
180 struct IpcDataEvMouseDown
181 {
182   int                b;
183   Evas_Button_Flags  flags;
184   int                mask;
185   unsigned int       timestamp;
186   Evas_Event_Flags   event_flags;
187
188   IpcDataEvMouseDown(unsigned long timestamp)
189   : b(1),
190     flags(EVAS_BUTTON_NONE),
191     mask(0),
192     timestamp(static_cast<unsigned int>(timestamp)),
193     event_flags(EVAS_EVENT_FLAG_NONE)
194   {
195   }
196 };
197
198 struct IpcDataEvMouseMove
199 {
200   int                x, y;
201   Evas_Button_Flags  flags;
202   int                mask;
203   unsigned int       timestamp;
204   Evas_Event_Flags   event_flags;
205
206   IpcDataEvMouseMove(const Dali::TouchPoint& touchPoint, unsigned long timestamp)
207   : x(static_cast<Evas_Coord>(touchPoint.local.x)),
208     y(static_cast<Evas_Coord>(touchPoint.local.y)),
209     flags(EVAS_BUTTON_NONE),
210     mask(0),
211     timestamp(static_cast<unsigned int>(timestamp)),
212     event_flags(EVAS_EVENT_FLAG_NONE)
213   {
214   }
215 };
216
217 struct IpcDataEvMouseOut
218 {
219   unsigned int     timestamp;
220   int              mask;
221   Evas_Event_Flags event_flags;
222
223   IpcDataEvMouseOut(unsigned long timestamp)
224   : timestamp(static_cast<unsigned int>(timestamp)),
225     mask(0),
226     event_flags(EVAS_EVENT_FLAG_NONE)
227   {
228   }
229 };
230
231 } // anonymous namespace
232
233
234 namespace Dali
235 {
236 namespace Internal
237 {
238 namespace Adaptor
239 {
240 #if defined(DEBUG_ENABLED)
241 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
242 #endif
243
244
245 Indicator::LockFile::LockFile(const std::string filename)
246 : mFilename(filename),
247   mErrorThrown(false)
248 {
249   mFileDescriptor = open(filename.c_str(), O_RDWR);
250   if( mFileDescriptor == -1 )
251   {
252     mFileDescriptor = 0;
253     mErrorThrown = true;
254     DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
255   }
256 }
257
258 Indicator::LockFile::~LockFile()
259 {
260   // Closing file descriptor also unlocks file.
261   close( mFileDescriptor );
262 }
263
264 bool Indicator::LockFile::Lock()
265 {
266   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
267
268   bool locked = false;
269   if( mFileDescriptor > 0 )
270   {
271     if( lockf( mFileDescriptor, F_LOCK, 0 ) == 0 ) // Note, operation may block.
272     {
273       locked = true;
274     }
275     else
276     {
277       if( errno == EBADF )
278       {
279         // file descriptor is no longer valid or not writable
280         mFileDescriptor = 0;
281         mErrorThrown = true;
282         DALI_LOG_ERROR( "### Cannot lock indicator: bad file descriptor for %s ###\n", mFilename.c_str() );
283       }
284     }
285   }
286
287   return locked;
288 }
289
290 void Indicator::LockFile::Unlock()
291 {
292   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
293   if( lockf( mFileDescriptor, F_ULOCK, 0 ) != 0 )
294   {
295     if( errno == EBADF )
296     {
297       // file descriptor is no longer valid or not writable
298       mFileDescriptor = 0;
299       mErrorThrown = true;
300       DALI_LOG_ERROR( "### Cannot unlock indicator: bad file descriptor for %s\n", mFilename.c_str() );
301     }
302   }
303 }
304
305 bool Indicator::LockFile::RetrieveAndClearErrorStatus()
306 {
307   bool error = mErrorThrown;
308   mErrorThrown = false;
309   return error;
310 }
311
312 Indicator::ScopedLock::ScopedLock(LockFile* lockFile)
313 : mLockFile(lockFile),
314   mLocked(false)
315 {
316   if(mLockFile)
317   {
318     mLocked = mLockFile->Lock();
319   }
320 }
321
322 Indicator::ScopedLock::~ScopedLock()
323 {
324   if( mLockFile )
325   {
326     mLockFile->Unlock();
327   }
328 }
329
330 bool Indicator::ScopedLock::IsLocked()
331 {
332   return mLocked;
333 }
334
335 Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, IndicatorInterface::Observer* observer )
336 : mPixmap( 0 ),
337   mGestureDetected( false ),
338   mConnection( this ),
339   mOpacityMode( Dali::Window::OPAQUE ),
340   mState( DISCONNECTED ),
341   mAdaptor(adaptor),
342   mServerConnection( NULL ),
343   mObserver( observer ),
344   mOrientation( orientation ),
345   mImageWidth( 0 ),
346   mImageHeight( 0 ),
347   mVisible( Dali::Window::INVISIBLE ),
348   mIsShowing( true ),
349   mIsAnimationPlaying( false ),
350   mCurrentSharedFile( 0 )
351 {
352   mIndicatorImageActor = Dali::ImageActor::New();
353   mIndicatorImageActor.SetBlendFunc( Dali::BlendingFactor::ONE, Dali::BlendingFactor::ONE_MINUS_SRC_ALPHA,
354                                     Dali::BlendingFactor::ONE, Dali::BlendingFactor::ONE );
355
356   mIndicatorImageActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
357   mIndicatorImageActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
358   mIndicatorImageActor.SetSortModifier( 1.0f );
359
360   // Indicator image handles the touch event including "leave"
361   mIndicatorImageActor.SetLeaveRequired( true );
362   mIndicatorImageActor.TouchedSignal().Connect( this, &Indicator::OnTouched );
363
364   mBackgroundActor = Dali::Actor::New();
365   mBackgroundActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
366   mBackgroundActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
367   mBackgroundActor.SetColor( Color::BLACK );
368
369   mIndicatorImageContainerActor = Dali::Actor::New();
370   mIndicatorImageContainerActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
371   mIndicatorImageContainerActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
372   mIndicatorImageContainerActor.Add( mBackgroundActor );
373   mIndicatorImageContainerActor.Add( mIndicatorImageActor );
374
375   mIndicatorActor = Dali::Actor::New();
376   mIndicatorActor.Add( mIndicatorImageContainerActor );
377
378   if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
379   {
380     mBackgroundActor.SetVisible( false );
381   }
382
383   // Event handler to find out flick down gesture
384   mEventActor = Dali::Actor::New();
385   mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
386   mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
387   mIndicatorActor.Add( mEventActor );
388
389   // Attach pan gesture to find flick down during hiding.
390   // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
391   // since it consumes the pan gesture in advance.
392   mPanDetector = Dali::PanGestureDetector::New();
393   mPanDetector.DetectedSignal().Connect( this, &Indicator::OnPan );
394   mPanDetector.Attach( mEventActor );
395
396   Open( orientation );
397
398   // register indicator to accessibility adaptor
399   Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
400   if(accessibilityAdaptor)
401   {
402     AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this );
403   }
404   // hide the indicator by default
405   mIndicatorActor.SetVisible( false );
406 }
407
408 Indicator::~Indicator()
409 {
410   if(mEventActor)
411   {
412     mEventActor.TouchedSignal().Disconnect( this, &Indicator::OnTouched );
413   }
414   Disconnect();
415 }
416
417 void Indicator::SetAdaptor(Adaptor* adaptor)
418 {
419   mAdaptor = adaptor;
420   mIndicatorBuffer->SetAdaptor( adaptor );
421 }
422
423 Dali::Actor Indicator::GetActor()
424 {
425   return mIndicatorActor;
426 }
427
428 void Indicator::Open( Dali::Window::WindowOrientation orientation )
429 {
430   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
431
432   // Calls from Window should be set up to ensure we are in a
433   // disconnected state before opening a second time.
434   DALI_ASSERT_DEBUG( mState == DISCONNECTED );
435
436   mOrientation = orientation;
437
438   Connect();
439
440   // Change background visibility depending on orientation
441   if(mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE  )
442   {
443     mBackgroundActor.SetVisible( false );
444   }
445   else
446   {
447     SetOpacityMode( mOpacityMode );
448   }
449 }
450
451 void Indicator::Close()
452 {
453   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) );
454
455   if( mState == CONNECTED )
456   {
457     Disconnect();
458     if( mObserver != NULL )
459     {
460       mObserver->IndicatorClosed( this );
461     }
462   }
463
464   Dali::Image emptyImage;
465   mIndicatorImageActor.SetImage(emptyImage);
466 }
467
468 void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
469 {
470   mOpacityMode = mode;
471
472   //@todo replace with a gradient renderer when that is implemented
473   Dali::Geometry geometry = CreateBackgroundGeometry();
474   if( geometry )
475   {
476     mBackgroundActor.SetVisible( true );
477
478     if( mBackgroundActor.GetRendererCount() > 0 )
479     {
480       Dali::Renderer renderer = mBackgroundActor.GetRendererAt( 0 );
481       if( renderer )
482       {
483         if( renderer.GetGeometry() == geometry )
484         {
485           return;
486         }
487         else
488         {
489           renderer.SetGeometry( geometry );
490         }
491       }
492     }
493     else
494     {
495       if( !mBackgroundMaterial )
496       {
497         Dali::Shader shader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::HINT_OUTPUT_IS_TRANSPARENT );
498         mBackgroundMaterial = Dali::Material::New( shader );
499       }
500
501       Dali::Renderer renderer = Dali::Renderer::New( geometry, mBackgroundMaterial );
502
503       mBackgroundActor.AddRenderer( renderer );
504     }
505   }
506   else
507   {
508     mBackgroundActor.SetVisible( false );
509   }
510 }
511
512 void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
513 {
514   if ( visibleMode != mVisible || forceUpdate )
515   {
516     // If we were previously hidden, then we should update the image data before we display the indicator
517     if ( mVisible == Dali::Window::INVISIBLE )
518     {
519       UpdateImageData( mCurrentSharedFile );
520     }
521     if ( visibleMode != Dali::Window::INVISIBLE )
522     {
523       mIndicatorActor.SetVisible( true );
524     }
525
526     mVisible = visibleMode;
527
528     if( mIndicatorImageActor.GetImage() )
529     {
530       if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
531       {
532         // hide indicator
533         ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
534       }
535       else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
536       {
537         // show indicator
538         ShowIndicator( KEEP_SHOWING );
539       }
540       else
541       {
542         // hide indicator
543         ShowIndicator( HIDE_NOW );
544       }
545     }
546   }
547 }
548
549 bool Indicator::IsConnected()
550 {
551   return ( mState == CONNECTED );
552 }
553
554 bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size )
555 {
556  if(IsConnected())
557  {
558    return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
559  }
560  else
561  {
562    return false;
563  }
564 }
565
566 bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEvent)
567 {
568   if( mServerConnection )
569   {
570     const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
571
572     // Send touch event to indicator server when indicator is showing
573     if( CheckVisibleState() || mIsShowing )
574     {
575       switch( touchPoint.state )
576       {
577         case Dali::TouchPoint::Down:
578         {
579           IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
580           IpcDataEvMouseDown ipcDown( touchEvent.time );
581           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
582           mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
583
584           if( mVisible == Dali::Window::AUTO )
585           {
586             // Stop hiding indicator
587             ShowIndicator( KEEP_SHOWING );
588           }
589         }
590         break;
591
592         case Dali::TouchPoint::Motion:
593         {
594           IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
595           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
596         }
597         break;
598
599         case Dali::TouchPoint::Up:
600         {
601           IpcDataEvMouseUp ipcUp( touchEvent.time );
602           mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
603
604           if( mVisible == Dali::Window::AUTO )
605           {
606             // Hide indicator
607             ShowIndicator( 0.5f /* hide after 0.5 sec */ );
608           }
609         }
610         break;
611
612         case Dali::TouchPoint::Leave:
613         {
614           IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
615           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
616           IpcDataEvMouseUp ipcOut( touchEvent.time );
617           mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
618         }
619         break;
620
621         default:
622           break;
623       }
624
625       return true;
626     }
627   }
628
629   return false;
630 }
631
632 bool Indicator::Connect()
633 {
634   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
635
636   DALI_ASSERT_DEBUG( mState == DISCONNECTED );
637
638   bool connected = false;
639
640   mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
641   if( mServerConnection )
642   {
643     connected = mServerConnection->IsConnected();
644     if( ! connected )
645     {
646       delete mServerConnection;
647       mServerConnection = NULL;
648     }
649   }
650
651   if( !connected )
652   {
653     StartReconnectionTimer();
654   }
655   else
656   {
657     mState = CONNECTED;
658   }
659
660   return connected;
661 }
662
663 void Indicator::StartReconnectionTimer()
664 {
665   if( ! mReconnectTimer )
666   {
667     mReconnectTimer = Dali::Timer::New(1000);
668     mConnection.DisconnectAll();
669     mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
670   }
671   mReconnectTimer.Start();
672 }
673
674 bool Indicator::OnReconnectTimer()
675 {
676   bool retry = false;
677
678   if( mState == DISCONNECTED )
679   {
680     if( !Connect() )
681     {
682       retry = true;
683     }
684   }
685
686   return retry;
687 }
688
689 void Indicator::Disconnect()
690 {
691   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
692
693   mState = DISCONNECTED;
694
695   delete mServerConnection;
696   mServerConnection = NULL;
697
698   ClearSharedFileInfo();
699 }
700
701 void Indicator::Resize( int width, int height )
702 {
703   if( width < 1 )
704   {
705     width = 1;
706   }
707   if( height < 1 )
708   {
709     height = 1;
710   }
711
712   if( mImageWidth != width || mImageHeight != height )
713   {
714     mImageWidth = width;
715     mImageHeight = height;
716
717     mIndicatorImageActor.SetSize( mImageWidth, mImageHeight );
718     mIndicatorActor.SetSize( mImageWidth, mImageHeight );
719     mEventActor.SetSize(mImageWidth, mImageHeight);
720     mBackgroundActor.SetSize( mImageWidth, mImageHeight );
721     mIndicatorImageContainerActor.SetSize( mImageWidth, mImageHeight );
722   }
723 }
724
725 void Indicator::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
726 {
727   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
728
729   // epcEvent->ref == w
730   // epcEvent->ref_to == h
731   // epcEvent->response == buffer num
732   // epcEvent->data = lockfile + nul byte
733
734   if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
735       (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
736   {
737     int n = epcEvent->response;
738
739     if( n >= 0 && n < SHARED_FILE_NUMBER )
740     {
741       mCurrentSharedFile = n;
742
743       mSharedFileInfo[n].mImageWidth  = epcEvent->ref;
744       mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
745
746       mSharedFileInfo[n].mLockFileName.clear();
747
748       mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
749
750       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
751                      n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
752     }
753   }
754 }
755
756 void Indicator::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
757 {
758   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
759
760   // epcEvent->ref == shm id
761   // epcEvent->ref_to == shm num
762   // epcEvent->response == buffer num
763   // epcEvent->data = shm ref string + nul byte
764
765   if ( (epcEvent->data) &&
766        (epcEvent->size > 0) &&
767        (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
768   {
769     int n = epcEvent->response;
770
771     if( n >= 0 && n < SHARED_FILE_NUMBER )
772     {
773       mCurrentSharedFile = n;
774
775       mSharedFileInfo[n].mSharedFileName.clear();
776
777       mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
778
779       mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
780       mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
781
782       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
783                      n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
784     }
785   }
786 }
787
788 void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
789 {
790   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
791
792   // epcEvent->ref == alpha
793   // epcEvent->ref_to == sys
794   // epcEvent->response == buffer num
795
796   int n = epcEvent->response;
797
798   if( n >= 0 && n < SHARED_FILE_NUMBER )
799   {
800     mCurrentSharedFile = n;
801
802     delete mSharedFileInfo[n].mSharedFile;
803     mSharedFileInfo[n].mSharedFile = NULL;
804
805     delete mSharedFileInfo[n].mLock;
806     mSharedFileInfo[n].mLock = NULL;
807
808     std::stringstream sharedFileID;
809     std::stringstream sharedFileNumber;
810
811     sharedFileID << mSharedFileInfo[n].mSharedFileID;
812     sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
813
814     std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
815
816     DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
817
818     mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
819     if( mSharedFileInfo[n].mSharedFile != NULL )
820     {
821       mSharedFileInfo[n].mLock = new Indicator::LockFile( mSharedFileInfo[n].mLockFileName );
822       if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
823       {
824         DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
825       }
826
827       CreateNewImage( n );
828
829       if( CheckVisibleState() )
830       {
831         // set default indicator type (enable the quick panel)
832         OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
833       }
834       else
835       {
836         // set default indicator type (disable the quick panel)
837         OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
838       }
839
840       SetVisible(mVisible, true);
841     }
842   }
843 }
844
845 void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
846 {
847   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
848
849   // epcEvent->ref == w
850   // epcEvent->ref_to == h
851   // epcEvent->response == alpha
852   // epcEvent->data = pixmap id
853
854   if( ( epcEvent->data ) &&
855       (epcEvent->size >= (int)sizeof(PixmapId)) )
856   {
857     ClearSharedFileInfo();
858
859     if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
860     {
861       mImageWidth  = epcEvent->ref;
862       mImageHeight = epcEvent->ref_to;
863
864       mPixmap = *(static_cast<PixmapId*>(epcEvent->data));
865       CreateNewPixmapImage();
866
867       if( CheckVisibleState() )
868       {
869         // set default indicator type (enable the quick panel)
870         OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
871       }
872       else
873       {
874         // set default indicator type (disable the quick panel)
875         OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
876       }
877
878       SetVisible(mVisible, true);
879     }
880   }
881 }
882
883 void Indicator::UpdateImageData( int bufferNumber )
884 {
885   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s  mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
886
887   if( mState == CONNECTED && mVisible )
888   {
889     if(mPixmap == 0)
890     {
891       // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false
892       CopyToBuffer( bufferNumber );
893     }
894     else
895     {
896       if(mIsShowing)
897       {
898         mAdaptor->RequestUpdateOnce();
899       }
900     }
901   }
902 }
903
904 bool Indicator::CopyToBuffer( int bufferNumber )
905 {
906   bool success = false;
907
908   if( mSharedFileInfo[bufferNumber].mLock )
909   {
910     Indicator::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
911     if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
912     {
913       // Do nothing here.
914     }
915     else if( scopedLock.IsLocked() )
916     {
917       unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
918       size_t size = mSharedFileInfo[bufferNumber].mImageWidth * mSharedFileInfo[bufferNumber].mImageHeight * 4;
919
920       if( mIndicatorBuffer->UpdatePixels( src, size ) )
921       {
922         mAdaptor->RequestUpdateOnce();
923         success = true;
924       }
925     }
926   }
927
928   return success;
929 }
930
931 void Indicator::CreateNewPixmapImage()
932 {
933   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mImageWidth, mImageHeight );
934   Dali::NativeImageSourcePtr nativeImageSource = Dali::NativeImageSource::New( mPixmap );
935
936   if( nativeImageSource )
937   {
938     mIndicatorImageActor.SetImage( Dali::NativeImage::New(*nativeImageSource) );
939     mIndicatorImageActor.SetSize( mImageWidth, mImageHeight );
940     mIndicatorActor.SetSize( mImageWidth, mImageHeight );
941     mEventActor.SetSize(mImageWidth, mImageHeight);
942     mBackgroundActor.SetSize( mImageWidth, mImageHeight );
943     mIndicatorImageContainerActor.SetSize( mImageWidth, mImageHeight );
944   }
945   else
946   {
947     DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
948     Disconnect();
949     if( mObserver != NULL )
950     {
951       mObserver->IndicatorClosed( this );
952     }
953     // Don't do connection in this callback - strange things happen!
954     StartReconnectionTimer();
955   }
956 }
957
958 void Indicator::CreateNewImage( int bufferNumber )
959 {
960   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
961   mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
962   Dali::Image image = Dali::NativeImage::New( mIndicatorBuffer->GetNativeImage() );
963
964   if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
965   {
966     mIndicatorImageActor.SetImage( image );
967   }
968   else
969   {
970     DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
971     Disconnect();
972     if( mObserver != NULL )
973     {
974       mObserver->IndicatorClosed( this );
975     }
976     // Don't do connection in this callback - strange things happen!
977     StartReconnectionTimer();
978   }
979 }
980
981 //@todo replace with a gradient renderer when that is implemented
982 Dali::Geometry Indicator::CreateBackgroundGeometry()
983 {
984   switch( mOpacityMode )
985   {
986     case Dali::Window::TRANSLUCENT:
987       if( !mTranslucentGeometry )
988       {
989         // Construct 5 interval mesh
990         // 0  +---+  1
991         //    | \ |
992         // 2  +---+  3
993         //    | \ |
994         // 4  +---+  5
995         //    | \ |
996         // 6  +---+  7
997         //    | \ |
998         // 8  +---+  9
999         //    | \ |
1000         // 10 +---+  11
1001
1002         // Create vertices
1003         struct BackgroundVertex
1004         {
1005           Vector2 mPosition;
1006           float   mAlpha;
1007         };
1008
1009         unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1010         BackgroundVertex vertices[ numVertices ];
1011
1012         float d = -0.5f;
1013         float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1014         BackgroundVertex* currentVertex = vertices;
1015         for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1016         {
1017           currentVertex->mPosition = Vector2( -0.5f, d );
1018           currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1019           currentVertex++;
1020
1021           currentVertex->mPosition = Vector2( 0.5f, d );
1022           currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1023           currentVertex++;
1024         }
1025
1026         // Create indices
1027         unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1028         unsigned int indices[ numIndices ];
1029
1030         unsigned int* currentIndex = indices;
1031         for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1032         {
1033           *currentIndex++ = (2 * y);
1034           *currentIndex++ = (2 * y) + 3;
1035           *currentIndex++ = (2 * y) + 1;
1036
1037           *currentIndex++ = (2 * y);
1038           *currentIndex++ = (2 * y) + 2;
1039           *currentIndex++ = (2 * y) + 3;
1040         }
1041
1042         Dali::Property::Map vertexFormat;
1043         vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1044         vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1045         Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1046         vertexPropertyBuffer.SetData( vertices, numVertices );
1047
1048         Dali::Property::Map indexFormat;
1049         indexFormat[ "indices" ] = Dali::Property::INTEGER;
1050         Dali::PropertyBuffer indexPropertyBuffer = Dali::PropertyBuffer::New( indexFormat );
1051         indexPropertyBuffer.SetData( indices, numIndices );
1052
1053         // Create the geometry object
1054         mTranslucentGeometry = Dali::Geometry::New();
1055         mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1056         mTranslucentGeometry.SetIndexBuffer( indexPropertyBuffer );
1057       }
1058
1059       return mTranslucentGeometry;
1060     case Dali::Window::OPAQUE:
1061
1062       if( !mSolidGeometry )
1063       {
1064         // Create vertices
1065         struct BackgroundVertex
1066         {
1067           Vector2 mPosition;
1068           float   mAlpha;
1069         };
1070
1071         BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1072                                            { Vector2( -0.5f,  0.5f ), 1.0f }, { Vector2( 0.5f,  0.5f ), 1.0f } };
1073
1074         // Create indices
1075         unsigned int indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1076
1077         Dali::Property::Map vertexFormat;
1078         vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1079         vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1080         Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1081         vertexPropertyBuffer.SetData( vertices, 4 );
1082
1083         Dali::Property::Map indexFormat;
1084         indexFormat[ "indices" ] = Dali::Property::INTEGER;
1085         Dali::PropertyBuffer indexPropertyBuffer = Dali::PropertyBuffer::New( indexFormat );
1086         indexPropertyBuffer.SetData( indices, 6 );
1087
1088         // Create the geometry object
1089         mSolidGeometry = Dali::Geometry::New();
1090         mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1091         mSolidGeometry.SetIndexBuffer( indexPropertyBuffer );
1092       }
1093
1094       return mSolidGeometry;
1095     case Dali::Window::TRANSPARENT:
1096       break;
1097   }
1098
1099   return Dali::Geometry();
1100 }
1101
1102 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
1103 {
1104   if( mObserver != NULL )
1105   {
1106     mObserver->IndicatorTypeChanged( indicatorType );
1107   }
1108 }
1109
1110 void Indicator::DataReceived( void* event )
1111 {
1112   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1113   Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1114
1115   switch( epcEvent->minor )
1116   {
1117     case OP_UPDATE:
1118     {
1119       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1120       if( mIsShowing )
1121       {
1122         mAdaptor->RequestUpdateOnce();
1123       }
1124       break;
1125     }
1126     case OP_UPDATE_DONE:
1127     {
1128       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1129       // epcEvent->response == display buffer #
1130       UpdateImageData( epcEvent->response );
1131       break;
1132     }
1133     case OP_SHM_REF0:
1134     {
1135       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1136       SetSharedImageInfo( epcEvent );
1137       break;
1138     }
1139     case OP_SHM_REF1:
1140     {
1141       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1142       SetLockFileInfo( epcEvent );
1143       break;
1144     }
1145     case OP_SHM_REF2:
1146     {
1147       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1148       LoadSharedImage( epcEvent );
1149       break;
1150     }
1151     case OP_RESIZE:
1152     {
1153       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1154
1155       if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1156       {
1157         IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1158         Resize( newSize->w, newSize->h );
1159       }
1160       break;
1161     }
1162     case OP_MSG_PARENT:
1163     {
1164       int msgDomain = epcEvent->ref;
1165       int msgId = epcEvent->ref_to;
1166
1167       void *msgData = NULL;
1168       int msgDataSize = 0;
1169       msgData = epcEvent->data;
1170       msgDataSize = epcEvent->size;
1171
1172       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1173
1174       if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1175       {
1176         switch( msgId )
1177         {
1178           case MSG_ID_INDICATOR_TYPE:
1179           {
1180             DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1181             Type* indicatorType = static_cast<Type*>( epcEvent->data );
1182             OnIndicatorTypeChanged( *indicatorType );
1183             break;
1184           }
1185
1186           case MSG_ID_INDICATOR_START_ANIMATION:
1187           {
1188             DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1189
1190             if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1191             {
1192               DALI_LOG_ERROR("Message data is incorrect");
1193               break;
1194             }
1195
1196             IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1197
1198             if(!CheckVisibleState())
1199             {
1200               ShowIndicator( animData->duration /* n sec */ );
1201             }
1202             break;
1203           }
1204
1205         }
1206       }
1207       break;
1208     }
1209   }
1210 }
1211
1212 void Indicator::ConnectionClosed()
1213 {
1214   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1215
1216   // Will get this callback if the server connection failed to start up.
1217   delete mServerConnection;
1218   mServerConnection = NULL;
1219   mState = DISCONNECTED;
1220
1221   // Attempt to re-connect
1222   Connect();
1223 }
1224
1225 bool Indicator::CheckVisibleState()
1226 {
1227   if( mOrientation == Dali::Window::LANDSCAPE
1228     || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1229     || (mVisible != Dali::Window::VISIBLE) )
1230   {
1231     return false;
1232   }
1233
1234   return true;
1235 }
1236
1237 void Indicator::ClearSharedFileInfo()
1238 {
1239   for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
1240   {
1241     delete mSharedFileInfo[i].mLock;
1242     mSharedFileInfo[i].mLock = NULL;
1243
1244     delete mSharedFileInfo[i].mSharedFile;
1245     mSharedFileInfo[i].mSharedFile = NULL;
1246
1247     mSharedFileInfo[i].mLockFileName.clear();
1248     mSharedFileInfo[i].mSharedFileName.clear();
1249   }
1250 }
1251
1252 /**
1253  * duration can be this
1254  *
1255  * enum
1256  * {
1257  *  KEEP_SHOWING = -1,
1258  *  HIDE_NOW = 0
1259  * };
1260  */
1261 void Indicator::ShowIndicator(float duration)
1262 {
1263   if( !mIndicatorAnimation )
1264   {
1265     mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1266     mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished);
1267   }
1268
1269   if(mIsShowing && !EqualsZero(duration))
1270   {
1271     // If need to show during showing, do nothing.
1272     // In 2nd phase (below) will update timer
1273   }
1274   else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1275   {
1276     // If need to hide during hiding or hidden already, do nothing
1277   }
1278   else
1279   {
1280     if( EqualsZero(duration) )
1281     {
1282       mIndicatorAnimation.AnimateTo( Property( mIndicatorImageContainerActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
1283
1284       mIsShowing = false;
1285
1286       OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1287     }
1288     else
1289     {
1290       mIndicatorAnimation.AnimateTo( Property( mIndicatorImageContainerActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
1291
1292       mIsShowing = true;
1293
1294       OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1295     }
1296
1297     mIndicatorAnimation.Play();
1298     mIsAnimationPlaying = true;
1299   }
1300
1301   if(duration > 0)
1302   {
1303     if(!mShowTimer)
1304     {
1305       mShowTimer = Dali::Timer::New(1000 * duration);
1306       mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer);
1307     }
1308     mShowTimer.SetInterval(1000* duration);
1309     mShowTimer.Start();
1310
1311     if( mVisible == Dali::Window::AUTO )
1312     {
1313       // check the stage touch
1314       Dali::Stage::GetCurrent().TouchedSignal().Connect( this, &Indicator::OnStageTouched );
1315     }
1316   }
1317   else
1318   {
1319     if(mShowTimer && mShowTimer.IsRunning())
1320     {
1321       mShowTimer.Stop();
1322     }
1323
1324     if( mVisible == Dali::Window::AUTO )
1325     {
1326       // check the stage touch
1327       Dali::Stage::GetCurrent().TouchedSignal().Disconnect( this, &Indicator::OnStageTouched );
1328     }
1329   }
1330 }
1331
1332 bool Indicator::OnShowTimer()
1333 {
1334   // after time up, hide indicator
1335   ShowIndicator( HIDE_NOW );
1336
1337   return false;
1338 }
1339
1340 void Indicator::OnAnimationFinished(Dali::Animation& animation)
1341 {
1342   mIsAnimationPlaying = false;
1343   // once animation is finished and indicator is hidden, take it off stage
1344   if( !mIsShowing )
1345   {
1346     if( mObserver != NULL )
1347     {
1348       mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
1349     }
1350   }
1351 }
1352
1353 void Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1354 {
1355   if( mServerConnection )
1356   {
1357     switch( gesture.state )
1358     {
1359       case Gesture::Started:
1360       {
1361         mGestureDetected = false;
1362
1363         // The gesture position is the current position after it has moved by the displacement.
1364         // We want to reference the original position.
1365         mGestureDeltaY = gesture.position.y - gesture.displacement.y;
1366       }
1367
1368       // No break, Fall through
1369       case Gesture::Continuing:
1370       {
1371         if( mVisible == Dali::Window::AUTO && !mIsShowing )
1372         {
1373           // Only take one touch point
1374           if( gesture.numberOfTouches == 1 && mGestureDetected == false )
1375           {
1376             mGestureDeltaY += gesture.displacement.y;
1377
1378             if( mGestureDeltaY >= mImageHeight * SHOWING_DISTANCE_HEIGHT_RATE )
1379             {
1380               ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1381               mGestureDetected = true;
1382             }
1383           }
1384         }
1385
1386         break;
1387       }
1388
1389       case Gesture::Finished:
1390       case Gesture::Cancelled:
1391       {
1392         // if indicator is showing, hide again when touching is finished (Since touch leave is activated, checking it in gesture::finish instead of touch::up)
1393         if( mVisible == Dali::Window::AUTO && mIsShowing )
1394         {
1395           ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1396         }
1397         break;
1398       }
1399
1400
1401       default:
1402         break;
1403     }
1404   }
1405 }
1406
1407 void Indicator::OnStageTouched(const Dali::TouchEvent& touchEvent)
1408 {
1409   const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
1410
1411   // when stage is touched while indicator is showing temporary, hide it
1412   if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1413   {
1414     switch( touchPoint.state )
1415     {
1416       case Dali::TouchPoint::Down:
1417       {
1418         ShowIndicator( HIDE_NOW );
1419         break;
1420       }
1421
1422       default:
1423       break;
1424     }
1425   }
1426 }
1427
1428 } // Adaptor
1429 } // Internal
1430 } // Dali