From f6f3c7ffcf43f922c8cb367ce16e0ce852050aa3 Mon Sep 17 00:00:00 2001 From: matejcik Date: Tue, 6 Apr 2021 14:31:03 +0200 Subject: [PATCH] fix(core): prevent flickering when homescreen does not need to redraw --- core/src/apps/homescreen/__init__.py | 21 +++++++++++++++++++++ core/src/apps/homescreen/homescreen.py | 12 +++++------- core/src/apps/homescreen/lockscreen.py | 9 +++------ core/src/storage/cache.py | 11 +++++++++++ core/src/trezor/ui/__init__.py | 7 +++++-- core/src/trezor/workflow.py | 3 +++ 6 files changed, 48 insertions(+), 15 deletions(-) diff --git a/core/src/apps/homescreen/__init__.py b/core/src/apps/homescreen/__init__.py index bc9447b9aa..0ad7f289ea 100644 --- a/core/src/apps/homescreen/__init__.py +++ b/core/src/apps/homescreen/__init__.py @@ -1,11 +1,32 @@ +import storage.cache import storage.device from trezor import res, ui class HomescreenBase(ui.Layout): + RENDER_INDICATOR: object | None = None + def __init__(self) -> None: super().__init__() self.label = storage.device.get_label() or "My Trezor" self.image = storage.device.get_homescreen() or res.load( "apps/homescreen/res/bg.toif" ) + self.repaint = storage.cache.homescreen_shown is not self.RENDER_INDICATOR + + def on_render(self) -> None: + if not self.repaint: + return + self.do_render() + self.set_repaint(False) + + def do_render(self) -> None: + raise NotImplementedError + + def set_repaint(self, value: bool) -> None: + self.repaint = value + storage.cache.homescreen_shown = None if value else self.RENDER_INDICATOR + + def _before_render(self) -> None: + if storage.cache.homescreen_shown is not self.RENDER_INDICATOR: + return super()._before_render() diff --git a/core/src/apps/homescreen/homescreen.py b/core/src/apps/homescreen/homescreen.py index 928c351501..6dbbaab41e 100644 --- a/core/src/apps/homescreen/homescreen.py +++ b/core/src/apps/homescreen/homescreen.py @@ -2,6 +2,7 @@ import utime from micropython import const import storage +import storage.cache import storage.device from trezor import config, ui from trezor.ui.loader import Loader, LoaderNeutral @@ -20,6 +21,8 @@ async def homescreen() -> None: class Homescreen(HomescreenBase): + RENDER_INDICATOR = storage.cache.HOMESCREEN_ON + def __init__(self) -> None: super().__init__() if not storage.device.is_initialized(): @@ -33,10 +36,7 @@ class Homescreen(HomescreenBase): ) self.touch_ms: int | None = None - def on_render(self) -> None: - if not self.repaint: - return - + def do_render(self) -> None: # warning bar on top if storage.device.is_initialized() and storage.device.no_backup(): ui.header_error("SEEDLESS") @@ -55,8 +55,6 @@ class Homescreen(HomescreenBase): ui.display.avatar(48, 48 - 10, self.image, ui.WHITE, ui.BLACK) ui.display.text_center(ui.WIDTH // 2, 220, self.label, ui.BOLD, ui.FG, ui.BG) - self.repaint = False - def on_touch_start(self, _x: int, _y: int) -> None: if self.loader.start_ms is not None: self.loader.start() @@ -65,7 +63,7 @@ class Homescreen(HomescreenBase): def on_touch_end(self, _x: int, _y: int) -> None: if self.loader.start_ms is not None: - self.repaint = True + self.set_repaint(True) self.loader.stop() self.touch_ms = None diff --git a/core/src/apps/homescreen/lockscreen.py b/core/src/apps/homescreen/lockscreen.py index 4f520d9795..a2b51647e4 100644 --- a/core/src/apps/homescreen/lockscreen.py +++ b/core/src/apps/homescreen/lockscreen.py @@ -1,3 +1,4 @@ +import storage.cache from trezor import loop, res, ui, wire from . import HomescreenBase @@ -22,6 +23,7 @@ async def lockscreen() -> None: class Lockscreen(HomescreenBase): BACKLIGHT_LEVEL = ui.BACKLIGHT_LOW RENDER_SLEEP = loop.SLEEP_FOREVER + RENDER_INDICATOR = storage.cache.LOCKSCREEN_ON def __init__(self, bootscreen: bool = False) -> None: if bootscreen: @@ -34,10 +36,7 @@ class Lockscreen(HomescreenBase): super().__init__() - def on_render(self) -> None: - if not self.repaint: - return - + def do_render(self) -> None: # homescreen with label text on top ui.display.text_center( ui.WIDTH // 2, 35, self.label, ui.BOLD, ui.TITLE_GREY, ui.BG @@ -57,7 +56,5 @@ class Lockscreen(HomescreenBase): ) ui.display.icon(45, 202, res.load(ui.ICON_CLICK), ui.TITLE_GREY, ui.BG) - self.repaint = False - def on_touch_end(self, _x: int, _y: int) -> None: raise ui.Result(None) diff --git a/core/src/storage/cache.py b/core/src/storage/cache.py index bc8b1bb032..b0827f1c55 100644 --- a/core/src/storage/cache.py +++ b/core/src/storage/cache.py @@ -23,6 +23,17 @@ APP_COMMON_SAFETY_CHECKS_TEMPORARY = 1 | _SESSIONLESS_FLAG STORAGE_DEVICE_EXPERIMENTAL_FEATURES = 2 | _SESSIONLESS_FLAG +# === Homescreen storage === +# This does not logically belong to the "cache" functionality, but the cache module is +# a convenient place to put this. +# When a Homescreen layout is instantiated, it checks the value of `homescreen_shown` +# to know whether it should render itself or whether the result of a previous instance +# is still on. This way we can avoid unnecessary fadeins/fadeouts when a workflow ends. +HOMESCREEN_ON = object() +LOCKSCREEN_ON = object() +homescreen_shown: object | None = None + + class InvalidSessionError(Exception): pass diff --git a/core/src/trezor/ui/__init__.py b/core/src/trezor/ui/__init__.py index b1408c9087..997be3c9e4 100644 --- a/core/src/trezor/ui/__init__.py +++ b/core/src/trezor/ui/__init__.py @@ -362,8 +362,7 @@ class Layout(Component): # way to get the lowest input-to-render latency. self.dispatch(RENDER, 0, 0) - def handle_rendering(self) -> loop.Task: # type: ignore - """Task that is rendering the layout in a busy loop.""" + def _before_render(self) -> None: # Before the first render, we dim the display. backlight_fade(style.BACKLIGHT_DIM) # Clear the screen of any leftovers, make sure everything is marked for @@ -387,6 +386,10 @@ class Layout(Component): # the brightness on again. refresh() backlight_fade(self.BACKLIGHT_LEVEL) + + def handle_rendering(self) -> loop.Task: # type: ignore + """Task that is rendering the layout in a busy loop.""" + self._before_render() sleep = self.RENDER_SLEEP while True: # Wait for a couple of ms and render the layout again. Because diff --git a/core/src/trezor/workflow.py b/core/src/trezor/workflow.py index 7e7b67a4c5..df6ae408e5 100644 --- a/core/src/trezor/workflow.py +++ b/core/src/trezor/workflow.py @@ -1,5 +1,6 @@ import utime +import storage.cache from trezor import log, loop if False: @@ -128,6 +129,8 @@ def close_others() -> None: if not task.is_running(): task.close() + storage.cache.homescreen_shown = None + # if tasks were running, closing the last of them will run start_default