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