2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/adaptor/common/framework.h>
22 #include <android_native_app_glue.h>
25 #include <unordered_set>
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>
37 #include <dali/internal/adaptor/android/android-framework-impl.h>
38 #include <dali/internal/system/common/callback-manager.h>
48 // Copied from x server
49 static unsigned int GetCurrentMilliSeconds(void)
54 static clockid_t clockid;
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)
62 clockid = CLOCK_MONOTONIC_COARSE;
66 if(clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
68 clockid = CLOCK_MONOTONIC;
75 if(clockid != ~0L && clock_gettime(clockid, &tp) == 0)
77 return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
80 gettimeofday(&tv, NULL);
81 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
84 /// Recursively removes constraints from an actor and all it's children.
85 void RemoveAllConstraints(Dali::Actor actor)
89 const auto childCount = actor.GetChildCount();
90 for(auto i = 0u; i < childCount; ++i)
92 Dali::Actor child = actor.GetChildAt(i);
93 RemoveAllConstraints(child);
95 actor.RemoveConstraints();
99 /// Removes constraints from all actors in all windows.
100 void RemoveAllConstraints(const Dali::WindowContainer& windows)
102 for(auto& window : windows)
104 RemoveAllConstraints(window.GetRootLayer());
108 } // Unnamed namespace
111 * Impl to hide android data members
113 struct Framework::Impl
121 bool (*callback)(void* data);
123 IdleCallback(int timeout, int id, void* data, bool (*callback)(void* data))
124 : timestamp(GetCurrentMilliSeconds() + timeout),
134 return callback(data);
137 bool operator<(const IdleCallback& rhs) const
139 return timestamp > rhs.timestamp;
145 Impl(Framework* framework)
146 : mAbortCallBack(nullptr),
147 mCallbackManager(CallbackManager::New()),
148 mLanguage("NOT_SUPPORTED"),
149 mRegion("NOT_SUPPORTED"),
150 mFinishRequested(false),
156 AndroidFramework::GetImplementation(AndroidFramework::Get()).SetFramework(framework);
161 AndroidFramework::GetImplementation(AndroidFramework::Get()).SetFramework(nullptr);
163 delete mAbortCallBack;
164 mAbortCallBack = nullptr;
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;
173 std::string GetLanguage() const
178 std::string GetRegion() const
187 read(mIdleReadPipe, &msg, sizeof(msg));
189 unsigned int ts = GetCurrentMilliSeconds();
191 if(!mIdleCallbacks.empty())
193 IdleCallback callback = mIdleCallbacks.top();
194 if(callback.timestamp <= ts)
196 mIdleCallbacks.pop();
198 // Callback wasn't removed
199 if(mRemovedIdleCallbacks.find(callback.id) == mRemovedIdleCallbacks.end())
201 if(callback()) // keep the callback
203 AddIdle(callback.timeout, callback.data, callback.callback, callback.id);
207 // Callback cane be also removed during the callback call
208 auto i = mRemovedIdleCallbacks.find(callback.id);
209 if(i != mRemovedIdleCallbacks.end())
211 mRemovedIdleCallbacks.erase(i);
216 if(mIdleCallbacks.empty())
218 mRemovedIdleCallbacks.clear();
222 unsigned int AddIdle(int timeout, void* data, bool (*callback)(void* data), unsigned int existingId = 0)
224 unsigned int chosenId;
227 chosenId = existingId;
239 mIdleCallbacks.push(IdleCallback(timeout, chosenId, data, callback));
241 // To wake up the idle pipe and to trigger OnIdle
243 write(mIdleWritePipe, &msg, sizeof(msg));
248 void RemoveIdle(unsigned int id)
252 mRemovedIdleCallbacks.insert(id);
260 if(!mIdleCallbacks.empty())
262 IdleCallback idleTimeout = mIdleCallbacks.top();
263 timeout = idleTimeout.timestamp - GetCurrentMilliSeconds();
274 CallbackBase* mAbortCallBack;
275 CallbackManager* mCallbackManager;
276 std::string mLanguage;
278 bool mFinishRequested;
282 unsigned int mIdleId;
283 std::priority_queue<IdleCallback> mIdleCallbacks;
284 std::unordered_set<int> mRemovedIdleCallbacks;
289 * Called by the native activity loop when the application APP_CMD_INIT_WINDOW event is processed.
291 static void NativeWindowCreated(Framework* framework, ANativeWindow* window)
295 framework->AppStatusHandler(APP_WINDOW_CREATED, window);
300 * Called by the native activity loop when the application APP_CMD_DESTROY event is processed.
302 static void NativeWindowDestroyed(Framework* framework, ANativeWindow* window)
306 framework->AppStatusHandler(APP_WINDOW_DESTROYED, window);
311 * Called by the native activity loop when the application APP_CMD_INIT_WINDOW event is processed.
313 static void NativeAppPaused(Framework* framework)
317 framework->AppStatusHandler(APP_PAUSE, nullptr);
322 * Called by the native activity loop when the application APP_CMD_TERM_WINDOW event is processed.
324 static void NativeAppResumed(Framework* framework)
328 framework->AppStatusHandler(APP_RESUME, nullptr);
333 * Called by the native activity loop when the application input touch event is processed.
335 static void NativeAppTouchEvent(Framework* framework, Dali::TouchPoint& touchPoint, int64_t timeStamp)
337 Dali::Adaptor::Get().FeedTouchPoint(touchPoint, timeStamp);
341 * Called by the native activity loop when the application input key event is processed.
343 static void NativeAppKeyEvent(Framework* framework, Dali::KeyEvent& keyEvent)
345 Dali::Adaptor::Get().FeedKeyEvent(keyEvent);
349 * Called by the native activity loop when the application APP_CMD_DESTROY event is processed.
351 static void NativeAppDestroyed(Framework* framework)
355 framework->AppStatusHandler(APP_DESTROYED, nullptr);
374 static void HandleAppCmd(struct android_app* app, int32_t cmd)
376 Framework* framework = AndroidFramework::GetImplementation(AndroidFramework::Get()).GetFramework();
379 case APP_CMD_SAVE_STATE:
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);
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);
401 case APP_CMD_GAINED_FOCUS:
403 case APP_CMD_LOST_FOCUS:
405 case APP_CMD_DESTROY:
406 Dali::Internal::Adaptor::Framework::Impl::NativeAppPaused(framework);
407 Dali::Internal::Adaptor::Framework::Impl::NativeAppDestroyed(framework);
412 static int32_t HandleAppInput(struct android_app* app, AInputEvent* event)
414 Framework* framework = AndroidFramework::GetImplementation(AndroidFramework::Get()).GetFramework();
416 if(AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION)
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);
425 switch(action & AMOTION_EVENT_ACTION_MASK)
427 case AMOTION_EVENT_ACTION_DOWN:
429 case AMOTION_EVENT_ACTION_UP:
430 state = Dali::PointState::UP;
432 case AMOTION_EVENT_ACTION_MOVE:
433 state = Dali::PointState::MOTION;
435 case AMOTION_EVENT_ACTION_CANCEL:
436 state = Dali::PointState::INTERRUPTED;
438 case AMOTION_EVENT_ACTION_OUTSIDE:
439 state = Dali::PointState::LEAVE;
443 Dali::TouchPoint point(deviceId, state, x, y);
444 Dali::Internal::Adaptor::Framework::Impl::NativeAppTouchEvent(framework, point, timeStamp);
447 else if(AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY)
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);
454 Dali::KeyEvent::State state = Dali::KeyEvent::DOWN;
457 case AKEY_EVENT_ACTION_DOWN:
459 case AKEY_EVENT_ACTION_UP:
460 state = Dali::KeyEvent::UP;
464 std::string keyName = "";
468 keyName = "XF86Back";
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);
481 static void HandleAppIdle(struct android_app* app, struct android_poll_source* source)
483 Framework* framework = AndroidFramework::GetImplementation(AndroidFramework::Get()).GetFramework();
484 if(framework && framework->mImpl)
486 framework->mImpl->OnIdle();
491 Framework::Framework(Framework::Observer& observer, int* argc, char*** argv, Type type)
492 : mObserver(observer),
500 mAbortHandler(MakeCallback(this, &Framework::AbortCallback)),
503 mImpl = new Impl(this);
506 Framework::~Framework()
517 void Framework::Run()
519 struct android_app* app = AndroidFramework::Get().GetNativeApplication();
520 app->onAppCmd = Framework::Impl::HandleAppCmd;
521 app->onInputEvent = Framework::Impl::HandleAppInput;
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;
532 DALI_LOG_ERROR("Failed to open idle pipe\n");
536 mImpl->mIdleReadPipe = idlePipe[0];
537 mImpl->mIdleWritePipe = idlePipe[1];
538 ALooper_addFd(app->looper,
547 // Read all pending events.
549 int idleTimeout = -1;
555 idleTimeout = mImpl->GetIdleTimeout();
558 int id = ALooper_pollAll(idleTimeout, NULL, &events, (void**)&source);
560 // Process the error.
561 if(id == ALOOPER_POLL_ERROR)
563 DALI_LOG_ERROR("ALooper error\n");
568 // Process the timeout, trigger OnIdle.
569 if(id == ALOOPER_POLL_TIMEOUT)
572 write(mImpl->mIdleWritePipe, &msg, sizeof(msg));
575 // Process the application event.
576 if(id >= 0 && source != NULL)
578 source->process(app, source);
581 // Check if we are exiting.
582 if(app->destroyRequested)
588 while(!mImpl->mIdleCallbacks.empty())
590 mImpl->mIdleCallbacks.pop();
593 mImpl->mRemovedIdleCallbacks.clear();
596 ALooper_removeFd(app->looper, idlePipe[0]);
599 mImpl->mIdleReadPipe = -1;
600 mImpl->mIdleWritePipe = -1;
608 unsigned int Framework::AddIdle(int timeout, void* data, bool (*callback)(void* data))
612 return mImpl->AddIdle(timeout, data, callback);
617 void Framework::RemoveIdle(unsigned int id)
621 mImpl->RemoveIdle(id);
625 void Framework::Quit()
627 struct android_app* app = AndroidFramework::Get().GetNativeApplication();
628 if(app && !app->destroyRequested && !mImpl->mFinishRequested)
630 mImpl->mFinishRequested = true;
631 ANativeActivity_finish(app->activity);
635 bool Framework::IsMainLoopRunning()
640 void Framework::AddAbortCallback(CallbackBase* callback)
642 mImpl->mAbortCallBack = callback;
645 std::string Framework::GetBundleName() const
650 void Framework::SetBundleName(const std::string& name)
655 std::string Framework::GetBundleId() const
660 std::string Framework::GetResourcePath()
662 return DALI_DATA_RO_DIR;
665 std::string Framework::GetDataPath()
670 void Framework::SetBundleId(const std::string& id)
675 void Framework::AbortCallback()
677 // if an abort call back has been installed run it.
678 if(mImpl->mAbortCallBack)
680 CallbackBase::Execute(*mImpl->mAbortCallBack);
688 bool Framework::AppStatusHandler(int type, void* data)
690 Dali::Adaptor* adaptor = nullptr;
693 case APP_WINDOW_CREATED:
701 mObserver.OnSurfaceCreated(data);
713 mObserver.OnResume();
714 adaptor = &Dali::Adaptor::Get();
719 case APP_WINDOW_DESTROYED:
721 mObserver.OnSurfaceDestroyed(data);
727 adaptor = &Dali::Adaptor::Get();
733 case APP_LANGUAGE_CHANGE:
735 mObserver.OnLanguageChanged();
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;
759 void Framework::InitThreads()
763 std::string Framework::GetLanguage() const
765 return mImpl->GetLanguage();
768 std::string Framework::GetRegion() const
770 return mImpl->GetRegion();
773 } // namespace Adaptor
775 } // namespace Internal