b5dbdec46ef9e02fd7c3a26f4e61532645ac57d7
[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         return;
1011       }
1012
1013       CreateNewImage( n );
1014       UpdateVisibility();
1015     }
1016   }
1017 }
1018
1019 void Indicator::SetupNativeIndicatorImage( Ecore_Ipc_Event_Server_Data *epcEvent )
1020 {
1021   // Bind tizen remote surface
1022   Eina_Inlist* globals;
1023   Ecore_Wl_Global* global;
1024   struct tizen_remote_surface_manager* remoteSurfaceManager = NULL;
1025   struct tizen_remote_surface* remoteSurface = NULL;
1026   struct wl_registry* registry;
1027   struct wayland_tbm_client* tbmClient;
1028   struct wl_tbm* wlTbm;
1029
1030   if ( !remoteSurfaceManager )
1031   {
1032     registry = ecore_wl_registry_get();
1033     globals = ecore_wl_globals_get();
1034
1035     if (!registry || !globals)
1036     {
1037       DALI_LOG_ERROR( "SetupNativeIndicatorImage registry or globals error\n" );
1038       return;
1039     }
1040
1041     EINA_INLIST_FOREACH(globals, global)
1042     {
1043       if ( !strcmp( global->interface, "tizen_remote_surface_manager" ) )
1044       {
1045         remoteSurfaceManager = ( struct tizen_remote_surface_manager* )wl_registry_bind( registry, global->id, &tizen_remote_surface_manager_interface, ( ( global->version < 2 )? global->version: 2 ) );
1046       }
1047     }
1048   }
1049   if ( !remoteSurfaceManager )
1050   {
1051     DALI_LOG_ERROR( "SetupNativeIndicatorImage bind error\n" );
1052     return;
1053   }
1054
1055   tbmClient = ( struct wayland_tbm_client* )wayland_tbm_client_init( ecore_wl_display_get() );
1056   if( !tbmClient )
1057   {
1058     DALI_LOG_ERROR( "SetupNativeIndicatorImage client init error\n" );
1059     return;
1060   }
1061
1062   wlTbm = ( struct wl_tbm* )wayland_tbm_client_get_wl_tbm( tbmClient );
1063   if( !wlTbm )
1064   {
1065     DALI_LOG_ERROR( "SetupNativeIndicatorImage wl tbm error\n" );
1066     return;
1067   }
1068
1069   uint32_t resourceId = epcEvent->ref;
1070   remoteSurface = tizen_remote_surface_manager_create_surface( remoteSurfaceManager, resourceId, wlTbm );
1071
1072   if( !remoteSurface )
1073   {
1074     DALI_LOG_ERROR( "SetupNativeIndicatorImage create surface error\n" );
1075     return;
1076   }
1077
1078   tizen_remote_surface_add_listener( remoteSurface, &remoteSurfaceCallback, this );
1079   tizen_remote_surface_redirect( remoteSurface );
1080   tizen_remote_surface_transfer_visibility( remoteSurface, TIZEN_REMOTE_SURFACE_VISIBILITY_TYPE_VISIBLE);
1081 }
1082
1083 void Indicator::UpdateIndicatorImage( Any source )
1084 {
1085   if( !mNativeImageSource )
1086   {
1087     mNativeImageSource = Dali::NativeImageSource::New( source );
1088     Dali::NativeImage nativeImage = Dali::NativeImage::New( *mNativeImageSource );
1089
1090     SetForegroundNativeImage( nativeImage );
1091     mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
1092     mIndicatorActor.SetSize( mImageWidth, mImageHeight );
1093     mEventActor.SetSize( mImageWidth, mImageHeight );
1094
1095     UpdateVisibility();
1096     return;
1097   }
1098
1099   mNativeImageSource->SetSource( source );
1100   Dali::Stage::GetCurrent().KeepRendering( 0.0f );
1101 }
1102
1103 void Indicator::UpdateTopMargin()
1104 {
1105   int newMargin = (mVisible == Dali::Window::VISIBLE && mOpacityMode == Dali::Window::OPAQUE) ? mImageHeight : 0;
1106   if (mTopMargin != newMargin)
1107   {
1108     mTopMargin = newMargin;
1109     mAdaptor->IndicatorSizeChanged( mTopMargin );
1110   }
1111 }
1112
1113 void Indicator::UpdateVisibility()
1114 {
1115   if( CheckVisibleState() )
1116   {
1117     // set default indicator type (enable the quick panel)
1118     OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
1119   }
1120   else
1121   {
1122     // set default indicator type (disable the quick panel)
1123     OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
1124   }
1125
1126   if( !mIsShowing )
1127   {
1128     mIndicatorContentActor.SetPosition( 0.0f, -mImageHeight, 0.0f );
1129   }
1130
1131   SetVisible(mVisible, true);
1132 }
1133
1134 void Indicator::UpdateImageData( int bufferNumber )
1135 {
1136   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s  mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
1137
1138   if( mState == CONNECTED && mVisible )
1139   {
1140     if(mPixmap == 0)
1141     {
1142       // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false
1143       CopyToBuffer( bufferNumber );
1144     }
1145     else
1146     {
1147       if(mIsShowing)
1148       {
1149         mAdaptor->RequestUpdateOnce();
1150       }
1151     }
1152   }
1153 }
1154
1155 bool Indicator::CopyToBuffer( int bufferNumber )
1156 {
1157   bool success = false;
1158
1159   if( mSharedFileInfo[bufferNumber].mLock )
1160   {
1161     Indicator::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
1162     if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
1163     {
1164       // Do nothing here.
1165     }
1166     else if( scopedLock.IsLocked() )
1167     {
1168       unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
1169       size_t size = mSharedFileInfo[bufferNumber].mImageWidth * mSharedFileInfo[bufferNumber].mImageHeight * 4;
1170
1171       if( mIndicatorBuffer->UpdatePixels( src, size ) )
1172       {
1173         mAdaptor->RequestUpdateOnce();
1174         success = true;
1175       }
1176     }
1177   }
1178
1179   return success;
1180 }
1181
1182 void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
1183 {
1184 }
1185
1186 void Indicator::CreateNewPixmapImage()
1187 {
1188 }
1189
1190 void Indicator::CreateNewImage( int bufferNumber )
1191 {
1192   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
1193   mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
1194   bool success = false;
1195
1196   if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
1197   {
1198     Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() );
1199     if( texture )
1200     {
1201       SetForegroundImage( texture );
1202       success = true;
1203     }
1204   }
1205
1206   if( !success )
1207   {
1208     DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1209     Disconnect();
1210     if( mObserver != NULL )
1211     {
1212       mObserver->IndicatorClosed( this );
1213     }
1214     // Don't do connection in this callback - strange things happen!
1215     StartReconnectionTimer();
1216   }
1217 }
1218
1219 Dali::Geometry Indicator::CreateBackgroundGeometry()
1220 {
1221   switch( mOpacityMode )
1222   {
1223     case Dali::Window::TRANSLUCENT:
1224       if( !mTranslucentGeometry )
1225       {
1226         // Construct 5 interval mesh
1227         // 0  +---+  1
1228         //    | \ |
1229         // 2  +---+  3
1230         //    | \ |
1231         // 4  +---+  5
1232         //    | \ |
1233         // 6  +---+  7
1234         //    | \ |
1235         // 8  +---+  9
1236         //    | \ |
1237         // 10 +---+  11
1238
1239         // Create vertices
1240         struct BackgroundVertex
1241         {
1242           Vector2 mPosition;
1243           float   mAlpha;
1244         };
1245
1246         unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1247         BackgroundVertex vertices[ numVertices ];
1248
1249         float d = -0.5f;
1250         float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1251         BackgroundVertex* currentVertex = vertices;
1252         for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1253         {
1254           currentVertex->mPosition = Vector2( -0.5f, d );
1255           currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1256           currentVertex++;
1257
1258           currentVertex->mPosition = Vector2( 0.5f, d );
1259           currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1260           currentVertex++;
1261         }
1262
1263         // Create indices
1264         unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1265         unsigned short indices[ numIndices ];
1266
1267         unsigned short* currentIndex = indices;
1268         for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1269         {
1270           *currentIndex++ = (2 * y);
1271           *currentIndex++ = (2 * y) + 3;
1272           *currentIndex++ = (2 * y) + 1;
1273
1274           *currentIndex++ = (2 * y);
1275           *currentIndex++ = (2 * y) + 2;
1276           *currentIndex++ = (2 * y) + 3;
1277         }
1278
1279         Dali::Property::Map vertexFormat;
1280         vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1281         vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1282         Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1283         vertexPropertyBuffer.SetData( vertices, numVertices );
1284
1285         // Create the geometry object
1286         mTranslucentGeometry = Dali::Geometry::New();
1287         mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1288         mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices );
1289       }
1290
1291       return mTranslucentGeometry;
1292     case Dali::Window::OPAQUE:
1293
1294       if( !mSolidGeometry )
1295       {
1296         // Create vertices
1297         struct BackgroundVertex
1298         {
1299           Vector2 mPosition;
1300           float   mAlpha;
1301         };
1302
1303         BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1304                                            { Vector2( -0.5f,  0.5f ), 1.0f }, { Vector2( 0.5f,  0.5f ), 1.0f } };
1305
1306         // Create indices
1307         unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1308
1309         Dali::Property::Map vertexFormat;
1310         vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1311         vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1312         Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1313         vertexPropertyBuffer.SetData( vertices, 4 );
1314
1315
1316         // Create the geometry object
1317         mSolidGeometry = Dali::Geometry::New();
1318         mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1319         mSolidGeometry.SetIndexBuffer( &indices[0], 6 );
1320       }
1321
1322       return mSolidGeometry;
1323     case Dali::Window::TRANSPARENT:
1324       break;
1325   }
1326
1327   return Dali::Geometry();
1328 }
1329
1330 void Indicator::SetForegroundImage( Dali::Texture texture )
1331 {
1332   if( !mForegroundRenderer && texture )
1333   {
1334     // Create Shader
1335     Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER );
1336
1337     // Create renderer from geometry and material
1338     Dali::Geometry quad = CreateQuadGeometry();
1339     mForegroundRenderer = Dali::Renderer::New( quad, shader );
1340     // Make sure the foreground stays in front of the background
1341     mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1342
1343     // Set blend function
1344     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB,    Dali::BlendFactor::ONE );
1345     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB,   Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1346     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA,  Dali::BlendFactor::ONE );
1347     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1348
1349     // Create a texture-set and add to renderer
1350
1351     Dali::TextureSet textureSet = Dali::TextureSet::New();
1352     textureSet.SetTexture( 0u, texture );
1353     mForegroundRenderer.SetTextures( textureSet );
1354
1355     mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1356   }
1357   else if( mForegroundRenderer )
1358   {
1359     Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1360     textureSet.SetTexture( 0u, texture );
1361   }
1362
1363   if( mImageWidth == 0 && mImageHeight == 0  && texture)
1364   {
1365     Resize( texture.GetWidth(), texture.GetHeight() );
1366   }
1367 }
1368
1369 void Indicator::SetForegroundNativeImage( Dali::Image image )
1370 {
1371   if( !mForegroundRenderer && image )
1372   {
1373
1374     std::string fragmentShader = "#extension GL_OES_EGL_image_external:require\n";
1375     fragmentShader += "\n";
1376     fragmentShader += FOREGROUND_TBM_FRAGMENT_SHADER;
1377
1378     // Create Shader
1379     Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, fragmentShader );
1380
1381     // Create renderer from geometry and material
1382     Dali::Geometry quad = CreateQuadGeometry();
1383     mForegroundRenderer = Dali::Renderer::New( quad, shader );
1384     // Make sure the foreground stays in front of the background
1385     mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1386
1387     // Set blend function
1388     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB,    Dali::BlendFactor::ONE );
1389     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB,   Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1390     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA,  Dali::BlendFactor::ONE );
1391     mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1392
1393     // Create a texture-set and add to renderer
1394
1395     Dali::TextureSet textureSet = Dali::TextureSet::New();
1396     Dali::TextureSetImage( textureSet, 0u, image );
1397
1398     mForegroundRenderer.SetTextures( textureSet );
1399
1400     mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1401   }
1402   else if( mForegroundRenderer )
1403   {
1404     Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1405     Dali::TextureSetImage( textureSet, 0u, image );
1406   }
1407
1408   if( mImageWidth == 0 && mImageHeight == 0  && image )
1409   {
1410     Resize( image.GetWidth(), image.GetHeight() );
1411   }
1412 }
1413
1414 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
1415 {
1416   if( mObserver != NULL )
1417   {
1418     mObserver->IndicatorTypeChanged( indicatorType );
1419   }
1420 }
1421
1422 void Indicator::DataReceived( void* event )
1423 {
1424   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1425   Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1426
1427   switch( epcEvent->minor )
1428   {
1429     case OP_UPDATE:
1430     {
1431       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1432       if( mIsShowing )
1433       {
1434         mAdaptor->RequestUpdateOnce();
1435       }
1436       break;
1437     }
1438     case OP_UPDATE_DONE:
1439     {
1440       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1441       // epcEvent->response == display buffer #
1442       UpdateImageData( epcEvent->response );
1443       break;
1444     }
1445     case OP_SHM_REF0:
1446     {
1447       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1448       SetSharedImageInfo( epcEvent );
1449       break;
1450     }
1451     case OP_SHM_REF1:
1452     {
1453       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1454       SetLockFileInfo( epcEvent );
1455       break;
1456     }
1457     case OP_SHM_REF2:
1458     {
1459       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1460       LoadSharedImage( epcEvent );
1461       break;
1462     }
1463     case OP_GL_REF:
1464     {
1465       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_GL_REF\n" );
1466       SetupNativeIndicatorImage( epcEvent );
1467       break;
1468     }
1469     case OP_RESIZE:
1470     {
1471       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1472
1473       if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1474       {
1475         IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1476         Resize( newSize->w, newSize->h );
1477       }
1478       break;
1479     }
1480     case OP_MSG_PARENT:
1481     {
1482       int msgDomain = epcEvent->ref;
1483       int msgId = epcEvent->ref_to;
1484
1485       void *msgData = NULL;
1486       int msgDataSize = 0;
1487       msgData = epcEvent->data;
1488       msgDataSize = epcEvent->size;
1489
1490       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1491
1492       if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1493       {
1494         switch( msgId )
1495         {
1496           case MSG_ID_INDICATOR_TYPE:
1497           {
1498             DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1499             Type* indicatorType = static_cast<Type*>( epcEvent->data );
1500             OnIndicatorTypeChanged( *indicatorType );
1501             break;
1502           }
1503
1504           case MSG_ID_INDICATOR_START_ANIMATION:
1505           {
1506             DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1507
1508             if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1509             {
1510               DALI_LOG_ERROR("Message data is incorrect\n");
1511               break;
1512             }
1513
1514             IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1515
1516             if(!CheckVisibleState())
1517             {
1518               ShowIndicator( animData->duration /* n sec */ );
1519             }
1520             break;
1521           }
1522         }
1523       }
1524       break;
1525     }
1526   }
1527 }
1528
1529 void Indicator::ConnectionClosed()
1530 {
1531   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1532
1533   // Will get this callback if the server connection failed to start up.
1534   delete mServerConnection;
1535   mServerConnection = NULL;
1536   mState = DISCONNECTED;
1537
1538   // Attempt to re-connect
1539   Connect();
1540 }
1541
1542 bool Indicator::CheckVisibleState()
1543 {
1544   if( mOrientation == Dali::Window::LANDSCAPE
1545     || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1546     || (mVisible == Dali::Window::INVISIBLE)
1547     || (mVisible == Dali::Window::AUTO && !mIsShowing) )
1548   {
1549     return false;
1550   }
1551
1552   return true;
1553 }
1554
1555 void Indicator::ClearSharedFileInfo()
1556 {
1557   for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
1558   {
1559     delete mSharedFileInfo[i].mLock;
1560     mSharedFileInfo[i].mLock = NULL;
1561
1562     delete mSharedFileInfo[i].mSharedFile;
1563     mSharedFileInfo[i].mSharedFile = NULL;
1564
1565     mSharedFileInfo[i].mLockFileName.clear();
1566     mSharedFileInfo[i].mSharedFileName.clear();
1567   }
1568 }
1569
1570 /**
1571  * duration can be this
1572  *
1573  * enum
1574  * {
1575  *  KEEP_SHOWING = -1,
1576  *  HIDE_NOW = 0
1577  * };
1578  */
1579 void Indicator::ShowIndicator(float duration)
1580 {
1581   if( !mIndicatorAnimation )
1582   {
1583     mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1584     mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished);
1585   }
1586
1587   if(mIsShowing && !EqualsZero(duration))
1588   {
1589     // If need to show during showing, do nothing.
1590     // In 2nd phase (below) will update timer
1591   }
1592   else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1593   {
1594     // If need to hide during hiding or hidden already, do nothing
1595   }
1596   else
1597   {
1598     mIndicatorAnimation.Clear();
1599
1600     if( EqualsZero(duration) )
1601     {
1602       mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
1603
1604       mIsShowing = false;
1605
1606       OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1607     }
1608     else
1609     {
1610       mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
1611
1612       mIsShowing = true;
1613
1614       OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1615     }
1616
1617     mIndicatorAnimation.Play();
1618     mIsAnimationPlaying = true;
1619   }
1620
1621   if(duration > 0)
1622   {
1623     if(!mShowTimer)
1624     {
1625       mShowTimer = Dali::Timer::New(1000 * duration);
1626       mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer);
1627     }
1628     mShowTimer.SetInterval(1000* duration);
1629     mShowTimer.Start();
1630
1631     if( mVisible == Dali::Window::AUTO )
1632     {
1633       // check the stage touch
1634       Dali::Stage::GetCurrent().TouchedSignal().Connect( this, &Indicator::OnStageTouched );
1635     }
1636   }
1637   else
1638   {
1639     if(mShowTimer && mShowTimer.IsRunning())
1640     {
1641       mShowTimer.Stop();
1642     }
1643
1644     if( mVisible == Dali::Window::AUTO )
1645     {
1646       // check the stage touch
1647       Dali::Stage::GetCurrent().TouchedSignal().Disconnect( this, &Indicator::OnStageTouched );
1648     }
1649   }
1650 }
1651
1652 bool Indicator::OnShowTimer()
1653 {
1654   // after time up, hide indicator
1655   ShowIndicator( HIDE_NOW );
1656
1657   return false;
1658 }
1659
1660 void Indicator::OnAnimationFinished(Dali::Animation& animation)
1661 {
1662   mIsAnimationPlaying = false;
1663   // once animation is finished and indicator is hidden, take it off stage
1664   if( mObserver != NULL )
1665   {
1666     mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
1667   }
1668 }
1669
1670 void Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1671 {
1672   return ;
1673
1674   if( mServerConnection )
1675   {
1676     switch( gesture.state )
1677     {
1678       case Gesture::Started:
1679       {
1680         mGestureDetected = false;
1681
1682         // The gesture position is the current position after it has moved by the displacement.
1683         // We want to reference the original position.
1684         mGestureDeltaY = gesture.position.y - gesture.displacement.y;
1685       }
1686
1687       // No break, Fall through
1688       case Gesture::Continuing:
1689       {
1690         if( mVisible == Dali::Window::AUTO && !mIsShowing )
1691         {
1692           // Only take one touch point
1693           if( gesture.numberOfTouches == 1 && mGestureDetected == false )
1694           {
1695             mGestureDeltaY += gesture.displacement.y;
1696
1697             if( mGestureDeltaY >= mImageHeight * SHOWING_DISTANCE_HEIGHT_RATE )
1698             {
1699               ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1700               mGestureDetected = true;
1701             }
1702           }
1703         }
1704
1705         break;
1706       }
1707
1708       case Gesture::Finished:
1709       case Gesture::Cancelled:
1710       {
1711         // if indicator is showing, hide again when touching is finished (Since touch leave is activated, checking it in gesture::finish instead of touch::up)
1712         if( mVisible == Dali::Window::AUTO && mIsShowing )
1713         {
1714           ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1715         }
1716         break;
1717       }
1718
1719
1720       default:
1721         break;
1722     }
1723   }
1724 }
1725
1726 void Indicator::OnStageTouched(const Dali::TouchEvent& touchEvent)
1727 {
1728   const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
1729
1730   // when stage is touched while indicator is showing temporary, hide it
1731   if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1732   {
1733     switch( touchPoint.state )
1734     {
1735       case Dali::PointState::DOWN:
1736       {
1737         // if touch point is inside the indicator, indicator is not hidden
1738         if( mImageHeight < int(touchPoint.screen.y) )
1739         {
1740           ShowIndicator( HIDE_NOW );
1741         }
1742         break;
1743       }
1744
1745       default:
1746       break;
1747     }
1748   }
1749 }
1750
1751 } // Adaptor
1752 } // Internal
1753 } // Dali