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