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