2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "indicator-impl.h"
25 #include <sys/types.h>
31 #include <dali/public-api/images/bitmap-image.h>
32 #include <pixmap-image.h>
33 #include <dali/public-api/actors/image-actor.h>
34 #include <dali/public-api/events/touch-event.h>
35 #include <dali/public-api/events/touch-point.h>
36 #include <dali/public-api/common/stage.h>
37 #include <dali/public-api/actors/blending.h>
38 #include <dali/public-api/shader-effects/shader-effect.h>
40 #include <dali/integration-api/debug.h>
43 #include <adaptor-impl.h>
44 #include <accessibility-manager-impl.h>
48 #if defined(DEBUG_ENABLED)
49 #define STATE_DEBUG_STRING(state) (state==DISCONNECTED?"DISCONNECTED":state==CONNECTED?"CONNECTED":"UNKNOWN")
55 const float SLIDING_ANIMATION_DURATION( 0.2f ); // 200 milli seconds
56 const float AUTO_INDICATOR_STAY_DURATION(3.0f); // 3 seconds
57 const float SHOWING_DISTANCE_HEIGHT_RATE(0.34f); // 20 pixels
65 const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals
66 const Dali::Vector4 GRADIENT_COLORS[NUM_GRADIENT_INTERVALS+1] =
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),
76 const float OPAQUE_THRESHOLD(0.99f);
77 const float TRANSPARENT_THRESHOLD(0.05f);
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");
85 const char* MESH_VERTEX_SHADER =
86 "attribute lowp vec3 aColor;\n"
87 "varying mediump vec4 vColor;\n"
90 " gl_Position = uMvpMatrix * vec4(aPosition, 1.0);\n"
91 " vColor = vec4(aColor.r, aColor.g, aColor.b, aTexCoord.x);\n"
94 const char* MESH_FRAGMENT_SHADER =
95 "varying mediump vec4 vColor;\n"
98 " gl_FragColor = vColor*uColor;\n"
101 // Copied from elm_win.h
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
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;
115 // Copied from ecore_evas_extn.c
145 // Copied from elm_conform.c
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);
164 struct IpcIndicatorDataAnimation
170 struct IpcDataEvMouseUp
173 Evas_Button_Flags flags;
175 unsigned int timestamp;
176 Evas_Event_Flags event_flags;
178 IpcDataEvMouseUp(unsigned long timestamp)
180 flags(EVAS_BUTTON_NONE),
182 timestamp(static_cast<unsigned int>(timestamp)),
183 event_flags(EVAS_EVENT_FLAG_NONE)
188 struct IpcDataEvMouseDown
191 Evas_Button_Flags flags;
193 unsigned int timestamp;
194 Evas_Event_Flags event_flags;
196 IpcDataEvMouseDown(unsigned long timestamp)
198 flags(EVAS_BUTTON_NONE),
200 timestamp(static_cast<unsigned int>(timestamp)),
201 event_flags(EVAS_EVENT_FLAG_NONE)
206 struct IpcDataEvMouseMove
209 Evas_Button_Flags flags;
211 unsigned int timestamp;
212 Evas_Event_Flags event_flags;
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),
219 timestamp(static_cast<unsigned int>(timestamp)),
220 event_flags(EVAS_EVENT_FLAG_NONE)
225 struct IpcDataEvMouseOut
227 unsigned int timestamp;
229 Evas_Event_Flags event_flags;
231 IpcDataEvMouseOut(unsigned long timestamp)
232 : timestamp(static_cast<unsigned int>(timestamp)),
234 event_flags(EVAS_EVENT_FLAG_NONE)
239 void SetMeshDataColors(Dali::AnimatableMesh mesh, const Vector4 (&colors)[NUM_GRADIENT_INTERVALS+1])
241 for( size_t i=0; i<NUM_GRADIENT_INTERVALS+1; i++ )
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));
251 void SetMeshDataColors(Dali::AnimatableMesh mesh, const Vector4& color)
253 for( size_t i=0, length=NUM_GRADIENT_INTERVALS+1 ; i<length; i++ )
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));
263 } // anonymous namespace
272 #if defined(DEBUG_ENABLED)
273 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
277 Indicator::LockFile::LockFile(const char* filename)
278 : mFilename(filename),
281 mFileDescriptor = open(filename, O_RDWR);
282 if( mFileDescriptor == -1 )
286 DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
290 Indicator::LockFile::~LockFile()
292 // Closing file descriptor also unlocks file.
293 close( mFileDescriptor );
296 bool Indicator::LockFile::Lock()
298 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
301 if( mFileDescriptor > 0 )
303 if( lockf( mFileDescriptor, F_LOCK, 0 ) == 0 ) // Note, operation may block.
311 // file descriptor is no longer valid or not writable
314 DALI_LOG_ERROR( "### Cannot lock indicator: bad file descriptor for %s ###\n", mFilename.c_str() );
322 void Indicator::LockFile::Unlock()
324 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
325 if( lockf( mFileDescriptor, F_ULOCK, 0 ) != 0 )
329 // file descriptor is no longer valid or not writable
332 DALI_LOG_ERROR( "### Cannot unlock indicator: bad file descriptor for %s\n", mFilename.c_str() );
337 bool Indicator::LockFile::RetrieveAndClearErrorStatus()
339 bool error = mErrorThrown;
340 mErrorThrown = false;
344 Indicator::ScopedLock::ScopedLock(LockFile* lockFile)
345 : mLockFile(lockFile),
350 mLocked = mLockFile->Lock();
354 Indicator::ScopedLock::~ScopedLock()
362 bool Indicator::ScopedLock::IsLocked()
367 Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, Dali::Window::IndicatorStyle style, Observer* observer )
369 mGestureDetected( false ),
372 mOpacityMode( Dali::Window::OPAQUE ),
373 mState( DISCONNECTED ),
375 mServerConnection( NULL ),
378 mObserver( observer ),
379 mOrientation( orientation ),
383 mVisible( Dali::Window::INVISIBLE ),
385 mIsAnimationPlaying( false )
387 mIndicatorImageActor = Dali::ImageActor::New();
388 mIndicatorImageActor.SetBlendFunc( Dali::BlendingFactor::ONE, Dali::BlendingFactor::ONE_MINUS_SRC_ALPHA,
389 Dali::BlendingFactor::ONE, Dali::BlendingFactor::ONE );
391 mIndicatorImageActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
392 mIndicatorImageActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
394 // Indicator image handles the touch event including "leave"
395 mIndicatorImageActor.SetLeaveRequired( true );
396 mIndicatorImageActor.TouchedSignal().Connect( this, &Indicator::OnTouched );
399 mBackgroundActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
400 mBackgroundActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
401 mBackgroundActor.SetZ( -0.02f );
403 // add background to image actor to move it with indicator image
404 mIndicatorImageActor.Add( mBackgroundActor );
406 mIndicatorActor = Dali::Actor::New();
407 mIndicatorActor.Add( mIndicatorImageActor );
409 if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
411 mBackgroundActor.SetVisible( false );
414 // Event handler to find out flick down gesture
415 mEventActor = Dali::Actor::New();
416 mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
417 mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
418 mEventActor.SetZ( -0.01f );
419 mIndicatorActor.Add( mEventActor );
421 // Attach pan gesture to find flick down during hiding.
422 // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
423 // since it consumes the pan gesture in advance.
424 mPanDetector = Dali::PanGestureDetector::New();
425 mPanDetector.DetectedSignal().Connect( this, &Indicator::OnPan );
426 mPanDetector.Attach( mEventActor );
430 // register indicator to accessibility manager
431 Dali::AccessibilityManager accessibilityManager = AccessibilityManager::Get();
432 if(accessibilityManager)
434 AccessibilityManager::GetImplementation( accessibilityManager ).SetIndicator( this );
436 // hide the indicator by default
437 mIndicatorActor.SetVisible( false );
440 Indicator::~Indicator()
444 mEventActor.TouchedSignal().Disconnect( this, &Indicator::OnTouched );
449 void Indicator::SetAdaptor(Adaptor* adaptor)
452 mIndicatorBuffer->SetAdaptor( adaptor );
455 Dali::Actor Indicator::GetActor()
457 return mIndicatorActor;
460 void Indicator::Open( Dali::Window::WindowOrientation orientation )
462 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
464 // Calls from Window should be set up to ensure we are in a
465 // disconnected state before opening a second time.
466 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
468 Connect( orientation );
470 // Change background visibility depending on orientation
471 if(mOrientation == Dali::Window::PORTRAIT || mOrientation == Dali::Window::PORTRAIT_INVERSE)
473 mBackgroundActor.SetVisible(true);
477 mBackgroundActor.SetVisible(false);
481 void Indicator::Close()
483 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s\n", STATE_DEBUG_STRING(mState) );
485 if( mState == CONNECTED )
488 if( mObserver != NULL )
490 mObserver->IndicatorClosed( this );
494 Dali::Image emptyImage;
495 mIndicatorImageActor.SetImage(emptyImage);
498 void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
504 void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
506 if ( visibleMode != mVisible || forceUpdate )
508 // If we were previously hidden, then we should update the image data before we display the indicator
509 if ( mVisible == Dali::Window::INVISIBLE )
513 if ( visibleMode != Dali::Window::INVISIBLE )
515 mIndicatorActor.SetVisible( true );
518 mVisible = visibleMode;
520 if( mIndicatorImageActor.GetImage() )
522 if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
525 ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
527 else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
530 ShowIndicator( KEEP_SHOWING );
535 ShowIndicator( HIDE_NOW );
541 bool Indicator::IsConnected()
543 return ( mState == CONNECTED );
546 bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size )
550 return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
558 bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEvent)
560 if( mServerConnection )
562 const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
564 // Send touch event to indicator server when indicator is showing
565 if( CheckVisibleState() || mIsShowing )
567 switch( touchPoint.state )
569 case Dali::TouchPoint::Down:
571 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
572 IpcDataEvMouseDown ipcDown( touchEvent.time );
573 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
574 mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
576 if( mVisible == Dali::Window::AUTO )
578 // Stop hiding indicator
579 ShowIndicator( KEEP_SHOWING );
584 case Dali::TouchPoint::Motion:
586 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
587 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
591 case Dali::TouchPoint::Up:
593 IpcDataEvMouseUp ipcUp( touchEvent.time );
594 mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
596 if( mVisible == Dali::Window::AUTO )
599 ShowIndicator( 0.5f /* hide after 0.5 sec */ );
604 case Dali::TouchPoint::Leave:
606 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
607 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
608 IpcDataEvMouseUp ipcOut( touchEvent.time );
609 mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
625 * Return the current orientation in degrees
626 * @return value of 0, 90, 180 or 270
628 int Indicator::OrientationToDegrees( Dali::Window::WindowOrientation orientation )
632 switch( orientation )
634 case Dali::Window::PORTRAIT:
637 case Dali::Window::PORTRAIT_INVERSE:
640 case Dali::Window::LANDSCAPE:
643 case Dali::Window::LANDSCAPE_INVERSE:
650 bool Indicator::Connect( Dali::Window::WindowOrientation orientation )
652 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
654 bool connected = false;
655 mOrientation = orientation;
656 mRotation = OrientationToDegrees(mOrientation);
658 switch( orientation )
660 case Dali::Window::PORTRAIT:
661 if(mStyle == Dali::Window::FIXED_COLOR)
663 connected = Connect( ELM_INDICATOR_PORTRAIT_FIXED_COLOR_STYLE );
667 connected = Connect( ELM_INDICATOR_PORTRAIT );
670 case Dali::Window::PORTRAIT_INVERSE:
671 if(mStyle == Dali::Window::FIXED_COLOR)
673 connected = Connect( ELM_INDICATOR_PORTRAIT_FIXED_COLOR_STYLE );
677 connected = Connect( ELM_INDICATOR_PORTRAIT );
680 case Dali::Window::LANDSCAPE:
681 if(mStyle == Dali::Window::FIXED_COLOR)
683 connected = Connect( ELM_INDICATOR_LANDSCAPE_FIXED_COLOR_STYLE );
687 connected = Connect( ELM_INDICATOR_LANDSCAPE );
690 case Dali::Window::LANDSCAPE_INVERSE:
691 if(mStyle == Dali::Window::FIXED_COLOR)
693 connected = Connect( ELM_INDICATOR_LANDSCAPE_FIXED_COLOR_STYLE );
697 connected = Connect( ELM_INDICATOR_LANDSCAPE );
705 bool Indicator::Connect( const char *serviceName )
707 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
709 bool connected = false;
711 mServerConnection = new ServerConnection( serviceName, 0, false, this );
712 if( mServerConnection )
714 connected = mServerConnection->IsConnected();
717 delete mServerConnection;
718 mServerConnection = NULL;
724 StartReconnectionTimer();
734 void Indicator::StartReconnectionTimer()
736 if( ! mReconnectTimer )
738 mReconnectTimer = Dali::Timer::New(1000);
739 mConnection.DisconnectAll();
740 mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
742 mReconnectTimer.Start();
745 bool Indicator::OnReconnectTimer()
749 if( mState == DISCONNECTED )
751 if( ! Connect( mOrientation ) )
760 void Indicator::Disconnect()
762 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
764 mState = DISCONNECTED;
772 delete mServerConnection;
773 mServerConnection = NULL;
776 void Indicator::NewLockFile( Ecore_Ipc_Event_Server_Data *epcEvent )
778 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
783 if ( (epcEvent->data) &&
784 (epcEvent->size > 0) &&
785 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
787 const char* lockFile = static_cast< const char* >( epcEvent->data );
788 mLock = new Indicator::LockFile( lockFile );
789 if( mLock->RetrieveAndClearErrorStatus() )
791 DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", lockFile );
796 void Indicator::Resize( int width, int height )
807 if( mImageWidth != width || mImageHeight != height )
810 mImageHeight = height;
812 // We don't currently handle the pixel buffer size being changed. Create a new image instead
820 void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
822 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
824 // epcEvent->ref == w
825 // epcEvent->ref_to == h
826 // epcEvent->response == alpha
827 // epcEvent->data = pixmap id
828 if( ( epcEvent->data ) &&
829 (epcEvent->size >= (int)sizeof(PixmapId)) )
831 if( mSharedFile != NULL )
837 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
839 mImageWidth = epcEvent->ref;
840 mImageHeight = epcEvent->ref_to;
842 mPixmap = *(static_cast<PixmapId*>(epcEvent->data));
843 CreateNewPixmapImage();
845 if( CheckVisibleState() )
847 // set default indicator type (enable the quick panel)
848 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
852 // set default indicator type (disable the quick panel)
853 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
856 SetVisible(mVisible, true);
861 void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
863 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
865 // epcEvent->ref == w
866 // epcEvent->ref_to == h
867 // epcEvent->response == alpha
868 // epcEvent->data = shm ref string + nul byte
869 if( ( epcEvent->data ) &&
870 ( ( unsigned char * ) epcEvent->data)[ epcEvent->size - 1 ] == 0 )
872 if( mSharedFile != NULL )
878 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
880 mImageWidth = epcEvent->ref;
881 mImageHeight = epcEvent->ref_to;
883 char* sharedFilename = static_cast<char*>(epcEvent->data);
885 mSharedFile = SharedFile::New( sharedFilename, mImageWidth * mImageWidth * 4, true );
886 if( mSharedFile != NULL )
889 mEventActor.SetSize(mImageWidth, mImageHeight);
891 if( CheckVisibleState() )
893 // set default indicator type (enable the quick panel)
894 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
898 // set default indicator type (disable the quick panel)
899 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
902 SetVisible(mVisible, true);
908 void Indicator::UpdateImageData()
910 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s mVisible: %s\n", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
912 if( mState == CONNECTED && mVisible )
916 // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false
923 mAdaptor->RequestUpdateOnce();
929 bool Indicator::CopyToBuffer()
931 bool success = false;
935 Indicator::ScopedLock scopedLock(mLock);
936 if( mLock->RetrieveAndClearErrorStatus() )
940 else if( scopedLock.IsLocked() )
942 unsigned char *src = mSharedFile->GetAddress();
943 size_t size = mImageWidth * mImageHeight * 4;
945 if( mIndicatorBuffer->UpdatePixels( src, size ) )
947 mAdaptor->RequestUpdateOnce();
956 void Indicator::SetBackground()
958 if( ! mBackgroundActor )
960 ConstructBackgroundMesh();
963 switch( mOpacityMode )
965 case Dali::Window::TRANSLUCENT:
967 SetMeshDataColors( mBackgroundMesh, GRADIENT_COLORS );
971 case Dali::Window::TRANSPARENT:
973 SetMeshDataColors( mBackgroundMesh, Color::TRANSPARENT );
977 case Dali::Window::OPAQUE:
980 SetMeshDataColors( mBackgroundMesh, Color::BLACK );
986 void Indicator::CreateNewPixmapImage()
988 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d\n", mImageWidth, mImageHeight );
989 Dali::PixmapImagePtr pixmapImage = Dali::PixmapImage::New( mPixmap );
993 mIndicatorImageActor.SetImage( Dali::Image::New(*pixmapImage) );
994 mIndicatorImageActor.SetSize( mImageWidth, mImageHeight );
995 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
996 mEventActor.SetSize(mImageWidth, mImageHeight);
999 if( mBackgroundActor )
1001 mBackgroundActor.SetSize( mImageWidth, mImageHeight );
1006 DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1008 if( mObserver != NULL )
1010 mObserver->IndicatorClosed( this );
1012 // Don't do connection in this callback - strange things happen!
1013 StartReconnectionTimer();
1017 void Indicator::CreateNewImage()
1019 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d\n", mImageWidth, mImageHeight );
1020 mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mImageWidth, mImageHeight, Pixel::BGRA8888 );
1021 Dali::Image image = Dali::Image::New( mIndicatorBuffer->GetNativeImage() );
1023 if( CopyToBuffer() ) // Only create images if we have valid image buffer
1025 mIndicatorImageActor.SetImage( image );
1026 mIndicatorImageActor.SetSize( mImageWidth, mImageHeight );
1027 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
1028 mEventActor.SetSize(mImageWidth, mImageHeight);
1031 if( mBackgroundActor )
1033 mBackgroundActor.SetSize( mImageWidth, mImageHeight );
1038 DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1040 if( mObserver != NULL )
1042 mObserver->IndicatorClosed( this );
1044 // Don't do connection in this callback - strange things happen!
1045 StartReconnectionTimer();
1049 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
1051 if( mObserver != NULL )
1053 mObserver->IndicatorTypeChanged( indicatorType );
1057 void Indicator::DataReceived( void* event )
1059 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1060 Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1062 switch( epcEvent->minor )
1065 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1066 if(mPixmap != 0 && mIsShowing)
1068 mAdaptor->RequestUpdateOnce();
1072 case OP_UPDATE_DONE:
1073 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE\n" );
1078 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_LOCK_FILE\n" );
1079 NewLockFile( epcEvent );
1083 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF\n" );
1084 LoadSharedImage( epcEvent );
1088 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_PIXMAP_REF\n" );
1089 LoadPixmapImage( epcEvent );
1093 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1095 if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1097 IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1098 Resize( newSize->w, newSize->h );
1104 int msgDomain = epcEvent->ref;
1105 int msgId = epcEvent->ref_to;
1107 void *msgData = NULL;
1108 int msgDataSize = 0;
1109 msgData = epcEvent->data;
1110 msgDataSize = epcEvent->size;
1112 if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1116 case MSG_ID_INDICATOR_TYPE:
1118 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1119 Type* indicatorType = static_cast<Type*>( epcEvent->data );
1120 OnIndicatorTypeChanged( *indicatorType );
1124 case MSG_ID_INDICATOR_START_ANIMATION:
1126 if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1128 DALI_LOG_ERROR("Message data is incorrect");
1132 IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1134 if(!CheckVisibleState())
1136 ShowIndicator( animData->duration /* n sec */ );
1148 void Indicator::ConnectionClosed()
1150 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1152 // Will get this callback if the server connection failed to start up.
1153 delete mServerConnection;
1154 mServerConnection = NULL;
1155 mState = DISCONNECTED;
1157 // Attempt to re-connect
1158 Connect(mOrientation);
1161 bool Indicator::CheckVisibleState()
1163 if( mOrientation == Dali::Window::LANDSCAPE
1164 || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1165 || (mVisible != Dali::Window::VISIBLE) )
1173 void Indicator::ConstructBackgroundMesh()
1175 // Construct 5 interval mesh
1187 Dali::AnimatableMesh::Faces faces;
1188 faces.reserve(NUM_GRADIENT_INTERVALS * 6); // 2 tris per interval
1189 for(int i=0; i<NUM_GRADIENT_INTERVALS; i++)
1192 faces.push_back(j); faces.push_back(j+3); faces.push_back(j+1);
1193 faces.push_back(j); faces.push_back(j+2); faces.push_back(j+3);
1196 mBackgroundMesh = Dali::AnimatableMesh::New((NUM_GRADIENT_INTERVALS+1)*2, faces);
1197 float interval=1.0f / (float)NUM_GRADIENT_INTERVALS;
1198 for(int i=0;i<NUM_GRADIENT_INTERVALS+1;i++)
1201 mBackgroundMesh[j ].SetPosition(Vector3(-0.5f, -0.5f+(interval*(float)i), 0.0f));
1202 mBackgroundMesh[j+1].SetPosition(Vector3( 0.5f, -0.5f+(interval*(float)i), 0.0f));
1205 mBackgroundActor = Dali::MeshActor::New(mBackgroundMesh);
1206 mBackgroundActor.SetAffectedByLighting(false);
1207 Dali::ShaderEffect shaderEffect = Dali::ShaderEffect::New( MESH_VERTEX_SHADER, MESH_FRAGMENT_SHADER,
1208 GEOMETRY_TYPE_UNTEXTURED_MESH, // Using vertex color
1209 Dali::ShaderEffect::HINT_BLENDING );
1210 mBackgroundActor.SetShaderEffect(shaderEffect);
1214 * duration can be this
1218 * KEEP_SHOWING = -1,
1222 void Indicator::ShowIndicator(float duration)
1224 if( !mIndicatorAnimation )
1226 mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1227 mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished);
1230 if(mIsShowing && !EqualsZero(duration))
1232 // If need to show during showing, do nothing.
1233 // In 2nd phase (below) will update timer
1235 else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1237 // If need to hide during hiding or hidden already, do nothing
1241 if( EqualsZero(duration) )
1243 mIndicatorAnimation.MoveTo(mIndicatorImageActor, Vector3(0, -mImageHeight, 0), Dali::AlphaFunctions::EaseOut);
1247 OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1251 mIndicatorAnimation.MoveTo(mIndicatorImageActor, Vector3(0, 0, 0), Dali::AlphaFunctions::EaseOut);
1255 OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1258 mIndicatorAnimation.Play();
1259 mIsAnimationPlaying = true;
1266 mShowTimer = Dali::Timer::New(1000 * duration);
1267 mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer);
1269 mShowTimer.SetInterval(1000* duration);
1272 if( mVisible == Dali::Window::AUTO )
1274 // check the stage touch
1275 Dali::Stage::GetCurrent().TouchedSignal().Connect( this, &Indicator::OnStageTouched );
1280 if(mShowTimer && mShowTimer.IsRunning())
1285 if( mVisible == Dali::Window::AUTO )
1287 // check the stage touch
1288 Dali::Stage::GetCurrent().TouchedSignal().Disconnect( this, &Indicator::OnStageTouched );
1293 bool Indicator::OnShowTimer()
1295 // after time up, hide indicator
1296 ShowIndicator( HIDE_NOW );
1301 void Indicator::OnAnimationFinished(Dali::Animation& animation)
1303 mIsAnimationPlaying = false;
1304 // once animation is finished and indicator is hidden, take it off stage
1307 mIndicatorActor.SetVisible( false );
1311 void Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1313 if( mServerConnection )
1315 switch( gesture.state )
1317 case Gesture::Started:
1319 mGestureDetected = false;
1321 // The gesture position is the current position after it has moved by the displacement.
1322 // We want to reference the original position.
1323 mGestureDeltaY = gesture.position.y - gesture.displacement.y;
1326 // No break, Fall through
1327 case Gesture::Continuing:
1329 if( mVisible == Dali::Window::AUTO && !mIsShowing )
1331 // Only take one touch point
1332 if( gesture.numberOfTouches == 1 && mGestureDetected == false )
1334 mGestureDeltaY += gesture.displacement.y;
1336 if( mGestureDeltaY >= mImageHeight * SHOWING_DISTANCE_HEIGHT_RATE )
1338 ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1339 mGestureDetected = true;
1347 case Gesture::Finished:
1348 case Gesture::Cancelled:
1350 // if indicator is showing, hide again when touching is finished (Since touch leave is activated, checking it in gesture::finish instead of touch::up)
1351 if( mVisible == Dali::Window::AUTO && mIsShowing )
1353 ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1365 void Indicator::OnStageTouched(const Dali::TouchEvent& touchEvent)
1367 const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
1369 // when stage is touched while indicator is showing temporary, hide it
1370 if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1372 switch( touchPoint.state )
1374 case Dali::TouchPoint::Down:
1376 ShowIndicator( HIDE_NOW );