1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-04-14 14:27:25 +00:00

feat(core): show welcome screen after device is connected

[no changelog]
This commit is contained in:
grdddj 2023-02-21 12:30:24 +01:00 committed by Jiří Musil
parent 5d987b2bc9
commit acec852aa4
13 changed files with 160 additions and 9 deletions

BIN
core/assets/logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -178,6 +178,7 @@ fn generate_micropython_bindings() {
.allowlist_var("mp_type_dict")
// fun
.allowlist_type("mp_obj_fun_builtin_fixed_t")
.allowlist_var("mp_type_fun_builtin_0")
.allowlist_var("mp_type_fun_builtin_1")
.allowlist_var("mp_type_fun_builtin_2")
.allowlist_var("mp_type_fun_builtin_3")

View File

@ -52,6 +52,7 @@ static void _librust_qstrs(void) {
MP_QSTR_show_group_share_success;
MP_QSTR_show_homescreen;
MP_QSTR_show_lockscreen;
MP_QSTR_draw_welcome_screen;
MP_QSTR_show_remaining_shares;
MP_QSTR_show_share_words;
MP_QSTR_show_progress;

View File

@ -1,3 +1,20 @@
/// Create an object for an exported function taking no arguments.
macro_rules! obj_fn_0 {
($f:expr) => {{
#[allow(unused_unsafe)]
unsafe {
use $crate::micropython::ffi;
ffi::mp_obj_fun_builtin_fixed_t {
base: ffi::mp_obj_base_t {
type_: &ffi::mp_type_fun_builtin_0,
},
fun: ffi::_mp_obj_fun_builtin_fixed_t__bindgen_ty_1 { _0: Some($f) },
}
}
}};
}
/// Create an object for an exported function taking 1 arg.
macro_rules! obj_fn_1 {
($f:expr) => {{

View File

@ -460,7 +460,8 @@ pub enum Alignment {
pub type Alignment2D = (Alignment, Alignment);
pub const TOP_LEFT: Alignment2D = (Alignment::Start, Alignment::Start);
pub const TOP_RIGHT: Alignment2D = (Alignment::Start, Alignment::End);
pub const TOP_RIGHT: Alignment2D = (Alignment::End, Alignment::Start);
pub const TOP_CENTER: Alignment2D = (Alignment::Center, Alignment::Start);
pub const CENTER: Alignment2D = (Alignment::Center, Alignment::Center);
pub const BOTTOM_LEFT: Alignment2D = (Alignment::Start, Alignment::End);
pub const BOTTOM_RIGHT: Alignment2D = (Alignment::End, Alignment::End);

View File

@ -13,6 +13,7 @@ mod page;
mod progress;
mod scroll;
mod swipe;
mod welcome_screen;
pub use button::{
Button, ButtonContent, ButtonMsg, ButtonStyle, ButtonStyleSheet, CancelConfirmMsg,
@ -37,5 +38,6 @@ pub use page::{SwipeHoldPage, SwipePage};
pub use progress::Progress;
pub use scroll::ScrollBar;
pub use swipe::{Swipe, SwipeDirection};
pub use welcome_screen::WelcomeScreen;
use super::theme;

View File

@ -0,0 +1,59 @@
use crate::ui::{
component::{Component, Event, EventCtx, Never},
display::{self, Icon},
geometry::{self, Offset, Rect},
model_tt::theme,
};
const TEXT_BOTTOM_MARGIN: i16 = 24; // matching the homescreen label margin
const ICON_TOP_MARGIN: i16 = 62;
const MODEL_NAME: &str = "Trezor Model T";
const MODEL_NAME_FONT: display::Font = display::Font::DEMIBOLD;
pub struct WelcomeScreen {
area: Rect,
}
impl WelcomeScreen {
pub fn new() -> Self {
Self { area: Rect::zero() }
}
}
impl Component for WelcomeScreen {
type Msg = Never;
fn place(&mut self, bounds: Rect) -> Rect {
self.area = bounds;
self.area
}
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
None
}
fn paint(&mut self) {
display::text_center(
self.area.bottom_center() - Offset::y(TEXT_BOTTOM_MARGIN),
MODEL_NAME,
MODEL_NAME_FONT,
theme::FG,
theme::BG,
);
Icon::new(theme::ICON_LOGO).draw(
self.area.top_center() + Offset::y(ICON_TOP_MARGIN),
geometry::TOP_CENTER,
theme::FG,
theme::BG,
);
}
}
#[cfg(feature = "ui_debug")]
impl crate::trace::Trace for WelcomeScreen {
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.open("WelcomeScreen");
t.string(MODEL_NAME);
t.close();
}
}

View File

@ -30,7 +30,7 @@ use crate::{
},
Border, Component, Empty, FormattedText, Timeout, TimeoutMsg,
},
display::{tjpgd::jpeg_info, toif::Icon},
display::{self, tjpgd::jpeg_info, toif::Icon},
geometry,
layout::{
obj::{ComponentMsgObj, LayoutObj},
@ -51,8 +51,9 @@ use super::{
MnemonicKeyboardMsg, NotificationFrame, NumberInputDialog, NumberInputDialogMsg,
PassphraseKeyboard, PassphraseKeyboardMsg, PinKeyboard, PinKeyboardMsg, Progress,
SelectWordCount, SelectWordCountMsg, SelectWordMsg, Slip39Input, SwipeHoldPage, SwipePage,
WelcomeScreen,
},
theme,
constant, theme,
};
impl TryFrom<CancelConfirmMsg> for Obj {
@ -1343,6 +1344,16 @@ extern "C" fn new_show_busyscreen(n_args: usize, args: *const Obj, kwargs: *mut
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
}
extern "C" fn draw_welcome_screen() -> Obj {
// No need of util::try_or_raise, this does not allocate
let mut screen = WelcomeScreen::new();
screen.place(constant::screen());
display::sync();
screen.paint();
display::set_backlight(150); // BACKLIGHT_NORMAL
Obj::const_none()
}
#[no_mangle]
pub static mp_module_trezorui2: Module = obj_module! {
Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorui2.to_obj(),
@ -1708,6 +1719,10 @@ pub static mp_module_trezorui2: Module = obj_module! {
/// ) -> CANCELLED:
/// """Homescreen used for indicating coinjoin in progress."""
Qstr::MP_QSTR_show_busyscreen => obj_fn_kw!(0, new_show_busyscreen).as_obj(),
/// def draw_welcome_screen() -> None:
/// """Show logo icon with the model name at the bottom and return."""
Qstr::MP_QSTR_draw_welcome_screen => obj_fn_0!(draw_welcome_screen).as_obj(),
};
#[cfg(test)]

Binary file not shown.

View File

@ -63,6 +63,7 @@ pub const ICON_MAGIC: &[u8] = include_res!("model_tt/res/magic.toif");
pub const ICON_LIST_CURRENT: &[u8] = include_res!("model_tt/res/current.toif");
pub const ICON_LIST_CHECK: &[u8] = include_res!("model_tt/res/check.toif");
pub const ICON_LOCK: &[u8] = include_res!("model_tt/res/lock.toif");
pub const ICON_LOGO: &[u8] = include_res!("model_tt/res/logo.toif");
// Large, three-color icons.
pub const WARN_COLOR: Color = YELLOW;

View File

@ -423,3 +423,8 @@ def show_busyscreen(
skip_first_paint: bool,
) -> CANCELLED:
"""Homescreen used for indicating coinjoin in progress."""
# rust/src/ui/model_tt/layout.rs
def draw_welcome_screen() -> None:
"""Show logo icon with the model name at the bottom and return."""

View File

@ -1,21 +1,58 @@
# isort:skip_file
import trezorui2
import utime
# Showing welcome screen as soon as possible
# (display is also prepared on that occasion).
# Remembering time to control how long we show it.
trezorui2.draw_welcome_screen()
welcome_screen_start_ms = utime.ticks_ms()
import storage
import storage.device
from trezor import config, log, loop, ui, utils, wire
from trezor.pin import show_pin_timeout
from trezor.pin import (
allow_all_loader_messages,
ignore_nonpin_loader_messages,
show_pin_timeout,
)
from trezor.ui.layouts.homescreen import Lockscreen
from apps.common.request_pin import can_lock_device, verify_user_pin
_WELCOME_SCREEN_MS = 1500 # how long do we want to show welcome screen (minimum)
def enforce_welcome_screen_duration() -> None:
"""Make sure we will show the welcome screen for appropriate amount of time."""
# Not wasting the time in debug builds (saves time during emulator debugging)
if __debug__:
return
while utime.ticks_ms() - welcome_screen_start_ms < _WELCOME_SCREEN_MS:
utime.sleep_ms(100)
async def bootscreen() -> None:
"""Sequence of actions to be done on boot (after device is connected).
We are starting with welcome_screen on the screen and want to show it
for at least _WELCOME_SCREEN_MS before any other screen.
Any non-PIN loaders are ignored during this function.
Allowing all of them before returning.
"""
lockscreen = Lockscreen(label=storage.device.get_label(), bootscreen=True)
ui.display.orientation(storage.device.get_rotation())
while True:
try:
if can_lock_device():
enforce_welcome_screen_duration()
await lockscreen
await verify_user_pin()
storage.init_unlocked()
enforce_welcome_screen_duration()
allow_all_loader_messages()
return
except wire.PinCancelled:
# verify_user_pin will convert a SdCardUnavailable (in case of sd salt)
@ -29,8 +66,9 @@ async def bootscreen() -> None:
utils.halt(e.__class__.__name__)
ui.display.backlight(ui.BACKLIGHT_NONE)
ui.backlight_fade(ui.BACKLIGHT_NORMAL)
# Ignoring all non-PIN messages in the boot-phase (turned off in `bootscreen()`).
ignore_nonpin_loader_messages()
config.init(show_pin_timeout)
if __debug__ and not utils.EMULATOR:

View File

@ -10,6 +10,18 @@ _progress_layout: ProgressLayout | None = None
_started_with_empty_loader = False
keepalive_callback: Any = None
_ignore_loader_messages: tuple[str, ...] = ()
def ignore_nonpin_loader_messages() -> None:
global _ignore_loader_messages
_ignore_loader_messages = ("Processing", "Starting up")
def allow_all_loader_messages() -> None:
global _ignore_loader_messages
_ignore_loader_messages = ()
def render_empty_loader(message: str, description: str) -> None:
"""Render empty loader to prevent the screen appear to be frozen."""
@ -27,9 +39,8 @@ def render_empty_loader(message: str, description: str) -> None:
def show_pin_timeout(seconds: int, progress: int, message: str) -> bool:
from trezor.ui.layouts import pin_progress
# We do not want to show the progress loader when starting the device.
# Progress should be shown only for PIN purposes.
if message == "Starting up":
# Possibility to ignore certain messages - not showing loader for them
if message in _ignore_loader_messages:
return False
global _previous_seconds