2 * Copyright (c) 2023 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.
18 #include <dali/internal/adaptor/android/framework-android.h>
21 #include <android_native_app_glue.h>
24 #include <unordered_set>
26 #include <dali/devel-api/events/key-event-devel.h>
27 #include <dali/devel-api/events/touch-point.h>
28 #include <dali/integration-api/adaptor-framework/adaptor.h>
29 #include <dali/integration-api/adaptor-framework/android/android-framework.h>
30 #include <dali/integration-api/debug.h>
31 #include <dali/public-api/actors/actor.h>
32 #include <dali/public-api/actors/layer.h>
33 #include <dali/public-api/events/key-event.h>
36 #include <dali/internal/adaptor/android/android-framework-impl.h>
46 // Copied from x server
47 static unsigned int GetCurrentMilliSeconds(void)
52 static clockid_t clockid;
56 #ifdef CLOCK_MONOTONIC_COARSE
57 if(clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
58 (tp.tv_nsec / 1000) <= 1000 && clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
60 clockid = CLOCK_MONOTONIC_COARSE;
64 if(clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
66 clockid = CLOCK_MONOTONIC;
73 if(clockid != ~0L && clock_gettime(clockid, &tp) == 0)
75 return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
78 gettimeofday(&tv, NULL);
79 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
82 /// Recursively removes constraints from an actor and all it's children.
83 void RemoveAllConstraints(Dali::Actor actor)
87 const auto childCount = actor.GetChildCount();
88 for(auto i = 0u; i < childCount; ++i)
90 Dali::Actor child = actor.GetChildAt(i);
91 RemoveAllConstraints(child);
93 actor.RemoveConstraints();
97 /// Removes constraints from all actors in all windows.
98 void RemoveAllConstraints(const Dali::WindowContainer& windows)
100 for(auto& window : windows)
102 RemoveAllConstraints(window.GetRootLayer());
106 } // Unnamed namespace
109 * Impl to hide android data members
111 struct FrameworkAndroid::Impl
119 bool (*callback)(void* data);
121 IdleCallback(int timeout, int id, void* data, bool (*callback)(void* data))
122 : timestamp(GetCurrentMilliSeconds() + timeout),
132 return callback(data);
135 bool operator<(const IdleCallback& rhs) const
137 return timestamp > rhs.timestamp;
143 Impl(FrameworkAndroid* framework)
144 : mFinishRequested(false),
150 AndroidFramework::GetImplementation(AndroidFramework::Get()).SetFramework(framework);
155 AndroidFramework::GetImplementation(AndroidFramework::Get()).SetFramework(nullptr);
162 read(mIdleReadPipe, &msg, sizeof(msg));
164 unsigned int ts = GetCurrentMilliSeconds();
166 if(!mIdleCallbacks.empty())
168 IdleCallback callback = mIdleCallbacks.top();
169 if(callback.timestamp <= ts)
171 mIdleCallbacks.pop();
173 // Callback wasn't removed
174 if(mRemovedIdleCallbacks.find(callback.id) == mRemovedIdleCallbacks.end())
176 if(callback()) // keep the callback
178 AddIdle(callback.timeout, callback.data, callback.callback, callback.id);
182 // Callback cane be also removed during the callback call
183 auto i = mRemovedIdleCallbacks.find(callback.id);
184 if(i != mRemovedIdleCallbacks.end())
186 mRemovedIdleCallbacks.erase(i);
191 if(mIdleCallbacks.empty())
193 mRemovedIdleCallbacks.clear();
197 unsigned int AddIdle(int timeout, void* data, bool (*callback)(void* data), unsigned int existingId = 0)
199 unsigned int chosenId;
202 chosenId = existingId;
214 mIdleCallbacks.push(IdleCallback(timeout, chosenId, data, callback));
216 // To wake up the idle pipe and to trigger OnIdle
218 write(mIdleWritePipe, &msg, sizeof(msg));
223 void RemoveIdle(unsigned int id)
227 mRemovedIdleCallbacks.insert(id);
235 if(!mIdleCallbacks.empty())
237 IdleCallback idleTimeout = mIdleCallbacks.top();
238 timeout = idleTimeout.timestamp - GetCurrentMilliSeconds();
249 bool mFinishRequested;
253 unsigned int mIdleId;
254 std::priority_queue<IdleCallback> mIdleCallbacks;
255 std::unordered_set<int> mRemovedIdleCallbacks;
260 * Called by the native activity loop when the application APP_CMD_INIT_WINDOW event is processed.
262 static void NativeWindowCreated(FrameworkAndroid* framework, ANativeWindow* window)
266 framework->AppStatusHandler(APP_WINDOW_CREATED, window);
271 * Called by the native activity loop when the application APP_CMD_DESTROY event is processed.
273 static void NativeWindowDestroyed(FrameworkAndroid* framework, ANativeWindow* window)
277 framework->AppStatusHandler(APP_WINDOW_DESTROYED, window);
282 * Called by the native activity loop when the application APP_CMD_INIT_WINDOW event is processed.
284 static void NativeAppPaused(FrameworkAndroid* framework)
288 framework->AppStatusHandler(APP_PAUSE, nullptr);
293 * Called by the native activity loop when the application APP_CMD_TERM_WINDOW event is processed.
295 static void NativeAppResumed(FrameworkAndroid* framework)
299 framework->AppStatusHandler(APP_RESUME, nullptr);
304 * Called by the native activity loop when the application input touch event is processed.
306 static void NativeAppTouchEvent(FrameworkAndroid* framework, Dali::TouchPoint& touchPoint, int64_t timeStamp)
308 Dali::Adaptor::Get().FeedTouchPoint(touchPoint, timeStamp);
312 * Called by the native activity loop when the application input key event is processed.
314 static void NativeAppKeyEvent(FrameworkAndroid* framework, Dali::KeyEvent& keyEvent)
316 Dali::Adaptor::Get().FeedKeyEvent(keyEvent);
320 * Called by the native activity loop when the application APP_CMD_DESTROY event is processed.
322 static void NativeAppDestroyed(FrameworkAndroid* framework)
326 framework->AppStatusHandler(APP_DESTROYED, nullptr);
345 static void HandleAppCmd(struct android_app* app, int32_t cmd)
347 FrameworkAndroid* framework = static_cast<FrameworkAndroid*>(AndroidFramework::GetImplementation(AndroidFramework::Get()).GetFramework());
350 case APP_CMD_SAVE_STATE:
360 case APP_CMD_INIT_WINDOW:
361 // The window is being shown, get it ready.
362 AndroidFramework::Get().SetApplicationWindow(app->window);
363 Dali::Internal::Adaptor::FrameworkAndroid::Impl::NativeWindowCreated(framework, app->window);
364 Dali::Internal::Adaptor::FrameworkAndroid::Impl::NativeAppResumed(framework);
366 case APP_CMD_TERM_WINDOW:
367 // The window is being hidden or closed, clean it up.
368 AndroidFramework::Get().SetApplicationWindow(nullptr);
369 Dali::Internal::Adaptor::FrameworkAndroid::Impl::NativeAppPaused(framework);
370 Dali::Internal::Adaptor::FrameworkAndroid::Impl::NativeWindowDestroyed(framework, app->window);
372 case APP_CMD_GAINED_FOCUS:
374 case APP_CMD_LOST_FOCUS:
376 case APP_CMD_DESTROY:
377 Dali::Internal::Adaptor::FrameworkAndroid::Impl::NativeAppPaused(framework);
378 Dali::Internal::Adaptor::FrameworkAndroid::Impl::NativeAppDestroyed(framework);
383 static int32_t HandleAppInput(struct android_app* app, AInputEvent* event)
385 FrameworkAndroid* framework = static_cast<FrameworkAndroid*>(AndroidFramework::GetImplementation(AndroidFramework::Get()).GetFramework());
387 if(AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION)
389 int32_t deviceId = AInputEvent_getDeviceId(event);
390 float x = AMotionEvent_getX(event, 0);
391 float y = AMotionEvent_getY(event, 0);
392 Dali::PointState::Type state = Dali::PointState::DOWN;
393 int32_t action = AMotionEvent_getAction(event);
394 int64_t timeStamp = AMotionEvent_getEventTime(event);
396 switch(action & AMOTION_EVENT_ACTION_MASK)
398 case AMOTION_EVENT_ACTION_DOWN:
400 case AMOTION_EVENT_ACTION_UP:
401 state = Dali::PointState::UP;
403 case AMOTION_EVENT_ACTION_MOVE:
404 state = Dali::PointState::MOTION;
406 case AMOTION_EVENT_ACTION_CANCEL:
407 state = Dali::PointState::INTERRUPTED;
409 case AMOTION_EVENT_ACTION_OUTSIDE:
410 state = Dali::PointState::LEAVE;
414 Dali::TouchPoint point(deviceId, state, x, y);
415 Dali::Internal::Adaptor::FrameworkAndroid::Impl::NativeAppTouchEvent(framework, point, timeStamp);
418 else if(AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY)
420 int32_t deviceId = AInputEvent_getDeviceId(event);
421 int32_t keyCode = AKeyEvent_getKeyCode(event);
422 int32_t action = AKeyEvent_getAction(event);
423 int64_t timeStamp = AKeyEvent_getEventTime(event);
425 Dali::KeyEvent::State state = Dali::KeyEvent::DOWN;
428 case AKEY_EVENT_ACTION_DOWN:
430 case AKEY_EVENT_ACTION_UP:
431 state = Dali::KeyEvent::UP;
435 std::string keyName = "";
439 keyName = "XF86Back";
444 Dali::KeyEvent keyEvent = Dali::DevelKeyEvent::New(keyName, "", "", keyCode, 0, timeStamp, state, "", "", Device::Class::NONE, Device::Subclass::NONE);
445 Dali::Internal::Adaptor::FrameworkAndroid::Impl::NativeAppKeyEvent(framework, keyEvent);
452 static void HandleAppIdle(struct android_app* app, struct android_poll_source* source)
454 FrameworkAndroid* framework = static_cast<FrameworkAndroid*>(AndroidFramework::GetImplementation(AndroidFramework::Get()).GetFramework());
455 if(framework && framework->mImpl)
457 framework->mImpl->OnIdle();
462 FrameworkAndroid::FrameworkAndroid(Framework::Observer& observer, Framework::TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread)
463 : Framework(observer, taskObserver, argc, argv, type, useUiThread),
467 mImpl = new Impl(this);
470 FrameworkAndroid::~FrameworkAndroid()
481 void FrameworkAndroid::Run()
483 struct android_app* app = AndroidFramework::Get().GetNativeApplication();
484 app->onAppCmd = FrameworkAndroid::Impl::HandleAppCmd;
485 app->onInputEvent = FrameworkAndroid::Impl::HandleAppInput;
487 struct android_poll_source* source;
488 struct android_poll_source idlePollSource;
489 idlePollSource.id = LOOPER_ID_USER;
490 idlePollSource.app = app;
491 idlePollSource.process = Impl::HandleAppIdle;
496 DALI_LOG_ERROR("Failed to open idle pipe\n");
500 mImpl->mIdleReadPipe = idlePipe[0];
501 mImpl->mIdleWritePipe = idlePipe[1];
502 ALooper_addFd(app->looper,
511 // Read all pending events.
513 int idleTimeout = -1;
519 idleTimeout = mImpl->GetIdleTimeout();
522 int id = ALooper_pollAll(idleTimeout, NULL, &events, (void**)&source);
524 // Process the error.
525 if(id == ALOOPER_POLL_ERROR)
527 DALI_LOG_ERROR("ALooper error\n");
532 // Process the timeout, trigger OnIdle.
533 if(id == ALOOPER_POLL_TIMEOUT)
536 write(mImpl->mIdleWritePipe, &msg, sizeof(msg));
539 // Process the application event.
540 if(id >= 0 && source != NULL)
542 source->process(app, source);
545 // Check if we are exiting.
546 if(app->destroyRequested)
552 while(!mImpl->mIdleCallbacks.empty())
554 mImpl->mIdleCallbacks.pop();
557 mImpl->mRemovedIdleCallbacks.clear();
560 ALooper_removeFd(app->looper, idlePipe[0]);
563 mImpl->mIdleReadPipe = -1;
564 mImpl->mIdleWritePipe = -1;
572 unsigned int FrameworkAndroid::AddIdle(int timeout, void* data, bool (*callback)(void* data))
576 return mImpl->AddIdle(timeout, data, callback);
582 void FrameworkAndroid::RemoveIdle(unsigned int id)
586 mImpl->RemoveIdle(id);
590 void FrameworkAndroid::Quit()
592 struct android_app* app = AndroidFramework::Get().GetNativeApplication();
593 if(app && !app->destroyRequested && !mImpl->mFinishRequested)
595 mImpl->mFinishRequested = true;
596 ANativeActivity_finish(app->activity);
600 bool FrameworkAndroid::AppStatusHandler(int type, void* data)
602 Dali::Adaptor* adaptor = nullptr;
605 case APP_WINDOW_CREATED:
613 mObserver.OnSurfaceCreated(data);
625 mObserver.OnResume();
626 adaptor = &Dali::Adaptor::Get();
631 case APP_WINDOW_DESTROYED:
633 mObserver.OnSurfaceDestroyed(data);
639 adaptor = &Dali::Adaptor::Get();
645 case APP_LANGUAGE_CHANGE:
647 mObserver.OnLanguageChanged();
653 adaptor = &Dali::Adaptor::Get();
654 // Need to remove constraints before Terminate is called as the constraint function
655 // can be destroyed before the constraints get a chance to clean up.
656 RemoveAllConstraints(adaptor->GetWindows());
657 mObserver.OnTerminate();
658 mInitialised = false;
671 } // namespace Adaptor
673 } // namespace Internal