2 * Copyright (c) 2016 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 "ecore-indicator-impl.h"
24 #include <Ecore_Wayland.h>
26 #include <sys/types.h>
32 #include <dali/public-api/images/native-image.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/images/buffer-image.h>
37 #include <dali/devel-api/images/texture-set-image.h>
38 #include <dali/integration-api/debug.h>
40 #include <tbm_surface.h>
41 #include <wayland-extension/tizen-remote-surface-client-protocol.h>
42 #include <wayland-client.h>
43 #include <wayland-tbm-client.h>
46 #include <adaptor-impl.h>
47 #include <accessibility-adaptor-impl.h>
48 #include <native-image-source.h>
52 #if defined(DEBUG_ENABLED)
53 #define STATE_DEBUG_STRING(state) (state==DISCONNECTED?"DISCONNECTED":state==CONNECTED?"CONNECTED":"UNKNOWN")
59 const float SLIDING_ANIMATION_DURATION( 0.2f ); // 200 milli seconds
60 const float AUTO_INDICATOR_STAY_DURATION(3.0f); // 3 seconds
61 const float SHOWING_DISTANCE_HEIGHT_RATE(0.34f); // 20 pixels
69 const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals
70 const float GRADIENT_ALPHA[NUM_GRADIENT_INTERVALS+1] = { 0.6f, 0.38f, 0.20f, 0.08f, 0.0f, 0.0f };
72 #define MAKE_SHADER(A)#A
74 const char* BACKGROUND_VERTEX_SHADER = MAKE_SHADER(
75 attribute mediump vec2 aPosition;
76 attribute mediump float aAlpha;
77 varying mediump float vAlpha;
78 uniform mediump mat4 uMvpMatrix;
79 uniform mediump vec3 uSize;
83 mediump vec4 vertexPosition = vec4( aPosition * uSize.xy, 0.0, 1.0 );
84 vertexPosition = uMvpMatrix * vertexPosition;
87 gl_Position = vertexPosition;
91 const char* BACKGROUND_FRAGMENT_SHADER = MAKE_SHADER(
92 uniform lowp vec4 uColor;
93 varying mediump float vAlpha;
97 gl_FragColor = uColor;
98 gl_FragColor.a *= vAlpha;
102 const char* FOREGROUND_VERTEX_SHADER = DALI_COMPOSE_SHADER(
103 attribute mediump vec2 aPosition;\n
104 varying mediump vec2 vTexCoord;\n
105 uniform mediump mat4 uMvpMatrix;\n
106 uniform mediump vec3 uSize;\n
107 uniform mediump vec4 sTextureRect;\n
111 gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);\n
112 vTexCoord = aPosition + vec2(0.5);\n
116 const char* FOREGROUND_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
117 varying mediump vec2 vTexCoord;\n
118 uniform sampler2D sTexture;\n
122 gl_FragColor = texture2D( sTexture, vTexCoord );\n // the foreground does not apply actor color
126 const char* FOREGROUND_TBM_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
127 varying mediump vec2 vTexCoord;\n
128 uniform samplerExternalOES sTexture;\n
132 gl_FragColor = texture2D( sTexture, vTexCoord );\n // the foreground does not apply actor color
136 Dali::Geometry CreateQuadGeometry()
138 Dali::Property::Map quadVertexFormat;
139 quadVertexFormat["aPosition"] = Dali::Property::VECTOR2;
140 Dali::PropertyBuffer vertexData = Dali::PropertyBuffer::New( quadVertexFormat );
142 const float halfQuadSize = .5f;
143 struct QuadVertex { Dali::Vector2 position; };
144 QuadVertex quadVertexData[4] = {
145 { Dali::Vector2(-halfQuadSize, -halfQuadSize) },
146 { Dali::Vector2(-halfQuadSize, halfQuadSize) },
147 { Dali::Vector2( halfQuadSize, -halfQuadSize) },
148 { Dali::Vector2( halfQuadSize, halfQuadSize) } };
149 vertexData.SetData(quadVertexData, 4);
151 Dali::Geometry quad = Dali::Geometry::New();
152 quad.AddVertexBuffer( vertexData );
153 quad.SetType( Dali::Geometry::TRIANGLE_STRIP );
157 const float OPAQUE_THRESHOLD(0.99f);
158 const float TRANSPARENT_THRESHOLD(0.05f);
160 // indicator service name
161 const char* INDICATOR_SERVICE_NAME("elm_indicator");
163 // Copied from ecore_evas_extn_engine.h
179 OP_PROFILE_CHANGE_REQUEST,
180 OP_PROFILE_CHANGE_DONE,
198 // Copied from elm_conform.c
200 const int MSG_DOMAIN_CONTROL_INDICATOR( 0x10001 );
201 const int MSG_ID_INDICATOR_REPEAT_EVENT( 0x10002 );
202 const int MSG_ID_INDICATOR_ROTATION( 0x10003 );
203 const int MSG_ID_INDICATOR_OPACITY( 0X1004 );
204 const int MSG_ID_INDICATOR_TYPE( 0X1005 );
205 const int MSG_ID_INDICATOR_START_ANIMATION( 0X10006 );
217 struct IpcIndicatorDataAnimation
223 struct IpcDataEvMouseUp
226 Evas_Button_Flags flags;
228 unsigned int timestamp;
229 Evas_Event_Flags event_flags;
231 IpcDataEvMouseUp(unsigned long timestamp)
233 flags(EVAS_BUTTON_NONE),
235 timestamp(static_cast<unsigned int>(timestamp)),
236 event_flags(EVAS_EVENT_FLAG_NONE)
241 struct IpcDataEvMouseDown
244 Evas_Button_Flags flags;
246 unsigned int timestamp;
247 Evas_Event_Flags event_flags;
249 IpcDataEvMouseDown(unsigned long timestamp)
251 flags(EVAS_BUTTON_NONE),
253 timestamp(static_cast<unsigned int>(timestamp)),
254 event_flags(EVAS_EVENT_FLAG_NONE)
259 struct IpcDataEvMouseMove
262 Evas_Button_Flags flags;
264 unsigned int timestamp;
265 Evas_Event_Flags event_flags;
267 IpcDataEvMouseMove(const Dali::TouchPoint& touchPoint, unsigned long timestamp)
268 : x(static_cast<Evas_Coord>(touchPoint.local.x)),
269 y(static_cast<Evas_Coord>(touchPoint.local.y)),
270 flags(EVAS_BUTTON_NONE),
272 timestamp(static_cast<unsigned int>(timestamp)),
273 event_flags(EVAS_EVENT_FLAG_NONE)
278 struct IpcDataEvMouseOut
280 unsigned int timestamp;
282 Evas_Event_Flags event_flags;
284 IpcDataEvMouseOut(unsigned long timestamp)
285 : timestamp(static_cast<unsigned int>(timestamp)),
287 event_flags(EVAS_EVENT_FLAG_NONE)
292 struct wl_buffer* preBuffer;
294 static void OnUpdateIndicatorImage( void* data, struct tizen_remote_surface* remoteSurface, struct wl_buffer* buffer, uint32_t time )
296 Dali::Internal::Adaptor::Indicator* indicator = static_cast< Dali::Internal::Adaptor::Indicator* >( data );
300 tbm_surface_h tbmSurface = static_cast< tbm_surface_h >( wl_buffer_get_user_data( buffer ) );
302 indicator->UpdateIndicatorImage( tbmSurface );
305 if( preBuffer != NULL && tizen_remote_surface_get_version( remoteSurface ) >= TIZEN_REMOTE_SURFACE_RELEASE_SINCE_VERSION )
307 tizen_remote_surface_release( remoteSurface, preBuffer );
313 static void OnMissingIndicatorImage( void* data, struct tizen_remote_surface* surface )
317 static const struct tizen_remote_surface_listener remoteSurfaceCallback =
319 OnUpdateIndicatorImage,
320 OnMissingIndicatorImage,
323 } // anonymous namespace
332 #if defined(DEBUG_ENABLED)
333 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
336 // Impl to hide EFL implementation.
338 struct Indicator::Impl
340 enum // operation mode
343 INDICATOR_STAY_WITH_DURATION
349 Impl(Indicator* indicator)
350 : mIndicator(indicator),
351 mEcoreEventHandler(NULL)
353 #if defined(DALI_PROFILE_MOBILE)
354 mEcoreEventHandler = ecore_event_handler_add(ECORE_WL_EVENT_INDICATOR_FLICK, EcoreEventIndicator, this);
355 #endif // WAYLAND && DALI_PROFILE_MOBILE
363 if ( mEcoreEventHandler )
365 ecore_event_handler_del(mEcoreEventHandler);
369 static void SetIndicatorVisibility( void* data, int operation )
371 Indicator::Impl* indicatorImpl((Indicator::Impl*)data);
373 if ( indicatorImpl == NULL || indicatorImpl->mIndicator == NULL)
377 if ( operation == INDICATOR_STAY_WITH_DURATION )
379 // if indicator is not showing, INDICATOR_FLICK_DONE is given
380 if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
381 !indicatorImpl->mIndicator->mIsShowing )
383 indicatorImpl->mIndicator->ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
386 else if( operation == INDICATOR_HIDE )
388 if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
389 indicatorImpl->mIndicator->mIsShowing )
391 indicatorImpl->mIndicator->ShowIndicator( HIDE_NOW );
395 #if defined(DALI_PROFILE_MOBILE)
397 * Called when the Ecore indicator event is received.
399 static Eina_Bool EcoreEventIndicator( void* data, int type, void* event )
401 SetIndicatorVisibility( data, INDICATOR_STAY_WITH_DURATION );
402 return ECORE_CALLBACK_PASS_ON;
404 #endif // WAYLAND && DALI_PROFILE_MOBILE
407 Indicator* mIndicator;
408 Ecore_Event_Handler* mEcoreEventHandler;
411 Indicator::LockFile::LockFile(const std::string filename)
412 : mFilename(filename),
415 mFileDescriptor = open(filename.c_str(), O_RDWR);
416 if( mFileDescriptor == -1 )
420 DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
424 Indicator::LockFile::~LockFile()
426 // Closing file descriptor also unlocks file.
427 close( mFileDescriptor );
430 bool Indicator::LockFile::Lock()
432 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
435 if( mFileDescriptor > 0 )
437 if( lockf( mFileDescriptor, F_LOCK, 0 ) == 0 ) // Note, operation may block.
445 // file descriptor is no longer valid or not writable
448 DALI_LOG_ERROR( "### Cannot lock indicator: bad file descriptor for %s ###\n", mFilename.c_str() );
456 void Indicator::LockFile::Unlock()
458 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
459 if( lockf( mFileDescriptor, F_ULOCK, 0 ) != 0 )
463 // file descriptor is no longer valid or not writable
466 DALI_LOG_ERROR( "### Cannot unlock indicator: bad file descriptor for %s\n", mFilename.c_str() );
471 bool Indicator::LockFile::RetrieveAndClearErrorStatus()
473 bool error = mErrorThrown;
474 mErrorThrown = false;
478 Indicator::ScopedLock::ScopedLock(LockFile* lockFile)
479 : mLockFile(lockFile),
484 mLocked = mLockFile->Lock();
488 Indicator::ScopedLock::~ScopedLock()
496 bool Indicator::ScopedLock::IsLocked()
501 Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, IndicatorInterface::Observer* observer )
503 mGestureDeltaY( 0.0f ),
504 mGestureDetected( false ),
506 mOpacityMode( Dali::Window::OPAQUE ),
507 mState( DISCONNECTED ),
509 mServerConnection( NULL ),
510 mObserver( observer ),
511 mOrientation( orientation ),
514 mVisible( Dali::Window::INVISIBLE ),
516 mIsAnimationPlaying( false ),
517 mCurrentSharedFile( 0 ),
518 mSharedBufferType( BUFFER_TYPE_SHM ),
520 mBackgroundVisible( false ),
523 mIndicatorContentActor = Dali::Actor::New();
524 mIndicatorContentActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
525 mIndicatorContentActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
527 // Indicator image handles the touch event including "leave"
528 mIndicatorContentActor.SetLeaveRequired( true );
529 mIndicatorContentActor.TouchedSignal().Connect( this, &Indicator::OnTouched );
530 mIndicatorContentActor.SetColor( Color::BLACK );
532 mIndicatorActor = Dali::Actor::New();
533 mIndicatorActor.Add( mIndicatorContentActor );
535 // Event handler to find out flick down gesture
536 mEventActor = Dali::Actor::New();
537 mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
538 mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
539 mIndicatorActor.Add( mEventActor );
541 // Attach pan gesture to find flick down during hiding.
542 // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
543 // since it consumes the pan gesture in advance.
544 mPanDetector = Dali::PanGestureDetector::New();
545 mPanDetector.DetectedSignal().Connect( this, &Indicator::OnPan );
546 mPanDetector.Attach( mEventActor );
550 // register indicator to accessibility adaptor
551 Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
552 if(accessibilityAdaptor)
554 AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this );
556 // hide the indicator by default
557 mIndicatorActor.SetVisible( false );
559 // create impl to handle ecore event
560 mImpl = new Impl(this);
563 Indicator::~Indicator()
573 mEventActor.TouchedSignal().Disconnect( this, &Indicator::OnTouched );
578 void Indicator::SetAdaptor(Adaptor* adaptor)
581 mIndicatorBuffer->SetAdaptor( adaptor );
584 Dali::Actor Indicator::GetActor()
586 return mIndicatorActor;
589 void Indicator::Open( Dali::Window::WindowOrientation orientation )
591 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
593 // Calls from Window should be set up to ensure we are in a
594 // disconnected state before opening a second time.
595 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
597 mOrientation = orientation;
601 // Change background visibility depending on orientation
602 if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
604 if( mBackgroundRenderer )
606 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
607 mBackgroundVisible = false;
612 SetOpacityMode( mOpacityMode );
616 void Indicator::Close()
618 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) );
620 if( mState == CONNECTED )
623 if( mObserver != NULL )
625 mObserver->IndicatorClosed( this );
629 Dali::Texture emptyTexture;
630 SetForegroundImage( emptyTexture );
633 void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
637 Dali::Geometry geometry = CreateBackgroundGeometry();
640 if( mBackgroundRenderer )
642 if( mBackgroundRenderer.GetGeometry() != geometry )
644 mBackgroundRenderer.SetGeometry( geometry );
649 if( !mBackgroundShader )
651 mBackgroundShader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT );
654 mBackgroundRenderer = Dali::Renderer::New( geometry, mBackgroundShader );
657 if( !mBackgroundVisible )
659 mIndicatorContentActor.AddRenderer( mBackgroundRenderer );
660 mBackgroundVisible = true;
663 else if( mBackgroundRenderer )
665 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
666 mBackgroundVisible = false;
671 void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
673 if ( visibleMode != mVisible || forceUpdate )
675 // If we were previously hidden, then we should update the image data before we display the indicator
676 if ( mVisible == Dali::Window::INVISIBLE )
678 UpdateImageData( mCurrentSharedFile );
681 if ( visibleMode == Dali::Window::INVISIBLE )
683 if (mServerConnection)
685 mServerConnection->SendEvent( OP_HIDE, NULL, 0 );
690 mIndicatorActor.SetVisible( true );
692 if( mServerConnection )
694 mServerConnection->SendEvent( OP_SHOW, NULL, 0 );
698 mVisible = visibleMode;
701 if( mForegroundRenderer &&
702 ( mForegroundRenderer.GetTextures().GetTexture( 0u ) ||
703 Dali::TextureGetImage( mForegroundRenderer.GetTextures(), 0u ) )
706 if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
709 ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
711 else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
714 ShowIndicator( KEEP_SHOWING );
719 ShowIndicator( HIDE_NOW );
729 bool Indicator::IsConnected()
731 return ( mState == CONNECTED );
734 bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size )
738 return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
746 bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEvent)
748 if( mServerConnection )
750 const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
752 // Send touch event to indicator server when indicator is showing
753 if( CheckVisibleState() || mIsShowing )
755 switch( touchPoint.state )
757 case Dali::PointState::DOWN:
759 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
760 IpcDataEvMouseDown ipcDown( touchEvent.time );
761 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
762 mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
764 if( mVisible == Dali::Window::AUTO )
766 // Stop hiding indicator
767 ShowIndicator( KEEP_SHOWING );
772 case Dali::PointState::MOTION:
774 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
775 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
779 case Dali::PointState::UP:
780 case Dali::PointState::INTERRUPTED:
782 IpcDataEvMouseUp ipcUp( touchEvent.time );
783 mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
785 if( mVisible == Dali::Window::AUTO )
788 ShowIndicator( 0.5f /* hide after 0.5 sec */ );
793 case Dali::TouchPoint::Leave:
795 IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
796 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
797 IpcDataEvMouseUp ipcOut( touchEvent.time );
798 mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
813 bool Indicator::Connect()
815 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
817 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
819 bool connected = false;
821 mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
822 if( mServerConnection )
824 connected = mServerConnection->IsConnected();
827 delete mServerConnection;
828 mServerConnection = NULL;
834 StartReconnectionTimer();
844 void Indicator::StartReconnectionTimer()
846 if( ! mReconnectTimer )
848 mReconnectTimer = Dali::Timer::New(1000);
849 mConnection.DisconnectAll();
850 mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
852 mReconnectTimer.Start();
855 bool Indicator::OnReconnectTimer()
859 if( mState == DISCONNECTED )
870 void Indicator::Disconnect()
872 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
874 mState = DISCONNECTED;
876 delete mServerConnection;
877 mServerConnection = NULL;
879 ClearSharedFileInfo();
882 void Indicator::Resize( int width, int height )
893 if( mImageWidth != width || mImageHeight != height )
896 mImageHeight = height;
898 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
899 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
900 mEventActor.SetSize(mImageWidth, mImageHeight);
905 void Indicator::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
907 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
909 // epcEvent->ref == w
910 // epcEvent->ref_to == h
911 // epcEvent->response == buffer num
912 // epcEvent->data = lockfile + nul byte
914 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
915 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
917 int n = epcEvent->response;
919 if( n >= 0 && n < SHARED_FILE_NUMBER )
921 mCurrentSharedFile = n;
923 mSharedFileInfo[n].mImageWidth = epcEvent->ref;
924 mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
926 mSharedFileInfo[n].mLockFileName.clear();
928 mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
930 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
931 n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
936 void Indicator::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
938 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
940 // epcEvent->ref == shm id
941 // epcEvent->ref_to == shm num
942 // epcEvent->response == buffer num
943 // epcEvent->data = shm ref string + nul byte
945 if ( (epcEvent->data) &&
946 (epcEvent->size > 0) &&
947 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
949 int n = epcEvent->response;
951 if( n >= 0 && n < SHARED_FILE_NUMBER )
953 mCurrentSharedFile = n;
955 mSharedFileInfo[n].mSharedFileName.clear();
957 mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
959 mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
960 mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
962 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
963 n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
968 void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
970 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
972 // epcEvent->ref == alpha
973 // epcEvent->ref_to == sys
974 // epcEvent->response == buffer num
976 if ( mSharedBufferType != BUFFER_TYPE_SHM )
981 int n = epcEvent->response;
983 if( n >= 0 && n < SHARED_FILE_NUMBER )
985 mCurrentSharedFile = n;
987 delete mSharedFileInfo[n].mSharedFile;
988 mSharedFileInfo[n].mSharedFile = NULL;
990 delete mSharedFileInfo[n].mLock;
991 mSharedFileInfo[n].mLock = NULL;
993 std::stringstream sharedFileID;
994 std::stringstream sharedFileNumber;
996 sharedFileID << mSharedFileInfo[n].mSharedFileID;
997 sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
999 std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
1001 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
1003 mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
1004 if( mSharedFileInfo[n].mSharedFile != NULL )
1006 mSharedFileInfo[n].mLock = new Indicator::LockFile( mSharedFileInfo[n].mLockFileName );
1007 if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
1009 DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
1014 CreateNewImage( n );
1020 void Indicator::SetupNativeIndicatorImage( Ecore_Ipc_Event_Server_Data *epcEvent )
1022 // Bind tizen remote surface
1023 Eina_Inlist* globals;
1024 Ecore_Wl_Global* global;
1025 struct tizen_remote_surface_manager* remoteSurfaceManager = NULL;
1026 struct tizen_remote_surface* remoteSurface = NULL;
1027 struct wl_registry* registry;
1028 struct wayland_tbm_client* tbmClient;
1029 struct wl_tbm* wlTbm;
1031 if ( !remoteSurfaceManager )
1033 registry = ecore_wl_registry_get();
1034 globals = ecore_wl_globals_get();
1036 if (!registry || !globals)
1038 DALI_LOG_ERROR( "SetupNativeIndicatorImage registry or globals error\n" );
1042 EINA_INLIST_FOREACH(globals, global)
1044 if ( !strcmp( global->interface, "tizen_remote_surface_manager" ) )
1046 remoteSurfaceManager = ( struct tizen_remote_surface_manager* )wl_registry_bind( registry, global->id, &tizen_remote_surface_manager_interface, ( ( global->version < 2 )? global->version: 2 ) );
1050 if ( !remoteSurfaceManager )
1052 DALI_LOG_ERROR( "SetupNativeIndicatorImage bind error\n" );
1056 tbmClient = ( struct wayland_tbm_client* )wayland_tbm_client_init( ecore_wl_display_get() );
1059 DALI_LOG_ERROR( "SetupNativeIndicatorImage client init error\n" );
1063 wlTbm = ( struct wl_tbm* )wayland_tbm_client_get_wl_tbm( tbmClient );
1066 DALI_LOG_ERROR( "SetupNativeIndicatorImage wl tbm error\n" );
1070 uint32_t resourceId = epcEvent->ref;
1071 remoteSurface = tizen_remote_surface_manager_create_surface( remoteSurfaceManager, resourceId, wlTbm );
1073 if( !remoteSurface )
1075 DALI_LOG_ERROR( "SetupNativeIndicatorImage create surface error\n" );
1079 tizen_remote_surface_add_listener( remoteSurface, &remoteSurfaceCallback, this );
1080 tizen_remote_surface_redirect( remoteSurface );
1081 tizen_remote_surface_transfer_visibility( remoteSurface, TIZEN_REMOTE_SURFACE_VISIBILITY_TYPE_VISIBLE);
1084 void Indicator::UpdateIndicatorImage( Any source )
1086 if( !mNativeImageSource )
1088 mNativeImageSource = Dali::NativeImageSource::New( source );
1089 Dali::NativeImage nativeImage = Dali::NativeImage::New( *mNativeImageSource );
1091 SetForegroundNativeImage( nativeImage );
1092 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
1093 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
1094 mEventActor.SetSize( mImageWidth, mImageHeight );
1100 mNativeImageSource->SetSource( source );
1101 Dali::Stage::GetCurrent().KeepRendering( 0.0f );
1104 void Indicator::UpdateTopMargin()
1106 int newMargin = (mVisible == Dali::Window::VISIBLE && mOpacityMode == Dali::Window::OPAQUE) ? mImageHeight : 0;
1107 if (mTopMargin != newMargin)
1109 mTopMargin = newMargin;
1110 mAdaptor->IndicatorSizeChanged( mTopMargin );
1114 void Indicator::UpdateVisibility()
1116 if( CheckVisibleState() )
1118 // set default indicator type (enable the quick panel)
1119 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
1123 // set default indicator type (disable the quick panel)
1124 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
1129 mIndicatorContentActor.SetPosition( 0.0f, -mImageHeight, 0.0f );
1132 SetVisible(mVisible, true);
1135 void Indicator::UpdateImageData( int bufferNumber )
1137 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
1139 if( mState == CONNECTED && mVisible )
1143 // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false
1144 CopyToBuffer( bufferNumber );
1150 mAdaptor->RequestUpdateOnce();
1156 bool Indicator::CopyToBuffer( int bufferNumber )
1158 bool success = false;
1160 if( mSharedFileInfo[bufferNumber].mLock )
1162 Indicator::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
1163 if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
1167 else if( scopedLock.IsLocked() )
1169 unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
1170 size_t size = mSharedFileInfo[bufferNumber].mImageWidth * mSharedFileInfo[bufferNumber].mImageHeight * 4;
1172 if( mIndicatorBuffer->UpdatePixels( src, size ) )
1174 mAdaptor->RequestUpdateOnce();
1183 void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
1187 void Indicator::CreateNewPixmapImage()
1191 void Indicator::CreateNewImage( int bufferNumber )
1193 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
1194 mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
1195 bool success = false;
1197 if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
1199 Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() );
1202 SetForegroundImage( texture );
1209 DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1211 if( mObserver != NULL )
1213 mObserver->IndicatorClosed( this );
1215 // Don't do connection in this callback - strange things happen!
1216 StartReconnectionTimer();
1220 Dali::Geometry Indicator::CreateBackgroundGeometry()
1222 switch( mOpacityMode )
1224 case Dali::Window::TRANSLUCENT:
1225 if( !mTranslucentGeometry )
1227 // Construct 5 interval mesh
1241 struct BackgroundVertex
1247 unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1248 BackgroundVertex vertices[ numVertices ];
1251 float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1252 BackgroundVertex* currentVertex = vertices;
1253 for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1255 currentVertex->mPosition = Vector2( -0.5f, d );
1256 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1259 currentVertex->mPosition = Vector2( 0.5f, d );
1260 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1265 unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1266 unsigned short indices[ numIndices ];
1268 unsigned short* currentIndex = indices;
1269 for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1271 *currentIndex++ = (2 * y);
1272 *currentIndex++ = (2 * y) + 3;
1273 *currentIndex++ = (2 * y) + 1;
1275 *currentIndex++ = (2 * y);
1276 *currentIndex++ = (2 * y) + 2;
1277 *currentIndex++ = (2 * y) + 3;
1280 Dali::Property::Map vertexFormat;
1281 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1282 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1283 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1284 vertexPropertyBuffer.SetData( vertices, numVertices );
1286 // Create the geometry object
1287 mTranslucentGeometry = Dali::Geometry::New();
1288 mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1289 mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices );
1292 return mTranslucentGeometry;
1293 case Dali::Window::OPAQUE:
1295 if( !mSolidGeometry )
1298 struct BackgroundVertex
1304 BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1305 { Vector2( -0.5f, 0.5f ), 1.0f }, { Vector2( 0.5f, 0.5f ), 1.0f } };
1308 unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1310 Dali::Property::Map vertexFormat;
1311 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1312 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1313 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1314 vertexPropertyBuffer.SetData( vertices, 4 );
1317 // Create the geometry object
1318 mSolidGeometry = Dali::Geometry::New();
1319 mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1320 mSolidGeometry.SetIndexBuffer( &indices[0], 6 );
1323 return mSolidGeometry;
1324 case Dali::Window::TRANSPARENT:
1328 return Dali::Geometry();
1331 void Indicator::SetForegroundImage( Dali::Texture texture )
1333 if( !mForegroundRenderer && texture )
1336 Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER );
1338 // Create renderer from geometry and material
1339 Dali::Geometry quad = CreateQuadGeometry();
1340 mForegroundRenderer = Dali::Renderer::New( quad, shader );
1341 // Make sure the foreground stays in front of the background
1342 mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1344 // Set blend function
1345 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB, Dali::BlendFactor::ONE );
1346 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB, Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1347 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA, Dali::BlendFactor::ONE );
1348 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1350 // Create a texture-set and add to renderer
1352 Dali::TextureSet textureSet = Dali::TextureSet::New();
1353 textureSet.SetTexture( 0u, texture );
1354 mForegroundRenderer.SetTextures( textureSet );
1356 mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1358 else if( mForegroundRenderer )
1360 Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1361 textureSet.SetTexture( 0u, texture );
1364 if( mImageWidth == 0 && mImageHeight == 0 && texture)
1366 Resize( texture.GetWidth(), texture.GetHeight() );
1370 void Indicator::SetForegroundNativeImage( Dali::Image image )
1372 if( !mForegroundRenderer && image )
1375 std::string fragmentShader = "#extension GL_OES_EGL_image_external:require\n";
1376 fragmentShader += "\n";
1377 fragmentShader += FOREGROUND_TBM_FRAGMENT_SHADER;
1380 Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, fragmentShader );
1382 // Create renderer from geometry and material
1383 Dali::Geometry quad = CreateQuadGeometry();
1384 mForegroundRenderer = Dali::Renderer::New( quad, shader );
1385 // Make sure the foreground stays in front of the background
1386 mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1388 // Set blend function
1389 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB, Dali::BlendFactor::ONE );
1390 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB, Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1391 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA, Dali::BlendFactor::ONE );
1392 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1394 // Create a texture-set and add to renderer
1396 Dali::TextureSet textureSet = Dali::TextureSet::New();
1397 Dali::TextureSetImage( textureSet, 0u, image );
1399 mForegroundRenderer.SetTextures( textureSet );
1401 mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1403 else if( mForegroundRenderer )
1405 Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1406 Dali::TextureSetImage( textureSet, 0u, image );
1409 if( mImageWidth == 0 && mImageHeight == 0 && image )
1411 Resize( image.GetWidth(), image.GetHeight() );
1415 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
1417 if( mObserver != NULL )
1419 mObserver->IndicatorTypeChanged( indicatorType );
1423 void Indicator::DataReceived( void* event )
1425 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1426 Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1428 switch( epcEvent->minor )
1432 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1435 mAdaptor->RequestUpdateOnce();
1439 case OP_UPDATE_DONE:
1441 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1442 // epcEvent->response == display buffer #
1443 UpdateImageData( epcEvent->response );
1448 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1449 SetSharedImageInfo( epcEvent );
1454 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1455 SetLockFileInfo( epcEvent );
1460 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1461 LoadSharedImage( epcEvent );
1466 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_GL_REF\n" );
1467 SetupNativeIndicatorImage( epcEvent );
1472 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1474 if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1476 IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1477 Resize( newSize->w, newSize->h );
1483 int msgDomain = epcEvent->ref;
1484 int msgId = epcEvent->ref_to;
1486 void *msgData = NULL;
1487 int msgDataSize = 0;
1488 msgData = epcEvent->data;
1489 msgDataSize = epcEvent->size;
1491 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1493 if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1497 case MSG_ID_INDICATOR_TYPE:
1499 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1500 Type* indicatorType = static_cast<Type*>( epcEvent->data );
1501 OnIndicatorTypeChanged( *indicatorType );
1505 case MSG_ID_INDICATOR_START_ANIMATION:
1507 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1509 if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1511 DALI_LOG_ERROR("Message data is incorrect\n");
1515 IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1517 if(!CheckVisibleState())
1519 ShowIndicator( animData->duration /* n sec */ );
1530 void Indicator::ConnectionClosed()
1532 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1534 // Will get this callback if the server connection failed to start up.
1535 delete mServerConnection;
1536 mServerConnection = NULL;
1537 mState = DISCONNECTED;
1539 // Attempt to re-connect
1543 bool Indicator::CheckVisibleState()
1545 if( mOrientation == Dali::Window::LANDSCAPE
1546 || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1547 || (mVisible == Dali::Window::INVISIBLE)
1548 || (mVisible == Dali::Window::AUTO && !mIsShowing) )
1556 void Indicator::ClearSharedFileInfo()
1558 for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
1560 delete mSharedFileInfo[i].mLock;
1561 mSharedFileInfo[i].mLock = NULL;
1563 delete mSharedFileInfo[i].mSharedFile;
1564 mSharedFileInfo[i].mSharedFile = NULL;
1566 mSharedFileInfo[i].mLockFileName.clear();
1567 mSharedFileInfo[i].mSharedFileName.clear();
1572 * duration can be this
1576 * KEEP_SHOWING = -1,
1580 void Indicator::ShowIndicator(float duration)
1582 if( !mIndicatorAnimation )
1584 mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1585 mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished);
1588 if(mIsShowing && !EqualsZero(duration))
1590 // If need to show during showing, do nothing.
1591 // In 2nd phase (below) will update timer
1593 else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1595 // If need to hide during hiding or hidden already, do nothing
1599 mIndicatorAnimation.Clear();
1601 if( EqualsZero(duration) )
1603 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
1607 OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1611 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
1615 OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1618 mIndicatorAnimation.Play();
1619 mIsAnimationPlaying = true;
1626 mShowTimer = Dali::Timer::New(1000 * duration);
1627 mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer);
1629 mShowTimer.SetInterval(1000* duration);
1632 if( mVisible == Dali::Window::AUTO )
1634 // check the stage touch
1635 Dali::Stage::GetCurrent().TouchedSignal().Connect( this, &Indicator::OnStageTouched );
1640 if(mShowTimer && mShowTimer.IsRunning())
1645 if( mVisible == Dali::Window::AUTO )
1647 // check the stage touch
1648 Dali::Stage::GetCurrent().TouchedSignal().Disconnect( this, &Indicator::OnStageTouched );
1653 bool Indicator::OnShowTimer()
1655 // after time up, hide indicator
1656 ShowIndicator( HIDE_NOW );
1661 void Indicator::OnAnimationFinished(Dali::Animation& animation)
1663 mIsAnimationPlaying = false;
1664 // once animation is finished and indicator is hidden, take it off stage
1665 if( mObserver != NULL )
1667 mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
1671 void Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1675 if( mServerConnection )
1677 switch( gesture.state )
1679 case Gesture::Started:
1681 mGestureDetected = false;
1683 // The gesture position is the current position after it has moved by the displacement.
1684 // We want to reference the original position.
1685 mGestureDeltaY = gesture.position.y - gesture.displacement.y;
1688 // No break, Fall through
1689 case Gesture::Continuing:
1691 if( mVisible == Dali::Window::AUTO && !mIsShowing )
1693 // Only take one touch point
1694 if( gesture.numberOfTouches == 1 && mGestureDetected == false )
1696 mGestureDeltaY += gesture.displacement.y;
1698 if( mGestureDeltaY >= mImageHeight * SHOWING_DISTANCE_HEIGHT_RATE )
1700 ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1701 mGestureDetected = true;
1709 case Gesture::Finished:
1710 case Gesture::Cancelled:
1712 // if indicator is showing, hide again when touching is finished (Since touch leave is activated, checking it in gesture::finish instead of touch::up)
1713 if( mVisible == Dali::Window::AUTO && mIsShowing )
1715 ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1727 void Indicator::OnStageTouched(const Dali::TouchEvent& touchEvent)
1729 const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
1731 // when stage is touched while indicator is showing temporary, hide it
1732 if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1734 switch( touchPoint.state )
1736 case Dali::PointState::DOWN:
1738 // if touch point is inside the indicator, indicator is not hidden
1739 if( mImageHeight < int(touchPoint.screen.y) )
1741 ShowIndicator( HIDE_NOW );