(Indicator) Added SetIndicatorStyle()
[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 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 <dali/public-api/adaptor-framework/common/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 <internal/common/adaptor-impl.h>
44 #include <internal/common/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.17f); // 10 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   mConnection( this ),
370   mStyle( style ),
371   mOpacityMode( Dali::Window::OPAQUE ),
372   mState( DISCONNECTED ),
373   mAdaptor(adaptor),
374   mServerConnection( NULL ),
375   mLock( NULL ),
376   mSharedFile( NULL ),
377   mObserver( observer ),
378   mOrientation( orientation ),
379   mRotation( 0 ),
380   mImageWidth( 0 ),
381   mImageHeight( 0 ),
382   mVisible( Dali::Window::VISIBLE ),
383   mIsShowing( true ),
384   mIsAnimationPlaying( false ),
385   mTouchedDown( 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   SetBackground();
395   mBackgroundActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
396   mBackgroundActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
397   mBackgroundActor.SetZ(-0.01f);
398
399   // add background to image actor to move it with indicator image
400   mIndicatorImageActor.Add( mBackgroundActor );
401
402   mIndicatorActor = Dali::Actor::New();
403   mIndicatorActor.Add( mIndicatorImageActor );
404
405   if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
406   {
407     mBackgroundActor.SetVisible( false );
408   }
409
410   // event handler
411   mEventActor = Dali::Actor::New();
412   mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
413   mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
414   mEventActor.SetPosition(0.0f, 0.0f, 1.0f);
415   mEventActor.TouchedSignal().Connect( this, &Indicator::OnTouched );
416   mEventActor.SetLeaveRequired( true );
417   mIndicatorActor.Add( mEventActor );
418
419   Open( orientation );
420
421   // register indicator to accessibility manager
422   Dali::AccessibilityManager accessibilityManager = AccessibilityManager::Get();
423   if(accessibilityManager)
424   {
425     AccessibilityManager::GetImplementation( accessibilityManager ).SetIndicator( this );
426   }
427 }
428
429 Indicator::~Indicator()
430 {
431   if(mEventActor)
432   {
433     mEventActor.TouchedSignal().Disconnect( this, &Indicator::OnTouched );
434   }
435   Disconnect();
436 }
437
438 void Indicator::SetAdaptor(Adaptor* adaptor)
439 {
440   mAdaptor = adaptor;
441   mIndicatorBuffer->SetAdaptor( adaptor );
442 }
443
444 Dali::Actor Indicator::GetActor()
445 {
446   return mIndicatorActor;
447 }
448
449 void Indicator::Open( Dali::Window::WindowOrientation orientation )
450 {
451   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
452
453   // Calls from Window should be set up to ensure we are in a
454   // disconnected state before opening a second time.
455   DALI_ASSERT_DEBUG( mState == DISCONNECTED );
456
457   Connect( orientation );
458
459   // Change background visibility depending on orientation
460   if(mOrientation == Dali::Window::PORTRAIT || mOrientation == Dali::Window::PORTRAIT_INVERSE)
461   {
462     mBackgroundActor.SetVisible(true);
463   }
464   else
465   {
466     mBackgroundActor.SetVisible(false);
467   }
468 }
469
470 void Indicator::Close()
471 {
472   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s\n", STATE_DEBUG_STRING(mState) );
473
474   if( mState == CONNECTED )
475   {
476     Disconnect();
477     if( mObserver != NULL )
478     {
479       mObserver->IndicatorClosed( this );
480     }
481   }
482
483   Dali::Image emptyImage;
484   mIndicatorImageActor.SetImage(emptyImage);
485 }
486
487 void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
488 {
489   mOpacityMode = mode;
490   SetBackground();
491 }
492
493 void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
494 {
495   if ( visibleMode != mVisible || forceUpdate )
496   {
497     // If we were previously hidden, then we should update the image data before we display the indicator
498     if ( mVisible == Dali::Window::INVISIBLE )
499     {
500       UpdateImageData();
501     }
502
503     mVisible = visibleMode;
504
505     if( mIndicatorImageActor.GetImage() )
506     {
507       if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
508       {
509         // hide indicator
510         ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
511       }
512       else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
513       {
514         // show indicator
515         ShowIndicator( KEEP_SHOWING );
516       }
517       else
518       {
519         // hide indicator
520         ShowIndicator( HIDE_NOW );
521       }
522     }
523   }
524 }
525
526 bool Indicator::IsConnected()
527 {
528   return ( mState == CONNECTED );
529 }
530
531 bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size )
532 {
533  if(IsConnected())
534  {
535    return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
536  }
537  else
538  {
539    return false;
540  }
541 }
542
543 bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEvent)
544 {
545   if(mServerConnection)
546   {
547     const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
548
549     // Send touch event to indicator server when indicator is showing
550     if( CheckVisibleState() || mIsShowing )
551     {
552       switch( touchPoint.state )
553       {
554         case Dali::TouchPoint::Down:
555         {
556           IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
557           IpcDataEvMouseDown ipcDown( touchEvent.time );
558           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
559           mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
560
561           if( mVisible == Dali::Window::AUTO )
562           {
563             // Stop hiding indicator
564             ShowIndicator( KEEP_SHOWING );
565             mEventActor.SetSize( Dali::Stage::GetCurrent().GetSize() );
566           }
567         }
568         break;
569
570         case Dali::TouchPoint::Motion:
571         {
572           IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
573           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
574         }
575         break;
576
577         case Dali::TouchPoint::Up:
578         {
579           IpcDataEvMouseUp ipcUp( touchEvent.time );
580           mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
581
582           if( mVisible == Dali::Window::AUTO )
583           {
584             // Hide indicator
585             ShowIndicator( 0.5f /* hide after 0.5 sec */ );
586             // TODO: not necessary if dali supports the event for both indicator and behind button
587             mEventActor.SetSize( mImageWidth, mImageHeight / 2 );
588           }
589         }
590         break;
591
592         case Dali::TouchPoint::Leave:
593         {
594           IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
595           mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
596           IpcDataEvMouseUp ipcOut( touchEvent.time );
597           mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
598         }
599         break;
600
601         default:
602           break;
603       }
604     }
605     // show indicator when it is invisible
606     else if( !mIsShowing && ( CheckVisibleState() == false && mVisible == Dali::Window::AUTO ) )
607     {
608       switch( touchPoint.state )
609       {
610         case Dali::TouchPoint::Down:
611         {
612           mTouchedDown = true;
613           mTouchDownPosition = touchPoint.local;
614
615         }
616         break;
617
618         case Dali::TouchPoint::Motion:
619         case Dali::TouchPoint::Up:
620         case Dali::TouchPoint::Leave:
621         {
622           if( mTouchedDown )
623           {
624             float moveDistance = sqrt( (mTouchDownPosition.x - touchPoint.local.x) * (mTouchDownPosition.x - touchPoint.local.x)
625                                + (mTouchDownPosition.y - touchPoint.local.y)*(mTouchDownPosition.y - touchPoint.local.y) );
626
627             if( moveDistance > 2 * (mImageHeight * SHOWING_DISTANCE_HEIGHT_RATE) /*threshold for distance*/
628               && touchPoint.local.y - mTouchDownPosition.y > mImageHeight * SHOWING_DISTANCE_HEIGHT_RATE /*threshold for y*/ )
629             {
630               ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
631               mTouchedDown = false;
632             }
633           }
634         }
635         break;
636
637         default:
638           break;
639       }
640     }
641   }
642
643   return true;
644 }
645
646 /**
647  * Return the current orientation in degrees
648  * @return value of 0, 90, 180 or 270
649  */
650 int Indicator::OrientationToDegrees( Dali::Window::WindowOrientation orientation )
651 {
652   int degree = 0;
653
654   switch( orientation )
655   {
656     case Dali::Window::PORTRAIT:
657       degree = 0;
658       break;
659     case Dali::Window::PORTRAIT_INVERSE:
660       degree = 180;
661       break;
662     case Dali::Window::LANDSCAPE:
663       degree = 90;
664       break;
665     case Dali::Window::LANDSCAPE_INVERSE:
666       degree = 270;
667       break;
668   }
669   return degree;
670 }
671
672 bool Indicator::Connect( Dali::Window::WindowOrientation orientation )
673 {
674   DALI_ASSERT_DEBUG( mState == DISCONNECTED );
675
676   bool connected = false;
677   mOrientation = orientation;
678   mRotation = OrientationToDegrees(mOrientation);
679
680   switch( orientation )
681   {
682     case Dali::Window::PORTRAIT:
683       if(mStyle == Dali::Window::FIXED_COLOR)
684       {
685         connected = Connect( ELM_INDICATOR_PORTRAIT_FIXED_COLOR_STYLE );
686       }
687       else
688       {
689         connected = Connect( ELM_INDICATOR_PORTRAIT );
690       }
691       break;
692     case Dali::Window::PORTRAIT_INVERSE:
693       if(mStyle == Dali::Window::FIXED_COLOR)
694       {
695         connected = Connect( ELM_INDICATOR_PORTRAIT_FIXED_COLOR_STYLE );
696       }
697       else
698       {
699         connected = Connect( ELM_INDICATOR_PORTRAIT );
700       }
701       break;
702     case Dali::Window::LANDSCAPE:
703       if(mStyle == Dali::Window::FIXED_COLOR)
704       {
705         connected = Connect( ELM_INDICATOR_LANDSCAPE_FIXED_COLOR_STYLE );
706       }
707       else
708       {
709         connected = Connect( ELM_INDICATOR_LANDSCAPE );
710       }
711       break;
712     case Dali::Window::LANDSCAPE_INVERSE:
713       if(mStyle == Dali::Window::FIXED_COLOR)
714       {
715         connected = Connect( ELM_INDICATOR_LANDSCAPE_FIXED_COLOR_STYLE );
716       }
717       else
718       {
719         connected = Connect( ELM_INDICATOR_LANDSCAPE );
720       }
721       break;
722   }
723
724   return connected;
725 }
726
727 bool Indicator::Connect( const char *serviceName )
728 {
729   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
730
731   bool connected = false;
732
733   mServerConnection = new ServerConnection( serviceName, 0, false, this );
734   if( mServerConnection )
735   {
736     connected = mServerConnection->IsConnected();
737     if( ! connected )
738     {
739       delete mServerConnection;
740       mServerConnection = NULL;
741     }
742   }
743
744   if( !connected )
745   {
746     StartReconnectionTimer();
747   }
748   else
749   {
750     mState = CONNECTED;
751   }
752
753   return connected;
754 }
755
756 void Indicator::StartReconnectionTimer()
757 {
758   if( ! mReconnectTimer )
759   {
760     mReconnectTimer = Dali::Timer::New(1000);
761     mConnection.DisconnectAll();
762     mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
763   }
764   mReconnectTimer.Start();
765 }
766
767 bool Indicator::OnReconnectTimer()
768 {
769   bool retry = false;
770
771   if( mState == DISCONNECTED )
772   {
773     if( ! Connect( mOrientation ) )
774     {
775       retry = true;
776     }
777   }
778
779   return retry;
780 }
781
782 void Indicator::Disconnect()
783 {
784   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
785
786   mState = DISCONNECTED;
787
788   delete mLock;
789   mLock = NULL;
790
791   delete mSharedFile;
792   mSharedFile = NULL;
793
794   delete mServerConnection;
795   mServerConnection = NULL;
796 }
797
798 void Indicator::NewLockFile( Ecore_Ipc_Event_Server_Data *epcEvent )
799 {
800   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
801
802   delete mLock;
803   mLock = NULL;
804
805   if ( (epcEvent->data) &&
806        (epcEvent->size > 0) &&
807        (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
808   {
809     const char* lockFile = static_cast< const char* >( epcEvent->data );
810     mLock = new Indicator::LockFile( lockFile );
811     if( mLock->RetrieveAndClearErrorStatus() )
812     {
813       DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", lockFile );
814     }
815   }
816 }
817
818 void Indicator::Resize( int width, int height )
819 {
820   if( width < 1 )
821   {
822     width = 1;
823   }
824   if( height < 1 )
825   {
826     height = 1;
827   }
828
829   if( mImageWidth != width || mImageHeight != height )
830   {
831     mImageWidth = width;
832     mImageHeight = height;
833
834     // We don't currently handle the pixel buffer size being changed. Create a new image instead
835     if( mSharedFile )
836     {
837       CreateNewImage();
838     }
839   }
840 }
841
842 void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
843 {
844   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
845
846   // epcEvent->ref == w
847   // epcEvent->ref_to == h
848   // epcEvent->response == alpha
849   // epcEvent->data = pixmap id
850   if( ( epcEvent->data ) &&
851       (epcEvent->size >= (int)sizeof(PixmapId)) )
852   {
853     if( mSharedFile != NULL )
854     {
855       delete mSharedFile;
856       mSharedFile = NULL;
857     }
858
859     if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
860     {
861       mImageWidth  = epcEvent->ref;
862       mImageHeight = epcEvent->ref_to;
863
864       mPixmap = *(static_cast<PixmapId*>(epcEvent->data));
865       CreateNewPixmapImage();
866
867       if( CheckVisibleState() )
868       {
869         // set default indicator type (enable the quick panel)
870         OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
871       }
872       else
873       {
874         // set default indicator type (disable the quick panel)
875         OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
876       }
877
878       SetVisible(mVisible, true);
879     }
880   }
881 }
882
883 void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
884 {
885   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
886
887   // epcEvent->ref == w
888   // epcEvent->ref_to == h
889   // epcEvent->response == alpha
890   // epcEvent->data = shm ref string + nul byte
891   if( ( epcEvent->data ) &&
892       ( ( unsigned char * ) epcEvent->data)[ epcEvent->size - 1 ] == 0 )
893   {
894     if( mSharedFile != NULL )
895     {
896       delete mSharedFile;
897       mSharedFile = NULL;
898     }
899
900     if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
901     {
902       mImageWidth  = epcEvent->ref;
903       mImageHeight = epcEvent->ref_to;
904
905       char* sharedFilename = static_cast<char*>(epcEvent->data);
906
907       mSharedFile = SharedFile::New( sharedFilename, mImageWidth * mImageWidth * 4, true );
908       if( mSharedFile != NULL )
909       {
910         CreateNewImage();
911         mEventActor.SetSize(mImageWidth, mImageHeight);
912
913         if( CheckVisibleState() )
914         {
915           // set default indicator type (enable the quick panel)
916           OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
917         }
918         else
919         {
920           // set default indicator type (disable the quick panel)
921           OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
922         }
923
924         SetVisible(mVisible, true);
925       }
926     }
927   }
928 }
929
930 void Indicator::UpdateImageData()
931 {
932   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s  mVisible: %s\n", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
933
934   if( mState == CONNECTED && mVisible )
935   {
936     if(mPixmap == 0)
937     {
938       CopyToBuffer();
939     }
940     else
941     {
942       mAdaptor->RequestUpdateOnce();
943     }
944   }
945 }
946
947 bool Indicator::CopyToBuffer()
948 {
949   bool success = false;
950
951   if( mLock )
952   {
953     Indicator::ScopedLock scopedLock(mLock);
954     if( mLock->RetrieveAndClearErrorStatus() )
955     {
956       // Do nothing here.
957     }
958     else if( scopedLock.IsLocked() )
959     {
960       unsigned char *src = mSharedFile->GetAddress();
961       size_t size = mImageWidth * mImageHeight * 4;
962
963       if( mIndicatorBuffer->UpdatePixels( src, size ) )
964       {
965         mAdaptor->RequestUpdateOnce();
966         success = true;
967       }
968     }
969   }
970
971   return success;
972 }
973
974 void Indicator::SetBackground()
975 {
976   if( ! mBackgroundActor )
977   {
978     ConstructBackgroundMesh();
979   }
980
981   switch( mOpacityMode )
982   {
983     case Dali::Window::TRANSLUCENT:
984     {
985       SetMeshDataColors( mBackgroundMesh, GRADIENT_COLORS );
986     }
987     break;
988
989     case Dali::Window::TRANSPARENT:
990     {
991       SetMeshDataColors( mBackgroundMesh, Color::TRANSPARENT );
992     }
993     break;
994
995     case Dali::Window::OPAQUE:
996     default :
997     {
998       SetMeshDataColors( mBackgroundMesh, Color::BLACK );
999     }
1000     break;
1001   }
1002 }
1003
1004 void Indicator::CreateNewPixmapImage()
1005 {
1006   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d\n", mImageWidth, mImageHeight );
1007   Dali::PixmapImagePtr pixmapImage = Dali::PixmapImage::New(mPixmap, Dali::Adaptor::Get());
1008
1009   if( pixmapImage )
1010   {
1011     mIndicatorImageActor.SetImage( Dali::Image::New(*pixmapImage) );
1012     mIndicatorImageActor.SetSize( mImageWidth, mImageHeight );
1013     mIndicatorActor.SetSize( mImageWidth, mImageHeight );
1014     mEventActor.SetSize(mImageWidth, mImageHeight);
1015
1016     SetBackground();
1017     if( mBackgroundActor )
1018     {
1019       mBackgroundActor.SetSize( mImageWidth, mImageHeight );
1020     }
1021   }
1022   else
1023   {
1024     DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1025     Disconnect();
1026     if( mObserver != NULL )
1027     {
1028       mObserver->IndicatorClosed( this );
1029     }
1030     // Don't do connection in this callback - strange things happen!
1031     StartReconnectionTimer();
1032   }
1033 }
1034
1035 void Indicator::CreateNewImage()
1036 {
1037   DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d\n", mImageWidth, mImageHeight );
1038   mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mImageWidth, mImageHeight, Pixel::BGRA8888 );
1039   Dali::Image image = Dali::Image::New( mIndicatorBuffer->GetNativeImage() );
1040
1041   if( CopyToBuffer() ) // Only create images if we have valid image buffer
1042   {
1043     mIndicatorImageActor.SetImage( image );
1044     mIndicatorImageActor.SetSize( mImageWidth, mImageHeight );
1045     mIndicatorActor.SetSize( mImageWidth, mImageHeight );
1046     mEventActor.SetSize(mImageWidth, mImageHeight);
1047
1048     SetBackground();
1049     if( mBackgroundActor )
1050     {
1051       mBackgroundActor.SetSize( mImageWidth, mImageHeight );
1052     }
1053   }
1054   else
1055   {
1056     DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1057     Disconnect();
1058     if( mObserver != NULL )
1059     {
1060       mObserver->IndicatorClosed( this );
1061     }
1062     // Don't do connection in this callback - strange things happen!
1063     StartReconnectionTimer();
1064   }
1065 }
1066
1067 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
1068 {
1069   if( mObserver != NULL )
1070   {
1071     mObserver->IndicatorTypeChanged( indicatorType );
1072   }
1073 }
1074
1075 void Indicator::DataReceived( void* event )
1076 {
1077   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1078   Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1079
1080   switch( epcEvent->minor )
1081   {
1082     case OP_UPDATE:
1083       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1084       if(mPixmap != 0)
1085       {
1086         mAdaptor->RequestUpdateOnce();
1087       }
1088       break;
1089
1090     case OP_UPDATE_DONE:
1091       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE\n" );
1092       UpdateImageData();
1093       break;
1094
1095     case OP_LOCK_FILE:
1096       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_LOCK_FILE\n" );
1097       NewLockFile( epcEvent );
1098       break;
1099
1100     case OP_SHM_REF:
1101       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF\n" );
1102       LoadSharedImage( epcEvent );
1103       break;
1104
1105     case OP_PIXMAP_REF:
1106       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_PIXMAP_REF\n" );
1107       LoadPixmapImage( epcEvent );
1108       break;
1109
1110     case OP_RESIZE:
1111       DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1112
1113       if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1114       {
1115         IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1116         Resize( newSize->w, newSize->h );
1117       }
1118       break;
1119
1120     case OP_MSG_PARENT:
1121     {
1122       int msgDomain = epcEvent->ref;
1123       int msgId = epcEvent->ref_to;
1124
1125       void *msgData = NULL;
1126       int msgDataSize = 0;
1127       msgData = epcEvent->data;
1128       msgDataSize = epcEvent->size;
1129
1130       if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1131       {
1132         switch( msgId )
1133         {
1134           case MSG_ID_INDICATOR_TYPE:
1135           {
1136             DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1137             Type* indicatorType = static_cast<Type*>( epcEvent->data );
1138             OnIndicatorTypeChanged( *indicatorType );
1139             break;
1140           }
1141
1142           case MSG_ID_INDICATOR_START_ANIMATION:
1143           {
1144             if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1145             {
1146               DALI_LOG_ERROR("Message data is incorrect");
1147               break;
1148             }
1149
1150             IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1151
1152             if(!CheckVisibleState())
1153             {
1154               ShowIndicator( animData->duration /* n sec */ );
1155             }
1156             break;
1157           }
1158
1159         }
1160       }
1161       break;
1162     }
1163   }
1164 }
1165
1166 void Indicator::ConnectionClosed()
1167 {
1168   DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1169
1170   // Will get this callback if the server connection failed to start up.
1171   delete mServerConnection;
1172   mServerConnection = NULL;
1173   mState = DISCONNECTED;
1174
1175   // Attempt to re-connect
1176   Connect(mOrientation);
1177 }
1178
1179 bool Indicator::CheckVisibleState()
1180 {
1181   if( mOrientation == Dali::Window::LANDSCAPE
1182     || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1183     || (mVisible != Dali::Window::VISIBLE) )
1184   {
1185     return false;
1186   }
1187
1188   return true;
1189 }
1190
1191 void Indicator::ConstructBackgroundMesh()
1192 {
1193   // Construct 5 interval mesh
1194   // 0  +---+  1
1195   //    | \ |
1196   // 2  +---+  3
1197   //    | \ |
1198   // 4  +---+  5
1199   //    | \ |
1200   // 6  +---+  7
1201   //    | \ |
1202   // 8  +---+  9
1203   //    | \ |
1204   // 10 +---+  11
1205   Dali::AnimatableMesh::Faces faces;
1206   faces.reserve(NUM_GRADIENT_INTERVALS * 6); // 2 tris per interval
1207   for(int i=0; i<NUM_GRADIENT_INTERVALS; i++)
1208   {
1209     int j=i*2;
1210     faces.push_back(j); faces.push_back(j+3); faces.push_back(j+1);
1211     faces.push_back(j); faces.push_back(j+2); faces.push_back(j+3);
1212   }
1213
1214   mBackgroundMesh = Dali::AnimatableMesh::New((NUM_GRADIENT_INTERVALS+1)*2, faces);
1215   float interval=1.0f / (float)NUM_GRADIENT_INTERVALS;
1216   for(int i=0;i<NUM_GRADIENT_INTERVALS+1;i++)
1217   {
1218     int j=i*2;
1219     mBackgroundMesh[j  ].SetPosition(Vector3(-0.5f, -0.5f+(interval*(float)i), 0.0f));
1220     mBackgroundMesh[j+1].SetPosition(Vector3( 0.5f, -0.5f+(interval*(float)i), 0.0f));
1221   }
1222
1223   mBackgroundActor = Dali::MeshActor::New(mBackgroundMesh);
1224   mBackgroundActor.SetAffectedByLighting(false);
1225   Dali::ShaderEffect shaderEffect = Dali::ShaderEffect::New( MESH_VERTEX_SHADER, MESH_FRAGMENT_SHADER,
1226                                                              GEOMETRY_TYPE_MESH, // Using vertex color
1227                                                              Dali::ShaderEffect::HINT_BLENDING );
1228   mBackgroundActor.SetShaderEffect(shaderEffect);
1229 }
1230
1231 void Indicator::ShowIndicator(float duration)
1232 {
1233   if( !mIndicatorAnimation )
1234   {
1235     mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1236     mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished);
1237   }
1238
1239   if(mIsShowing && duration != 0)
1240   {
1241     // do not need to show it again
1242   }
1243   else if(!mIsShowing && mIsAnimationPlaying && duration == 0)
1244   {
1245     // do not need to hide it again
1246   }
1247   else
1248   {
1249     if(duration == 0)
1250     {
1251       mIndicatorAnimation.MoveTo(mIndicatorImageActor, Vector3(0, -mImageHeight, 0), Dali::AlphaFunctions::EaseOut);
1252
1253       mIsShowing = false;
1254
1255       OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1256     }
1257     else
1258     {
1259       mIndicatorAnimation.MoveTo(mIndicatorImageActor, Vector3(0, 0, 0), Dali::AlphaFunctions::EaseOut);
1260
1261       mIsShowing = true;
1262
1263       OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1264     }
1265
1266     mIndicatorAnimation.Play();
1267     mIsAnimationPlaying = true;
1268   }
1269
1270   if(duration > 0)
1271   {
1272     if(!mShowTimer)
1273     {
1274       mShowTimer = Dali::Timer::New(1000 * duration);
1275       mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer);
1276     }
1277     mShowTimer.SetInterval(1000* duration);
1278     mShowTimer.Start();
1279
1280     if( mVisible == Dali::Window::AUTO )
1281     {
1282         // check the stage touch
1283         Dali::Stage::GetCurrent().TouchedSignal().Connect( this, &Indicator::OnStageTouched );
1284     }
1285   }
1286   else
1287   {
1288     if(mShowTimer && mShowTimer.IsRunning())
1289     {
1290       mShowTimer.Stop();
1291     }
1292
1293     if( mVisible == Dali::Window::AUTO )
1294     {
1295         // check the stage touch
1296         Dali::Stage::GetCurrent().TouchedSignal().Disconnect( this, &Indicator::OnStageTouched );
1297     }
1298   }
1299 }
1300
1301 bool Indicator::OnShowTimer()
1302 {
1303   // after time up, hide indicator
1304   ShowIndicator( HIDE_NOW );
1305
1306   return false;
1307 }
1308
1309 void Indicator::OnAnimationFinished(Dali::Animation& animation)
1310 {
1311   mIsAnimationPlaying = false;
1312
1313   if( mIsShowing == false )
1314   {
1315     // TODO: not necessary if dali supports the event for both indicator and behind button
1316     mEventActor.SetSize(mImageWidth, mImageHeight /2);
1317   }
1318   else
1319   {
1320     mEventActor.SetSize(mImageWidth, mImageHeight);
1321   }
1322 }
1323
1324 void Indicator::OnStageTouched(const Dali::TouchEvent& touchEvent)
1325 {
1326   const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
1327
1328   // when stage is touched while indicator is showing temporary, hide it
1329   if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1330   {
1331     switch( touchPoint.state )
1332     {
1333       case Dali::TouchPoint::Down:
1334       {
1335         ShowIndicator( HIDE_NOW );
1336         break;
1337       }
1338
1339       default:
1340       break;
1341     }
1342   }
1343 }
1344
1345 } // Adaptor
1346 } // Internal
1347 } // Dali