Add handling double slash in Android assets path.
[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   while (!mImpl->mIdleCallbacks.empty())
555   {
556     mImpl->mIdleCallbacks.pop();
557   }
558
559   mImpl->mRemovedIdleCallbacks.clear();
560   mImpl->mIdleId = 0;
561
562   ALooper_removeFd( app->looper, idlePipe[0] );
563   if ( mImpl )
564   {
565     mImpl->mIdleReadPipe = -1;
566     mImpl->mIdleWritePipe = -1;
567   }
568   close( idlePipe[0] );
569   close( idlePipe[1] );
570
571   mRunning = false;
572 }
573
574 unsigned int Framework::AddIdle( int timeout, void* data, bool ( *callback )( void *data ) )
575 {
576   if( mImpl )
577   {
578     return mImpl->AddIdle( timeout, data, callback );
579   }
580
581   return -1;
582 }
583 void Framework::RemoveIdle( unsigned int id )
584 {
585   if( mImpl )
586   {
587     mImpl->RemoveIdle( id );
588   }
589 }
590
591 void Framework::Quit()
592 {
593   struct android_app* app = AndroidFramework::Get().GetNativeApplication();
594   if( app && !app->destroyRequested && !mImpl->mFinishRequested )
595   {
596     mImpl->mFinishRequested = true;
597     ANativeActivity_finish( app->activity );
598   }
599 }
600
601 bool Framework::IsMainLoopRunning()
602 {
603   return mRunning;
604 }
605
606 void Framework::AddAbortCallback( CallbackBase* callback )
607 {
608   mImpl->mAbortCallBack = callback;
609 }
610
611 std::string Framework::GetBundleName() const
612 {
613   return mBundleName;
614 }
615
616 void Framework::SetBundleName(const std::string& name)
617 {
618   mBundleName = name;
619 }
620
621 std::string Framework::GetBundleId() const
622 {
623   return mBundleId;
624 }
625
626 std::string Framework::GetResourcePath()
627 {
628   return DALI_DATA_RO_DIR;
629 }
630
631 std::string Framework::GetDataPath()
632 {
633   return "";
634 }
635
636 void Framework::SetBundleId(const std::string& id)
637 {
638   mBundleId = id;
639 }
640
641 void Framework::AbortCallback( )
642 {
643   // if an abort call back has been installed run it.
644   if( mImpl->mAbortCallBack )
645   {
646     CallbackBase::Execute( *mImpl->mAbortCallBack );
647   }
648   else
649   {
650     Quit();
651   }
652 }
653
654 bool Framework::AppStatusHandler(int type, void* data)
655 {
656   switch (type)
657   {
658     case APP_WINDOW_CREATED:
659       if( !mInitialised )
660       {
661         mObserver.OnInit();
662         mInitialised = true;
663       }
664
665       mObserver.OnSurfaceCreated( data );
666       break;
667
668     case APP_RESET:
669       mObserver.OnReset();
670       break;
671
672     case APP_RESUME:
673       mObserver.OnResume();
674       break;
675
676     case APP_WINDOW_DESTROYED:
677       mObserver.OnSurfaceDestroyed( data );
678       break;
679
680     case APP_PAUSE:
681       mObserver.OnPause();
682       break;
683
684     case APP_LANGUAGE_CHANGE:
685       mObserver.OnLanguageChanged();
686       break;
687
688     case APP_DESTROYED:
689       mObserver.OnTerminate();
690       mInitialised = false;
691       break;
692
693     default:
694       break;
695   }
696
697   return true;
698 }
699
700 void Framework::InitThreads()
701 {
702 }
703
704 std::string Framework::GetLanguage() const
705 {
706   return mImpl->GetLanguage();
707 }
708
709 std::string Framework::GetRegion() const
710 {
711   return mImpl->GetRegion();
712 }
713
714 } // namespace Adaptor
715
716 } // namespace Internal
717
718 } // namespace Dali