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