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