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>
32 #include <dali/devel-api/events/key-event-devel.h>
35 #include <dali/internal/system/common/callback-manager.h>
36 #include <dali/internal/adaptor/android/android-framework-impl.h>
50 // Copied from x server
51 static unsigned int GetCurrentMilliSeconds(void)
56 static clockid_t clockid;
60 #ifdef CLOCK_MONOTONIC_COARSE
61 if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
62 (tp.tv_nsec / 1000) <= 1000 && clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
64 clockid = CLOCK_MONOTONIC_COARSE;
68 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
70 clockid = CLOCK_MONOTONIC;
77 if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
79 return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
82 gettimeofday(&tv, NULL);
83 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
86 } // Unnamed namespace
89 * Impl to hide android data members
91 struct Framework::Impl
100 bool ( *callback )( void *data );
102 IdleCallback( int timeout, int id, void* data, bool ( *callback )( void *data ) )
103 : timestamp( GetCurrentMilliSeconds() + timeout ),
113 return callback( data );
116 bool operator<( const IdleCallback& rhs ) const
118 return timestamp > rhs.timestamp;
124 Impl( Framework* framework )
125 : mAbortCallBack( nullptr ),
126 mCallbackManager( CallbackManager::New() ),
127 mLanguage( "NOT_SUPPORTED" ),
128 mRegion( "NOT_SUPPORTED" ),
129 mFinishRequested( false ),
136 AndroidFramework::GetImplementation( AndroidFramework::Get() ).SetFramework( framework );
141 AndroidFramework::GetImplementation( AndroidFramework::Get() ).SetFramework( nullptr );
143 delete mAbortCallBack;
144 mAbortCallBack = nullptr;
146 // we're quiting the main loop so
147 // mCallbackManager->RemoveAllCallBacks() does not need to be called
148 // to delete our abort handler
149 delete mCallbackManager;
150 mCallbackManager = nullptr;
153 std::string GetLanguage() const
158 std::string GetRegion() const
167 read( mIdleReadPipe, &msg, sizeof( msg ) );
169 unsigned int ts = GetCurrentMilliSeconds();
171 if ( !mIdleCallbacks.empty() )
173 IdleCallback callback = mIdleCallbacks.top();
174 if( callback.timestamp <= ts )
176 mIdleCallbacks.pop();
178 // Callback wasn't removed
179 if( mRemovedIdleCallbacks.find( callback.id ) == mRemovedIdleCallbacks.end() )
181 if ( callback() ) // keep the callback
183 AddIdle( callback.timeout, callback.data, callback.callback );
187 // Callback cane be also removed during the callback call
188 auto i = mRemovedIdleCallbacks.find( callback.id );
189 if( i != mRemovedIdleCallbacks.end() )
191 mRemovedIdleCallbacks.erase( i );
196 if( mIdleCallbacks.empty() )
198 mRemovedIdleCallbacks.clear();
202 unsigned int AddIdle( int timeout, void* data, bool ( *callback )( void *data ) )
210 mIdleCallbacks.push( IdleCallback( timeout, mIdleId, data, callback ) );
212 // To wake up the idle pipe and to trigger OnIdle
214 write( mIdleWritePipe, &msg, sizeof( msg ) );
219 void RemoveIdle( unsigned int id )
223 mRemovedIdleCallbacks.insert( id );
231 if( !mIdleCallbacks.empty() )
233 IdleCallback idleTimeout = mIdleCallbacks.top();
234 timeout = idleTimeout.timestamp - GetCurrentMilliSeconds();
245 CallbackBase* mAbortCallBack;
246 CallbackManager* mCallbackManager;
247 std::string mLanguage;
249 bool mFinishRequested;
253 unsigned int mIdleId;
254 std::priority_queue<IdleCallback> mIdleCallbacks;
255 std::unordered_set<int> mRemovedIdleCallbacks;
260 * Called by the native activity loop when the application APP_CMD_INIT_WINDOW event is processed.
262 static void NativeWindowCreated( Framework* framework, ANativeWindow* window )
266 framework->AppStatusHandler( APP_WINDOW_CREATED, window );
271 * Called by the native activity loop when the application APP_CMD_DESTROY event is processed.
273 static void NativeWindowDestroyed( Framework* framework, ANativeWindow* window )
277 framework->AppStatusHandler( APP_WINDOW_DESTROYED, window );
282 * Called by the native activity loop when the application APP_CMD_INIT_WINDOW event is processed.
284 static void NativeAppPaused( Framework* framework )
288 framework->AppStatusHandler( APP_PAUSE, nullptr );
293 * Called by the native activity loop when the application APP_CMD_TERM_WINDOW event is processed.
295 static void NativeAppResumed( Framework* framework )
299 framework->AppStatusHandler( APP_RESUME, nullptr );
304 * Called by the native activity loop when the application input touch event is processed.
306 static void NativeAppTouchEvent( Framework* framework, Dali::TouchPoint& touchPoint, int64_t timeStamp )
308 Dali::Adaptor::Get().FeedTouchPoint( touchPoint, timeStamp );
312 * Called by the native activity loop when the application input key event is processed.
314 static void NativeAppKeyEvent( Framework* framework, Dali::KeyEvent& keyEvent )
316 Dali::Adaptor::Get().FeedKeyEvent( keyEvent );
320 * Called by the native activity loop when the application APP_CMD_DESTROY event is processed.
322 static void NativeAppDestroyed( Framework* framework )
326 framework->AppStatusHandler( APP_DESTROYED, nullptr );
345 static void HandleAppCmd(struct android_app* app, int32_t cmd)
347 Framework* framework = AndroidFramework::GetImplementation( AndroidFramework::Get() ).GetFramework();
350 case APP_CMD_SAVE_STATE:
360 case APP_CMD_INIT_WINDOW:
361 // The window is being shown, get it ready.
362 AndroidFramework::Get().SetApplicationWindow( app->window );
363 Dali::Internal::Adaptor::Framework::Impl::NativeWindowCreated( framework, app->window );
364 Dali::Internal::Adaptor::Framework::Impl::NativeAppResumed( framework );
366 case APP_CMD_TERM_WINDOW:
367 // The window is being hidden or closed, clean it up.
368 AndroidFramework::Get().SetApplicationWindow( nullptr );
369 Dali::Internal::Adaptor::Framework::Impl::NativeAppPaused( framework );
370 Dali::Internal::Adaptor::Framework::Impl::NativeWindowDestroyed( framework, app->window );
372 case APP_CMD_GAINED_FOCUS:
374 case APP_CMD_LOST_FOCUS:
376 case APP_CMD_DESTROY:
377 Dali::Internal::Adaptor::Framework::Impl::NativeAppPaused( framework );
378 Dali::Internal::Adaptor::Framework::Impl::NativeAppDestroyed( framework );
383 static int32_t HandleAppInput(struct android_app* app, AInputEvent* event)
385 Framework* framework = AndroidFramework::GetImplementation( AndroidFramework::Get() ).GetFramework();
387 if( AInputEvent_getType( event ) == AINPUT_EVENT_TYPE_MOTION )
389 int32_t deviceId = AInputEvent_getDeviceId( event );
390 float x = AMotionEvent_getX( event, 0 );
391 float y = AMotionEvent_getY( event, 0 );
392 TouchPoint::State state = TouchPoint::Down;
393 int32_t action = AMotionEvent_getAction( event );
394 int64_t timeStamp = AMotionEvent_getEventTime( event );
396 switch ( action & AMOTION_EVENT_ACTION_MASK )
398 case AMOTION_EVENT_ACTION_DOWN:
400 case AMOTION_EVENT_ACTION_UP:
401 state = TouchPoint::Up;
403 case AMOTION_EVENT_ACTION_MOVE:
404 state = TouchPoint::Motion;
406 case AMOTION_EVENT_ACTION_CANCEL:
407 state = TouchPoint::Interrupted;
409 case AMOTION_EVENT_ACTION_OUTSIDE:
410 state = TouchPoint::Leave;
414 Dali::TouchPoint point( deviceId, state, x, y );
415 Dali::Internal::Adaptor::Framework::Impl::NativeAppTouchEvent( framework, point, timeStamp );
418 else if ( AInputEvent_getType( event ) == AINPUT_EVENT_TYPE_KEY )
420 int32_t deviceId = AInputEvent_getDeviceId( event );
421 int32_t keyCode = AKeyEvent_getKeyCode( event );
422 int32_t action = AKeyEvent_getAction( event );
423 int64_t timeStamp = AKeyEvent_getEventTime( event );
425 Dali::KeyEvent::State state = Dali::KeyEvent::DOWN;
428 case AKEY_EVENT_ACTION_DOWN:
430 case AKEY_EVENT_ACTION_UP:
431 state = Dali::KeyEvent::UP;
435 std::string keyName = "";
439 keyName = "XF86Back";
444 Dali::KeyEvent keyEvent = Dali::DevelKeyEvent::New( keyName, "", "", keyCode, 0, timeStamp, state, "", "", Device::Class::NONE, Device::Subclass::NONE );
445 Dali::Internal::Adaptor::Framework::Impl::NativeAppKeyEvent( framework, keyEvent );
452 static void HandleAppIdle(struct android_app* app, struct android_poll_source* source) {
453 Framework* framework = AndroidFramework::GetImplementation( AndroidFramework::Get() ).GetFramework();
454 if( framework && framework->mImpl )
456 framework->mImpl->OnIdle();
462 Framework::Framework( Framework::Observer& observer, int *argc, char ***argv, Type type )
463 : mObserver( observer ),
464 mInitialised( false ),
471 mAbortHandler( MakeCallback( this, &Framework::AbortCallback ) ),
474 mImpl = new Impl( this );
477 Framework::~Framework()
488 void Framework::Run()
490 struct android_app* app = AndroidFramework::Get().GetNativeApplication();
491 app->onAppCmd = Framework::Impl::HandleAppCmd;
492 app->onInputEvent = Framework::Impl::HandleAppInput;
494 struct android_poll_source* source;
495 struct android_poll_source idlePollSource;
496 idlePollSource.id = LOOPER_ID_USER;
497 idlePollSource.app = app;
498 idlePollSource.process = Impl::HandleAppIdle;
501 if( pipe( idlePipe ) )
503 DALI_LOG_ERROR( "Failed to open idle pipe\n" );
507 mImpl->mIdleReadPipe = idlePipe[0];
508 mImpl->mIdleWritePipe = idlePipe[1];
509 ALooper_addFd( app->looper,
510 idlePipe[0], LOOPER_ID_USER, ALOOPER_EVENT_INPUT, NULL, &idlePollSource );
514 // Read all pending events.
516 int idleTimeout = -1;
522 idleTimeout = mImpl->GetIdleTimeout();
525 int id = ALooper_pollAll( idleTimeout, NULL, &events, (void**)&source );
527 // Process the error.
528 if( id == ALOOPER_POLL_ERROR )
530 DALI_LOG_ERROR( "ALooper error\n" );
535 // Process the timeout, trigger OnIdle.
536 if( id == ALOOPER_POLL_TIMEOUT )
539 write( mImpl->mIdleWritePipe, &msg, sizeof( msg ) );
542 // Process the application event.
543 if( id >= 0 && source != NULL )
545 source->process( app, source );
548 // Check if we are exiting.
549 if( app->destroyRequested )
555 while (!mImpl->mIdleCallbacks.empty())
557 mImpl->mIdleCallbacks.pop();
560 mImpl->mRemovedIdleCallbacks.clear();
563 ALooper_removeFd( app->looper, idlePipe[0] );
566 mImpl->mIdleReadPipe = -1;
567 mImpl->mIdleWritePipe = -1;
569 close( idlePipe[0] );
570 close( idlePipe[1] );
575 unsigned int Framework::AddIdle( int timeout, void* data, bool ( *callback )( void *data ) )
579 return mImpl->AddIdle( timeout, data, callback );
584 void Framework::RemoveIdle( unsigned int id )
588 mImpl->RemoveIdle( id );
592 void Framework::Quit()
594 struct android_app* app = AndroidFramework::Get().GetNativeApplication();
595 if( app && !app->destroyRequested && !mImpl->mFinishRequested )
597 mImpl->mFinishRequested = true;
598 ANativeActivity_finish( app->activity );
602 bool Framework::IsMainLoopRunning()
607 void Framework::AddAbortCallback( CallbackBase* callback )
609 mImpl->mAbortCallBack = callback;
612 std::string Framework::GetBundleName() const
617 void Framework::SetBundleName(const std::string& name)
622 std::string Framework::GetBundleId() const
627 std::string Framework::GetResourcePath()
629 return DALI_DATA_RO_DIR;
632 std::string Framework::GetDataPath()
637 void Framework::SetBundleId(const std::string& id)
642 void Framework::AbortCallback( )
644 // if an abort call back has been installed run it.
645 if( mImpl->mAbortCallBack )
647 CallbackBase::Execute( *mImpl->mAbortCallBack );
655 bool Framework::AppStatusHandler(int type, void* data)
659 case APP_WINDOW_CREATED:
666 mObserver.OnSurfaceCreated( data );
674 mObserver.OnResume();
677 case APP_WINDOW_DESTROYED:
678 mObserver.OnSurfaceDestroyed( data );
685 case APP_LANGUAGE_CHANGE:
686 mObserver.OnLanguageChanged();
690 mObserver.OnTerminate();
691 mInitialised = false;
701 void Framework::InitThreads()
705 std::string Framework::GetLanguage() const
707 return mImpl->GetLanguage();
710 std::string Framework::GetRegion() const
712 return mImpl->GetRegion();
715 } // namespace Adaptor
717 } // namespace Internal