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