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 <dali/internal/adaptor/common/framework.h>
24 #include <unordered_set>
25 #include <android_native_app_glue.h>
27 #include <dali/integration-api/debug.h>
28 #include <dali/integration-api/adaptor-framework/adaptor.h>
29 #include <dali/integration-api/adaptor-framework/android/android-framework.h>
30 #include <dali/public-api/events/touch-point.h>
31 #include <dali/public-api/events/key-event.h>
34 #include <dali/internal/system/common/callback-manager.h>
35 #include <dali/internal/adaptor/android/android-framework-impl.h>
49 // Copied from x server
50 static unsigned int GetCurrentMilliSeconds(void)
55 static clockid_t clockid;
59 #ifdef CLOCK_MONOTONIC_COARSE
60 if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
61 (tp.tv_nsec / 1000) <= 1000 && clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
63 clockid = CLOCK_MONOTONIC_COARSE;
67 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
69 clockid = CLOCK_MONOTONIC;
76 if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
78 return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
81 gettimeofday(&tv, NULL);
82 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
85 } // Unnamed namespace
88 * Impl to hide android data members
90 struct Framework::Impl
99 bool ( *callback )( void *data );
101 IdleCallback( int timeout, int id, void* data, bool ( *callback )( void *data ) )
102 : timestamp( GetCurrentMilliSeconds() + timeout ),
112 return callback( data );
115 bool operator<( const IdleCallback& rhs ) const
117 return timestamp > rhs.timestamp;
123 Impl( Framework* framework )
124 : mAbortCallBack( nullptr ),
125 mCallbackManager( CallbackManager::New() ),
126 mLanguage( "NOT_SUPPORTED" ),
127 mRegion( "NOT_SUPPORTED" ),
128 mFinishRequested( false ),
135 AndroidFramework::GetImplementation( AndroidFramework::Get() ).SetFramework( framework );
140 AndroidFramework::GetImplementation( AndroidFramework::Get() ).SetFramework( nullptr );
142 delete mAbortCallBack;
143 mAbortCallBack = nullptr;
145 // we're quiting the main loop so
146 // mCallbackManager->RemoveAllCallBacks() does not need to be called
147 // to delete our abort handler
148 delete mCallbackManager;
149 mCallbackManager = nullptr;
152 std::string GetLanguage() const
157 std::string GetRegion() const
166 read( mIdleReadPipe, &msg, sizeof( msg ) );
168 unsigned int ts = GetCurrentMilliSeconds();
170 if ( !mIdleCallbacks.empty() )
172 IdleCallback callback = mIdleCallbacks.top();
173 if( callback.timestamp <= ts )
175 mIdleCallbacks.pop();
177 // Callback wasn't removed
178 if( mRemovedIdleCallbacks.find( callback.id ) == mRemovedIdleCallbacks.end() )
180 if ( callback() ) // keep the callback
182 AddIdle( callback.timeout, callback.data, callback.callback );
186 // Callback cane be also removed during the callback call
187 auto i = mRemovedIdleCallbacks.find( callback.id );
188 if( i != mRemovedIdleCallbacks.end() )
190 mRemovedIdleCallbacks.erase( i );
195 if( mIdleCallbacks.empty() )
197 mRemovedIdleCallbacks.clear();
201 unsigned int AddIdle( int timeout, void* data, bool ( *callback )( void *data ) )
209 mIdleCallbacks.push( IdleCallback( timeout, mIdleId, data, callback ) );
211 // To wake up the idle pipe and to trigger OnIdle
213 write( mIdleWritePipe, &msg, sizeof( msg ) );
218 void RemoveIdle( unsigned int id )
222 mRemovedIdleCallbacks.insert( id );
230 if( !mIdleCallbacks.empty() )
232 IdleCallback idleTimeout = mIdleCallbacks.top();
233 timeout = idleTimeout.timestamp - GetCurrentMilliSeconds();
244 CallbackBase* mAbortCallBack;
245 CallbackManager* mCallbackManager;
246 std::string mLanguage;
248 bool mFinishRequested;
252 unsigned int mIdleId;
253 std::priority_queue<IdleCallback> mIdleCallbacks;
254 std::unordered_set<int> mRemovedIdleCallbacks;
259 * Called by the native activity loop when the application APP_CMD_INIT_WINDOW event is processed.
261 static void NativeWindowCreated( Framework* framework, ANativeWindow* window )
265 framework->AppStatusHandler( APP_WINDOW_CREATED, window );
270 * Called by the native activity loop when the application APP_CMD_DESTROY event is processed.
272 static void NativeWindowDestroyed( Framework* framework, ANativeWindow* window )
276 framework->AppStatusHandler( APP_WINDOW_DESTROYED, window );
281 * Called by the native activity loop when the application APP_CMD_INIT_WINDOW event is processed.
283 static void NativeAppPaused( Framework* framework )
287 framework->AppStatusHandler( APP_PAUSE, nullptr );
292 * Called by the native activity loop when the application APP_CMD_TERM_WINDOW event is processed.
294 static void NativeAppResumed( Framework* framework )
298 framework->AppStatusHandler( APP_RESUME, nullptr );
303 * Called by the native activity loop when the application input touch event is processed.
305 static void NativeAppTouchEvent( Framework* framework, Dali::TouchPoint& touchPoint, int64_t timeStamp )
307 Dali::Adaptor::Get().FeedTouchPoint( touchPoint, timeStamp );
311 * Called by the native activity loop when the application input key event is processed.
313 static void NativeAppKeyEvent( Framework* framework, Dali::KeyEvent& keyEvent )
315 Dali::Adaptor::Get().FeedKeyEvent( keyEvent );
319 * Called by the native activity loop when the application APP_CMD_DESTROY event is processed.
321 static void NativeAppDestroyed( Framework* framework )
325 framework->AppStatusHandler( APP_DESTROYED, nullptr );
344 static void HandleAppCmd(struct android_app* app, int32_t cmd)
346 Framework* framework = AndroidFramework::GetImplementation( AndroidFramework::Get() ).GetFramework();
349 case APP_CMD_SAVE_STATE:
359 case APP_CMD_INIT_WINDOW:
360 // The window is being shown, get it ready.
361 AndroidFramework::Get().SetApplicationWindow( app->window );
362 Dali::Internal::Adaptor::Framework::Impl::NativeWindowCreated( framework, app->window );
363 Dali::Internal::Adaptor::Framework::Impl::NativeAppResumed( framework );
365 case APP_CMD_TERM_WINDOW:
366 // The window is being hidden or closed, clean it up.
367 AndroidFramework::Get().SetApplicationWindow( nullptr );
368 Dali::Internal::Adaptor::Framework::Impl::NativeAppPaused( framework );
369 Dali::Internal::Adaptor::Framework::Impl::NativeWindowDestroyed( framework, app->window );
371 case APP_CMD_GAINED_FOCUS:
373 case APP_CMD_LOST_FOCUS:
375 case APP_CMD_DESTROY:
376 Dali::Internal::Adaptor::Framework::Impl::NativeAppPaused( framework );
377 Dali::Internal::Adaptor::Framework::Impl::NativeAppDestroyed( framework );
382 static int32_t HandleAppInput(struct android_app* app, AInputEvent* event)
384 Framework* framework = AndroidFramework::GetImplementation( AndroidFramework::Get() ).GetFramework();
386 if( AInputEvent_getType( event ) == AINPUT_EVENT_TYPE_MOTION )
388 int32_t deviceId = AInputEvent_getDeviceId( event );
389 float x = AMotionEvent_getX( event, 0 );
390 float y = AMotionEvent_getY( event, 0 );
391 TouchPoint::State state = TouchPoint::Down;
392 int32_t action = AMotionEvent_getAction( event );
393 int64_t timeStamp = AMotionEvent_getEventTime( event );
395 switch ( action & AMOTION_EVENT_ACTION_MASK )
397 case AMOTION_EVENT_ACTION_DOWN:
399 case AMOTION_EVENT_ACTION_UP:
400 state = TouchPoint::Up;
402 case AMOTION_EVENT_ACTION_MOVE:
403 state = TouchPoint::Motion;
405 case AMOTION_EVENT_ACTION_CANCEL:
406 state = TouchPoint::Interrupted;
408 case AMOTION_EVENT_ACTION_OUTSIDE:
409 state = TouchPoint::Leave;
413 Dali::TouchPoint point( deviceId, state, x, y );
414 Dali::Internal::Adaptor::Framework::Impl::NativeAppTouchEvent( framework, point, timeStamp );
417 else if ( AInputEvent_getType( event ) == AINPUT_EVENT_TYPE_KEY )
419 int32_t deviceId = AInputEvent_getDeviceId( event );
420 int32_t keyCode = AKeyEvent_getKeyCode( event );
421 int32_t action = AKeyEvent_getAction( event );
422 int64_t timeStamp = AKeyEvent_getEventTime( event );
424 KeyEvent::State state = KeyEvent::Down;
427 case AKEY_EVENT_ACTION_DOWN:
429 case AKEY_EVENT_ACTION_UP:
430 state = KeyEvent::Up;
434 std::string keyName = "";
438 keyName = "XF86Back";
443 Dali::KeyEvent keyEvent( keyName, "", keyCode, 0, timeStamp, state );
444 Dali::Internal::Adaptor::Framework::Impl::NativeAppKeyEvent( framework, keyEvent );
451 static void HandleAppIdle(struct android_app* app, struct android_poll_source* source) {
452 Framework* framework = AndroidFramework::GetImplementation( AndroidFramework::Get() ).GetFramework();
453 if( framework && framework->mImpl )
455 framework->mImpl->OnIdle();
461 Framework::Framework( Framework::Observer& observer, int *argc, char ***argv, Type type )
462 : mObserver( observer ),
463 mInitialised( false ),
469 mAbortHandler( MakeCallback( this, &Framework::AbortCallback ) ),
472 mImpl = new Impl( this );
475 Framework::~Framework()
486 void Framework::Run()
488 struct android_app* app = AndroidFramework::Get().GetNativeApplication();
489 app->onAppCmd = Framework::Impl::HandleAppCmd;
490 app->onInputEvent = Framework::Impl::HandleAppInput;
492 struct android_poll_source* source;
493 struct android_poll_source idlePollSource;
494 idlePollSource.id = LOOPER_ID_USER;
495 idlePollSource.app = app;
496 idlePollSource.process = Impl::HandleAppIdle;
499 if( pipe( idlePipe ) )
501 DALI_LOG_ERROR( "Failed to open idle pipe\n" );
505 mImpl->mIdleReadPipe = idlePipe[0];
506 mImpl->mIdleWritePipe = idlePipe[1];
507 ALooper_addFd( app->looper,
508 idlePipe[0], LOOPER_ID_USER, ALOOPER_EVENT_INPUT, NULL, &idlePollSource );
512 // Read all pending events.
514 int idleTimeout = -1;
520 idleTimeout = mImpl->GetIdleTimeout();
523 int id = ALooper_pollAll( idleTimeout, NULL, &events, (void**)&source );
525 // Process the error.
526 if( id == ALOOPER_POLL_ERROR )
528 DALI_LOG_ERROR( "ALooper error\n" );
533 // Process the timeout, trigger OnIdle.
534 if( id == ALOOPER_POLL_TIMEOUT )
537 write( mImpl->mIdleWritePipe, &msg, sizeof( msg ) );
540 // Process the application event.
541 if( id >= 0 && source != NULL )
543 source->process( app, source );
546 // Check if we are exiting.
547 if( app->destroyRequested )
553 ALooper_removeFd( app->looper, idlePipe[0] );
556 mImpl->mIdleReadPipe = -1;
557 mImpl->mIdleWritePipe = -1;
559 close( idlePipe[0] );
560 close( idlePipe[1] );
565 unsigned int Framework::AddIdle( int timeout, void* data, bool ( *callback )( void *data ) )
569 return mImpl->AddIdle( timeout, data, callback );
574 void Framework::RemoveIdle( unsigned int id )
578 mImpl->RemoveIdle( id );
582 void Framework::Quit()
584 struct android_app* app = AndroidFramework::Get().GetNativeApplication();
585 if( app && !app->destroyRequested && !mImpl->mFinishRequested )
587 mImpl->mFinishRequested = true;
588 ANativeActivity_finish( app->activity );
592 bool Framework::IsMainLoopRunning()
597 void Framework::AddAbortCallback( CallbackBase* callback )
599 mImpl->mAbortCallBack = callback;
602 std::string Framework::GetBundleName() const
607 void Framework::SetBundleName(const std::string& name)
612 std::string Framework::GetBundleId() const
617 std::string Framework::GetResourcePath()
619 return DALI_DATA_RO_DIR;
622 std::string Framework::GetDataPath()
627 void Framework::SetBundleId(const std::string& id)
632 void Framework::AbortCallback( )
634 // if an abort call back has been installed run it.
635 if( mImpl->mAbortCallBack )
637 CallbackBase::Execute( *mImpl->mAbortCallBack );
645 bool Framework::AppStatusHandler(int type, void* data)
649 case APP_WINDOW_CREATED:
656 mObserver.OnSurfaceCreated( data );
664 mObserver.OnResume();
667 case APP_WINDOW_DESTROYED:
668 mObserver.OnSurfaceDestroyed( data );
675 case APP_LANGUAGE_CHANGE:
676 mObserver.OnLanguageChanged();
680 mObserver.OnTerminate();
681 mInitialised = false;
691 void Framework::InitThreads()
695 std::string Framework::GetLanguage() const
697 return mImpl->GetLanguage();
700 std::string Framework::GetRegion() const
702 return mImpl->GetRegion();
705 } // namespace Adaptor
707 } // namespace Internal