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