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-data.h>
34 #include <dali/public-api/common/stage.h>
35 #include <dali/public-api/images/buffer-image.h>
36 #include <dali/devel-api/images/texture-set-image.h>
37 #include <dali/integration-api/debug.h>
39 #include <tbm_surface.h>
40 #include <wayland-extension/tizen-remote-surface-client-protocol.h>
41 #include <wayland-client.h>
42 #include <wayland-tbm-client.h>
45 #include <adaptor-impl.h>
46 #include <accessibility-adaptor-impl.h>
47 #include <native-image-source.h>
51 #if defined(DEBUG_ENABLED)
52 #define STATE_DEBUG_STRING(state) (state==DISCONNECTED?"DISCONNECTED":state==CONNECTED?"CONNECTED":"UNKNOWN")
58 const float SLIDING_ANIMATION_DURATION( 0.2f ); // 200 milli seconds
59 const float AUTO_INDICATOR_STAY_DURATION(3.0f); // 3 seconds
60 const float SHOWING_DISTANCE_HEIGHT_RATE(0.34f); // 20 pixels
68 const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals
69 const float GRADIENT_ALPHA[NUM_GRADIENT_INTERVALS+1] = { 0.6f, 0.38f, 0.20f, 0.08f, 0.0f, 0.0f };
71 #define MAKE_SHADER(A)#A
73 const char* BACKGROUND_VERTEX_SHADER = MAKE_SHADER(
74 attribute mediump vec2 aPosition;
75 attribute mediump float aAlpha;
76 varying mediump float vAlpha;
77 uniform mediump mat4 uMvpMatrix;
78 uniform mediump vec3 uSize;
82 mediump vec4 vertexPosition = vec4( aPosition * uSize.xy, 0.0, 1.0 );
83 vertexPosition = uMvpMatrix * vertexPosition;
86 gl_Position = vertexPosition;
90 const char* BACKGROUND_FRAGMENT_SHADER = MAKE_SHADER(
91 uniform lowp vec4 uColor;
92 varying mediump float vAlpha;
96 gl_FragColor = uColor;
97 gl_FragColor.a *= vAlpha;
101 const char* FOREGROUND_VERTEX_SHADER = DALI_COMPOSE_SHADER(
102 attribute mediump vec2 aPosition;\n
103 varying mediump vec2 vTexCoord;\n
104 uniform mediump mat4 uMvpMatrix;\n
105 uniform mediump vec3 uSize;\n
106 uniform mediump vec4 sTextureRect;\n
110 gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);\n
111 vTexCoord = aPosition + vec2(0.5);\n
115 const char* FOREGROUND_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
116 varying mediump vec2 vTexCoord;\n
117 uniform sampler2D sTexture;\n
121 gl_FragColor = texture2D( sTexture, vTexCoord );\n // the foreground does not apply actor color
125 const char* FOREGROUND_TBM_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
126 varying mediump vec2 vTexCoord;\n
127 uniform samplerExternalOES sTexture;\n
131 gl_FragColor = texture2D( sTexture, vTexCoord );\n // the foreground does not apply actor color
135 Dali::Geometry CreateQuadGeometry()
137 Dali::Property::Map quadVertexFormat;
138 quadVertexFormat["aPosition"] = Dali::Property::VECTOR2;
139 Dali::PropertyBuffer vertexData = Dali::PropertyBuffer::New( quadVertexFormat );
141 const float halfQuadSize = .5f;
142 struct QuadVertex { Dali::Vector2 position; };
143 QuadVertex quadVertexData[4] = {
144 { Dali::Vector2(-halfQuadSize, -halfQuadSize) },
145 { Dali::Vector2(-halfQuadSize, halfQuadSize) },
146 { Dali::Vector2( halfQuadSize, -halfQuadSize) },
147 { Dali::Vector2( halfQuadSize, halfQuadSize) } };
148 vertexData.SetData(quadVertexData, 4);
150 Dali::Geometry quad = Dali::Geometry::New();
151 quad.AddVertexBuffer( vertexData );
152 quad.SetType( Dali::Geometry::TRIANGLE_STRIP );
156 const float OPAQUE_THRESHOLD(0.99f);
157 const float TRANSPARENT_THRESHOLD(0.05f);
159 // indicator service name
160 const char* INDICATOR_SERVICE_NAME("elm_indicator");
162 // Copied from ecore_evas_extn_engine.h
178 OP_PROFILE_CHANGE_REQUEST,
179 OP_PROFILE_CHANGE_DONE,
197 // Copied from elm_conform.c
199 const int MSG_DOMAIN_CONTROL_INDICATOR( 0x10001 );
200 const int MSG_ID_INDICATOR_REPEAT_EVENT( 0x10002 );
201 const int MSG_ID_INDICATOR_ROTATION( 0x10003 );
202 const int MSG_ID_INDICATOR_OPACITY( 0X1004 );
203 const int MSG_ID_INDICATOR_TYPE( 0X1005 );
204 const int MSG_ID_INDICATOR_START_ANIMATION( 0X10006 );
216 struct IpcIndicatorDataAnimation
222 struct IpcDataEvMouseUp
225 Evas_Button_Flags flags;
227 unsigned int timestamp;
228 Evas_Event_Flags event_flags;
230 IpcDataEvMouseUp(unsigned long timestamp)
232 flags(EVAS_BUTTON_NONE),
234 timestamp(static_cast<unsigned int>(timestamp)),
235 event_flags(EVAS_EVENT_FLAG_NONE)
240 struct IpcDataEvMouseDown
243 Evas_Button_Flags flags;
245 unsigned int timestamp;
246 Evas_Event_Flags event_flags;
248 IpcDataEvMouseDown(unsigned long timestamp)
250 flags(EVAS_BUTTON_NONE),
252 timestamp(static_cast<unsigned int>(timestamp)),
253 event_flags(EVAS_EVENT_FLAG_NONE)
258 struct IpcDataEvMouseMove
261 Evas_Button_Flags flags;
263 unsigned int timestamp;
264 Evas_Event_Flags event_flags;
266 IpcDataEvMouseMove(const Dali::TouchData& touchData, unsigned long timestamp)
267 : x(static_cast<Evas_Coord>(touchData.GetLocalPosition( 0 ).x)),
268 y(static_cast<Evas_Coord>(touchData.GetLocalPosition( 0 ).y)),
269 flags(EVAS_BUTTON_NONE),
271 timestamp(static_cast<unsigned int>(timestamp)),
272 event_flags(EVAS_EVENT_FLAG_NONE)
277 struct IpcDataEvMouseOut
279 unsigned int timestamp;
281 Evas_Event_Flags event_flags;
283 IpcDataEvMouseOut(unsigned long timestamp)
284 : timestamp(static_cast<unsigned int>(timestamp)),
286 event_flags(EVAS_EVENT_FLAG_NONE)
291 struct wl_buffer* preBuffer;
293 static void OnUpdateIndicatorImage( void* data, struct tizen_remote_surface* remoteSurface, struct wl_buffer* buffer, uint32_t time )
295 Dali::Internal::Adaptor::Indicator* indicator = static_cast< Dali::Internal::Adaptor::Indicator* >( data );
299 tbm_surface_h tbmSurface = static_cast< tbm_surface_h >( wl_buffer_get_user_data( buffer ) );
301 indicator->UpdateIndicatorImage( tbmSurface );
304 if( preBuffer != NULL && tizen_remote_surface_get_version( remoteSurface ) >= TIZEN_REMOTE_SURFACE_RELEASE_SINCE_VERSION )
306 tizen_remote_surface_release( remoteSurface, preBuffer );
312 static void OnMissingIndicatorImage( void* data, struct tizen_remote_surface* surface )
316 static const struct tizen_remote_surface_listener remoteSurfaceCallback =
318 OnUpdateIndicatorImage,
319 OnMissingIndicatorImage,
322 } // anonymous namespace
331 #if defined(DEBUG_ENABLED)
332 Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
335 // Impl to hide EFL implementation.
337 struct Indicator::Impl
339 enum // operation mode
342 INDICATOR_STAY_WITH_DURATION
348 Impl(Indicator* indicator)
349 : mIndicator(indicator),
350 mEcoreEventHandler(NULL)
352 #if defined(DALI_PROFILE_MOBILE)
353 mEcoreEventHandler = ecore_event_handler_add(ECORE_WL_EVENT_INDICATOR_FLICK, EcoreEventIndicator, this);
354 #endif // WAYLAND && DALI_PROFILE_MOBILE
362 if ( mEcoreEventHandler )
364 ecore_event_handler_del(mEcoreEventHandler);
368 static void SetIndicatorVisibility( void* data, int operation )
370 Indicator::Impl* indicatorImpl((Indicator::Impl*)data);
372 if ( indicatorImpl == NULL || indicatorImpl->mIndicator == NULL)
376 if ( operation == INDICATOR_STAY_WITH_DURATION )
378 // if indicator is not showing, INDICATOR_FLICK_DONE is given
379 if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
380 !indicatorImpl->mIndicator->mIsShowing )
382 indicatorImpl->mIndicator->ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
385 else if( operation == INDICATOR_HIDE )
387 if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
388 indicatorImpl->mIndicator->mIsShowing )
390 indicatorImpl->mIndicator->ShowIndicator( HIDE_NOW );
394 #if defined(DALI_PROFILE_MOBILE)
396 * Called when the Ecore indicator event is received.
398 static Eina_Bool EcoreEventIndicator( void* data, int type, void* event )
400 SetIndicatorVisibility( data, INDICATOR_STAY_WITH_DURATION );
401 return ECORE_CALLBACK_PASS_ON;
403 #endif // WAYLAND && DALI_PROFILE_MOBILE
406 Indicator* mIndicator;
407 Ecore_Event_Handler* mEcoreEventHandler;
410 Indicator::LockFile::LockFile(const std::string filename)
411 : mFilename(filename),
414 mFileDescriptor = open(filename.c_str(), O_RDWR);
415 if( mFileDescriptor == -1 )
419 DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
423 Indicator::LockFile::~LockFile()
425 // Closing file descriptor also unlocks file.
426 close( mFileDescriptor );
429 bool Indicator::LockFile::Lock()
431 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
434 if( mFileDescriptor > 0 )
436 struct flock filelock;
438 filelock.l_type = F_RDLCK;
439 filelock.l_whence = SEEK_SET;
440 filelock.l_start = 0;
442 if( fcntl( mFileDescriptor, F_SETLKW, &filelock ) == -1 )
445 DALI_LOG_ERROR( "### Failed to lock with fd : %s ###\n", mFilename.c_str() );
455 DALI_LOG_ERROR( "### Invalid fd ###\n" );
461 void Indicator::LockFile::Unlock()
463 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
465 struct flock filelock;
467 filelock.l_type = F_UNLCK;
468 filelock.l_whence = SEEK_SET;
469 filelock.l_start = 0;
471 if (fcntl(mFileDescriptor, F_SETLKW, &filelock) == -1)
474 DALI_LOG_ERROR( "### Failed to lock with fd : %s ###\n", mFilename.c_str() );
478 bool Indicator::LockFile::RetrieveAndClearErrorStatus()
480 bool error = mErrorThrown;
481 mErrorThrown = false;
485 Indicator::ScopedLock::ScopedLock(LockFile* lockFile)
486 : mLockFile(lockFile),
491 mLocked = mLockFile->Lock();
495 Indicator::ScopedLock::~ScopedLock()
503 bool Indicator::ScopedLock::IsLocked()
508 Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, IndicatorInterface::Observer* observer )
510 mGestureDeltaY( 0.0f ),
511 mGestureDetected( false ),
513 mOpacityMode( Dali::Window::OPAQUE ),
514 mState( DISCONNECTED ),
516 mServerConnection( NULL ),
517 mObserver( observer ),
518 mOrientation( orientation ),
521 mVisible( Dali::Window::INVISIBLE ),
523 mIsAnimationPlaying( false ),
524 mCurrentSharedFile( 0 ),
525 mSharedBufferType( BUFFER_TYPE_SHM ),
527 mBackgroundVisible( false ),
530 mIndicatorContentActor = Dali::Actor::New();
531 mIndicatorContentActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
532 mIndicatorContentActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
534 // Indicator image handles the touch event including "leave"
535 mIndicatorContentActor.SetLeaveRequired( true );
536 mIndicatorContentActor.TouchSignal().Connect( this, &Indicator::OnTouched );
537 mIndicatorContentActor.SetColor( Color::BLACK );
539 mIndicatorActor = Dali::Actor::New();
540 mIndicatorActor.Add( mIndicatorContentActor );
542 // Event handler to find out flick down gesture
543 mEventActor = Dali::Actor::New();
544 mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
545 mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
546 mIndicatorActor.Add( mEventActor );
548 // Attach pan gesture to find flick down during hiding.
549 // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
550 // since it consumes the pan gesture in advance.
551 mPanDetector = Dali::PanGestureDetector::New();
552 mPanDetector.DetectedSignal().Connect( this, &Indicator::OnPan );
553 mPanDetector.Attach( mEventActor );
557 // register indicator to accessibility adaptor
558 Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
559 if(accessibilityAdaptor)
561 AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this );
563 // hide the indicator by default
564 mIndicatorActor.SetVisible( false );
566 // create impl to handle ecore event
567 mImpl = new Impl(this);
570 Indicator::~Indicator()
580 mEventActor.TouchSignal().Disconnect( this, &Indicator::OnTouched );
585 void Indicator::SetAdaptor(Adaptor* adaptor)
588 mIndicatorBuffer->SetAdaptor( adaptor );
591 Dali::Actor Indicator::GetActor()
593 return mIndicatorActor;
596 void Indicator::Open( Dali::Window::WindowOrientation orientation )
598 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
600 // Calls from Window should be set up to ensure we are in a
601 // disconnected state before opening a second time.
602 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
604 mOrientation = orientation;
608 // Change background visibility depending on orientation
609 if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
611 if( mBackgroundRenderer )
613 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
614 mBackgroundVisible = false;
619 SetOpacityMode( mOpacityMode );
623 void Indicator::Close()
625 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) );
627 if( mState == CONNECTED )
630 if( mObserver != NULL )
632 mObserver->IndicatorClosed( this );
636 Dali::Texture emptyTexture;
637 SetForegroundImage( emptyTexture );
640 void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
644 Dali::Geometry geometry = CreateBackgroundGeometry();
647 if( mBackgroundRenderer )
649 if( mBackgroundRenderer.GetGeometry() != geometry )
651 mBackgroundRenderer.SetGeometry( geometry );
656 if( !mBackgroundShader )
658 mBackgroundShader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT );
661 mBackgroundRenderer = Dali::Renderer::New( geometry, mBackgroundShader );
664 if( !mBackgroundVisible )
666 mIndicatorContentActor.AddRenderer( mBackgroundRenderer );
667 mBackgroundVisible = true;
670 else if( mBackgroundRenderer )
672 mIndicatorContentActor.RemoveRenderer( mBackgroundRenderer );
673 mBackgroundVisible = false;
678 void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
680 if ( visibleMode != mVisible || forceUpdate )
682 // If we were previously hidden, then we should update the image data before we display the indicator
683 if ( mVisible == Dali::Window::INVISIBLE )
685 UpdateImageData( mCurrentSharedFile );
688 if ( visibleMode == Dali::Window::INVISIBLE )
690 if (mServerConnection)
692 mServerConnection->SendEvent( OP_HIDE, NULL, 0 );
697 mIndicatorActor.SetVisible( true );
699 if( mServerConnection )
701 mServerConnection->SendEvent( OP_SHOW, NULL, 0 );
705 mVisible = visibleMode;
708 if( mForegroundRenderer &&
709 ( mForegroundRenderer.GetTextures().GetTexture( 0u ) ||
710 Dali::TextureGetImage( mForegroundRenderer.GetTextures(), 0u ) )
713 if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
716 ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
718 else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
721 ShowIndicator( KEEP_SHOWING );
726 ShowIndicator( HIDE_NOW );
736 bool Indicator::IsConnected()
738 return ( mState == CONNECTED );
741 bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size )
745 return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
753 bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchData& touchData)
755 if( mServerConnection )
757 // Send touch event to indicator server when indicator is showing
758 if( CheckVisibleState() || mIsShowing )
760 switch( touchData.GetState( 0 ) )
762 case Dali::PointState::DOWN:
764 IpcDataEvMouseMove ipcMove( touchData, touchData.GetTime() );
765 IpcDataEvMouseDown ipcDown( touchData.GetTime() );
766 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
767 mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
769 if( mVisible == Dali::Window::AUTO )
771 // Stop hiding indicator
772 ShowIndicator( KEEP_SHOWING );
777 case Dali::PointState::MOTION:
779 IpcDataEvMouseMove ipcMove( touchData, touchData.GetTime() );
780 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
784 case Dali::PointState::UP:
785 case Dali::PointState::INTERRUPTED:
787 IpcDataEvMouseUp ipcUp( touchData.GetTime() );
788 mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
790 if( mVisible == Dali::Window::AUTO )
793 ShowIndicator( 0.5f /* hide after 0.5 sec */ );
798 case Dali::PointState::LEAVE:
800 IpcDataEvMouseMove ipcMove( touchData, touchData.GetTime() );
801 mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
802 IpcDataEvMouseUp ipcOut( touchData.GetTime() );
803 mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
818 bool Indicator::Connect()
820 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
822 DALI_ASSERT_DEBUG( mState == DISCONNECTED );
824 bool connected = false;
826 mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
827 if( mServerConnection )
829 connected = mServerConnection->IsConnected();
832 delete mServerConnection;
833 mServerConnection = NULL;
839 StartReconnectionTimer();
849 void Indicator::StartReconnectionTimer()
851 if( ! mReconnectTimer )
853 mReconnectTimer = Dali::Timer::New(1000);
854 mConnection.DisconnectAll();
855 mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
857 mReconnectTimer.Start();
860 bool Indicator::OnReconnectTimer()
864 if( mState == DISCONNECTED )
875 void Indicator::Disconnect()
877 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
879 mState = DISCONNECTED;
881 delete mServerConnection;
882 mServerConnection = NULL;
884 ClearSharedFileInfo();
887 void Indicator::Resize( int width, int height )
898 if( mImageWidth != width || mImageHeight != height )
901 mImageHeight = height;
903 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
904 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
905 mEventActor.SetSize(mImageWidth, mImageHeight);
910 void Indicator::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
912 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
914 // epcEvent->ref == w
915 // epcEvent->ref_to == h
916 // epcEvent->response == buffer num
917 // epcEvent->data = lockfile + nul byte
919 if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
920 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
922 int n = epcEvent->response;
924 if( n >= 0 && n < SHARED_FILE_NUMBER )
926 mCurrentSharedFile = n;
928 mSharedFileInfo[n].mImageWidth = epcEvent->ref;
929 mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
931 mSharedFileInfo[n].mLockFileName.clear();
933 mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
935 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
936 n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
941 void Indicator::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
943 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
945 // epcEvent->ref == shm id
946 // epcEvent->ref_to == shm num
947 // epcEvent->response == buffer num
948 // epcEvent->data = shm ref string + nul byte
950 if ( (epcEvent->data) &&
951 (epcEvent->size > 0) &&
952 (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
954 int n = epcEvent->response;
956 if( n >= 0 && n < SHARED_FILE_NUMBER )
958 mCurrentSharedFile = n;
960 mSharedFileInfo[n].mSharedFileName.clear();
962 mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
964 mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
965 mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
967 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
968 n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
973 void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
975 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
977 // epcEvent->ref == alpha
978 // epcEvent->ref_to == sys
979 // epcEvent->response == buffer num
981 if ( mSharedBufferType != BUFFER_TYPE_SHM )
986 int n = epcEvent->response;
988 if( n >= 0 && n < SHARED_FILE_NUMBER )
990 mCurrentSharedFile = n;
992 delete mSharedFileInfo[n].mSharedFile;
993 mSharedFileInfo[n].mSharedFile = NULL;
995 delete mSharedFileInfo[n].mLock;
996 mSharedFileInfo[n].mLock = NULL;
998 std::stringstream sharedFileID;
999 std::stringstream sharedFileNumber;
1001 sharedFileID << mSharedFileInfo[n].mSharedFileID;
1002 sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
1004 std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
1006 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
1008 mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
1009 if( mSharedFileInfo[n].mSharedFile != NULL )
1011 mSharedFileInfo[n].mLock = new Indicator::LockFile( mSharedFileInfo[n].mLockFileName );
1012 if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
1014 DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
1019 CreateNewImage( n );
1025 void Indicator::SetupNativeIndicatorImage( Ecore_Ipc_Event_Server_Data *epcEvent )
1027 // Bind tizen remote surface
1028 Eina_Inlist* globals;
1029 Ecore_Wl_Global* global;
1030 struct tizen_remote_surface_manager* remoteSurfaceManager = NULL;
1031 struct tizen_remote_surface* remoteSurface = NULL;
1032 struct wl_registry* registry;
1033 struct wayland_tbm_client* tbmClient;
1034 struct wl_tbm* wlTbm;
1036 if ( !remoteSurfaceManager )
1038 registry = ecore_wl_registry_get();
1039 globals = ecore_wl_globals_get();
1041 if (!registry || !globals)
1043 DALI_LOG_ERROR( "SetupNativeIndicatorImage registry or globals error\n" );
1047 EINA_INLIST_FOREACH(globals, global)
1049 if ( !strcmp( global->interface, "tizen_remote_surface_manager" ) )
1051 remoteSurfaceManager = ( struct tizen_remote_surface_manager* )wl_registry_bind( registry, global->id, &tizen_remote_surface_manager_interface, ( ( global->version < 2 )? global->version: 2 ) );
1055 if ( !remoteSurfaceManager )
1057 DALI_LOG_ERROR( "SetupNativeIndicatorImage bind error\n" );
1061 tbmClient = ( struct wayland_tbm_client* )wayland_tbm_client_init( ecore_wl_display_get() );
1064 DALI_LOG_ERROR( "SetupNativeIndicatorImage client init error\n" );
1068 wlTbm = ( struct wl_tbm* )wayland_tbm_client_get_wl_tbm( tbmClient );
1071 DALI_LOG_ERROR( "SetupNativeIndicatorImage wl tbm error\n" );
1075 uint32_t resourceId = epcEvent->ref;
1076 remoteSurface = tizen_remote_surface_manager_create_surface( remoteSurfaceManager, resourceId, wlTbm );
1078 if( !remoteSurface )
1080 DALI_LOG_ERROR( "SetupNativeIndicatorImage create surface error\n" );
1084 tizen_remote_surface_add_listener( remoteSurface, &remoteSurfaceCallback, this );
1085 tizen_remote_surface_redirect( remoteSurface );
1086 tizen_remote_surface_transfer_visibility( remoteSurface, TIZEN_REMOTE_SURFACE_VISIBILITY_TYPE_VISIBLE);
1089 void Indicator::UpdateIndicatorImage( Any source )
1091 if( !mNativeImageSource )
1093 mNativeImageSource = Dali::NativeImageSource::New( source );
1094 Dali::NativeImage nativeImage = Dali::NativeImage::New( *mNativeImageSource );
1096 SetForegroundNativeImage( nativeImage );
1097 mIndicatorContentActor.SetSize( mImageWidth, mImageHeight );
1098 mIndicatorActor.SetSize( mImageWidth, mImageHeight );
1099 mEventActor.SetSize( mImageWidth, mImageHeight );
1105 mNativeImageSource->SetSource( source );
1106 Dali::Stage::GetCurrent().KeepRendering( 0.0f );
1109 void Indicator::UpdateTopMargin()
1111 int newMargin = (mVisible == Dali::Window::VISIBLE && mOpacityMode == Dali::Window::OPAQUE) ? mImageHeight : 0;
1112 if (mTopMargin != newMargin)
1114 mTopMargin = newMargin;
1115 mAdaptor->IndicatorSizeChanged( mTopMargin );
1119 void Indicator::UpdateVisibility()
1121 if( CheckVisibleState() )
1123 // set default indicator type (enable the quick panel)
1124 OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
1128 // set default indicator type (disable the quick panel)
1129 OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
1134 mIndicatorContentActor.SetPosition( 0.0f, -mImageHeight, 0.0f );
1137 SetVisible(mVisible, true);
1140 void Indicator::UpdateImageData( int bufferNumber )
1142 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
1144 if( mState == CONNECTED && mVisible )
1148 // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false
1149 CopyToBuffer( bufferNumber );
1155 mAdaptor->RequestUpdateOnce();
1161 bool Indicator::CopyToBuffer( int bufferNumber )
1163 bool success = false;
1165 if( mSharedFileInfo[bufferNumber].mLock )
1167 Indicator::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
1168 if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
1172 else if( scopedLock.IsLocked() )
1174 unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
1175 size_t size = mSharedFileInfo[bufferNumber].mImageWidth * mSharedFileInfo[bufferNumber].mImageHeight * 4;
1177 if( mIndicatorBuffer->UpdatePixels( src, size ) )
1179 mAdaptor->RequestUpdateOnce();
1188 void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
1192 void Indicator::CreateNewPixmapImage()
1196 void Indicator::CreateNewImage( int bufferNumber )
1198 DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
1199 mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
1200 bool success = false;
1202 if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
1204 Dali::Texture texture = Dali::Texture::New( mIndicatorBuffer->GetNativeImage() );
1207 SetForegroundImage( texture );
1214 DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
1216 if( mObserver != NULL )
1218 mObserver->IndicatorClosed( this );
1220 // Don't do connection in this callback - strange things happen!
1221 StartReconnectionTimer();
1225 Dali::Geometry Indicator::CreateBackgroundGeometry()
1227 switch( mOpacityMode )
1229 case Dali::Window::TRANSLUCENT:
1230 if( !mTranslucentGeometry )
1232 // Construct 5 interval mesh
1246 struct BackgroundVertex
1252 unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
1253 BackgroundVertex vertices[ numVertices ];
1256 float delta = 1.0f / NUM_GRADIENT_INTERVALS;
1257 BackgroundVertex* currentVertex = vertices;
1258 for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
1260 currentVertex->mPosition = Vector2( -0.5f, d );
1261 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1264 currentVertex->mPosition = Vector2( 0.5f, d );
1265 currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
1270 unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
1271 unsigned short indices[ numIndices ];
1273 unsigned short* currentIndex = indices;
1274 for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
1276 *currentIndex++ = (2 * y);
1277 *currentIndex++ = (2 * y) + 3;
1278 *currentIndex++ = (2 * y) + 1;
1280 *currentIndex++ = (2 * y);
1281 *currentIndex++ = (2 * y) + 2;
1282 *currentIndex++ = (2 * y) + 3;
1285 Dali::Property::Map vertexFormat;
1286 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1287 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1288 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1289 vertexPropertyBuffer.SetData( vertices, numVertices );
1291 // Create the geometry object
1292 mTranslucentGeometry = Dali::Geometry::New();
1293 mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
1294 mTranslucentGeometry.SetIndexBuffer( &indices[0], numIndices );
1297 return mTranslucentGeometry;
1298 case Dali::Window::OPAQUE:
1300 if( !mSolidGeometry )
1303 struct BackgroundVertex
1309 BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
1310 { Vector2( -0.5f, 0.5f ), 1.0f }, { Vector2( 0.5f, 0.5f ), 1.0f } };
1313 unsigned short indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
1315 Dali::Property::Map vertexFormat;
1316 vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
1317 vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
1318 Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat );
1319 vertexPropertyBuffer.SetData( vertices, 4 );
1322 // Create the geometry object
1323 mSolidGeometry = Dali::Geometry::New();
1324 mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
1325 mSolidGeometry.SetIndexBuffer( &indices[0], 6 );
1328 return mSolidGeometry;
1329 case Dali::Window::TRANSPARENT:
1333 return Dali::Geometry();
1336 void Indicator::SetForegroundImage( Dali::Texture texture )
1338 if( !mForegroundRenderer && texture )
1341 Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, FOREGROUND_FRAGMENT_SHADER );
1343 // Create renderer from geometry and material
1344 Dali::Geometry quad = CreateQuadGeometry();
1345 mForegroundRenderer = Dali::Renderer::New( quad, shader );
1346 // Make sure the foreground stays in front of the background
1347 mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1349 // Set blend function
1350 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB, Dali::BlendFactor::ONE );
1351 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB, Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1352 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA, Dali::BlendFactor::ONE );
1353 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1355 // Create a texture-set and add to renderer
1357 Dali::TextureSet textureSet = Dali::TextureSet::New();
1358 textureSet.SetTexture( 0u, texture );
1359 mForegroundRenderer.SetTextures( textureSet );
1361 mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1363 else if( mForegroundRenderer )
1365 Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1366 textureSet.SetTexture( 0u, texture );
1369 if( mImageWidth == 0 && mImageHeight == 0 && texture)
1371 Resize( texture.GetWidth(), texture.GetHeight() );
1375 void Indicator::SetForegroundNativeImage( Dali::Image image )
1377 if( !mForegroundRenderer && image )
1380 std::string fragmentShader = "#extension GL_OES_EGL_image_external:require\n";
1381 fragmentShader += "\n";
1382 fragmentShader += FOREGROUND_TBM_FRAGMENT_SHADER;
1385 Dali::Shader shader = Dali::Shader::New( FOREGROUND_VERTEX_SHADER, fragmentShader );
1387 // Create renderer from geometry and material
1388 Dali::Geometry quad = CreateQuadGeometry();
1389 mForegroundRenderer = Dali::Renderer::New( quad, shader );
1390 // Make sure the foreground stays in front of the background
1391 mForegroundRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, 1.f );
1393 // Set blend function
1394 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB, Dali::BlendFactor::ONE );
1395 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB, Dali::BlendFactor::ONE_MINUS_SRC_ALPHA );
1396 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA, Dali::BlendFactor::ONE );
1397 mForegroundRenderer.SetProperty( Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA, Dali::BlendFactor::ONE );
1399 // Create a texture-set and add to renderer
1401 Dali::TextureSet textureSet = Dali::TextureSet::New();
1402 Dali::TextureSetImage( textureSet, 0u, image );
1404 mForegroundRenderer.SetTextures( textureSet );
1406 mIndicatorContentActor.AddRenderer( mForegroundRenderer );
1408 else if( mForegroundRenderer )
1410 Dali::TextureSet textureSet = mForegroundRenderer.GetTextures();
1411 Dali::TextureSetImage( textureSet, 0u, image );
1414 if( mImageWidth == 0 && mImageHeight == 0 && image )
1416 Resize( image.GetWidth(), image.GetHeight() );
1420 void Indicator::OnIndicatorTypeChanged( Type indicatorType )
1422 if( mObserver != NULL )
1424 mObserver->IndicatorTypeChanged( indicatorType );
1428 void Indicator::DataReceived( void* event )
1430 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1431 Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
1433 switch( epcEvent->minor )
1437 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
1440 mAdaptor->RequestUpdateOnce();
1444 case OP_UPDATE_DONE:
1446 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
1447 // epcEvent->response == display buffer #
1448 UpdateImageData( epcEvent->response );
1453 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
1454 SetSharedImageInfo( epcEvent );
1459 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
1460 SetLockFileInfo( epcEvent );
1465 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
1466 LoadSharedImage( epcEvent );
1471 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_GL_REF\n" );
1472 SetupNativeIndicatorImage( epcEvent );
1477 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
1479 if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
1481 IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
1482 Resize( newSize->w, newSize->h );
1488 int msgDomain = epcEvent->ref;
1489 int msgId = epcEvent->ref_to;
1491 void *msgData = NULL;
1492 int msgDataSize = 0;
1493 msgData = epcEvent->data;
1494 msgDataSize = epcEvent->size;
1496 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
1498 if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
1502 case MSG_ID_INDICATOR_TYPE:
1504 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
1505 Type* indicatorType = static_cast<Type*>( epcEvent->data );
1506 OnIndicatorTypeChanged( *indicatorType );
1510 case MSG_ID_INDICATOR_START_ANIMATION:
1512 DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
1514 if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
1516 DALI_LOG_ERROR("Message data is incorrect\n");
1520 IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
1522 if(!CheckVisibleState())
1524 ShowIndicator( animData->duration /* n sec */ );
1535 void Indicator::ConnectionClosed()
1537 DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
1539 // Will get this callback if the server connection failed to start up.
1540 delete mServerConnection;
1541 mServerConnection = NULL;
1542 mState = DISCONNECTED;
1544 // Attempt to re-connect
1548 bool Indicator::CheckVisibleState()
1550 if( mOrientation == Dali::Window::LANDSCAPE
1551 || mOrientation == Dali::Window::LANDSCAPE_INVERSE
1552 || (mVisible == Dali::Window::INVISIBLE)
1553 || (mVisible == Dali::Window::AUTO && !mIsShowing) )
1561 void Indicator::ClearSharedFileInfo()
1563 for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
1565 delete mSharedFileInfo[i].mLock;
1566 mSharedFileInfo[i].mLock = NULL;
1568 delete mSharedFileInfo[i].mSharedFile;
1569 mSharedFileInfo[i].mSharedFile = NULL;
1571 mSharedFileInfo[i].mLockFileName.clear();
1572 mSharedFileInfo[i].mSharedFileName.clear();
1577 * duration can be this
1581 * KEEP_SHOWING = -1,
1585 void Indicator::ShowIndicator(float duration)
1587 if( !mIndicatorAnimation )
1589 mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
1590 mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished);
1593 if(mIsShowing && !EqualsZero(duration))
1595 // If need to show during showing, do nothing.
1596 // In 2nd phase (below) will update timer
1598 else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
1600 // If need to hide during hiding or hidden already, do nothing
1604 mIndicatorAnimation.Clear();
1606 if( EqualsZero(duration) )
1608 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
1612 OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
1616 mIndicatorAnimation.AnimateTo( Property( mIndicatorContentActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
1620 OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
1623 mIndicatorAnimation.Play();
1624 mIsAnimationPlaying = true;
1631 mShowTimer = Dali::Timer::New(1000 * duration);
1632 mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer);
1634 mShowTimer.SetInterval(1000* duration);
1637 if( mVisible == Dali::Window::AUTO )
1639 // check the stage touch
1640 Dali::Stage::GetCurrent().TouchSignal().Connect( this, &Indicator::OnStageTouched );
1645 if(mShowTimer && mShowTimer.IsRunning())
1650 if( mVisible == Dali::Window::AUTO )
1652 // check the stage touch
1653 Dali::Stage::GetCurrent().TouchSignal().Disconnect( this, &Indicator::OnStageTouched );
1658 bool Indicator::OnShowTimer()
1660 // after time up, hide indicator
1661 ShowIndicator( HIDE_NOW );
1666 void Indicator::OnAnimationFinished(Dali::Animation& animation)
1668 mIsAnimationPlaying = false;
1669 // once animation is finished and indicator is hidden, take it off stage
1670 if( mObserver != NULL )
1672 mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
1676 void Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
1680 if( mServerConnection )
1682 switch( gesture.state )
1684 case Gesture::Started:
1686 mGestureDetected = false;
1688 // The gesture position is the current position after it has moved by the displacement.
1689 // We want to reference the original position.
1690 mGestureDeltaY = gesture.position.y - gesture.displacement.y;
1693 // No break, Fall through
1694 case Gesture::Continuing:
1696 if( mVisible == Dali::Window::AUTO && !mIsShowing )
1698 // Only take one touch point
1699 if( gesture.numberOfTouches == 1 && mGestureDetected == false )
1701 mGestureDeltaY += gesture.displacement.y;
1703 if( mGestureDeltaY >= mImageHeight * SHOWING_DISTANCE_HEIGHT_RATE )
1705 ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1706 mGestureDetected = true;
1714 case Gesture::Finished:
1715 case Gesture::Cancelled:
1717 // if indicator is showing, hide again when touching is finished (Since touch leave is activated, checking it in gesture::finish instead of touch::up)
1718 if( mVisible == Dali::Window::AUTO && mIsShowing )
1720 ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
1732 void Indicator::OnStageTouched(const Dali::TouchData& touchData)
1734 // when stage is touched while indicator is showing temporary, hide it
1735 if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
1737 switch( touchData.GetState( 0 ) )
1739 case Dali::PointState::DOWN:
1741 // if touch point is inside the indicator, indicator is not hidden
1742 if( mImageHeight < int( touchData.GetScreenPosition( 0 ).y ) )
1744 ShowIndicator( HIDE_NOW );