mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-18 12:28:09 +00:00
fix(core): prevent flickering when homescreen does not need to redraw
This commit is contained in:
parent
5d12b943b3
commit
f6f3c7ffcf
@ -1,11 +1,32 @@
|
|||||||
|
import storage.cache
|
||||||
import storage.device
|
import storage.device
|
||||||
from trezor import res, ui
|
from trezor import res, ui
|
||||||
|
|
||||||
|
|
||||||
class HomescreenBase(ui.Layout):
|
class HomescreenBase(ui.Layout):
|
||||||
|
RENDER_INDICATOR: object | None = None
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.label = storage.device.get_label() or "My Trezor"
|
self.label = storage.device.get_label() or "My Trezor"
|
||||||
self.image = storage.device.get_homescreen() or res.load(
|
self.image = storage.device.get_homescreen() or res.load(
|
||||||
"apps/homescreen/res/bg.toif"
|
"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()
|
||||||
|
@ -2,6 +2,7 @@ import utime
|
|||||||
from micropython import const
|
from micropython import const
|
||||||
|
|
||||||
import storage
|
import storage
|
||||||
|
import storage.cache
|
||||||
import storage.device
|
import storage.device
|
||||||
from trezor import config, ui
|
from trezor import config, ui
|
||||||
from trezor.ui.loader import Loader, LoaderNeutral
|
from trezor.ui.loader import Loader, LoaderNeutral
|
||||||
@ -20,6 +21,8 @@ async def homescreen() -> None:
|
|||||||
|
|
||||||
|
|
||||||
class Homescreen(HomescreenBase):
|
class Homescreen(HomescreenBase):
|
||||||
|
RENDER_INDICATOR = storage.cache.HOMESCREEN_ON
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
if not storage.device.is_initialized():
|
if not storage.device.is_initialized():
|
||||||
@ -33,10 +36,7 @@ class Homescreen(HomescreenBase):
|
|||||||
)
|
)
|
||||||
self.touch_ms: int | None = None
|
self.touch_ms: int | None = None
|
||||||
|
|
||||||
def on_render(self) -> None:
|
def do_render(self) -> None:
|
||||||
if not self.repaint:
|
|
||||||
return
|
|
||||||
|
|
||||||
# warning bar on top
|
# warning bar on top
|
||||||
if storage.device.is_initialized() and storage.device.no_backup():
|
if storage.device.is_initialized() and storage.device.no_backup():
|
||||||
ui.header_error("SEEDLESS")
|
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.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)
|
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:
|
def on_touch_start(self, _x: int, _y: int) -> None:
|
||||||
if self.loader.start_ms is not None:
|
if self.loader.start_ms is not None:
|
||||||
self.loader.start()
|
self.loader.start()
|
||||||
@ -65,7 +63,7 @@ class Homescreen(HomescreenBase):
|
|||||||
|
|
||||||
def on_touch_end(self, _x: int, _y: int) -> None:
|
def on_touch_end(self, _x: int, _y: int) -> None:
|
||||||
if self.loader.start_ms is not None:
|
if self.loader.start_ms is not None:
|
||||||
self.repaint = True
|
self.set_repaint(True)
|
||||||
self.loader.stop()
|
self.loader.stop()
|
||||||
self.touch_ms = None
|
self.touch_ms = None
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import storage.cache
|
||||||
from trezor import loop, res, ui, wire
|
from trezor import loop, res, ui, wire
|
||||||
|
|
||||||
from . import HomescreenBase
|
from . import HomescreenBase
|
||||||
@ -22,6 +23,7 @@ async def lockscreen() -> None:
|
|||||||
class Lockscreen(HomescreenBase):
|
class Lockscreen(HomescreenBase):
|
||||||
BACKLIGHT_LEVEL = ui.BACKLIGHT_LOW
|
BACKLIGHT_LEVEL = ui.BACKLIGHT_LOW
|
||||||
RENDER_SLEEP = loop.SLEEP_FOREVER
|
RENDER_SLEEP = loop.SLEEP_FOREVER
|
||||||
|
RENDER_INDICATOR = storage.cache.LOCKSCREEN_ON
|
||||||
|
|
||||||
def __init__(self, bootscreen: bool = False) -> None:
|
def __init__(self, bootscreen: bool = False) -> None:
|
||||||
if bootscreen:
|
if bootscreen:
|
||||||
@ -34,10 +36,7 @@ class Lockscreen(HomescreenBase):
|
|||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def on_render(self) -> None:
|
def do_render(self) -> None:
|
||||||
if not self.repaint:
|
|
||||||
return
|
|
||||||
|
|
||||||
# homescreen with label text on top
|
# homescreen with label text on top
|
||||||
ui.display.text_center(
|
ui.display.text_center(
|
||||||
ui.WIDTH // 2, 35, self.label, ui.BOLD, ui.TITLE_GREY, ui.BG
|
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)
|
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:
|
def on_touch_end(self, _x: int, _y: int) -> None:
|
||||||
raise ui.Result(None)
|
raise ui.Result(None)
|
||||||
|
@ -23,6 +23,17 @@ APP_COMMON_SAFETY_CHECKS_TEMPORARY = 1 | _SESSIONLESS_FLAG
|
|||||||
STORAGE_DEVICE_EXPERIMENTAL_FEATURES = 2 | _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):
|
class InvalidSessionError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -362,8 +362,7 @@ class Layout(Component):
|
|||||||
# way to get the lowest input-to-render latency.
|
# way to get the lowest input-to-render latency.
|
||||||
self.dispatch(RENDER, 0, 0)
|
self.dispatch(RENDER, 0, 0)
|
||||||
|
|
||||||
def handle_rendering(self) -> loop.Task: # type: ignore
|
def _before_render(self) -> None:
|
||||||
"""Task that is rendering the layout in a busy loop."""
|
|
||||||
# Before the first render, we dim the display.
|
# Before the first render, we dim the display.
|
||||||
backlight_fade(style.BACKLIGHT_DIM)
|
backlight_fade(style.BACKLIGHT_DIM)
|
||||||
# Clear the screen of any leftovers, make sure everything is marked for
|
# Clear the screen of any leftovers, make sure everything is marked for
|
||||||
@ -387,6 +386,10 @@ class Layout(Component):
|
|||||||
# the brightness on again.
|
# the brightness on again.
|
||||||
refresh()
|
refresh()
|
||||||
backlight_fade(self.BACKLIGHT_LEVEL)
|
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
|
sleep = self.RENDER_SLEEP
|
||||||
while True:
|
while True:
|
||||||
# Wait for a couple of ms and render the layout again. Because
|
# Wait for a couple of ms and render the layout again. Because
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import utime
|
import utime
|
||||||
|
|
||||||
|
import storage.cache
|
||||||
from trezor import log, loop
|
from trezor import log, loop
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
@ -128,6 +129,8 @@ def close_others() -> None:
|
|||||||
if not task.is_running():
|
if not task.is_running():
|
||||||
task.close()
|
task.close()
|
||||||
|
|
||||||
|
storage.cache.homescreen_shown = None
|
||||||
|
|
||||||
# if tasks were running, closing the last of them will run start_default
|
# if tasks were running, closing the last of them will run start_default
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user