1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-18 04:18:10 +00:00

fix(core): prevent flickering when homescreen does not need to redraw

This commit is contained in:
matejcik 2021-04-06 14:31:03 +02:00 committed by matejcik
parent 5d12b943b3
commit f6f3c7ffcf
6 changed files with 48 additions and 15 deletions

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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