1
0
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:
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 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()

View File

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

View File

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

View File

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

View File

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

View File

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