b129bcd39570538438185372b442bfeb4d763f98
[platform/core/uifw/dali-adaptor.git] / dali / internal / adaptor / android / framework-android.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/adaptor/common/framework.h>
20
21 // EXTERNAL INCLUDES
22 #include <unistd.h>
23 #include <queue>
24 #include <unordered_set>
25 #include <android_native_app_glue.h>
26
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>
33
34 // INTERNAL INCLUDES
35 #include <dali/internal/system/common/callback-manager.h>
36 #include <dali/internal/adaptor/android/android-framework-impl.h>
37
38 namespace Dali
39 {
40
41 namespace Internal
42 {
43
44 namespace Adaptor
45 {
46
47 namespace
48 {
49
50 // Copied from x server
51 static unsigned int GetCurrentMilliSeconds(void)
52 {
53   struct timeval tv;
54
55   struct timespec tp;
56   static clockid_t clockid;
57
58   if (!clockid)
59   {
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)
63     {
64       clockid = CLOCK_MONOTONIC_COARSE;
65     }
66     else
67 #endif
68     if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
69     {
70       clockid = CLOCK_MONOTONIC;
71     }
72     else
73     {
74       clockid = ~0L;
75     }
76   }
77   if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
78   {
79     return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
80   }
81
82   gettimeofday(&tv, NULL);
83   return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
84 }
85
86 } // Unnamed namespace
87
88 /**
89  * Impl to hide android data members
90  */
91 struct Framework::Impl
92 {
93
94   struct IdleCallback
95   {
96     int timestamp;
97     int timeout;
98     int id;
99     void* data;
100     bool ( *callback )( void *data );
101
102     IdleCallback( int timeout, int id, void* data, bool ( *callback )( void *data ) )
103     : timestamp( GetCurrentMilliSeconds() + timeout ),
104       timeout( timeout ),
105       id ( id ),
106       data( data ),
107       callback( callback )
108     {
109     }
110
111     bool operator()()
112     {
113       return callback( data );
114     }
115
116     bool operator<( const IdleCallback& rhs ) const
117     {
118       return timestamp > rhs.timestamp;
119     }
120   };
121
122   // Constructor
123
124   Impl( Framework* framework )
125   : mAbortCallBack( nullptr ),
126     mCallbackManager( CallbackManager::New() ),
127     mLanguage( "NOT_SUPPORTED" ),
128     mRegion( "NOT_SUPPORTED" ),
129     mFinishRequested( false ),
130     mIdleId( 0 ),
131     mIdleReadPipe( -1 ),
132     mIdleWritePipe( -1 )
133
134
135   {
136     AndroidFramework::GetImplementation( AndroidFramework::Get() ).SetFramework( framework );
137   }
138
139   ~Impl()
140   {
141     AndroidFramework::GetImplementation( AndroidFramework::Get() ).SetFramework( nullptr );
142
143     delete mAbortCallBack;
144     mAbortCallBack = nullptr;
145
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;
151   }
152
153   std::string GetLanguage() const
154   {
155     return mLanguage;
156   }
157
158   std::string GetRegion() const
159   {
160     return mRegion;
161   }
162
163   void OnIdle()
164   {
165     // Dequeue the pipe
166     int8_t msg = -1;
167     read( mIdleReadPipe, &msg, sizeof( msg ) );
168
169     unsigned int ts = GetCurrentMilliSeconds();
170
171     if ( !mIdleCallbacks.empty() )
172     {
173       IdleCallback callback = mIdleCallbacks.top();
174       if( callback.timestamp <= ts )
175       {
176         mIdleCallbacks.pop();
177
178         // Callback wasn't removed
179         if( mRemovedIdleCallbacks.find( callback.id ) == mRemovedIdleCallbacks.end() )
180         {
181           if ( callback() ) // keep the callback
182           {
183             AddIdle( callback.timeout, callback.data, callback.callback );
184           }
185         }
186
187         // Callback cane be also removed during the callback call
188         auto i = mRemovedIdleCallbacks.find( callback.id );
189         if( i != mRemovedIdleCallbacks.end() )
190         {
191           mRemovedIdleCallbacks.erase( i );
192         }
193       }
194     }
195
196     if( mIdleCallbacks.empty() )
197     {
198       mRemovedIdleCallbacks.clear();
199     }
200   }
201
202   unsigned int AddIdle( int timeout, void* data, bool ( *callback )( void *data ) )
203   {
204     ++mIdleId;
205     if( mIdleId == 0 )
206     {
207       ++mIdleId;
208     }
209
210     mIdleCallbacks.push( IdleCallback( timeout, mIdleId, data, callback ) );
211
212     // To wake up the idle pipe and to trigger OnIdle
213     int8_t msg = 1;
214     write( mIdleWritePipe, &msg, sizeof( msg ) );
215
216     return mIdleId;
217   }
218
219   void RemoveIdle( unsigned int id )
220   {
221     if( id != 0 )
222     {
223       mRemovedIdleCallbacks.insert( id );
224     }
225   }
226
227   int GetIdleTimeout()
228   {
229     int timeout = -1;
230
231     if( !mIdleCallbacks.empty() )
232     {
233       IdleCallback idleTimeout = mIdleCallbacks.top();
234       timeout = idleTimeout.timestamp - GetCurrentMilliSeconds();
235       if( timeout < 0 )
236       {
237          timeout = 0;
238       }
239     }
240
241     return timeout;
242   }
243
244   // Data
245   CallbackBase* mAbortCallBack;
246   CallbackManager* mCallbackManager;
247   std::string mLanguage;
248   std::string mRegion;
249   bool mFinishRequested;
250
251   int mIdleReadPipe;
252   int mIdleWritePipe;
253   unsigned int mIdleId;
254   std::priority_queue<IdleCallback> mIdleCallbacks;
255   std::unordered_set<int> mRemovedIdleCallbacks;
256
257   // Static methods
258
259   /**
260    * Called by the native activity loop when the application APP_CMD_INIT_WINDOW event is processed.
261    */
262   static void NativeWindowCreated( Framework* framework, ANativeWindow* window )
263   {
264     if( framework )
265     {
266       framework->AppStatusHandler( APP_WINDOW_CREATED, window );
267     }
268   }
269
270   /**
271    * Called by the native activity loop when the application APP_CMD_DESTROY event is processed.
272    */
273   static void NativeWindowDestroyed( Framework* framework, ANativeWindow* window )
274   {
275     if( framework )
276     {
277       framework->AppStatusHandler( APP_WINDOW_DESTROYED, window );
278     }
279   }
280
281   /**
282    * Called by the native activity loop when the application APP_CMD_INIT_WINDOW event is processed.
283    */
284   static void NativeAppPaused( Framework* framework )
285   {
286     if( framework )
287     {
288       framework->AppStatusHandler( APP_PAUSE, nullptr );
289     }
290   }
291
292   /**
293    * Called by the native activity loop when the application APP_CMD_TERM_WINDOW event is processed.
294    */
295   static void NativeAppResumed( Framework* framework )
296   {
297     if( framework )
298     {
299       framework->AppStatusHandler( APP_RESUME, nullptr );
300     }
301   }
302
303   /**
304    * Called by the native activity loop when the application input touch event is processed.
305    */
306   static void NativeAppTouchEvent( Framework* framework, Dali::TouchPoint& touchPoint, int64_t timeStamp )
307   {
308     Dali::Adaptor::Get().FeedTouchPoint( touchPoint, timeStamp );
309   }
310
311   /**
312    * Called by the native activity loop when the application input key event is processed.
313    */
314   static void NativeAppKeyEvent( Framework* framework, Dali::KeyEvent& keyEvent )
315   {
316     Dali::Adaptor::Get().FeedKeyEvent( keyEvent );
317   }
318
319   /**
320    * Called by the native activity loop when the application APP_CMD_DESTROY event is processed.
321    */
322   static void NativeAppDestroyed( Framework* framework )
323   {
324     if( framework )
325     {
326       framework->AppStatusHandler( APP_DESTROYED, nullptr );
327     }
328   }
329
330 /*
331   Order of events:
332
333   APP_CMD_START
334   APP_CMD_RESUME
335   APP_CMD_INIT_WINDOW
336   APP_CMD_GAINED_FOCUS
337
338   APP_CMD_PAUSE
339   APP_CMD_LOST_FOCUS
340   APP_CMD_SAVE_STATE
341   APP_CMD_STOP
342   APP_CMD_TERM_WINDOW
343 */
344
345   static void HandleAppCmd(struct android_app* app, int32_t cmd)
346   {
347     Framework* framework = AndroidFramework::GetImplementation( AndroidFramework::Get() ).GetFramework();
348     switch( cmd )
349     {
350       case APP_CMD_SAVE_STATE:
351         break;
352       case APP_CMD_START:
353         break;
354       case APP_CMD_STOP:
355         break;
356       case APP_CMD_RESUME:
357         break;
358       case APP_CMD_PAUSE:
359         break;
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 );
365         break;
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 );
371         break;
372       case APP_CMD_GAINED_FOCUS:
373         break;
374       case APP_CMD_LOST_FOCUS:
375         break;
376       case APP_CMD_DESTROY:
377         Dali::Internal::Adaptor::Framework::Impl::NativeAppPaused( framework );
378         Dali::Internal::Adaptor::Framework::Impl::NativeAppDestroyed( framework );
379         break;
380     }
381   }
382
383   static int32_t HandleAppInput(struct android_app* app, AInputEvent* event)
384   {
385     Framework* framework = AndroidFramework::GetImplementation( AndroidFramework::Get() ).GetFramework();
386
387     if( AInputEvent_getType( event ) == AINPUT_EVENT_TYPE_MOTION )
388     {
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 );
395
396       switch ( action & AMOTION_EVENT_ACTION_MASK )
397       {
398       case AMOTION_EVENT_ACTION_DOWN:
399         break;
400       case AMOTION_EVENT_ACTION_UP:
401         state = TouchPoint::Up;
402         break;
403       case AMOTION_EVENT_ACTION_MOVE:
404         state = TouchPoint::Motion;
405         break;
406       case AMOTION_EVENT_ACTION_CANCEL:
407         state = TouchPoint::Interrupted;
408         break;
409       case AMOTION_EVENT_ACTION_OUTSIDE:
410         state = TouchPoint::Leave;
411         break;
412       }
413
414       Dali::TouchPoint point( deviceId, state, x, y );
415       Dali::Internal::Adaptor::Framework::Impl::NativeAppTouchEvent( framework, point, timeStamp );
416       return 1;
417     }
418     else if ( AInputEvent_getType( event ) == AINPUT_EVENT_TYPE_KEY )
419     {
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 );
424
425       Dali::KeyEvent::State state = Dali::KeyEvent::Down;
426       switch ( action )
427       {
428       case AKEY_EVENT_ACTION_DOWN:
429         break;
430       case AKEY_EVENT_ACTION_UP:
431         state = Dali::KeyEvent::Up;
432         break;
433       }
434
435       std::string keyName = "";
436       switch( keyCode )
437       {
438       case 4:
439         keyName = "XF86Back";
440         break;
441       default:
442         break;
443       }
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 );
446       return 1;
447     }
448
449     return 0;
450   }
451
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 )
455     {
456       framework->mImpl->OnIdle();
457     }
458   }
459
460 };
461
462 Framework::Framework( Framework::Observer& observer, int *argc, char ***argv, Type type )
463 : mObserver( observer ),
464   mInitialised( false ),
465   mPaused(false),
466   mRunning( false ),
467   mArgc( argc ),
468   mArgv( argv ),
469   mBundleName( "" ),
470   mBundleId( "" ),
471   mAbortHandler( MakeCallback( this, &Framework::AbortCallback ) ),
472   mImpl( NULL )
473 {
474   mImpl = new Impl( this );
475 }
476
477 Framework::~Framework()
478 {
479   if( mRunning )
480   {
481     Quit();
482   }
483
484   delete mImpl;
485   mImpl = nullptr;
486 }
487
488 void Framework::Run()
489 {
490   struct android_app* app = AndroidFramework::Get().GetNativeApplication();
491   app->onAppCmd = Framework::Impl::HandleAppCmd;
492   app->onInputEvent = Framework::Impl::HandleAppInput;
493
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;
499
500   int idlePipe[2];
501   if( pipe( idlePipe ) )
502   {
503     DALI_LOG_ERROR( "Failed to open idle pipe\n" );
504     return;
505   }
506
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 );
511
512   mRunning = true;
513
514   // Read all pending events.
515   int events;
516   int idleTimeout = -1;
517
518   while( true )
519   {
520     if ( mImpl )
521     {
522       idleTimeout = mImpl->GetIdleTimeout();
523     }
524
525     int id = ALooper_pollAll( idleTimeout, NULL, &events, (void**)&source );
526
527     // Process the error.
528     if( id == ALOOPER_POLL_ERROR )
529     {
530        DALI_LOG_ERROR( "ALooper error\n" );
531        Quit();
532        std::abort();
533     }
534
535     // Process the timeout, trigger OnIdle.
536     if( id == ALOOPER_POLL_TIMEOUT )
537     {
538       int8_t msg = 1;
539       write( mImpl->mIdleWritePipe, &msg, sizeof( msg ) );
540     }
541
542     // Process the application event.
543     if( id >= 0 && source != NULL )
544     {
545       source->process( app, source );
546     }
547
548     // Check if we are exiting.
549     if( app->destroyRequested )
550     {
551       break;
552     }
553   }
554
555   while (!mImpl->mIdleCallbacks.empty())
556   {
557     mImpl->mIdleCallbacks.pop();
558   }
559
560   mImpl->mRemovedIdleCallbacks.clear();
561   mImpl->mIdleId = 0;
562
563   ALooper_removeFd( app->looper, idlePipe[0] );
564   if ( mImpl )
565   {
566     mImpl->mIdleReadPipe = -1;
567     mImpl->mIdleWritePipe = -1;
568   }
569   close( idlePipe[0] );
570   close( idlePipe[1] );
571
572   mRunning = false;
573 }
574
575 unsigned int Framework::AddIdle( int timeout, void* data, bool ( *callback )( void *data ) )
576 {
577   if( mImpl )
578   {
579     return mImpl->AddIdle( timeout, data, callback );
580   }
581
582   return -1;
583 }
584 void Framework::RemoveIdle( unsigned int id )
585 {
586   if( mImpl )
587   {
588     mImpl->RemoveIdle( id );
589   }
590 }
591
592 void Framework::Quit()
593 {
594   struct android_app* app = AndroidFramework::Get().GetNativeApplication();
595   if( app && !app->destroyRequested && !mImpl->mFinishRequested )
596   {
597     mImpl->mFinishRequested = true;
598     ANativeActivity_finish( app->activity );
599   }
600 }
601
602 bool Framework::IsMainLoopRunning()
603 {
604   return mRunning;
605 }
606
607 void Framework::AddAbortCallback( CallbackBase* callback )
608 {
609   mImpl->mAbortCallBack = callback;
610 }
611
612 std::string Framework::GetBundleName() const
613 {
614   return mBundleName;
615 }
616
617 void Framework::SetBundleName(const std::string& name)
618 {
619   mBundleName = name;
620 }
621
622 std::string Framework::GetBundleId() const
623 {
624   return mBundleId;
625 }
626
627 std::string Framework::GetResourcePath()
628 {
629   return DALI_DATA_RO_DIR;
630 }
631
632 std::string Framework::GetDataPath()
633 {
634   return "";
635 }
636
637 void Framework::SetBundleId(const std::string& id)
638 {
639   mBundleId = id;
640 }
641
642 void Framework::AbortCallback( )
643 {
644   // if an abort call back has been installed run it.
645   if( mImpl->mAbortCallBack )
646   {
647     CallbackBase::Execute( *mImpl->mAbortCallBack );
648   }
649   else
650   {
651     Quit();
652   }
653 }
654
655 bool Framework::AppStatusHandler(int type, void* data)
656 {
657   switch (type)
658   {
659     case APP_WINDOW_CREATED:
660       if( !mInitialised )
661       {
662         mObserver.OnInit();
663         mInitialised = true;
664       }
665
666       mObserver.OnSurfaceCreated( data );
667       break;
668
669     case APP_RESET:
670       mObserver.OnReset();
671       break;
672
673     case APP_RESUME:
674       mObserver.OnResume();
675       break;
676
677     case APP_WINDOW_DESTROYED:
678       mObserver.OnSurfaceDestroyed( data );
679       break;
680
681     case APP_PAUSE:
682       mObserver.OnPause();
683       break;
684
685     case APP_LANGUAGE_CHANGE:
686       mObserver.OnLanguageChanged();
687       break;
688
689     case APP_DESTROYED:
690       mObserver.OnTerminate();
691       mInitialised = false;
692       break;
693
694     default:
695       break;
696   }
697
698   return true;
699 }
700
701 void Framework::InitThreads()
702 {
703 }
704
705 std::string Framework::GetLanguage() const
706 {
707   return mImpl->GetLanguage();
708 }
709
710 std::string Framework::GetRegion() const
711 {
712   return mImpl->GetRegion();
713 }
714
715 } // namespace Adaptor
716
717 } // namespace Internal
718
719 } // namespace Dali