2 * Copyright (c) 2020 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/devel-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, callback.id );
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 ) , unsigned int existingId = 0 )
204 unsigned int chosenId;
207 chosenId = existingId;
219 mIdleCallbacks.push( IdleCallback( timeout, chosenId, data, callback ) );
221 // To wake up the idle pipe and to trigger OnIdle
223 write( mIdleWritePipe, &msg, sizeof( msg ) );
228 void RemoveIdle( unsigned int id )
232 mRemovedIdleCallbacks.insert( id );
240 if( !mIdleCallbacks.empty() )
242 IdleCallback idleTimeout = mIdleCallbacks.top();
243 timeout = idleTimeout.timestamp - GetCurrentMilliSeconds();
254 CallbackBase* mAbortCallBack;
255 CallbackManager* mCallbackManager;
256 std::string mLanguage;
258 bool mFinishRequested;
262 unsigned int mIdleId;
263 std::priority_queue<IdleCallback> mIdleCallbacks;
264 std::unordered_set<int> mRemovedIdleCallbacks;
269 * Called by the native activity loop when the application APP_CMD_INIT_WINDOW event is processed.
271 static void NativeWindowCreated( Framework* framework, ANativeWindow* window )
275 framework->AppStatusHandler( APP_WINDOW_CREATED, window );
280 * Called by the native activity loop when the application APP_CMD_DESTROY event is processed.
282 static void NativeWindowDestroyed( Framework* framework, ANativeWindow* window )
286 framework->AppStatusHandler( APP_WINDOW_DESTROYED, window );
291 * Called by the native activity loop when the application APP_CMD_INIT_WINDOW event is processed.
293 static void NativeAppPaused( Framework* framework )
297 framework->AppStatusHandler( APP_PAUSE, nullptr );
302 * Called by the native activity loop when the application APP_CMD_TERM_WINDOW event is processed.
304 static void NativeAppResumed( Framework* framework )
308 framework->AppStatusHandler( APP_RESUME, nullptr );
313 * Called by the native activity loop when the application input touch event is processed.
315 static void NativeAppTouchEvent( Framework* framework, Dali::TouchPoint& touchPoint, int64_t timeStamp )
317 Dali::Adaptor::Get().FeedTouchPoint( touchPoint, timeStamp );
321 * Called by the native activity loop when the application input key event is processed.
323 static void NativeAppKeyEvent( Framework* framework, Dali::KeyEvent& keyEvent )
325 Dali::Adaptor::Get().FeedKeyEvent( keyEvent );
329 * Called by the native activity loop when the application APP_CMD_DESTROY event is processed.
331 static void NativeAppDestroyed( Framework* framework )
335 framework->AppStatusHandler( APP_DESTROYED, nullptr );
354 static void HandleAppCmd(struct android_app* app, int32_t cmd)
356 Framework* framework = AndroidFramework::GetImplementation( AndroidFramework::Get() ).GetFramework();
359 case APP_CMD_SAVE_STATE:
369 case APP_CMD_INIT_WINDOW:
370 // The window is being shown, get it ready.
371 AndroidFramework::Get().SetApplicationWindow( app->window );
372 Dali::Internal::Adaptor::Framework::Impl::NativeWindowCreated( framework, app->window );
373 Dali::Internal::Adaptor::Framework::Impl::NativeAppResumed( framework );
375 case APP_CMD_TERM_WINDOW:
376 // The window is being hidden or closed, clean it up.
377 AndroidFramework::Get().SetApplicationWindow( nullptr );
378 Dali::Internal::Adaptor::Framework::Impl::NativeAppPaused( framework );
379 Dali::Internal::Adaptor::Framework::Impl::NativeWindowDestroyed( framework, app->window );
381 case APP_CMD_GAINED_FOCUS:
383 case APP_CMD_LOST_FOCUS:
385 case APP_CMD_DESTROY:
386 Dali::Internal::Adaptor::Framework::Impl::NativeAppPaused( framework );
387 Dali::Internal::Adaptor::Framework::Impl::NativeAppDestroyed( framework );
392 static int32_t HandleAppInput(struct android_app* app, AInputEvent* event)
394 Framework* framework = AndroidFramework::GetImplementation( AndroidFramework::Get() ).GetFramework();
396 if( AInputEvent_getType( event ) == AINPUT_EVENT_TYPE_MOTION )
398 int32_t deviceId = AInputEvent_getDeviceId( event );
399 float x = AMotionEvent_getX( event, 0 );
400 float y = AMotionEvent_getY( event, 0 );
401 Dali::PointState::Type state = Dali::PointState::DOWN;
402 int32_t action = AMotionEvent_getAction( event );
403 int64_t timeStamp = AMotionEvent_getEventTime( event );
405 switch ( action & AMOTION_EVENT_ACTION_MASK )
407 case AMOTION_EVENT_ACTION_DOWN:
409 case AMOTION_EVENT_ACTION_UP:
410 state = Dali::PointState::UP;
412 case AMOTION_EVENT_ACTION_MOVE:
413 state = Dali::PointState::MOTION;
415 case AMOTION_EVENT_ACTION_CANCEL:
416 state = Dali::PointState::INTERRUPTED;
418 case AMOTION_EVENT_ACTION_OUTSIDE:
419 state = Dali::PointState::LEAVE;
423 Dali::TouchPoint point( deviceId, state, x, y );
424 Dali::Internal::Adaptor::Framework::Impl::NativeAppTouchEvent( framework, point, timeStamp );
427 else if ( AInputEvent_getType( event ) == AINPUT_EVENT_TYPE_KEY )
429 int32_t deviceId = AInputEvent_getDeviceId( event );
430 int32_t keyCode = AKeyEvent_getKeyCode( event );
431 int32_t action = AKeyEvent_getAction( event );
432 int64_t timeStamp = AKeyEvent_getEventTime( event );
434 Dali::KeyEvent::State state = Dali::KeyEvent::DOWN;
437 case AKEY_EVENT_ACTION_DOWN:
439 case AKEY_EVENT_ACTION_UP:
440 state = Dali::KeyEvent::UP;
444 std::string keyName = "";
448 keyName = "XF86Back";
453 Dali::KeyEvent keyEvent = Dali::DevelKeyEvent::New( keyName, "", "", keyCode, 0, timeStamp, state, "", "", Device::Class::NONE, Device::Subclass::NONE );
454 Dali::Internal::Adaptor::Framework::Impl::NativeAppKeyEvent( framework, keyEvent );
461 static void HandleAppIdle(struct android_app* app, struct android_poll_source* source) {
462 Framework* framework = AndroidFramework::GetImplementation( AndroidFramework::Get() ).GetFramework();
463 if( framework && framework->mImpl )
465 framework->mImpl->OnIdle();
471 Framework::Framework( Framework::Observer& observer, int *argc, char ***argv, Type type )
472 : mObserver( observer ),
473 mInitialised( false ),
480 mAbortHandler( MakeCallback( this, &Framework::AbortCallback ) ),
483 mImpl = new Impl( this );
486 Framework::~Framework()
497 void Framework::Run()
499 struct android_app* app = AndroidFramework::Get().GetNativeApplication();
500 app->onAppCmd = Framework::Impl::HandleAppCmd;
501 app->onInputEvent = Framework::Impl::HandleAppInput;
503 struct android_poll_source* source;
504 struct android_poll_source idlePollSource;
505 idlePollSource.id = LOOPER_ID_USER;
506 idlePollSource.app = app;
507 idlePollSource.process = Impl::HandleAppIdle;
510 if( pipe( idlePipe ) )
512 DALI_LOG_ERROR( "Failed to open idle pipe\n" );
516 mImpl->mIdleReadPipe = idlePipe[0];
517 mImpl->mIdleWritePipe = idlePipe[1];
518 ALooper_addFd( app->looper,
519 idlePipe[0], LOOPER_ID_USER, ALOOPER_EVENT_INPUT, NULL, &idlePollSource );
523 // Read all pending events.
525 int idleTimeout = -1;
531 idleTimeout = mImpl->GetIdleTimeout();
534 int id = ALooper_pollAll( idleTimeout, NULL, &events, (void**)&source );
536 // Process the error.
537 if( id == ALOOPER_POLL_ERROR )
539 DALI_LOG_ERROR( "ALooper error\n" );
544 // Process the timeout, trigger OnIdle.
545 if( id == ALOOPER_POLL_TIMEOUT )
548 write( mImpl->mIdleWritePipe, &msg, sizeof( msg ) );
551 // Process the application event.
552 if( id >= 0 && source != NULL )
554 source->process( app, source );
557 // Check if we are exiting.
558 if( app->destroyRequested )
564 while (!mImpl->mIdleCallbacks.empty())
566 mImpl->mIdleCallbacks.pop();
569 mImpl->mRemovedIdleCallbacks.clear();
572 ALooper_removeFd( app->looper, idlePipe[0] );
575 mImpl->mIdleReadPipe = -1;
576 mImpl->mIdleWritePipe = -1;
578 close( idlePipe[0] );
579 close( idlePipe[1] );
584 unsigned int Framework::AddIdle( int timeout, void* data, bool ( *callback )( void *data ) )
588 return mImpl->AddIdle( timeout, data, callback );
593 void Framework::RemoveIdle( unsigned int id )
597 mImpl->RemoveIdle( id );
601 void Framework::Quit()
603 struct android_app* app = AndroidFramework::Get().GetNativeApplication();
604 if( app && !app->destroyRequested && !mImpl->mFinishRequested )
606 mImpl->mFinishRequested = true;
607 ANativeActivity_finish( app->activity );
611 bool Framework::IsMainLoopRunning()
616 void Framework::AddAbortCallback( CallbackBase* callback )
618 mImpl->mAbortCallBack = callback;
621 std::string Framework::GetBundleName() const
626 void Framework::SetBundleName(const std::string& name)
631 std::string Framework::GetBundleId() const
636 std::string Framework::GetResourcePath()
638 return DALI_DATA_RO_DIR;
641 std::string Framework::GetDataPath()
646 void Framework::SetBundleId(const std::string& id)
651 void Framework::AbortCallback( )
653 // if an abort call back has been installed run it.
654 if( mImpl->mAbortCallBack )
656 CallbackBase::Execute( *mImpl->mAbortCallBack );
664 bool Framework::AppStatusHandler(int type, void* data)
668 case APP_WINDOW_CREATED:
675 mObserver.OnSurfaceCreated( data );
683 mObserver.OnResume();
686 case APP_WINDOW_DESTROYED:
687 mObserver.OnSurfaceDestroyed( data );
694 case APP_LANGUAGE_CHANGE:
695 mObserver.OnLanguageChanged();
699 mObserver.OnTerminate();
700 mInitialised = false;
710 void Framework::InitThreads()
714 std::string Framework::GetLanguage() const
716 return mImpl->GetLanguage();
719 std::string Framework::GetRegion() const
721 return mImpl->GetRegion();
724 } // namespace Adaptor
726 } // namespace Internal