introduce generic swipe container to reset_device

Now its possible to block multiple generators on one interface.
pull/25/head
Jan Pochyla 8 years ago committed by Pavol Rusnak
parent 7aaba5c6ce
commit ae4540c59b
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D

@ -3,7 +3,7 @@ from trezor.ui.swipe import Swipe, SWIPE_UP, SWIPE_DOWN
from trezor.ui.button import Button, CONFIRM_BUTTON, CONFIRM_BUTTON_ACTIVE
from trezor.ui.scroll import Scroll
from trezor.crypto import hashlib, random, bip39
from trezor.utils import unimport_gen
from trezor.utils import unimport_gen, chunks
def generate_mnemonic(strength, display_random):
@ -24,7 +24,7 @@ def generate_mnemonic(strength, display_random):
def request_new_pin():
from trezor.workflows.pin import request_pin
from trezor.workflows.request_pin import request_pin
pin = yield from request_pin()
pin_again = yield from request_pin('Enter PIN again')
@ -35,58 +35,95 @@ def request_new_pin():
raise Exception() # TODO: wrong PIN should be handled in unified way
@unimport_gen
def layout_reset_device(m):
def change_page(page, page_count):
while True:
swipe = yield from Swipe().wait()
if swipe == SWIPE_UP and page < page_count - 1: # Scroll down
return page + 1
elif swipe == SWIPE_DOWN and page > 0: # Scroll up
return page - 1
# TODO: Failure if not empty
def paginate(render_page, page_count, page=0):
while True:
changer = change_page(page, page_count)
renderer = render_page(page, page_count)
waiter = loop.Wait([changer, renderer])
result = yield waiter
if changer in waiter.finished:
page = result
else:
return result
mnemonic = yield from generate_mnemonic(m.strength, m.display_random)
if m.pin_protection:
pin = yield from request_new_pin()
else:
pin = None
def render_scrollbar(page, page_count):
screen_height = const(220)
size = const(8)
padding = 15
if page_count * padding > screen_height:
padding = screen_height // page_count
mnemonic_words = mnemonic.split()
x = 225
y = (screen_height // 2) - (page_count // 2) * padding
for i in range(0, page_count):
if i != page:
ui.display.bar(x, y + i * padding, size, size, ui.GREY, ui.BLACK, 4)
ui.display.bar(x, y + page * padding, size, size, ui.WHITE, ui.BLACK, 4)
def animate_swipe():
def render(fg):
ui.display.bar(102, 214, 36, 4, fg, ui.BLACK, 2)
ui.display.bar(106, 222, 28, 4, fg, ui.BLACK, 2)
ui.display.bar(110, 230, 20, 4, fg, ui.BLACK, 2)
yield from ui.animate_pulse(render, ui.WHITE, ui.GREY, speed=300000, delay=200000)
def show_mnemonic(mnemonic):
words_per_page = const(4)
mnemonic_words = list(enumerate(mnemonic.split()))
mnemonic_pages = list(chunks(mnemonic_words, words_per_page))
def render(page, page_count):
def render(page):
# Header
ui.clear()
ui.display.text(10, 30, 'Write down your seed', ui.BOLD, ui.LIGHT_GREEN, ui.BLACK)
# print mnemonic words for proper page
render_scrollbar(page, page_count)
for i in range(0, words_per_page):
index = i + page * words_per_page
word = mnemonic_words[index]
top = 74 + i * 30
ui.display.text_right(40, top, '%d.' % (index + 1), ui.BOLD, ui.LIGHT_GREEN, ui.BLACK)
# Mnemonic page
for pi, (wi, word) in enumerate(mnemonic_pages[page]):
top = pi * 30 + 74
pos = wi + 1
ui.display.text_right(40, top, '%d.' % pos, ui.BOLD, ui.LIGHT_GREEN, ui.BLACK)
ui.display.text(45, top, '%s' % word, ui.BOLD, ui.WHITE, ui.BLACK)
scroll = Scroll(page=page, totale_lines=mnemonic_words, lines_per_page=words_per_page)
scroll.render()
# TODO: remove swipedown icon when this button is showed
if(len(mnemonic_words) // words_per_page == page + 1):
finish = Button((0, 240 - 48, 240, 48), 'Finish', normal_style=CONFIRM_BUTTON, active_style=CONFIRM_BUTTON_ACTIVE)
finish.render()
def paginate():
count = len(mnemonic_words) // words_per_page
page = 0
while True:
render(page)
degrees = yield from Swipe().wait()
if degrees == SWIPE_UP:
page = min(page + 1, count - 1)
elif degrees == SWIPE_DOWN:
page = max(page - 1, 0)
def animate_arrow():
def func(foreground):
ui.display.icon(105, 200, res.load('apps/management/res/small-arrow.toig'), foreground, ui.BLACK)
yield from ui.animate_pulse(func, ui.WHITE, ui.BLACK, speed=190000)
yield loop.Wait([paginate(),
animate_arrow()])
# Finish button
if page + 1 == page_count:
finish = Button((0, 240 - 48, 240, 48), 'Finish',
normal_style=CONFIRM_BUTTON,
active_style=CONFIRM_BUTTON_ACTIVE)
yield from finish.wait()
# Swipe icon
else:
yield from animate_swipe()
yield from paginate(render, len(mnemonic_pages))
@unimport_gen
def layout_reset_device(m):
# TODO: Failure if not empty
mnemonic = yield from generate_mnemonic(m.strength, m.display_random)
# if m.pin_protection:
# pin = yield from request_new_pin()
# else:
# pin = None
yield from show_mnemonic(mnemonic)

@ -5,6 +5,7 @@ from trezor.workflows.request_pin import request_pin
@unimport_gen
def layout_get_public_key(message):
ui.clear()
pin = yield from request_pin()

@ -18,7 +18,7 @@ TOUCH_START = const(1)
TOUCH_MOVE = const(2)
TOUCH_END = const(4)
msg_handlers = {} # Interface -> generator
msg_handlers = {} # Message interface -> [generator]
time_queue = []
time_ticket = 0
@ -39,17 +39,16 @@ def unschedule(gen):
def block(gen, iface):
curr = msg_handlers.get(iface, None)
if curr:
log.warning(__name__, 'Closing %s blocked on %s', curr, iface)
curr.close()
msg_handlers[iface] = gen
if iface in msg_handlers:
msg_handlers[iface].append(gen)
else:
msg_handlers[iface] = [gen]
def unblock(gen):
for iface in msg_handlers:
if msg_handlers[iface] is gen:
msg_handlers[iface] = None
if gen in msg_handlers[iface]:
msg_handlers[iface].remove(gen)
class Syscall():
@ -80,7 +79,7 @@ class Wait(Syscall):
self.gens = gens
self.wait_for = wait_for
self.exit_others = exit_others
self.scheduled = []
self.scheduled = [] # In uPython, set() cannot contain generators
self.finished = []
self.callback = None
@ -115,6 +114,19 @@ class Wait(Syscall):
self.callback = None
def step_task(gen, data):
if isinstance(data, Exception):
result = gen.throw(data)
else:
result = gen.send(data)
if isinstance(result, Syscall):
result.register(gen) # Execute the syscall
elif result is None:
schedule(gen) # Just call us asap
else:
raise Exception('Unhandled result %s by %s' % (result, gen))
def run_forever():
if __debug__:
global log_delay_pos, log_delay_rb, log_delay_rb_len
@ -135,40 +147,27 @@ def run_forever():
log_delay_rb[log_delay_pos] = delay
log_delay_pos = (log_delay_pos + 1) % log_delay_rb_len
message = msg.select(delay)
if message:
# Run interrupt handler right away, they have priority
iface, *data = message
gen = msg_handlers.pop(iface, None)
if not gen:
m = msg.select(delay)
if m:
# Run interrupt handlers right away, they have priority
iface, *data = m
tasks = msg_handlers.pop(iface, None)
if not tasks:
log.info(__name__, 'No handler for message: %s', iface)
continue
else:
# Run something from the time queue
if time_queue:
_, _, gen, data = heappop(time_queue)
tasks = (gen,)
else:
continue
try:
if isinstance(data, Exception):
result = gen.throw(data)
else:
result = gen.send(data)
except StopIteration as e:
log.debug(__name__, '%s finished', gen)
continue
except Exception as e:
log.exception(__name__, e)
continue
if isinstance(result, Syscall):
# Execute the syscall
result.register(gen)
elif result is None:
# Just call us asap
schedule(gen)
else:
raise Exception('Unhandled result %s by %s' % (result, gen))
# Run the tasks
for gen in tasks:
try:
step_task(gen, data)
except StopIteration as e:
log.debug(__name__, '%s finished', gen)
except Exception as e:
log.exception(__name__, e)

Loading…
Cancel
Save