From 7d9d84662dc75b4458c8da61df50a3fed568d9c9 Mon Sep 17 00:00:00 2001 From: Malcolm Smith Date: Wed, 19 Oct 2022 13:34:15 +0100 Subject: [PATCH 1/2] Android: make Paths cache __main__ module location during startup --- src/android/toga_android/paths.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/android/toga_android/paths.py b/src/android/toga_android/paths.py index 37ad58d97b..653f0074bc 100644 --- a/src/android/toga_android/paths.py +++ b/src/android/toga_android/paths.py @@ -13,18 +13,13 @@ class Paths: def __context(self): return App.app._impl.native.getApplicationContext() + def __init__(self): + # On Android, __main__ only exists during app startup, so cache its location now. + self._app = Path(sys.modules["__main__"].__file__).parent + @property def app(self): - try: - return Path(sys.modules["__main__"].__file__).parent - except KeyError: - # If we're running in test conditions, - # there is no __main__ module. - return Path.cwd() - except AttributeError: - # If we're running at an interactive prompt, - # the __main__ module isn't file-based. - return Path.cwd() + return self._app @property def data(self): From 70f076f90eff5c48eb0fbc5005e0718c5e3412a4 Mon Sep 17 00:00:00 2001 From: Malcolm Smith Date: Wed, 19 Oct 2022 15:04:39 +0100 Subject: [PATCH 2/2] Android: refresh content layout when container size changes --- .../toga_android/widgets/scrollcontainer.py | 2 +- src/android/toga_android/window.py | 58 ++++++++++--------- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/src/android/toga_android/widgets/scrollcontainer.py b/src/android/toga_android/widgets/scrollcontainer.py index 3175d92737..8200d54ea2 100644 --- a/src/android/toga_android/widgets/scrollcontainer.py +++ b/src/android/toga_android/widgets/scrollcontainer.py @@ -59,7 +59,7 @@ def create(self): self.set_content(self.interface.content) def set_content(self, widget): - widget.viewport = AndroidViewport(self.native) + widget.viewport = AndroidViewport(self.native, self.interface) content_view_params = LinearLayout__LayoutParams( LinearLayout__LayoutParams.MATCH_PARENT, LinearLayout__LayoutParams.MATCH_PARENT diff --git a/src/android/toga_android/window.py b/src/android/toga_android/window.py index 5946f615d8..e1af62f3bf 100644 --- a/src/android/toga_android/window.py +++ b/src/android/toga_android/window.py @@ -2,51 +2,57 @@ from .libs.android.view import ViewTreeObserver__OnGlobalLayoutListener -class AndroidViewport: - # `content_parent` should be the view that will become the parent of the widget passed to - # `Window.set_content`. This ensures that the viewport `width` and `height` attributes - # return the usable area of the app, not including the action bar or status bar. - def __init__(self, content_parent): - self.content_parent = content_parent - self.dpi = content_parent.getContext().getResources().getDisplayMetrics().densityDpi +class AndroidViewport(ViewTreeObserver__OnGlobalLayoutListener): + def __init__(self, native, container): + """ + :param native: A native widget whose size will be tracked. + :param container: An object with a ``content`` attribute, which will have + ``refresh()`` called on it whenever the native widget's size changes. + """ + super().__init__() + self.native = native + self.container = container + self.last_size = (None, None) + native.getViewTreeObserver().addOnGlobalLayoutListener(self) + + self.dpi = native.getContext().getResources().getDisplayMetrics().densityDpi # Toga needs to know how the current DPI compares to the platform default, # which is 160: https://developer.android.com/training/multiscreen/screendensities self.baseline_dpi = 160 self.scale = float(self.dpi) / self.baseline_dpi + def onGlobalLayout(self): + """This listener is run after each native layout pass. If any view's size or + position has changed, the new values will be visible here. + """ + new_size = (self.width, self.height) + if self.last_size != new_size: + self.last_size = new_size + if self.container.content: + self.container.content.refresh() + @property def width(self): - return self.content_parent.getWidth() + return self.native.getWidth() @property def height(self): - return self.content_parent.getHeight() + return self.native.getHeight() -class Window(ViewTreeObserver__OnGlobalLayoutListener): +class Window: def __init__(self, interface, title, position, size): super().__init__() self.interface = interface self.interface._impl = self - self.last_size = (None, None) - # self.set_title(title) def set_app(self, app): self.app = app - content_parent = self.app.native.findViewById(R__id.content).__global__() - self.viewport = AndroidViewport(content_parent) - content_parent.getViewTreeObserver().addOnGlobalLayoutListener(self) - - def onGlobalLayout(self): - """This listener is run after each native layout pass. If any view's size or position has - changed, the new values will be visible here. - """ - new_size = (self.viewport.width, self.viewport.height) - if self.last_size != new_size: - self.last_size = new_size - if self.interface.content: - self.interface.content.refresh() + self.viewport = AndroidViewport( + self.app.native.findViewById(R__id.content).__global__(), + self.interface + ) def clear_content(self): if self.interface.content: @@ -79,7 +85,7 @@ def set_position(self, position): pass def get_size(self): - return self.last_size + return self.viewport.last_size def set_size(self, size): # Does nothing on mobile