Merge "Direct Rendering" into devel/master
[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, Framework::TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread)
492 : mObserver(observer),
493   mTaskObserver(taskObserver),
494   mInitialised(false),
495   mPaused(false),
496   mRunning(false),
497   mArgc(argc),
498   mArgv(argv),
499   mBundleName(""),
500   mBundleId(""),
501   mAbortHandler(MakeCallback(this, &Framework::AbortCallback)),
502   mImpl(NULL)
503 {
504   mImpl = new Impl(this);
505 }
506
507 Framework::~Framework()
508 {
509   if(mRunning)
510   {
511     Quit();
512   }
513
514   delete mImpl;
515   mImpl = nullptr;
516 }
517
518 void Framework::Run()
519 {
520   struct android_app* app = AndroidFramework::Get().GetNativeApplication();
521   app->onAppCmd           = Framework::Impl::HandleAppCmd;
522   app->onInputEvent       = Framework::Impl::HandleAppInput;
523
524   struct android_poll_source* source;
525   struct android_poll_source  idlePollSource;
526   idlePollSource.id      = LOOPER_ID_USER;
527   idlePollSource.app     = app;
528   idlePollSource.process = Impl::HandleAppIdle;
529
530   int idlePipe[2];
531   if(pipe(idlePipe))
532   {
533     DALI_LOG_ERROR("Failed to open idle pipe\n");
534     return;
535   }
536
537   mImpl->mIdleReadPipe  = idlePipe[0];
538   mImpl->mIdleWritePipe = idlePipe[1];
539   ALooper_addFd(app->looper,
540                 idlePipe[0],
541                 LOOPER_ID_USER,
542                 ALOOPER_EVENT_INPUT,
543                 NULL,
544                 &idlePollSource);
545
546   mRunning = true;
547
548   // Read all pending events.
549   int events;
550   int idleTimeout = -1;
551
552   while(true)
553   {
554     if(mImpl)
555     {
556       idleTimeout = mImpl->GetIdleTimeout();
557     }
558
559     int id = ALooper_pollAll(idleTimeout, NULL, &events, (void**)&source);
560
561     // Process the error.
562     if(id == ALOOPER_POLL_ERROR)
563     {
564       DALI_LOG_ERROR("ALooper error\n");
565       Quit();
566       std::abort();
567     }
568
569     // Process the timeout, trigger OnIdle.
570     if(id == ALOOPER_POLL_TIMEOUT)
571     {
572       int8_t msg = 1;
573       write(mImpl->mIdleWritePipe, &msg, sizeof(msg));
574     }
575
576     // Process the application event.
577     if(id >= 0 && source != NULL)
578     {
579       source->process(app, source);
580     }
581
582     // Check if we are exiting.
583     if(app->destroyRequested)
584     {
585       break;
586     }
587   }
588
589   while(!mImpl->mIdleCallbacks.empty())
590   {
591     mImpl->mIdleCallbacks.pop();
592   }
593
594   mImpl->mRemovedIdleCallbacks.clear();
595   mImpl->mIdleId = 0;
596
597   ALooper_removeFd(app->looper, idlePipe[0]);
598   if(mImpl)
599   {
600     mImpl->mIdleReadPipe  = -1;
601     mImpl->mIdleWritePipe = -1;
602   }
603   close(idlePipe[0]);
604   close(idlePipe[1]);
605
606   mRunning = false;
607 }
608
609 unsigned int Framework::AddIdle(int timeout, void* data, bool (*callback)(void* data))
610 {
611   if(mImpl)
612   {
613     return mImpl->AddIdle(timeout, data, callback);
614   }
615
616   return 0;
617 }
618 void Framework::RemoveIdle(unsigned int id)
619 {
620   if(mImpl)
621   {
622     mImpl->RemoveIdle(id);
623   }
624 }
625
626 void Framework::Quit()
627 {
628   struct android_app* app = AndroidFramework::Get().GetNativeApplication();
629   if(app && !app->destroyRequested && !mImpl->mFinishRequested)
630   {
631     mImpl->mFinishRequested = true;
632     ANativeActivity_finish(app->activity);
633   }
634 }
635
636 bool Framework::IsMainLoopRunning()
637 {
638   return mRunning;
639 }
640
641 void Framework::AddAbortCallback(CallbackBase* callback)
642 {
643   mImpl->mAbortCallBack = callback;
644 }
645
646 std::string Framework::GetBundleName() const
647 {
648   return mBundleName;
649 }
650
651 void Framework::SetBundleName(const std::string& name)
652 {
653   mBundleName = name;
654 }
655
656 std::string Framework::GetBundleId() const
657 {
658   return mBundleId;
659 }
660
661 std::string Framework::GetResourcePath()
662 {
663   return DALI_DATA_RO_DIR;
664 }
665
666 std::string Framework::GetDataPath()
667 {
668   return "";
669 }
670
671 void Framework::SetBundleId(const std::string& id)
672 {
673   mBundleId = id;
674 }
675
676 void Framework::AbortCallback()
677 {
678   // if an abort call back has been installed run it.
679   if(mImpl->mAbortCallBack)
680   {
681     CallbackBase::Execute(*mImpl->mAbortCallBack);
682   }
683   else
684   {
685     Quit();
686   }
687 }
688
689 bool Framework::AppStatusHandler(int type, void* data)
690 {
691   Dali::Adaptor* adaptor = nullptr;
692   switch(type)
693   {
694     case APP_WINDOW_CREATED:
695     {
696       if(!mInitialised)
697       {
698         mObserver.OnInit();
699         mInitialised = true;
700       }
701
702       mObserver.OnSurfaceCreated(data);
703       break;
704     }
705
706     case APP_RESET:
707     {
708       mObserver.OnReset();
709       break;
710     }
711
712     case APP_RESUME:
713     {
714       mObserver.OnResume();
715       adaptor = &Dali::Adaptor::Get();
716       adaptor->Resume();
717       break;
718     }
719
720     case APP_WINDOW_DESTROYED:
721     {
722       mObserver.OnSurfaceDestroyed(data);
723       break;
724     }
725
726     case APP_PAUSE:
727     {
728       adaptor = &Dali::Adaptor::Get();
729       adaptor->Pause();
730       mObserver.OnPause();
731       break;
732     }
733
734     case APP_LANGUAGE_CHANGE:
735     {
736       mObserver.OnLanguageChanged();
737       break;
738     }
739
740     case APP_DESTROYED:
741     {
742       adaptor = &Dali::Adaptor::Get();
743       // Need to remove constraints before Terminate is called as the constraint function
744       // can be destroyed before the constraints get a chance to clean up.
745       RemoveAllConstraints(adaptor->GetWindows());
746       mObserver.OnTerminate();
747       mInitialised = false;
748       break;
749     }
750
751     default:
752     {
753       break;
754     }
755   }
756
757   return true;
758 }
759
760 void Framework::InitThreads()
761 {
762 }
763
764 std::string Framework::GetLanguage() const
765 {
766   return mImpl->GetLanguage();
767 }
768
769 std::string Framework::GetRegion() const
770 {
771   return mImpl->GetRegion();
772 }
773
774 } // namespace Adaptor
775
776 } // namespace Internal
777
778 } // namespace Dali