1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Support services for Gamnit on Android
16 module gamnit_android
is
19 android_manifest_activity
"""android:theme="@android:style/Theme.NoTitleBar.Fullscreen""""
20 android_manifest_activity """android:configChanges="orientation
|screenSize
|keyboard
|keyboardHidden
""""
26 intrude import android::input_events
29 private import realtime
31 # Print Android lifecycle events to the log?
32 fun print_lifecycle_events: Bool do return true
39 redef fun feed_events do app.poll_looper 0
41 redef fun native_input_key(event) do return accept_event(event)
43 redef fun native_input_motion(event)
45 if not scene_created then return false
47 var ie = new AndroidMotionEvent(event)
48 var handled = accept_event(ie)
50 if not handled then accept_event ie.acting_pointer
56 # Handle OS lifecycle and set current state flag
58 # State between `init_window` and `term_window`
59 private var window_created = false
61 # State between `gained_focus` and `lost_focus`
62 private var focused = false
64 # State between `resume` and `pause`
65 private var resumed = false
67 # Stage after `destroy`
68 private var destroyed = false
72 if print_lifecycle_events then print "+ init_window"
80 if print_lifecycle_events then print "+ term_window"
81 window_created = false
88 if print_lifecycle_events then print "+ resume"
96 if print_lifecycle_events then print "+ pause"
102 redef fun gained_focus
104 if print_lifecycle_events then print "+ gained_focus"
112 if print_lifecycle_events then print "+ lost_focus"
119 if print_lifecycle_events then print "+ destroy"
126 if print_lifecycle_events then print "+ start"
132 if print_lifecycle_events then print "+ stop"
137 redef fun config_changed
139 if print_lifecycle_events then print "+ config_changed"
143 redef fun window_resized
145 if print_lifecycle_events then print "+ window_resized"
149 redef fun content_rect_changed
151 if print_lifecycle_events then print "+ content_rect_changed"
158 # The app is fully visible and focused
159 private var active = false
161 # The scene was set up
162 private var scene_created = false
164 private fun set_active
167 if window_created and resumed and focused and not active then
168 var display = display
169 if display == null then
173 display = self.display
175 # Try to reuse the EGL context
176 var native_window = app.native_app_glue.window
177 assert not native_window.address_is_null
178 var needs_recreate = display.check_egl_context(native_window)
179 if needs_recreate then
182 if display.native_window_is_invalid then
183 print_error "the native window is invalid, skip frame"
187 # The context was lost, reload everything
193 # Update screen dimensions
194 assert display != null
196 app.on_resize display
198 if not scene_created then
200 if debug_gamnit then print "set_active: create"
205 # Next to first launch, reload
206 if debug_gamnit then print "set_active: recreate"
213 private fun set_inactive
219 # Implement gamnit entry points
221 redef fun recreate_gamnit
225 # Reload all textures
226 if debug_gamnit then print "recreate_gamnit: reloading {all_root_textures.length} textures"
227 for texture in all_root_textures do
228 if debug_gamnit then print "recreate_gamnit: loading {texture}"
230 var gamnit_error = texture.error
231 if gamnit_error != null then print_error gamnit_error
237 if debug_gamnit then print "run: start"
238 scene_created = false
240 while not destroyed do
242 if debug_gamnit then print "run: wait"
243 app.poll_looper_pause -1
246 if debug_gamnit then print "run: frame"
248 var native_window = app.native_app_glue.window
249 assert not native_window.address_is_null
251 var display = display
252 assert display != null
254 var needs_recreate = display.check_egl_context(native_window)
255 if needs_recreate then
256 if display.native_window_is_invalid then
257 # This should be rare and may cause more issues, log it
258 print "The native window is invalid, skip frame"
263 # The context was lost, reload everything
273 if debug_gamnit then print "run: exit"
278 redef class GamnitDisplay
280 redef var width = 1080
281 redef var height = 720
283 # Update `width` and `height`
284 private fun update_size
286 var context = app.native_activity
287 self.width = context.window_width
288 self.height = context.window_height
292 redef class NativeActivity
294 private fun window_height: Int in "Java" `{
295 android.view.View view = self.getWindow().getDecorView();
296 return view.getBottom() - view.getTop();
299 private fun window_width: Int in "Java" `{
300 android.view.View view = self.getWindow().getDecorView();
301 return view.getRight() - view.getLeft();
304 private fun orientation: Int in "Java" `{
305 return self.getResources().getConfiguration().orientation;