[dali_1.4.48] Merge branch 'devel/master'
[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   mRunning( false ),
465   mArgc( argc ),
466   mArgv( argv ),
467   mBundleName( "" ),
468   mBundleId( "" ),
469   mAbortHandler( MakeCallback( this, &Framework::AbortCallback ) ),
470   mImpl( NULL )
471 {
472   mImpl = new Impl( this );
473 }
474
475 Framework::~Framework()
476 {
477   if( mRunning )
478   {
479     Quit();
480   }
481
482   delete mImpl;
483   mImpl = nullptr;
484 }
485
486 void Framework::Run()
487 {
488   struct android_app* app = AndroidFramework::Get().GetNativeApplication();
489   app->onAppCmd = Framework::Impl::HandleAppCmd;
490   app->onInputEvent = Framework::Impl::HandleAppInput;
491
492   struct android_poll_source* source;
493   struct android_poll_source idlePollSource;
494   idlePollSource.id = LOOPER_ID_USER;
495   idlePollSource.app = app;
496   idlePollSource.process = Impl::HandleAppIdle;
497
498   int idlePipe[2];
499   if( pipe( idlePipe ) )
500   {
501     DALI_LOG_ERROR( "Failed to open idle pipe\n" );
502     return;
503   }
504
505   mImpl->mIdleReadPipe = idlePipe[0];
506   mImpl->mIdleWritePipe = idlePipe[1];
507   ALooper_addFd( app->looper,
508       idlePipe[0], LOOPER_ID_USER, ALOOPER_EVENT_INPUT, NULL, &idlePollSource );
509
510   mRunning = true;
511
512   // Read all pending events.
513   int events;
514   int idleTimeout = -1;
515
516   while( true )
517   {
518     if ( mImpl )
519     {
520       idleTimeout = mImpl->GetIdleTimeout();
521     }
522
523     int id = ALooper_pollAll( idleTimeout, NULL, &events, (void**)&source );
524
525     // Process the error.
526     if( id == ALOOPER_POLL_ERROR )
527     {
528        DALI_LOG_ERROR( "ALooper error\n" );
529        Quit();
530        std::abort();
531     }
532
533     // Process the timeout, trigger OnIdle.
534     if( id == ALOOPER_POLL_TIMEOUT )
535     {
536       int8_t msg = 1;
537       write( mImpl->mIdleWritePipe, &msg, sizeof( msg ) );
538     }
539
540     // Process the application event.
541     if( id >= 0 && source != NULL )
542     {
543       source->process( app, source );
544     }
545
546     // Check if we are exiting.
547     if( app->destroyRequested )
548     {
549       break;
550     }
551   }
552
553   ALooper_removeFd( app->looper, idlePipe[0] );
554   if ( mImpl )
555   {
556     mImpl->mIdleReadPipe = -1;
557     mImpl->mIdleWritePipe = -1;
558   }
559   close( idlePipe[0] );
560   close( idlePipe[1] );
561
562   mRunning = false;
563 }
564
565 unsigned int Framework::AddIdle( int timeout, void* data, bool ( *callback )( void *data ) )
566 {
567   if( mImpl )
568   {
569     return mImpl->AddIdle( timeout, data, callback );
570   }
571
572   return -1;
573 }
574 void Framework::RemoveIdle( unsigned int id )
575 {
576   if( mImpl )
577   {
578     mImpl->RemoveIdle( id );
579   }
580 }
581
582 void Framework::Quit()
583 {
584   struct android_app* app = AndroidFramework::Get().GetNativeApplication();
585   if( app && !app->destroyRequested && !mImpl->mFinishRequested )
586   {
587     mImpl->mFinishRequested = true;
588     ANativeActivity_finish( app->activity );
589   }
590 }
591
592 bool Framework::IsMainLoopRunning()
593 {
594   return mRunning;
595 }
596
597 void Framework::AddAbortCallback( CallbackBase* callback )
598 {
599   mImpl->mAbortCallBack = callback;
600 }
601
602 std::string Framework::GetBundleName() const
603 {
604   return mBundleName;
605 }
606
607 void Framework::SetBundleName(const std::string& name)
608 {
609   mBundleName = name;
610 }
611
612 std::string Framework::GetBundleId() const
613 {
614   return mBundleId;
615 }
616
617 std::string Framework::GetResourcePath()
618 {
619   return DALI_DATA_RO_DIR;
620 }
621
622 std::string Framework::GetDataPath()
623 {
624   return "";
625 }
626
627 void Framework::SetBundleId(const std::string& id)
628 {
629   mBundleId = id;
630 }
631
632 void Framework::AbortCallback( )
633 {
634   // if an abort call back has been installed run it.
635   if( mImpl->mAbortCallBack )
636   {
637     CallbackBase::Execute( *mImpl->mAbortCallBack );
638   }
639   else
640   {
641     Quit();
642   }
643 }
644
645 bool Framework::AppStatusHandler(int type, void* data)
646 {
647   switch (type)
648   {
649     case APP_WINDOW_CREATED:
650       if( !mInitialised )
651       {
652         mObserver.OnInit();
653         mInitialised = true;
654       }
655
656       mObserver.OnSurfaceCreated( data );
657       break;
658
659     case APP_RESET:
660       mObserver.OnReset();
661       break;
662
663     case APP_RESUME:
664       mObserver.OnResume();
665       break;
666
667     case APP_WINDOW_DESTROYED:
668       mObserver.OnSurfaceDestroyed( data );
669       break;
670
671     case APP_PAUSE:
672       mObserver.OnPause();
673       break;
674
675     case APP_LANGUAGE_CHANGE:
676       mObserver.OnLanguageChanged();
677       break;
678
679     case APP_DESTROYED:
680       mObserver.OnTerminate();
681       mInitialised = false;
682       break;
683
684     default:
685       break;
686   }
687
688   return true;
689 }
690
691 void Framework::InitThreads()
692 {
693 }
694
695 std::string Framework::GetLanguage() const
696 {
697   return mImpl->GetLanguage();
698 }
699
700 std::string Framework::GetRegion() const
701 {
702   return mImpl->GetRegion();
703 }
704
705 } // namespace Adaptor
706
707 } // namespace Internal
708
709 } // namespace Dali