diff --git a/src/apps/common/request_pin.py b/src/apps/common/request_pin.py index 1ccbe8453..a2fdb6da2 100644 --- a/src/apps/common/request_pin.py +++ b/src/apps/common/request_pin.py @@ -23,18 +23,35 @@ async def request_pin_on_display(ctx: wire.Context, code: int=None) -> str: await ctx.call(ButtonRequest(code=ProtectCall), ButtonAck) + def onchange(): + c = dialog.cancel + if matrix.pin: + c.content = 'Clean' + else: + c.content = 'Cancel' + c.taint() + c.render() + ui.display.clear() - matrix = PinMatrix(label) + matrix = PinMatrix(label, with_zero=True) + matrix.onchange = onchange dialog = ConfirmDialog(matrix) - - result = await dialog - pin = matrix.pin - matrix = None - - if result != CONFIRMED: - raise wire.FailureError(PinCancelled, 'PIN cancelled') - - return pin + dialog.cancel.area = (0, 240 - 48, 80, 48) + dialog.confirm.area = (240 - 80, 240 - 48, 80, 48) + + while True: + res = await dialog + pin = matrix.pin + + if res == CONFIRMED: + matrix = None + return pin + elif res != CONFIRMED and pin: + matrix.change('') + continue + else: + matrix = None + raise wire.FailureError(PinCancelled, 'PIN cancelled') @unimport diff --git a/src/trezor/ui/pin.py b/src/trezor/ui/pin.py index f1e8c0e7d..f1ab6e277 100644 --- a/src/trezor/ui/pin.py +++ b/src/trezor/ui/pin.py @@ -2,42 +2,43 @@ from micropython import const from trezor import ui, res from trezor.crypto import random from trezor.ui import display -from trezor.ui.button import Button, BTN_CLICKED, CLEAR_BUTTON, CLEAR_BUTTON_ACTIVE +from trezor.ui.button import Button, BTN_CLICKED def digit_area(i): width = const(80) height = const(48) + if i == 9: # 0-position + i = 10 # display it in the middle x = (i % 3) * width y = (i // 3) * height - # 48px is offset of input line / -1px is due to corner bug of overlaying - # elements + # 48px is offset of input line, -1px is the border size return (x, y + 48, width - 1, height - 1) -def generate_digits(): - digits = list(range(1, 10)) # 1-9 +def generate_digits(with_zero): + if with_zero: + digits = list(range(0, 10)) # 0-9 + else: + digits = list(range(1, 10)) # 1-9 random.shuffle(digits) return digits class PinMatrix(ui.Widget): - def __init__(self, label, pin=''): + def __init__(self, label, pin='', maxlength=9, with_zero=False): self.label = label self.pin = pin - self.digits = generate_digits() + self.maxlength = maxlength + self.digits = generate_digits(with_zero) # we lay out the buttons top-left to bottom-right, but the order of the # digits is defined as bottom-left to top-right (on numpad) reordered_digits = self.digits[6:] + self.digits[3:6] + self.digits[:3] self.pin_buttons = [Button(digit_area(i), str(d)) for i, d in enumerate(reordered_digits)] - - self.clear_button = Button((240 - 35, 5, 30, 30), - res.load('trezor/res/pin_close.toig'), - normal_style=CLEAR_BUTTON, - active_style=CLEAR_BUTTON_ACTIVE) + self.onchange = None def render(self): @@ -49,12 +50,6 @@ class PinMatrix(ui.Widget): # input line with a header display.text_center(120, 30, header, ui.BOLD, ui.GREY, ui.BLACK) - # render clear button - if self.pin: - self.clear_button.render() - else: - display.bar(240 - 48, 0, 48, 42, ui.BLACK) - # pin matrix buttons for btn in self.pin_buttons: btn.render() @@ -68,9 +63,13 @@ class PinMatrix(ui.Widget): # display.bar(0, 142, 240, 2, ui.blend(ui.BLACK, ui.WHITE, 0.25)) def touch(self, event, pos): - if self.clear_button.touch(event, pos) == BTN_CLICKED: - self.pin = '' for btn in self.pin_buttons: if btn.touch(event, pos) == BTN_CLICKED: - if len(self.pin) < 9: - self.pin += btn.content + if len(self.pin) < self.maxlength: + self.change(self.pin + btn.content) + break + + def change(self, pin): + self.pin = pin + if self.onchange: + self.onchange()