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 ),
470 mAbortHandler( MakeCallback( this, &Framework::AbortCallback ) ),
473 mImpl = new Impl( this );
476 Framework::~Framework()
487 void Framework::Run()
489 struct android_app* app = AndroidFramework::Get().GetNativeApplication();
490 app->onAppCmd = Framework::Impl::HandleAppCmd;
491 app->onInputEvent = Framework::Impl::HandleAppInput;
493 struct android_poll_source* source;
494 struct android_poll_source idlePollSource;
495 idlePollSource.id = LOOPER_ID_USER;
496 idlePollSource.app = app;
497 idlePollSource.process = Impl::HandleAppIdle;
500 if( pipe( idlePipe ) )
502 DALI_LOG_ERROR( "Failed to open idle pipe\n" );
506 mImpl->mIdleReadPipe = idlePipe[0];
507 mImpl->mIdleWritePipe = idlePipe[1];
508 ALooper_addFd( app->looper,
509 idlePipe[0], LOOPER_ID_USER, ALOOPER_EVENT_INPUT, NULL, &idlePollSource );
513 // Read all pending events.
515 int idleTimeout = -1;
521 idleTimeout = mImpl->GetIdleTimeout();
524 int id = ALooper_pollAll( idleTimeout, NULL, &events, (void**)&source );
526 // Process the error.
527 if( id == ALOOPER_POLL_ERROR )
529 DALI_LOG_ERROR( "ALooper error\n" );
534 // Process the timeout, trigger OnIdle.
535 if( id == ALOOPER_POLL_TIMEOUT )
538 write( mImpl->mIdleWritePipe, &msg, sizeof( msg ) );
541 // Process the application event.
542 if( id >= 0 && source != NULL )
544 source->process( app, source );
547 // Check if we are exiting.
548 if( app->destroyRequested )
554 while (!mImpl->mIdleCallbacks.empty())
556 mImpl->mIdleCallbacks.pop();
559 mImpl->mRemovedIdleCallbacks.clear();
562 ALooper_removeFd( app->looper, idlePipe[0] );
565 mImpl->mIdleReadPipe = -1;
566 mImpl->mIdleWritePipe = -1;
568 close( idlePipe[0] );
569 close( idlePipe[1] );
574 unsigned int Framework::AddIdle( int timeout, void* data, bool ( *callback )( void *data ) )
578 return mImpl->AddIdle( timeout, data, callback );
583 void Framework::RemoveIdle( unsigned int id )
587 mImpl->RemoveIdle( id );
591 void Framework::Quit()
593 struct android_app* app = AndroidFramework::Get().GetNativeApplication();
594 if( app && !app->destroyRequested && !mImpl->mFinishRequested )
596 mImpl->mFinishRequested = true;
597 ANativeActivity_finish( app->activity );
601 bool Framework::IsMainLoopRunning()
606 void Framework::AddAbortCallback( CallbackBase* callback )
608 mImpl->mAbortCallBack = callback;
611 std::string Framework::GetBundleName() const
616 void Framework::SetBundleName(const std::string& name)
621 std::string Framework::GetBundleId() const
626 std::string Framework::GetResourcePath()
628 return DALI_DATA_RO_DIR;
631 std::string Framework::GetDataPath()
636 void Framework::SetBundleId(const std::string& id)
641 void Framework::AbortCallback( )
643 // if an abort call back has been installed run it.
644 if( mImpl->mAbortCallBack )
646 CallbackBase::Execute( *mImpl->mAbortCallBack );
654 bool Framework::AppStatusHandler(int type, void* data)
658 case APP_WINDOW_CREATED:
665 mObserver.OnSurfaceCreated( data );
673 mObserver.OnResume();
676 case APP_WINDOW_DESTROYED:
677 mObserver.OnSurfaceDestroyed( data );
684 case APP_LANGUAGE_CHANGE:
685 mObserver.OnLanguageChanged();
689 mObserver.OnTerminate();
690 mInitialised = false;
700 void Framework::InitThreads()
704 std::string Framework::GetLanguage() const
706 return mImpl->GetLanguage();
709 std::string Framework::GetRegion() const
711 return mImpl->GetRegion();
714 } // namespace Adaptor
716 } // namespace Internal