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