18 #include "os_helpers.h"
25 #define PAGE_NB_ELEMENTS_BITS 3
26 #define GET_PAGE_NB_ELEMENTS(pageData) ((pageData) &0x07)
27 #define SET_PAGE_NB_ELEMENTS(nbElements) ((nbElements) &0x07)
29 #define PAGE_FLAG_BITS 1
30 #define GET_PAGE_FLAG(pageData) (((pageData) &0x08) >> 3)
31 #define SET_PAGE_FLAG(flag) (((flag) &0x01) << 3)
33 #define PAGE_DATA_BITS (PAGE_NB_ELEMENTS_BITS + PAGE_FLAG_BITS)
34 #define PAGES_PER_UINT8 (8 / PAGE_DATA_BITS)
35 #define SET_PAGE_DATA(pageIdx, pageData) \
36 (pagesData[pageIdx / PAGES_PER_UINT8] = pageData \
37 << ((pageIdx % PAGES_PER_UINT8) * PAGE_DATA_BITS))
39 #define MAX_PAGE_NB 256
42 #define STARTING_CONTENT localContentsList[0]
43 #define FINISHING_CONTENT localContentsList[1]
46 #define QRCODE_NB_MAX_LINES 3
48 #define QRCODE_REDUCED_ADDR_LEN 128
51 #define keypadContext sharedContext.keypad
52 #define addressConfirmationContext sharedContext.addressConfirmation
53 #define blindSigningContext sharedContext.blindSigning
65 ADDRESS_QRCODE_BUTTON_TOKEN,
83 typedef struct DetailsContext_s {
89 const char *nextPageStart;
92 typedef struct AddressConfirmationContext_s {
95 } AddressConfirmationContext_t;
98 typedef struct KeypadContext_s {
108 typedef struct BlindSigningContext_s {
113 const char *reviewTitle;
114 const char *reviewSubTitle;
115 const char *finishTitle;
119 } BlindSigningContext_t;
125 KeypadContext_t keypad;
127 AddressConfirmationContext_t addressConfirmation;
128 BlindSigningContext_t blindSigning;
134 uint8_t currentContentElementNb;
136 bool hasStartingContent;
137 bool hasFinishingContent;
138 const char *detailsItem;
139 const char *detailsvalue;
140 bool detailsWrapping;
157 } nbgl_homeAndSettingsContext_t;
162 } nbgl_reviewContext_t;
170 } nbgl_reviewStreamingContext_t;
173 nbgl_homeAndSettingsContext_t homeAndSettings;
174 nbgl_reviewContext_t review;
175 nbgl_reviewStreamingContext_t reviewStreaming;
176 } nbgl_BundleNavContext_t;
204 static const char *pageTitle;
207 static const char *tipBoxModalTitle;
212 static bool forwardNavOnly;
213 static NavType_t navType;
215 static DetailsContext_t detailsContext;
218 static SharedContext_t sharedContext;
221 static GenericContext_t genericContext;
223 localContentsList[3];
224 static uint8_t genericContextPagesInfo[MAX_PAGE_NB / PAGES_PER_UINT8];
227 static nbgl_BundleNavContext_t bundleNavContext;
230 static const uint8_t nbMaxElementsPerContentType[] = {
246 static char reducedAddress[QRCODE_REDUCED_ADDR_LEN];
252 static void displayReviewPage(
uint8_t page,
bool forceFullRefresh);
253 static void displayDetailsPage(
uint8_t page,
bool forceFullRefresh);
256 static void displayTipBoxModal(
void);
257 static void displaySettingsPage(
uint8_t page,
bool forceFullRefresh);
258 static void displayGenericContextPage(
uint8_t pageIdx,
bool forceFullRefresh);
259 static void pageCallback(
int token,
uint8_t index);
261 static void displayAddressQRCode(
void);
262 static void addressLayoutTouchCallbackQR(
int token,
uint8_t index);
264 static void modalLayoutTouchCallback(
int token,
uint8_t index);
265 static void displaySkipWarning(
void);
267 static void bundleNavStartHome(
void);
268 static void bundleNavStartSettingsAtPage(
uint8_t initSettingPage);
269 static void bundleNavStartSettings(
void);
271 static void bundleNavReviewStreamingChoice(
bool confirm);
272 static void blindSigningWarning(
void);
276 const char *reviewTitle,
277 const char *reviewSubTitle,
278 const char *finishTitle,
282 bool playNotifSound);
285 const char *reviewTitle,
286 const char *reviewSubTitle,
288 bool playNotifSound);
289 static void useCaseHomeExt(
const char *appName,
297 static void reset_callbacks(
void)
304 onContentAction = NULL;
306 onModalConfirm = NULL;
308 onValidatePin = NULL;
313 static void genericContextSetPageInfo(
uint8_t pageIdx,
uint8_t nbElements,
bool flag)
315 uint8_t pageData = SET_PAGE_NB_ELEMENTS(nbElements) + SET_PAGE_FLAG(flag);
317 genericContextPagesInfo[pageIdx / PAGES_PER_UINT8]
318 &= ~(0x0F << ((pageIdx % PAGES_PER_UINT8) * PAGE_DATA_BITS));
319 genericContextPagesInfo[pageIdx / PAGES_PER_UINT8]
320 |= pageData << ((pageIdx % PAGES_PER_UINT8) * PAGE_DATA_BITS);
324 static void genericContextGetPageInfo(
uint8_t pageIdx,
uint8_t *nbElements,
bool *flag)
326 uint8_t pageData = genericContextPagesInfo[pageIdx / PAGES_PER_UINT8]
327 >> ((pageIdx % PAGES_PER_UINT8) * PAGE_DATA_BITS);
328 if (nbElements != NULL) {
329 *nbElements = GET_PAGE_NB_ELEMENTS(pageData);
332 *flag = GET_PAGE_FLAG(pageData);
339 switch (content->
type) {
361 if (contentIdx < 0 || contentIdx >= genericContents->
nbContents) {
378 static void prepareNavInfo(
bool isReview,
uint8_t nbPages,
const char *rejectText)
380 memset(&navInfo, 0,
sizeof(navInfo));
383 navInfo.
tuneId = TUNE_TAP_CASUAL;
387 if (isReview ==
false) {
396 = ((navType == STREAMING_NAV) && (nbPages < 2)) ?
false :
true;
403 const char *reviewTitle,
404 const char *reviewSubTitle)
406 contentCenter->
icon = icon;
407 contentCenter->
title = reviewTitle;
409 contentCenter->
subText =
"Swipe to review";
412 contentCenter->
padding =
false;
417 const char *finishTitle)
419 infoLongPress->
text = finishTitle;
420 infoLongPress->
icon = icon;
427 const char *finishTitle)
429 infoButton->
text = finishTitle;
430 infoButton->
icon = icon;
437 UNUSED(operationType);
443 static void pageModalCallback(
int token,
uint8_t index)
447 modalPageContext = NULL;
448 if (token == NAV_TOKEN) {
455 displayDetailsPage(index,
false);
458 if (token == QUIT_TOKEN) {
463 else if (token == SKIP_TOKEN) {
474 else if (token == CHOICE_TOKEN) {
476 if (onModalConfirm != NULL) {
489 static void pageCallback(
int token,
uint8_t index)
492 if (token == QUIT_TOKEN) {
493 if (onQuit != NULL) {
497 else if (token == CONTINUE_TOKEN) {
498 if (onContinue != NULL) {
502 else if (token == CHOICE_TOKEN) {
503 if (onChoice != NULL) {
504 onChoice((index == 0) ?
true :
false);
507 else if (token == ACTION_BUTTON_TOKEN) {
508 if ((index == 0) && (onAction != NULL)) {
511 else if ((index == 1) && (onQuit != NULL)) {
516 else if (token == ADDRESS_QRCODE_BUTTON_TOKEN) {
517 displayAddressQRCode();
520 else if (token == CONFIRM_TOKEN) {
521 if (onChoice != NULL) {
525 else if (token == REJECT_TOKEN) {
526 if (onChoice != NULL) {
530 else if (token == DETAILS_BUTTON_TOKEN) {
532 genericContext.detailsvalue,
533 genericContext.detailsWrapping);
535 else if (token == NAV_TOKEN) {
537 if (onQuit != NULL) {
542 if (navType == GENERIC_NAV || navType == STREAMING_NAV) {
543 displayGenericContextPage(index,
false);
545 else if (navType == REVIEW_NAV) {
546 displayReviewPage(index,
false);
549 displaySettingsPage(index,
false);
553 else if (token == NEXT_TOKEN) {
555 displayReviewPage(navInfo.
activePage + 1,
false);
558 displayGenericContextPage(navInfo.
activePage + 1,
false);
561 else if (token == BACK_TOKEN) {
563 displayReviewPage(navInfo.
activePage - 1,
true);
566 displayGenericContextPage(navInfo.
activePage - 1,
false);
569 else if (token == SKIP_TOKEN) {
571 displaySkipWarning();
573 else if (token == VALUE_ALIAS_TOKEN) {
576 if (genericContext.currentPairs != NULL) {
577 pair = &genericContext.currentPairs[genericContext.currentElementIdx + index];
580 pair = genericContext.currentCallback(genericContext.currentElementIdx + index);
582 displayFullValuePage(pair);
584 else if (token == BLIND_WARNING_TOKEN) {
585 if (navType == STREAMING_NAV) {
586 displayBlindWarning(bundleNavContext.reviewStreaming.operationType
590 displayBlindWarning(bundleNavContext.review.operationType
594 else if (token == TIP_BOX_TOKEN) {
595 displayTipBoxModal();
598 if (onContentAction != NULL) {
599 onContentAction(token, index, navInfo.
activePage);
601 if (onControls != NULL) {
602 onControls(token, index);
608 static void tickerCallback(
void)
611 if (onQuit != NULL) {
617 static void displaySettingsPage(
uint8_t page,
bool forceFullRefresh)
621 if ((onNav == NULL) || (onNav(page, &content) ==
false)) {
626 content.title = pageTitle;
627 content.isTouchableTitle =
true;
628 content.titleToken = QUIT_TOKEN;
629 content.tuneId = TUNE_TAP_CASUAL;
634 if (forceFullRefresh) {
643 static void displayReviewPage(
uint8_t page,
bool forceFullRefresh)
652 if ((onNav == NULL) || (onNav(navInfo.
activePage, &content) ==
false)) {
657 content.title = NULL;
658 content.isTouchableTitle =
false;
659 content.tuneId = TUNE_TAP_CASUAL;
665 content.infoLongPress.longPressToken = CONFIRM_TOKEN;
666 if (forwardNavOnly) {
674 content.tagValueDetails.tagValueList.smallCaseForValue =
false;
680 content.tagValueList.smallCaseForValue =
false;
683 content.tagValueConfirm.tagValueList.smallCaseForValue =
false;
685 content.tagValueConfirm.confirmationToken = CONFIRM_TOKEN;
690 if (forceFullRefresh) {
702 uint8_t *p_nbElementsInNextPage,
705 int8_t nextContentIdx = genericContext.currentContentIdx;
706 int16_t nextElementIdx = genericContext.currentElementIdx;
710 genericContextGetPageInfo(pageIdx, &nbElementsInNextPage, p_flag);
711 *p_nbElementsInNextPage = nbElementsInNextPage;
716 uint8_t nbElementsInCurrentPage;
718 genericContextGetPageInfo(navInfo.
activePage, &nbElementsInCurrentPage, NULL);
719 nextElementIdx += nbElementsInCurrentPage;
723 if (nextElementIdx >= genericContext.currentContentElementNb) {
733 nextElementIdx -= nbElementsInNextPage;
739 if (nextElementIdx < 0) {
741 nextElementIdx = -nbElementsInNextPage;
747 if ((nextContentIdx == -1) && (genericContext.hasStartingContent)) {
748 p_content = &STARTING_CONTENT;
750 else if ((nextContentIdx == genericContext.genericContents.nbContents)
751 && (genericContext.hasFinishingContent)) {
752 p_content = &FINISHING_CONTENT;
755 p_content = getContentAtIdx(&genericContext.genericContents, nextContentIdx, content);
757 if (p_content == NULL) {
772 if ((nextContentIdx != genericContext.currentContentIdx)
773 || (genericContext.currentContentElementNb == 0)) {
774 genericContext.currentContentIdx = nextContentIdx;
775 genericContext.currentContentElementNb = getContentNbElement(p_content);
777 if (nextElementIdx < 0) {
778 nextElementIdx = genericContext.currentContentElementNb + nextElementIdx;
783 if ((nextElementIdx < 0) || (nextElementIdx >= genericContext.currentContentElementNb)) {
785 "Invalid element index %d / %d\n",
787 genericContext.currentContentElementNb);
792 genericContext.currentElementIdx = nextElementIdx;
800 static bool genericContextPreparePageContent(
const nbgl_content_t *p_content,
805 uint8_t nextElementIdx = genericContext.currentElementIdx;
807 pageContent->title = pageTitle;
808 pageContent->isTouchableTitle =
false;
809 pageContent->titleToken = QUIT_TOKEN;
810 pageContent->tuneId = TUNE_TAP_CASUAL;
812 pageContent->type = p_content->
type;
813 switch (pageContent->type) {
815 memcpy(&pageContent->centeredInfo,
817 sizeof(pageContent->centeredInfo));
820 memcpy(&pageContent->extendedCenter,
822 sizeof(pageContent->extendedCenter));
825 memcpy(&pageContent->infoLongPress,
827 sizeof(pageContent->infoLongPress));
831 memcpy(&pageContent->infoButton,
833 sizeof(pageContent->infoButton));
859 prepareReviewFirstPage(&pageContent->extendedCenter.contentCenter,
865 p_tagValueList = NULL;
870 pageContent->tagValueDetails.detailsButtonText =
"More";
871 pageContent->tagValueDetails.detailsButtonIcon = NULL;
872 pageContent->tagValueDetails.detailsButtonToken = DETAILS_BUTTON_TOKEN;
874 p_tagValueList = &pageContent->tagValueDetails.tagValueList;
877 genericContext.detailsItem = pair->
item;
878 genericContext.detailsvalue = pair->
value;
883 if (p_tagValueList != NULL) {
884 p_tagValueList->
nbPairs = nbElementsInPage;
887 p_tagValueList->
pairs
890 for (
uint8_t i = 0; i < nbElementsInPage; i++) {
892 p_tagValueList->
token = VALUE_ALIAS_TOKEN;
898 p_tagValueList->
pairs = NULL;
902 for (
uint8_t i = 0; i < nbElementsInPage; i++) {
906 p_tagValueList->
token = VALUE_ALIAS_TOKEN;
919 memcpy(&pageContent->tagValueConfirm,
921 sizeof(pageContent->tagValueConfirm));
924 pageContent->switchesList.nbSwitches = nbElementsInPage;
925 pageContent->switchesList.switches
929 pageContent->infosList.nbInfos = nbElementsInPage;
930 pageContent->infosList.infoTypes
932 pageContent->infosList.infoContents
936 memcpy(&pageContent->choicesList,
938 sizeof(pageContent->choicesList));
939 pageContent->choicesList.nbChoices = nbElementsInPage;
940 pageContent->choicesList.names
944 < nextElementIdx + nbElementsInPage)) {
945 pageContent->choicesList.initChoice
949 pageContent->choicesList.initChoice = nbElementsInPage;
953 pageContent->barsList.nbBars = nbElementsInPage;
954 pageContent->barsList.barTexts
964 bool isFirstOrLastPage
967 bool isStreamingNavAndBlindOperation
968 = (navType == STREAMING_NAV)
970 bool isGenericNavAndBlindOperation
971 = (navType == GENERIC_NAV) && (bundleNavContext.review.operationType &
BLIND_OPERATION);
974 if (isFirstOrLastPage && (isStreamingNavAndBlindOperation || isGenericNavAndBlindOperation)) {
976 pageContent->topRightToken = BLIND_WARNING_TOKEN;
983 static void displayGenericContextPage(
uint8_t pageIdx,
bool forceFullRefresh)
991 if (navType == STREAMING_NAV) {
993 if (bundleNavContext.reviewStreaming.skipCallback != NULL) {
994 bundleNavContext.reviewStreaming.skipCallback();
998 else if (pageIdx >= bundleNavContext.reviewStreaming.stepPageNb) {
999 bundleNavReviewStreamingChoice(
true);
1006 = genericContextComputeNextPageParams(pageIdx, &content, &nbElementsInPage, &flag);
1011 for (
int i = navInfo.
activePage + 1; i <= pageIdx; i++) {
1012 p_content = genericContextComputeNextPageParams(i, &content, &nbElementsInPage, &flag);
1022 = genericContextComputeNextPageParams(pageIdx, &content, &nbElementsInPage, &flag);
1025 if (p_content == NULL) {
1031 if (!genericContextPreparePageContent(p_content, nbElementsInPage, flag, &pageContent)) {
1037 if (forceFullRefresh) {
1046 static const char *getDetailsPageAt(
uint8_t detailsPage)
1049 const char *currentChar = detailsContext.value;
1050 while (page < detailsPage) {
1060 detailsContext.wrapping);
1062 currentChar = currentChar + len;
1070 static void displayDetailsPage(
uint8_t detailsPage,
bool forceFullRefresh)
1074 .nbPages = detailsContext.nbPages,
1076 .quitToken = QUIT_TOKEN,
1077 .navWithButtons.navToken = NAV_TOKEN,
1078 .navWithButtons.quitButton =
true,
1079 .navWithButtons.backButton =
true,
1080 .navWithButtons.quitText = NULL,
1081 .progressIndicator =
false,
1082 .tuneId = TUNE_TAP_CASUAL};
1084 .topRightIcon = NULL,
1085 .tagValueList.nbPairs = 1,
1086 .tagValueList.pairs = ¤tPair,
1087 .tagValueList.smallCaseForValue =
true,
1088 .tagValueList.wrapping = detailsContext.wrapping};
1090 if (modalPageContext != NULL) {
1093 currentPair.
item = detailsContext.tag;
1095 if (detailsPage <= detailsContext.currentPage) {
1097 currentPair.
value = getDetailsPageAt(detailsPage);
1098 forceFullRefresh =
true;
1102 currentPair.
value = detailsContext.nextPageStart;
1104 detailsContext.currentPage = detailsPage;
1115 detailsContext.wrapping);
1118 detailsContext.nextPageStart = currentPair.
value + len;
1124 detailsContext.nextPageStart = NULL;
1125 content.tagValueList.nbMaxLinesForValue = 0;
1133 if (forceFullRefresh) {
1145 .withLeftBorder =
true,
1146 .onActionCallback = &modalLayoutTouchCallback,
1147 .tapActionText = NULL};
1149 .separationLine =
false,
1150 .backAndText.token = 0,
1151 .backAndText.tuneId = TUNE_TAP_CASUAL,
1152 .backAndText.text = PIC(pair->
item)};
1160 info =
"ENS names are resolved by Ledger backend.";
1163 info =
"This account label comes from your Address Book in Ledger Live.";
1184 .withLeftBorder =
true,
1185 .onActionCallback = &modalLayoutTouchCallback,
1186 .tapActionText = NULL};
1188 .separationLine =
false,
1189 .backAndText.token = 0,
1190 .backAndText.tuneId = TUNE_TAP_CASUAL,
1191 .backAndText.text = NULL};
1194 centeredInfo.
text1 =
"Security risk detected";
1197 =
"This transaction cannot be fully decoded. If you sign it, you could be authorizing "
1198 "malicious actions that can drain your wallet.\n\n"
1199 "Learn more: ledger.com/e8";
1203 =
"This message cannot be fully decoded. If you sign it, you could be authorizing "
1204 "malicious actions that can drain your wallet.\n\n"
1205 "Learn more: ledger.com/e8";
1219 static void displayTipBoxModal(
void)
1224 .quitToken = QUIT_TOKEN,
1225 .navWithButtons.navToken = NAV_TOKEN,
1226 .navWithButtons.quitButton =
false,
1227 .navWithButtons.backButton =
true,
1228 .navWithButtons.quitText = NULL,
1229 .progressIndicator =
false,
1230 .tuneId = TUNE_TAP_CASUAL};
1232 .topRightIcon = NULL,
1233 .infosList.nbInfos = tipBoxInfoList.
nbInfos,
1234 .infosList.infoTypes = tipBoxInfoList.
infoTypes,
1236 .title = tipBoxModalTitle,
1237 .titleToken = QUIT_TOKEN};
1239 if (modalPageContext != NULL) {
1248 static void displayAddressQRCode(
void)
1252 .withLeftBorder =
true,
1253 .onActionCallback = &addressLayoutTouchCallbackQR,
1254 .tapActionText = NULL};
1262 addressConfirmationContext.modalLayout =
nbgl_layoutGet(&layoutDescription);
1267 SMALL_REGULAR_FONT, addressConfirmationContext.tagValuePair.value,
AVAILABLE_WIDTH,
false);
1269 if (nbLines <= QRCODE_NB_MAX_LINES) {
1270 qrCode.
text2 = addressConfirmationContext.tagValuePair.value;
1275 addressConfirmationContext.tagValuePair.value,
1277 QRCODE_NB_MAX_LINES,
1279 QRCODE_REDUCED_ADDR_LEN);
1280 qrCode.
text2 = reducedAddress;
1291 static void addressLayoutTouchCallbackQR(
int token,
uint8_t index)
1304 static void modalLayoutTouchCallback(
int token,
uint8_t index)
1316 static void displaySkipWarning(
void)
1319 .cancelText =
"Go back to review",
1320 .centeredInfo.text1 =
"Skip review?",
1322 =
"If you're sure you don't need to review all fields, you can skip straight to signing.",
1323 .centeredInfo.text3 = NULL,
1325 .centeredInfo.icon = &C_Important_Circle_64px,
1326 .centeredInfo.offsetY = 0,
1327 .confirmationText =
"Yes, skip",
1328 .confirmationToken = SKIP_TOKEN,
1329 .tuneId = TUNE_TAP_CASUAL,
1340 static void updateKeyPad(
bool add)
1342 bool enableValidate, enableBackspace, enableDigits;
1343 bool redrawKeypad =
false;
1346 enableDigits = (keypadContext.pinLen < keypadContext.pinMaxDigits);
1347 enableValidate = (keypadContext.pinLen >= keypadContext.pinMinDigits);
1348 enableBackspace = (keypadContext.pinLen > 0);
1350 if ((keypadContext.pinLen == keypadContext.pinMinDigits)
1352 (keypadContext.pinLen == keypadContext.pinMaxDigits)
1354 (keypadContext.pinLen == 1)) {
1355 redrawKeypad =
true;
1359 if ((keypadContext.pinLen == 0) ||
1360 (keypadContext.pinLen == (keypadContext.pinMinDigits - 1))
1362 (keypadContext.pinLen
1363 == (keypadContext.pinMaxDigits - 1))) {
1364 redrawKeypad =
true;
1367 if (keypadContext.hidden ==
true) {
1372 keypadContext.layoutCtx,
false, 0, (
const char *) keypadContext.pinEntry);
1376 keypadContext.layoutCtx, 0, enableValidate, enableBackspace, enableDigits);
1379 if ((!add) && (keypadContext.pinLen == 0)) {
1387 static void keypadCallback(
char touchedKey)
1389 switch (touchedKey) {
1391 if (keypadContext.pinLen > 0) {
1392 keypadContext.pinLen--;
1393 keypadContext.pinEntry[keypadContext.pinLen] = 0;
1395 updateKeyPad(
false);
1404 onValidatePin(keypadContext.pinEntry, keypadContext.pinLen);
1408 if ((touchedKey >= 0x30) && (touchedKey < 0x40)) {
1409 if (keypadContext.pinLen < keypadContext.pinMaxDigits) {
1410 keypadContext.pinEntry[keypadContext.pinLen] = touchedKey;
1411 keypadContext.pinLen++;
1420 static void keypadGenericUseCase(
const char *title,
1426 tune_index_e tuneId,
1432 .separationLine =
true,
1433 .backAndText.token = backToken,
1434 .backAndText.tuneId = tuneId,
1435 .backAndText.text = NULL};
1444 memset(&keypadContext, 0,
sizeof(KeypadContext_t));
1448 layoutDescription.
modal =
false;
1451 keypadContext.hidden = hidden;
1463 keypadContext.layoutCtx, title, keypadContext.hidden, maxDigits,
"");
1470 onValidatePin = validatePinCallback;
1472 keypadContext.pinMinDigits = minDigits;
1473 keypadContext.pinMaxDigits = maxDigits;
1490 nbElements = getContentNbElement(content);
1492 while (nbElements > 0) {
1495 bool hasNav = !isLast || (pageIdxStart > 0) || (elemIdx > 0);
1517 nbElementsInPage =
MIN(nbMaxElementsPerContentType[content->
type], nbElements);
1520 elemIdx += nbElementsInPage;
1521 genericContextSetPageInfo(pageIdxStart + nbPages, nbElementsInPage, flag);
1522 nbElements -= nbElementsInPage;
1529 static uint8_t nbgl_useCaseGetNbPagesForGenericContents(
1537 for (
int i = 0; i < genericContents->
nbContents; i++) {
1538 p_content = getContentAtIdx(genericContents, i, &content);
1539 if (p_content == NULL) {
1542 nbPages += nbgl_useCaseGetNbPagesForContent(
1543 p_content, pageIdxStart + nbPages, (i == (genericContents->
nbContents - 1)));
1549 static void prepareAddressConfirmationPages(
const char *address,
1556 addressConfirmationContext.tagValuePair.item =
"Address";
1557 addressConfirmationContext.tagValuePair.value = address;
1566 if (tagValueList != NULL) {
1577 tagValueConfirm->tuneId = TUNE_TAP_CASUAL;
1585 if (tagValueList != NULL) {
1595 if (tagValueList != NULL) {
1603 tagValueConfirm->tuneId = TUNE_TAP_CASUAL;
1608 static void bundleNavStartHome(
void)
1610 nbgl_homeAndSettingsContext_t *context = &bundleNavContext.homeAndSettings;
1612 useCaseHomeExt(context->appName,
1615 context->settingContents != NULL ?
true :
false,
1616 &context->homeAction,
1617 bundleNavStartSettings,
1618 context->quitCallback);
1621 static void bundleNavStartSettingsAtPage(
uint8_t initSettingPage)
1623 nbgl_homeAndSettingsContext_t *context = &bundleNavContext.homeAndSettings;
1627 context->settingContents,
1629 bundleNavStartHome);
1632 static void bundleNavStartSettings(
void)
1634 bundleNavStartSettingsAtPage(0);
1637 static void bundleNavReviewConfirmRejection(
void)
1639 bundleNavContext.review.choiceCallback(
false);
1646 const char *confirmText;
1650 title =
"Reject transaction?";
1651 confirmText =
"Go back to transaction";
1654 title =
"Reject message?";
1655 confirmText =
"Go back to message";
1658 title =
"Reject operation?";
1659 confirmText =
"Go back to operation";
1666 static void bundleNavReviewChoice(
bool confirm)
1669 bundleNavContext.review.choiceCallback(
true);
1672 bundleNavReviewAskRejectionConfirmation(bundleNavContext.review.operationType,
1673 bundleNavReviewConfirmRejection);
1677 static void bundleNavReviewStreamingConfirmRejection(
void)
1679 bundleNavContext.reviewStreaming.choiceCallback(
false);
1682 static void bundleNavReviewStreamingChoice(
bool confirm)
1689 bundleNavContext.reviewStreaming.choiceCallback(
true);
1692 bundleNavReviewAskRejectionConfirmation(bundleNavContext.reviewStreaming.operationType,
1693 bundleNavReviewStreamingConfirmRejection);
1698 static void blindSigningWarningCallback(
bool confirm)
1701 blindSigningContext.choiceCallback(
false);
1704 if (blindSigningContext.isStreaming) {
1705 useCaseReviewStreamingStart(blindSigningContext.operationType,
1706 blindSigningContext.icon,
1707 blindSigningContext.reviewTitle,
1708 blindSigningContext.reviewSubTitle,
1709 blindSigningContext.choiceCallback,
1713 useCaseReview(blindSigningContext.operationType,
1714 blindSigningContext.tagValueList,
1715 blindSigningContext.icon,
1716 blindSigningContext.reviewTitle,
1717 blindSigningContext.reviewSubTitle,
1718 blindSigningContext.finishTitle,
1719 blindSigningContext.tipBox,
1720 blindSigningContext.choiceCallback,
1728 static void blindSigningWarning(
void)
1731 #ifdef HAVE_PIEZO_SOUND
1732 io_seproxyhal_play_tune(TUNE_LOOK_AT_ME);
1736 "Blind signing ahead",
1737 "This transaction's details are not fully verifiable. If you sign it, you could lose all "
1741 blindSigningWarningCallback);
1748 const char *reviewTitle,
1749 const char *reviewSubTitle,
1750 const char *finishTitle,
1754 bool playNotifSound)
1757 memset(&genericContext, 0,
sizeof(genericContext));
1759 bundleNavContext.review.operationType = operationType;
1760 bundleNavContext.review.choiceCallback = choiceCallback;
1763 onChoice = bundleNavReviewChoice;
1764 navType = GENERIC_NAV;
1767 genericContext.genericContents.contentsList = localContentsList;
1768 genericContext.genericContents.nbContents = 3;
1773 prepareReviewFirstPage(
1774 &STARTING_CONTENT.content.extendedCenter.contentCenter, icon, reviewTitle, reviewSubTitle);
1775 if (tipBox != NULL) {
1776 STARTING_CONTENT.content.extendedCenter.tipBox.icon = tipBox->
icon;
1777 STARTING_CONTENT.content.extendedCenter.tipBox.text = tipBox->
text;
1778 STARTING_CONTENT.content.extendedCenter.tipBox.token = TIP_BOX_TOKEN;
1779 STARTING_CONTENT.content.extendedCenter.tipBox.tuneId = TUNE_TAP_CASUAL;
1789 memcpy(&localContentsList[1].content.tagValueList,
1797 prepareReviewLightLastPage(&localContentsList[2].content.infoButton, icon, finishTitle);
1801 prepareReviewLastPage(&localContentsList[2].content.infoLongPress, icon, finishTitle);
1805 uint8_t nbPages = nbgl_useCaseGetNbPagesForGenericContents(&genericContext.genericContents, 0);
1806 prepareNavInfo(
true, nbPages, getRejectReviewText(operationType));
1809 if (playNotifSound) {
1810 #ifdef HAVE_PIEZO_SOUND
1811 io_seproxyhal_play_tune(TUNE_LOOK_AT_ME);
1815 displayGenericContextPage(0,
true);
1821 const char *reviewTitle,
1822 const char *reviewSubTitle,
1824 bool playNotifSound)
1827 memset(&genericContext, 0,
sizeof(genericContext));
1829 bundleNavContext.reviewStreaming.operationType = operationType;
1830 bundleNavContext.reviewStreaming.choiceCallback = choiceCallback;
1831 bundleNavContext.reviewStreaming.icon = icon;
1834 onChoice = bundleNavReviewStreamingChoice;
1835 navType = STREAMING_NAV;
1838 genericContext.genericContents.contentsList = localContentsList;
1839 genericContext.genericContents.nbContents = 1;
1844 prepareReviewFirstPage(
1845 &STARTING_CONTENT.content.extendedCenter.contentCenter, icon, reviewTitle, reviewSubTitle);
1848 bundleNavContext.reviewStreaming.stepPageNb
1849 = nbgl_useCaseGetNbPagesForGenericContents(&genericContext.genericContents, 0);
1855 if (playNotifSound) {
1856 #ifdef HAVE_PIEZO_SOUND
1857 io_seproxyhal_play_tune(TUNE_LOOK_AT_ME);
1861 displayGenericContextPage(0,
true);
1880 static void useCaseHomeExt(
const char *appName,
1882 const char *tagline,
1891 .centeredInfo.text1 = appName,
1892 .centeredInfo.text3 = NULL,
1894 .centeredInfo.offsetY = 0,
1897 .tapActionText = NULL,
1899 .topRightToken = CONTINUE_TOKEN,
1900 .tuneId = TUNE_TAP_CASUAL};
1901 if ((homeAction->
text != NULL) || (homeAction->
icon != NULL)) {
1916 if (tagline == NULL) {
1918 snprintf(appDescription,
1920 "This app enables signing\ntransactions on its network.");
1923 snprintf(appDescription,
1935 snprintf(appDescription,
1948 onContinue = topRightCallback;
1949 onQuit = quitCallback;
1974 bool *requireSpecificDisplay)
1983 *requireSpecificDisplay =
false;
1984 while (nbPairsInPage < nbPairs) {
1991 if (nbPairsInPage > 0) {
1993 currentHeight += 12;
1995 currentHeight += 24;
1999 if (tagValueList->
pairs != NULL) {
2000 pair = PIC(&tagValueList->
pairs[startIndex + nbPairsInPage]);
2003 pair = PIC(tagValueList->
callback(startIndex + nbPairsInPage));
2012 if (nbPairsInPage > 0) {
2019 *requireSpecificDisplay =
true;
2031 value_font = SMALL_REGULAR_FONT;
2034 value_font = LARGE_MEDIUM_FONT;
2043 if (nbPairsInPage == 0) {
2047 *requireSpecificDisplay =
true;
2053 return nbPairsInPage;
2074 const char *
const *infoTypes = PIC(infosList->
infoTypes);
2075 const char *
const *infoContents = PIC(infosList->
infoContents);
2077 while (nbInfosInPage < nbInfos) {
2083 SMALL_BOLD_FONT, PIC(infoTypes[startIndex + nbInfosInPage]),
AVAILABLE_WIDTH,
true);
2089 PIC(infoContents[startIndex + nbInfosInPage]),
2102 previousHeight = currentHeight;
2105 return nbInfosInPage;
2128 while (nbSwitchesInPage < nbSwitches) {
2134 switchArray[startIndex + nbSwitchesInPage].text,
2143 switchArray[startIndex + nbSwitchesInPage].subText,
2156 previousHeight = currentHeight;
2159 return nbSwitchesInPage;
2184 while (nbBarsInPage < nbBars) {
2195 previousHeight = currentHeight;
2198 return nbBarsInPage;
2220 UNUSED(choicesList);
2223 while (nbChoicesInPage < nbChoices) {
2234 previousHeight = currentHeight;
2237 return nbChoicesInPage;
2254 while (i < tagValueList->nbPairs) {
2258 nbPairs -= nbPairsInPage;
2278 const char *tagline,
2284 appName, appIcon, tagline, withSettings, NULL, NULL, topRightCallback, quitCallback);
2307 const char *tagline,
2309 const char *actionButtonText,
2317 .text = actionButtonText};
2320 appName, appIcon, tagline, withSettings, &homeAction, topRightCallback, quitCallback);
2340 const char *appName,
2342 const char *tagline,
2343 const char *subTagline,
2351 .centeredInfo.text1 = plugInName,
2353 .centeredInfo.offsetY = -16,
2356 .tapActionText = NULL,
2358 .topRightToken = CONTINUE_TOKEN,
2359 .actionButtonText = NULL,
2360 .tuneId = TUNE_TAP_CASUAL};
2363 if (tagline == NULL) {
2364 snprintf(appDescription,
2366 "This app confirms actions for\n%s.",
2373 if (subTagline == NULL) {
2381 onContinue = topRightCallback;
2382 onQuit = quitCallback;
2413 onQuit = quitCallback;
2414 onNav = navCallback;
2415 onControls = controlsCallback;
2417 navType = SETTINGS_NAV;
2420 prepareNavInfo(
false, nbPages, NULL);
2422 displaySettingsPage(initPage,
true);
2444 memset(&genericContext, 0,
sizeof(genericContext));
2447 onQuit = quitCallback;
2448 pageTitle = appName;
2449 navType = GENERIC_NAV;
2451 if (settingContents != NULL) {
2454 if (infosList != NULL) {
2455 genericContext.hasFinishingContent =
true;
2458 memcpy(&FINISHING_CONTENT.content, infosList,
sizeof(
nbgl_content_u));
2462 uint8_t nbPages = nbgl_useCaseGetNbPagesForGenericContents(&genericContext.genericContents, 0);
2463 if (infosList != NULL) {
2464 nbPages += nbgl_useCaseGetNbPagesForContent(&FINISHING_CONTENT, nbPages,
true);
2467 prepareNavInfo(
false, nbPages, NULL);
2469 displayGenericContextPage(initPage,
true);
2508 const char *appName,
2510 const char *tagline,
2518 nbgl_homeAndSettingsContext_t *context = &bundleNavContext.homeAndSettings;
2520 context->appName = appName;
2521 context->appIcon = appIcon;
2522 context->tagline = tagline;
2523 context->settingContents = settingContents;
2524 context->infosList = infosList;
2525 if (action != NULL) {
2531 context->quitCallback = quitCallback;
2534 bundleNavStartSettingsAtPage(initSettingPage);
2537 bundleNavStartHome();
2553 .tickerCallback = &tickerCallback,
2554 .tickerIntervale = 0,
2557 onQuit = quitCallback;
2559 #ifdef HAVE_PIEZO_SOUND
2560 io_seproxyhal_play_tune(TUNE_LEDGER_MOMENT);
2568 .centeredInfo.icon = &C_Denied_Circle_64px,
2570 .centeredInfo.onTop =
false,
2572 .centeredInfo.text1 = message,
2573 .centeredInfo.text2 = NULL,
2574 .centeredInfo.text3 = NULL,
2575 .tapActionText =
"",
2576 .isSwipeable =
false,
2577 .tapActionToken = QUIT_TOKEN,
2579 .actionButtonText = NULL,
2580 .tuneId = TUNE_TAP_CASUAL};
2597 switch (reviewStatusType) {
2599 msg =
"Operation signed";
2603 msg =
"Operation rejected";
2607 msg =
"Transaction signed";
2611 msg =
"Transaction rejected";
2615 msg =
"Message signed";
2619 msg =
"Message rejected";
2623 msg =
"Address verified";
2627 msg =
"Address verification\ncancelled";
2649 const char *message,
2650 const char *subMessage,
2651 const char *confirmText,
2652 const char *cancelText,
2659 .centeredInfo.text2 = subMessage,
2660 .centeredInfo.text3 = NULL,
2662 .centeredInfo.icon = icon,
2663 .centeredInfo.offsetY = 0,
2664 .confirmationText = confirmText,
2665 .confirmationToken = CHOICE_TOKEN,
2666 .tuneId = TUNE_TAP_CASUAL,
2669 if ((confirmText == NULL) || (cancelText == NULL)) {
2672 onChoice = callback;
2691 const char *subMessage,
2692 const char *confirmText,
2693 const char *cancelText,
2699 .centeredInfo.text1 = message,
2700 .centeredInfo.text2 = subMessage,
2701 .centeredInfo.text3 = NULL,
2703 .centeredInfo.icon = &C_Important_Circle_64px,
2704 .centeredInfo.offsetY = 0,
2705 .confirmationText = confirmText,
2706 .confirmationToken = CHOICE_TOKEN,
2707 .tuneId = TUNE_TAP_CASUAL,
2709 onModalConfirm = callback;
2726 const char *reviewTitle,
2727 const char *reviewSubTitle,
2728 const char *rejectText,
2735 .footerToken = QUIT_TOKEN,
2736 .tapActionText = NULL,
2737 .isSwipeable =
true,
2738 .tapActionToken = CONTINUE_TOKEN,
2740 .actionButtonText = NULL,
2741 .tuneId = TUNE_TAP_CASUAL};
2748 onQuit = rejectCallback;
2749 onContinue = continueCallback;
2751 #ifdef HAVE_PIEZO_SOUND
2753 io_seproxyhal_play_tune(TUNE_LOOK_AT_ME);
2775 const char *rejectText,
2783 onChoice = choiceCallback;
2784 onNav = navCallback;
2785 onControls = buttonCallback;
2786 forwardNavOnly =
false;
2787 navType = REVIEW_NAV;
2791 prepareNavInfo(
true, nbPages, getRejectReviewText(
TYPE_OPERATION));
2793 displayReviewPage(initPage,
true);
2820 onChoice = choiceCallback;
2821 onNav = navCallback;
2822 onControls = buttonCallback;
2823 forwardNavOnly =
true;
2824 navType = REVIEW_NAV;
2834 displayReviewPage(0,
true);
2861 onChoice = choiceCallback;
2862 onNav = navCallback;
2863 onControls = buttonCallback;
2864 forwardNavOnly =
true;
2865 navType = REVIEW_NAV;
2871 displayReviewPage(0,
false);
2888 const char *rejectText,
2894 memset(&genericContext, 0,
sizeof(genericContext));
2897 onChoice = callback;
2898 navType = GENERIC_NAV;
2902 genericContext.genericContents.contentsList = localContentsList;
2905 if (tagValueList != NULL && tagValueList->
nbPairs != 0) {
2907 memcpy(&localContentsList[offset].content.tagValueList,
2914 memcpy(&localContentsList[offset].content.infoLongPress,
2920 genericContext.genericContents.nbContents = offset;
2923 uint8_t nbPages = nbgl_useCaseGetNbPagesForGenericContents(&genericContext.genericContents, 0);
2925 prepareNavInfo(
true, nbPages, getRejectReviewText(
TYPE_OPERATION));
2927 displayGenericContextPage(0,
true);
2945 const char *rejectText,
2951 memset(&genericContext, 0,
sizeof(genericContext));
2954 onChoice = callback;
2955 navType = GENERIC_NAV;
2958 genericContext.genericContents.contentsList = localContentsList;
2961 if (tagValueList != NULL && tagValueList->
nbPairs != 0) {
2963 memcpy(&localContentsList[offset].content.tagValueList,
2977 genericContext.genericContents.nbContents = offset;
2980 uint8_t nbPages = nbgl_useCaseGetNbPagesForGenericContents(&genericContext.genericContents, 0);
2982 prepareNavInfo(
true, nbPages, getRejectReviewText(
TYPE_OPERATION));
2984 displayGenericContextPage(0,
true);
3006 const char *reviewTitle,
3007 const char *reviewSubTitle,
3008 const char *finishTitle,
3011 useCaseReview(operationType,
3043 const char *reviewTitle,
3044 const char *reviewSubTitle,
3045 const char *finishTitle,
3049 useCaseReview(operationType,
3083 const char *reviewTitle,
3084 const char *reviewSubTitle,
3085 const char *finishTitle,
3089 memset(&blindSigningContext, 0,
sizeof(blindSigningContext));
3091 blindSigningContext.isStreaming =
false;
3093 blindSigningContext.tagValueList = tagValueList;
3094 blindSigningContext.icon = icon;
3095 blindSigningContext.reviewTitle = reviewTitle;
3096 blindSigningContext.reviewSubTitle = reviewSubTitle;
3097 blindSigningContext.finishTitle = finishTitle;
3098 blindSigningContext.tipBox = tipBox;
3099 blindSigningContext.choiceCallback = choiceCallback;
3101 blindSigningWarning();
3122 const char *reviewTitle,
3123 const char *reviewSubTitle,
3124 const char *finishTitle,
3127 useCaseReview(operationType,
3148 const char *rejectText,
3152 memset(&genericContext, 0,
sizeof(genericContext));
3155 onQuit = rejectCallback;
3156 navType = GENERIC_NAV;
3163 uint8_t nbPages = nbgl_useCaseGetNbPagesForGenericContents(&genericContext.genericContents, 0);
3164 prepareNavInfo(
true, nbPages, rejectText);
3167 #ifdef HAVE_PIEZO_SOUND
3169 io_seproxyhal_play_tune(TUNE_LOOK_AT_ME);
3172 displayGenericContextPage(0,
true);
3189 const char *reviewTitle,
3190 const char *reviewSubTitle,
3193 useCaseReviewStreamingStart(
3194 operationType, icon, reviewTitle, reviewSubTitle, choiceCallback,
true);
3212 const char *reviewTitle,
3213 const char *reviewSubTitle,
3216 memset(&blindSigningContext, 0,
sizeof(blindSigningContext));
3218 blindSigningContext.isStreaming =
true;
3220 blindSigningContext.icon = icon;
3221 blindSigningContext.reviewTitle = reviewTitle;
3222 blindSigningContext.reviewSubTitle = reviewSubTitle;
3223 blindSigningContext.choiceCallback = choiceCallback;
3225 blindSigningWarning();
3246 memset(&genericContext, 0,
sizeof(genericContext));
3248 bundleNavContext.reviewStreaming.choiceCallback = choiceCallback;
3249 bundleNavContext.reviewStreaming.skipCallback = skipCallback;
3252 onChoice = bundleNavReviewStreamingChoice;
3253 navType = STREAMING_NAV;
3256 genericContext.genericContents.contentsList = localContentsList;
3257 genericContext.genericContents.nbContents = 1;
3266 bundleNavContext.reviewStreaming.stepPageNb
3267 = nbgl_useCaseGetNbPagesForGenericContents(&genericContext.genericContents, 0);
3268 prepareNavInfo(
true,
3270 getRejectReviewText(bundleNavContext.reviewStreaming.operationType));
3278 displayGenericContextPage(0,
true);
3309 memset(&genericContext, 0,
sizeof(genericContext));
3311 bundleNavContext.reviewStreaming.choiceCallback = choiceCallback;
3314 onChoice = bundleNavReviewStreamingChoice;
3315 navType = STREAMING_NAV;
3318 genericContext.genericContents.contentsList = localContentsList;
3319 genericContext.genericContents.nbContents = 1;
3324 prepareReviewLastPage(&STARTING_CONTENT.content.infoLongPress,
3325 bundleNavContext.reviewStreaming.icon,
3329 bundleNavContext.reviewStreaming.stepPageNb
3330 = nbgl_useCaseGetNbPagesForGenericContents(&genericContext.genericContents, 0);
3331 prepareNavInfo(
true, 1, getRejectReviewText(bundleNavContext.reviewStreaming.operationType));
3333 displayGenericContextPage(0,
true);
3346 memset(&detailsContext, 0,
sizeof(detailsContext));
3352 detailsContext.tag = tag;
3353 detailsContext.value = value;
3355 detailsContext.currentPage = 0;
3356 detailsContext.wrapping = wrapping;
3358 if (detailsContext.nbPages > 1) {
3359 uint16_t nbLostChars = (detailsContext.nbPages - 1) * 3;
3368 detailsContext.nbPages++;
3372 displayDetailsPage(0,
true);
3406 memset(&genericContext, 0,
sizeof(genericContext));
3407 memset(&addressConfirmationContext, 0,
sizeof(addressConfirmationContext));
3410 onChoice = callback;
3411 navType = GENERIC_NAV;
3414 genericContext.genericContents.contentsList = localContentsList;
3415 genericContext.genericContents.nbContents = (tagValueList == NULL) ? 1 : 2;
3417 prepareAddressConfirmationPages(
3418 address, tagValueList, &STARTING_CONTENT, &localContentsList[1]);
3421 uint8_t nbPages = nbgl_useCaseGetNbPagesForGenericContents(&genericContext.genericContents, 0);
3423 prepareNavInfo(
true, nbPages,
"Cancel");
3425 #ifdef HAVE_PIEZO_SOUND
3427 io_seproxyhal_play_tune(TUNE_LOOK_AT_ME);
3430 displayGenericContextPage(0,
true);
3452 const char *reviewTitle,
3453 const char *reviewSubTitle,
3457 memset(&genericContext, 0,
sizeof(genericContext));
3458 memset(&addressConfirmationContext, 0,
sizeof(addressConfirmationContext));
3461 onChoice = choiceCallback;
3462 navType = GENERIC_NAV;
3466 genericContext.genericContents.contentsList = localContentsList;
3467 genericContext.genericContents.nbContents = (additionalTagValueList == NULL) ? 2 : 3;
3472 prepareReviewFirstPage(
3473 &STARTING_CONTENT.content.extendedCenter.contentCenter, icon, reviewTitle, reviewSubTitle);
3474 STARTING_CONTENT.content.extendedCenter.contentCenter.subText =
"Swipe to continue";
3477 prepareAddressConfirmationPages(
3478 address, additionalTagValueList, &localContentsList[1], &localContentsList[2]);
3481 uint8_t nbPages = nbgl_useCaseGetNbPagesForGenericContents(&genericContext.genericContents, 0);
3483 prepareNavInfo(
true, nbPages,
"Cancel");
3485 #ifdef HAVE_PIEZO_SOUND
3487 io_seproxyhal_play_tune(TUNE_LOOK_AT_ME);
3490 displayGenericContextPage(0,
true);
3530 tune_index_e tuneId,
3534 keypadGenericUseCase(title,
3541 validatePinCallback,
3568 tune_index_e tuneId,
3572 keypadGenericUseCase(title,
3579 validatePinCallback,
@ LARGE_CASE_INFO
text in BLACK and large case (INTER 32px), subText in black in Inter24px
nbgl_contentTagValue_t *(* nbgl_contentTagValueCallback_t)(uint8_t pairIndex)
prototype of tag/value pair retrieval callback
@ INFO_LONG_PRESS
a centered info and a long press button
@ EXTENDED_CENTER
a centered content and a possible tip-box
@ CHOICES_LIST
list of choices through radio buttons
@ CENTERED_INFO
a centered info
@ SWITCHES_LIST
list of switches with descriptions
@ TAG_VALUE_DETAILS
a tag/value pair and a small button to get details.
@ INFOS_LIST
list of infos with titles
@ TAG_VALUE_CONFIRM
tag/value pairs and a black button/footer to confirm/cancel.
@ TAG_VALUE_LIST
list of tag/value pairs
@ BARS_LIST
list of touchable bars (with > on the right to go to sub-pages)
@ INFO_BUTTON
a centered info and a simple black button
@ ENS_ALIAS
alias comes from ENS
@ ADDRESS_BOOK_ALIAS
alias comes from Address Book
void(* nbgl_contentActionCallback_t)(int token, uint8_t index, int page)
prototype of function to be called when an action on a content object occurs
#define LOG_DEBUG(__logger,...)
bool nbgl_getTextMaxLenInNbLines(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, uint16_t maxNbLines, uint16_t *len, bool wrapping)
compute the len of the given text (in bytes) fitting in the given maximum nb lines,...
void nbgl_textReduceOnNbLines(nbgl_font_id_e fontId, const char *origText, uint16_t maxWidth, uint8_t nbLines, char *reducedText, uint16_t reducedTextLen)
Create a reduced version of given ASCII text to wrap it on the given max width (in pixels),...
uint16_t nbgl_getTextHeightInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
return the height of the given multiline text, with the given font.
uint16_t nbgl_getTextNbLinesInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
compute the number of lines of the given text fitting in the given maxWidth
void(* nbgl_layoutTouchCallback_t)(int token, uint8_t index)
prototype of function to be called when an object is touched
#define SIMPLE_FOOTER_HEIGHT
int nbgl_layoutAddTextContent(nbgl_layout_t *layout, const char *title, const char *description, const char *info)
Creates in the main container three text areas:
int nbgl_layoutUpdateKeypad(nbgl_layout_t *layout, uint8_t index, bool enableValidate, bool enableBackspace, bool enableDigits)
Updates an existing keypad on bottom of the screen, with the given configuration.
#define TEXT_SUBTEXT_MARGIN
int nbgl_layoutAddQRCode(nbgl_layout_t *layout, const nbgl_layoutQRCode_t *info)
Creates an area on the center of the main panel, with a QRCode, a possible text in black (bold) under...
int nbgl_layoutAddCenteredInfo(nbgl_layout_t *layout, const nbgl_layoutCenteredInfo_t *info)
Creates an area on the center of the main panel, with a possible icon/image, a possible text in black...
#define TOUCHABLE_BAR_HEIGHT
int nbgl_layoutDraw(nbgl_layout_t *layout)
Applies given layout. The screen will be redrawn.
@ WHITE_BACKGROUND
rounded bordered button, with text/icon in black, on white background
@ BLACK_BACKGROUND
rounded bordered button, with text/icon in white, on black background
void * nbgl_layout_t
type shared externally
@ HEADER_EMPTY
empty space, to have a better vertical centering of centered info
@ HEADER_BACK_AND_TEXT
back key and optional text
#define SMALL_FOOTER_HEIGHT
int nbgl_layoutAddKeypadContent(nbgl_layout_t *layout, const char *title, bool hidden, uint8_t nbDigits, const char *text)
Adds an area with a title and a placeholder for hidden digits on top of a keypad, to represent the en...
int nbgl_layoutUpdateKeypadContent(nbgl_layout_t *layout, bool hidden, uint8_t nbActiveDigits, const char *text)
Updates an existing set of hidden digits, with the given configuration.
#define NBGL_NO_PROGRESS_INDICATOR
To be used when a control token shall not be used.
#define POST_SUBTEXT_MARGIN
int nbgl_layoutAddHeader(nbgl_layout_t *layout, const nbgl_layoutHeader_t *headerDesc)
Creates a touchable (or not) area at the header of the screen, containing various controls,...
#define SMALL_CENTERING_HEADER
int nbgl_layoutRelease(nbgl_layout_t *layout)
Release the layout obtained with nbgl_layoutGet()
int nbgl_layoutAddFooter(nbgl_layout_t *layout, const char *text, uint8_t token, tune_index_e tuneId)
Creates a touchable text at the footer of the screen, separated with a thin line from the rest of the...
int nbgl_layoutAddKeypad(nbgl_layout_t *layout, keyboardCallback_t callback, bool shuffled)
Adds a keypad on bottom of the screen, with the associated callback.
nbgl_layout_t * nbgl_layoutGet(const nbgl_layoutDescription_t *description)
returns a layout of the given type. The layout is reset
void nbgl_refresh(void)
This functions refreshes the actual screen on display with what has changed since the last refresh.
#define KEYPAD_MAX_DIGITS
void nbgl_refreshSpecial(nbgl_refresh_mode_t mode)
This functions refreshes the actual screen on display with what has changed since the last refresh,...
void nbgl_refreshSpecialWithPostRefresh(nbgl_refresh_mode_t mode, nbgl_post_refresh_t post_refresh)
nbgl_page_t * nbgl_pageDrawGenericContent(nbgl_layoutTouchCallback_t onActionCallback, const nbgl_pageNavigationInfo_t *nav, nbgl_pageContent_t *content)
draw a generic content page, with the given content, and if nav parameter is not NULL,...
nbgl_page_t * nbgl_pageDrawSpinner(nbgl_layoutTouchCallback_t onActionCallback, const char *text)
draw a spinner page with the given parameters. The spinner will "rotate" automatically every 800 ms
nbgl_page_t * nbgl_pageDrawLedgerInfo(nbgl_layoutTouchCallback_t onActionCallback, const nbgl_screenTickerConfiguration_t *ticker, const char *text, int tapActionToken)
draw a page with a centered text in large case, with a round check icon
void * nbgl_page_t
type shared externally
@ NAV_WITH_BUTTONS
move forward and backward with buttons in bottom nav bar
nbgl_page_t * nbgl_pageDrawGenericContentExt(nbgl_layoutTouchCallback_t onActionCallback, const nbgl_pageNavigationInfo_t *nav, nbgl_pageContent_t *content, bool modal)
draw a generic content page, with the given content, and if nav parameter is not NULL,...
nbgl_page_t * nbgl_pageDrawInfo(nbgl_layoutTouchCallback_t onActionCallback, const nbgl_screenTickerConfiguration_t *ticker, const nbgl_pageInfoDescription_t *info)
draw a page with a centered info (icon and/or texts) with a touchable footer, in a potential "tapable...
int nbgl_pageRelease(nbgl_page_t *)
Release the page obtained with any of the nbgl_pageDrawXXX() functions.
nbgl_page_t * nbgl_pageDrawConfirmation(nbgl_layoutTouchCallback_t onActionCallback, const nbgl_pageConfirmationDescription_t *info)
draw a confirmation page, with a centered info (icon and/or text), a button to confirm and a footer t...
@ QUIT_APP_TEXT
A full width button with "Quit app" text (only for bottom button)
@ INFO_ICON
info (i) icon in the button.
@ NO_BUTTON_STYLE
no button.
@ SETTINGS_ICON
settings (wheel) icon in the button.
struct PACKED__ nbgl_screenTickerConfiguration_s nbgl_screenTickerConfiguration_t
struct to configure a screen layer
void nbgl_screenRedraw(void)
This function redraws the whole screen on top of stack and its children.
@ POST_REFRESH_FORCE_POWER_ON
Force screen power on after refresh.
struct PACKED__ nbgl_icon_details_s nbgl_icon_details_t
Represents all information about an icon.
nbgl_refresh_mode_t
different modes of refresh for nbgl_refreshSpecial()
@ FULL_COLOR_CLEAN_REFRESH
to be used for lock screen display (cleaner but longer refresh)
@ BLACK_AND_WHITE_FAST_REFRESH
to be used for pure B&W area, when contrast is not priority
@ FULL_COLOR_PARTIAL_REFRESH
to be used for small partial refresh (radio buttons, switches)
@ FULL_COLOR_REFRESH
to be used for normal refresh
API of the Advanced BOLOS Graphical Library, for typical application use-cases.
#define NB_MAX_LINES_IN_REVIEW
maximum number of lines for value field in review pages
void(* nbgl_callback_t)(void)
prototype of generic callback function
void nbgl_useCasePlugInHome(const char *plugInName, const char *appName, const nbgl_icon_details_t *appIcon, const char *tagline, const char *subTagline, bool withSettings, nbgl_callback_t topRightCallback, nbgl_callback_t quitCallback)
#define SKIPPABLE_OPERATION
This is to use in nbgl_operationType_t when the operation is skippable. This is used.
void nbgl_useCaseHomeExt(const char *appName, const nbgl_icon_details_t *appIcon, const char *tagline, bool withSettings, const char *actionButtonText, nbgl_callback_t actionCallback, nbgl_callback_t topRightCallback, nbgl_callback_t quitCallback)
void nbgl_useCaseGenericSettings(const char *appName, uint8_t initPage, const nbgl_genericContents_t *settingContents, const nbgl_contentInfoList_t *infosList, nbgl_callback_t quitCallback)
void nbgl_useCaseKeypadPIN(const char *title, uint8_t minDigits, uint8_t maxDigits, uint8_t backToken, bool shuffled, tune_index_e tuneId, nbgl_pinValidCallback_t validatePinCallback, nbgl_layoutTouchCallback_t actionCallback)
uint32_t nbgl_operationType_t
This mask is used to describe the type of operation to review with additional options It is a mask of...
void nbgl_useCaseReview(nbgl_operationType_t operationType, const nbgl_contentTagValueList_t *tagValueList, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, const char *finishTitle, nbgl_choiceCallback_t choiceCallback)
uint8_t nbgl_useCaseGetNbTagValuesInPage(uint8_t nbPairs, const nbgl_contentTagValueList_t *tagValueList, uint8_t startIndex, bool *requireSpecificDisplay)
void nbgl_useCaseAddressConfirmationExt(const char *address, nbgl_choiceCallback_t callback, const nbgl_contentTagValueList_t *tagValueList)
uint8_t nbgl_useCaseGetNbPagesForTagValueList(const nbgl_contentTagValueList_t *tagValueList)
void nbgl_useCaseViewDetails(const char *tag, const char *value, bool wrapping)
void nbgl_useCaseReviewStreamingStart(nbgl_operationType_t operationType, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseHomeAndSettings(const char *appName, const nbgl_icon_details_t *appIcon, const char *tagline, const uint8_t initSettingPage, const nbgl_genericContents_t *settingContents, const nbgl_contentInfoList_t *infosList, const nbgl_homeAction_t *action, nbgl_callback_t quitCallback)
void nbgl_useCaseStaticReviewLight(const nbgl_contentTagValueList_t *tagValueList, const nbgl_pageInfoLongPress_t *infoLongPress, const char *rejectText, nbgl_choiceCallback_t callback)
uint8_t nbgl_useCaseGetNbInfosInPage(uint8_t nbInfos, const nbgl_contentInfoList_t *infosList, uint8_t startIndex, bool withNav)
void(* nbgl_choiceCallback_t)(bool confirm)
prototype of choice callback function
uint8_t nbgl_useCaseGetNbBarsInPage(uint8_t nbBars, const nbgl_contentBarsList_t *barsList, uint8_t startIndex, bool withNav)
#define INFOS_AREA_HEIGHT
height available for infos pairs display
void nbgl_useCaseSettings(const char *settingsTitle, uint8_t initPage, uint8_t nbPages, bool touchableTitle, nbgl_callback_t quitCallback, nbgl_navCallback_t navCallback, nbgl_layoutTouchCallback_t controlsCallback)
@ STRONG_HOME_ACTION
Black button, implicating the main action of the App.
void nbgl_useCaseReviewStreamingFinish(const char *finishTitle, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseSpinner(const char *text)
void nbgl_useCaseConfirm(const char *message, const char *subMessage, const char *confirmText, const char *rejectText, nbgl_callback_t callback)
#define NB_MAX_LINES_IN_DETAILS
maximum number of lines for value field in details pages
void nbgl_useCaseReviewStart(const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, const char *rejectText, nbgl_callback_t continueCallback, nbgl_callback_t rejectCallback)
void nbgl_useCaseForwardOnlyReview(const char *rejectText, nbgl_layoutTouchCallback_t buttonCallback, nbgl_navCallback_t navCallback, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseKeypadDigits(const char *title, uint8_t minDigits, uint8_t maxDigits, uint8_t backToken, bool shuffled, tune_index_e tuneId, nbgl_pinValidCallback_t validatePinCallback, nbgl_layoutTouchCallback_t actionCallback)
#define APP_DESCRIPTION_MAX_LEN
Length of buffer used for the default Home tagline.
void nbgl_useCaseForwardOnlyReviewNoSkip(const char *rejectText, nbgl_layoutTouchCallback_t buttonCallback, nbgl_navCallback_t navCallback, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseStatus(const char *message, bool isSuccess, nbgl_callback_t quitCallback)
void nbgl_useCaseGenericConfiguration(const char *title, uint8_t initPage, const nbgl_genericContents_t *contents, nbgl_callback_t quitCallback)
#define INIT_HOME_PAGE
Value to pass to nbgl_useCaseHomeAndSettings() initSettingPage parameter to initialize the use case o...
void nbgl_useCaseReviewStreamingContinueExt(const nbgl_contentTagValueList_t *tagValueList, nbgl_choiceCallback_t choiceCallback, nbgl_callback_t skipCallback)
void nbgl_useCaseReviewBlindSigning(nbgl_operationType_t operationType, const nbgl_contentTagValueList_t *tagValueList, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, const char *finishTitle, const nbgl_tipBox_t *tipBox, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseChoice(const nbgl_icon_details_t *icon, const char *message, const char *subMessage, const char *confirmText, const char *rejectString, nbgl_choiceCallback_t callback)
void nbgl_useCaseHome(const char *appName, const nbgl_icon_details_t *appIcon, const char *tagline, bool withSettings, nbgl_callback_t topRightCallback, nbgl_callback_t quitCallback)
#define TAG_VALUE_AREA_HEIGHT
height available for tag/value pairs display
#define BLIND_OPERATION
This is to use in nbgl_operationType_t when the operation is "blind" This is used to indicate a warni...
#define TAGLINE_PART1
Default strings used in the Home tagline.
void nbgl_useCaseAddressConfirmation(const char *address, nbgl_choiceCallback_t callback)
void nbgl_useCaseGenericReview(const nbgl_genericContents_t *contents, const char *rejectText, nbgl_callback_t rejectCallback)
void nbgl_useCaseRegularReview(uint8_t initPage, uint8_t nbPages, const char *rejectText, nbgl_layoutTouchCallback_t buttonCallback, nbgl_navCallback_t navCallback, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseStaticReview(const nbgl_contentTagValueList_t *tagValueList, const nbgl_pageInfoLongPress_t *infoLongPress, const char *rejectText, nbgl_choiceCallback_t callback)
void nbgl_useCaseReviewStreamingBlindSigningStart(nbgl_operationType_t operationType, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseAdvancedReview(nbgl_operationType_t operationType, const nbgl_contentTagValueList_t *tagValueList, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, const char *finishTitle, const nbgl_tipBox_t *tipBox, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseReviewStreamingContinue(const nbgl_contentTagValueList_t *tagValueList, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseReviewLight(nbgl_operationType_t operationType, const nbgl_contentTagValueList_t *tagValueList, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, const char *finishTitle, nbgl_choiceCallback_t choiceCallback)
uint8_t nbgl_useCaseGetNbChoicesInPage(uint8_t nbChoices, const nbgl_contentRadioChoice_t *choicesList, uint8_t startIndex, bool withNav)
void nbgl_useCaseReviewStatus(nbgl_reviewStatusType_t reviewStatusType, nbgl_callback_t quitCallback)
#define LAST_PAGE_FOR_REVIEW
value of page parameter used with navigation callback when "skip" button is touched,...
nbgl_reviewStatusType_t
The different types of review status.
@ STATUS_TYPE_TRANSACTION_REJECTED
@ STATUS_TYPE_ADDRESS_REJECTED
@ STATUS_TYPE_TRANSACTION_SIGNED
@ STATUS_TYPE_OPERATION_REJECTED
@ STATUS_TYPE_OPERATION_SIGNED
@ STATUS_TYPE_ADDRESS_VERIFIED
@ STATUS_TYPE_MESSAGE_SIGNED
@ STATUS_TYPE_MESSAGE_REJECTED
bool(* nbgl_navCallback_t)(uint8_t page, nbgl_pageContent_t *content)
prototype of navigation callback function
#define MAX_APP_NAME_FOR_SDK_TAGLINE
Max supported length of appName used for the default Home tagline.
void nbgl_useCaseAddressReview(const char *address, const nbgl_contentTagValueList_t *additionalTagValueList, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, nbgl_choiceCallback_t choiceCallback)
nbgl_opType_t
The different types of operation to review.
@ TYPE_TRANSACTION
For operations transferring a coin or taken from an account to another.
@ TYPE_OPERATION
For other types of operation (generic type)
void(* nbgl_pinValidCallback_t)(const uint8_t *content, uint8_t page)
prototype of pin validation callback function
uint8_t nbgl_useCaseGetNbSwitchesInPage(uint8_t nbSwitches, const nbgl_contentSwitchesList_t *switchesList, uint8_t startIndex, bool withNav)
This structure contains data to build a BARS_LIST content.
const uint8_t * tokens
array of tokens, one for each bar (nbBars items)
const char *const * barTexts
array of texts for each bar (nbBars items, in black/bold)
uint8_t nbBars
number of elements in barTexts and tokens array
This structure contains info to build a centered (vertically and horizontally) area,...
uint16_t iconHug
vertical margin to apply on top and bottom of the icon
const nbgl_icon_details_t * icon
the icon (can be null)
const char * title
title in black large (can be null)
const char * description
description in black small regular case (can be null)
const char * subText
sub-text in dark gray regular small case
bool padding
if true, apply a padding of 40px at the bottom
const char * smallTitle
sub-title in black small bold case (can be null)
This structure contains info to build a centered (vertically and horizontally) area,...
const char * text2
second text (can be null)
const char * text1
first text (can be null)
nbgl_contentCenteredInfoStyle_t style
style to apply to this info
int16_t offsetY
vertical shift to apply to this info (if >0, shift to bottom)
const char * text3
third text (can be null)
const nbgl_icon_details_t * icon
a buffer containing the 1BPP icon
This structure contains data to build a centered info + simple black button content.
const char * buttonText
text of the long press button
const nbgl_icon_details_t * icon
a buffer containing the 1BPP icon
const char * text
centered text in large case
This structure contains data to build a INFOS_LIST content.
uint8_t nbInfos
number of elements in infoTypes and infoContents array
const char *const * infoContents
array of contents of infos (in black)
const char *const * infoTypes
array of types of infos (in black/bold)
This structure contains data to build a centered info + long press button content.
const char * longPressText
text of the long press button
const nbgl_icon_details_t * icon
a buffer containing the 1BPP icon
const char * text
centered text in large case
This structure contains a list of names to build a list of radio buttons (on the right part of screen...
uint8_t initChoice
index of the current choice
const char *const * names
array of strings giving the choices (nbChoices)
uint8_t nbChoices
number of choices
This structure contains info to build a switch (on the right) with a description (on the left),...
This structure contains [item,value] pair(s) and info about a potential "details" button,...
const char * confirmationText
text of the confirmation button, if NULL "It matches" is used
uint8_t detailsButtonToken
uint8_t confirmationToken
the token used as argument of the onActionCallback
nbgl_contentTagValueList_t tagValueList
list of tag/value pairs
const char * detailsButtonText
this text is used for "details" button (if NULL, no button)
const nbgl_icon_details_t * detailsButtonIcon
icon to use in details button
This structure contains a list of [tag,value] pairs.
nbgl_contentActionCallback_t actionCallback
called when a valueIcon is touched on a given pair
const nbgl_contentTagValue_t * pairs
array of [tag,value] pairs (nbPairs items). If NULL, callback is used instead
bool wrapping
if set to true, value text will be wrapped on ' ' to avoid cutting words
uint8_t startIndex
index of the first pair to get with callback
nbgl_contentTagValueCallback_t callback
function to call to retrieve a given pair
uint8_t nbMaxLinesForValue
This structure contains a [tag,value] pair.
const nbgl_contentValueExt_t * extension
if not NULL, gives additional info on value field
const nbgl_icon_details_t * valueIcon
int8_t centeredInfo
if set to 1, the tag will be displayed as a centered info
const char * value
string giving the value name
const char * item
string giving the tag name
const char * fullValue
full string of the value when used as an alias
nbgl_contentValueAliasType_t aliasType
type of alias
This structure contains data to build a content.
nbgl_contentActionCallback_t contentActionCallback
callback to be called when an action on an object occurs
nbgl_contentType_t type
type of page content in the content union
uint8_t nbContents
number of contents
const nbgl_content_t * contentsList
array of nbgl_content_t (nbContents items).
nbgl_contentCallback_t contentGetterCallback
function to call to retrieve a given content
Structure describing the action button in Home Screen.
const nbgl_icon_details_t * icon
icon to use in action button in Home page
nbgl_callback_t callback
function to call when action button is touched in Home page
const char * text
text to use in action button in Home page
nbgl_homeActionStyle_t style
style of action button
Structure containing all information when creating a layout. This structure must be passed as argumen...
nbgl_layoutTouchCallback_t onActionCallback
the callback to be called on any action on the layout
This structure contains info to build a centered (vertically and horizontally) area,...
const char * text2
second text (can be null)
const char * url
URL for QR code.
Structure containing all specific information when creating a confirmation page.
const char * cancelText
the text used for cancel action, if NULL a simple X button is used
Structure containing all specific information when creating an information page.
nbgl_layoutButtonStyle_t actionButtonStyle
style of "action" button
const char * actionButtonText
if not NULL an "action" button is set under the centered info
uint8_t bottomButtonsToken
const nbgl_icon_details_t * actionButtonIcon
potential icon of "action" button
nbgl_pageButtonStyle_t bottomButtonStyle
style to apply to the Bottom button
nbgl_layoutCenteredInfo_t centeredInfo
description of the centered info to be used
Structure containing all specific information when creating a multi-screens page.
uint8_t nbPages
the number of pages to display (if <2, no navigation bar)
uint8_t quitToken
the token used as argument of the actionCallback when the footer is touched
uint8_t skipToken
if skipText is NULL the token used when right part of footer is touched
nbgl_pageNavigationType_t navType
uint8_t activePage
the index of the page to display at start-up
bool progressIndicator
if set to true, display a progress indicator on top of the page
nbgl_pageNavWithButtons_t navWithButtons
structure used when navigation with buttons
tune_index_e tuneId
if not NBGL_NO_TUNE, a tune will be played when next or back is pressed
bool visiblePageIndicator
if set to true, the page indicator will be visible in navigation
const char * quitText
the text displayed in footer (on the left), used to quit (only on Flex)
bool backButton
if set to true, a back button (<-) is displayed in the nav bar
This structure contains data to build a SWITCHES_LIST content.
uint8_t nbSwitches
number of elements in switches and tokens array
const nbgl_contentSwitch_t * switches
array of switches (nbSwitches items)
Structure containing all specific information when creating a NBGL step.
The necessary parameters to build a tip-box in first review page and the modal if this tip box is tou...
const nbgl_contentInfoList_t infos
infos pairs displayed in modal.
const char * modalTitle
title given to modal window displayed when tip-box is touched
const char * text
text of the tip-box
nbgl_contentType_t type
type of page content in the following union
const nbgl_icon_details_t * icon
icon of the tip-box
Union of the different type of contents.
nbgl_contentInfoList_t infosList
INFOS_LIST type
nbgl_contentInfoLongPress_t infoLongPress
INFO_LONG_PRESS type
nbgl_contentTagValueConfirm_t tagValueConfirm
TAG_VALUE_CONFIRM type
nbgl_contentTagValueList_t tagValueList
TAG_VALUE_LIST type
nbgl_contentCenteredInfo_t centeredInfo
CENTERED_INFO type
nbgl_contentBarsList_t barsList
BARS_LIST type
nbgl_contentExtendedCenter_t extendedCenter
EXTENDED_CENTER type
nbgl_contentSwitchesList_t switchesList
SWITCHES_LIST type
nbgl_contentInfoButton_t infoButton
INFO_BUTTON type
nbgl_contentRadioChoice_t choicesList
CHOICES_LIST type