#include "TuiPinpadScreen.h"
#include "TZ_Vendor_tl.h"
#include "tci.h"
#include "tl_tui_bc_error_msg.h"
#include "Vendor_Interface.h"
#include "TuiPng.h"
#include "TuiScreenProperty.h"
#include "TuiPinpadState.h"
#include "spay_pin_random_util_tl.h"
#include "ta_log.h"
#include "TuiLayout.h"

#if defined(USE_BF)
#include "TZ_Vendor_tl.h"
#include "BF_TZ_debug.h"
#include "bf_spay_tui.h"
#endif

#if defined(UX3_0)
#if defined(DPI640)
#if defined(SUPPORT_SOFTKEY)
#include "softkey_resource_1440x2560-640dpi_3_0.h"
#elif defined(SUPPORT_SOFTKEY_PUNCHCUT)
#include "punchCut_resource_1440x2560-640dpi_3_0.h"
#else
#include "resource_1440x2560-640dpi_3_0.h"
#endif
#elif defined(DPI480)
#if defined(SUPPORT_SOFTKEY)
#include "softkey_resource_1080x1920-480dpi_3_0.h"
#elif defined(SUPPORT_SOFTKEY_PUNCHCUT)
#include "punchCut_resource_1080x1920-480dpi_3_0.h"
#elif defined(SUPPORT_SOFTKEY_PUNCHHOLE)
#include "punchHole_resource_1080x1920-480dpi_3_0.h"
#elif defined(SUPPORT_DISPLAY_HIDE_NOTCH)
#include "punchHole_hide_camera_resource_1080x1920-480dpi_3_0.h"
#elif defined(SUPPORT_DUAL_LCD_MAIN)
#include "dualMain_resource_1536x2152-480dpi_3_0.h"
#else
#include "resource_1080x1920-480dpi_3_0.h"
#endif
#elif defined(DPI320)
#if defined(SUPPORT_SOFTKEY)
#include "softkey_resource_720x1280-320dpi_3_0.h"
#elif defined(SUPPORT_SOFTKEY_PUNCHCUT)
#include "punchCut_resource_720x1280-320dpi_3_0.h"
#elif defined(SUPPORT_DUAL_LCD_SUB)
#include "dualSub_resource_720x1680-320dpi_3_0.h"
#else
#include "resource_720x1280-320dpi_3_0.h"
#endif
#else
#if defined(SUPPORT_SOFTKEY)
#include "softkey_resource_1440x2560-640dpi_3_0.h"
#elif defined(SUPPORT_SOFTKEY_PUNCHCUT)
#include "punchCut_resource_1440x2560-640dpi_3_0.h"
#else
#include "resource_1440x2560-640dpi_3_0.h"
#endif
#endif
#endif

#define CHECK_INT_OVERFLOW(a, b) \
		((uint32_t)a + (uint32_t)b < (uint32_t)a || (uint32_t)a + (uint32_t)b < (uint32_t)b)

extern preference_t g_preference;

loadable_img_t g_loadable_img[RES_END - RES_BACKGROUND] = { 0 };
uint8_t g_pin[PIN_SIZE];
uint32_t g_pin_length = 0;
uint8_t g_pin_verify[PIN_SIZE];
uint32_t g_pin_verify_len = 0;
uint8_t g_min_pin_len = US_PIN_SIZE;
uint8_t g_pin_old[PIN_SIZE];	// existing pin
uint32_t g_pin_old_len = 0;
coordinate_t pin_coordinate[PIN_SIZE];	// the (x,y) for each star cache buffer. (optimization, only x needs to be an array. All y is the same)
uint8_t g_current_button;
uint64_t backspace_press_start;
uint8_t g_close_tui_after_verify;
uint64_t tui_verify_timestamp = 0;
bool g_display_normal_pinbox = true;
bool g_cancel_button_enabled = false;

/** getTouchedKey() - Translate x,y coordinates into key
 *
 * @param x                 x coordinate of touch event
 * @param y                 y coordinate of touch event
 * @param[out] touched_key  key structure of touched key
 *
 * Loops over the layout structure to find the pressed key.
 * If found, copies the key description into touched_key.
 * Otherwise, <NULL> key is returned.
 *
 * @return  true upon success or false upon not found
 */
uint32_t getTouchedKey(
	uint32_t x,
	uint32_t y,
	sPinPadKey_t * const touched_key
)
{
	const sPinPadKey_t *key;
	uint32_t ret = 0;
	sLayout_t *layout = (sLayout_t *)& g_pinpad_layout;
	*touched_key = layout->buttons_array[0];
	int i, j;

#if defined(SUPPORT_SOFTKEY) || defined(SUPPORT_SOFTKEY_PUNCHCUT) || defined(SUPPORT_SOFTKEY_PUNCHHOLE) || defined(SUPPORT_DISPLAY_HIDE_NOTCH) || defined(SUPPORT_DUAL_LCD_MAIN) || defined(SUPPORT_DUAL_LCD_SUB)
	// lookup softkey first:
	for (i = 0; i < SOFTKEY_SIZE; i++) {
		key = g_preference.isBHR ? &g_softkey_bhr[i] : &g_softkey[i];
#if defined(SUPPORT_DUAL_LCD_MAIN)
		DBG_LOG("%s softkey: New Compare (%d,%d) and (xLeft=%d yBottom=%d xRight=%d yTop=%d) isBHR=%d",
			LOG_TAG, x, y, getScreenWidth() - key->yBottom, key->xLeft, getScreenWidth() - key->yTop, key->xRight, g_preference.isBHR);
		if (y >= key->xLeft && y <= key->xRight &&
			x <= getScreenWidth() - key->yTop && x >= getScreenWidth() - key->yBottom) {
			memcpy(touched_key, key, sizeof(sPinPadKey_t));
			return 0;
		}

#else
		DBG_LOG("%s softkey: Compare (%d,%d) and (xLeft=%d yTop=%d xRight=%d yBottom=%d) isBHR=%d",
			LOG_TAG, x, y, key->xLeft, key->yTop, key->xRight, key->yBottom, g_preference.isBHR);
		if (x >= key->xLeft && x <= key->xRight &&
			y <= key->yBottom && y >= key->yTop) {
			memcpy(touched_key, key, sizeof(sPinPadKey_t));
			return 0;
		}
#endif
	}
#endif

	i = 1;
	j = PINPAD_SIZE - 2;

	for (; i <= j; i++) {
		key = &layout->buttons_array[i];
#if defined(SUPPORT_DUAL_LCD_MAIN)
		DBG_LOG("%s New Compare (%d,%d) and (xLeft=%d yBottom=%d xRight=%d yTop=%d)",
			LOG_TAG, x, y, getScreenWidth() - key->yBottom, key->xLeft, getScreenWidth() - key->yTop, key->xRight);
		if (y >= key->xLeft && y <= key->xRight &&
			x <= getScreenWidth() - key->yTop && x >= getScreenWidth() - key->yBottom) {
			memcpy(touched_key, key, sizeof(sPinPadKey_t));
			break;
			//return true;
		}
#else
		DBG_LOG("%s Compare (%d,%d) and (xLeft=%d yTop=%d xRight=%d yBottom=%d)",
			LOG_TAG, x, y, key->xLeft, key->yTop, key->xRight, key->yBottom);
		if (x >= key->xLeft && x <= key->xRight &&
			y <= key->yBottom && y >= key->yTop) {
			memcpy(touched_key, key, sizeof(sPinPadKey_t));
			break;
			//return true;
		}
#endif
	}
	return ret;
}


static int checkImageBounds(
	uint32_t type,
	uint32_t x,
	uint32_t y,
	uint32_t width,
	uint32_t height
)
{
	int ret = 0;
	uint32_t screenWidth = getScreenWidth();
	uint32_t screenHeight = getScreenHeight();

	DBG_LOG("%s gets started!", __func__);

	if (x >= screenWidth || width > screenWidth ||
		CHECK_INT_OVERFLOW(x, width) || x + width > screenWidth ||
		y >= screenHeight || height > screenHeight ||
		CHECK_INT_OVERFLOW(y, height) ||
		y + height > screenHeight) {
		STORE_TA_ERROR("%s invalid image size and/or coordinates! type[%d]x[%d]w[%d]y[%d]h[%d]gw[%d]gh[%d]",
			LOG_TAG, type, x, width, y, height, screenWidth, screenHeight);
		return TIMA_ERROR_TUI_IMG_BAD_FORMAT;
	}

	DBG_LOG("%s Type ACTION_BAR_TEXT[1], SECURE_MODE_TEXT[2], PROMPT_ABOVE_PINBOX[3], PROMPT_BELOW_PINBOX[4]", LOG_TAG);
	DBG_LOG("%s image size and/or coordinates! type[%d] x[%d] w[%d] y[%d] h[%d] gw[%d] gh[%d]",
		LOG_TAG, type, x, width, y, height, screenWidth, screenHeight);

#if defined(SUPPORT_DUAL_LCD_MAIN)
	uint32_t y_bottom = screenWidth - x;
#else
	uint32_t y_bottom = y + height;
#endif
	uint32_t len = 0;
	switch (type) {
	case RES_ACTION_BAR_TEXT:
		if (y_bottom > PINPAD_SECURE_MODE_TEXT_TOP * SCREEN_PIX_PER_DP) {
			ret = TIMA_ERROR_TUI_IMG_BAD_FORMAT;
		}
		break;
	case RES_SECURE_MODE_TEXT:
		len = (PINPAD_SECURE_ICON_WIDTH + PINPAD_SECURE_ICON_TEXT_DISTANCE) * SCREEN_PIX_PER_DP;
		if (CHECK_INT_OVERFLOW(len, width)
			|| len + width > screenWidth
			|| y_bottom > PINPAD_LINE1_TOP_HD) {
			ret = TIMA_ERROR_TUI_IMG_BAD_FORMAT;
		}
		break;
	case RES_PROMPT_ABOVE_PINBOX:
	case RES_PROMPT_BELOW_PINBOX:
		if (y < PINPAD_ACTION_BAR_TOP + PINPAD_ACTION_BAR_HEIGHT
			|| y_bottom > PINPAD_LINE1_TOP_HD) {
			ret = TIMA_ERROR_TUI_IMG_BAD_FORMAT;
		}
		break;
	case RES_NORMAL_PINBOX:
	case RES_ERROR_PINBOX:
	case RES_DISABLED_PINBOX:
		if (y < PINPAD_ACTION_BAR_TOP + PINPAD_ACTION_BAR_HEIGHT
			|| y_bottom > PINPAD_LINE1_TOP_HD) {
			ret = TIMA_ERROR_TUI_IMG_BAD_FORMAT;
		}
		break;
	default:
		return TIMA_ERROR_TUI_IMG_BAD_FORMAT;

	}
	if (ret) {
		STORE_TA_ERROR("%s: failed type:%d", __func__, type);
	}
	return ret;
}

/*
 * Load images from normal world
 */
uint32_t loadPinpadImage(
	uint32_t type,
	uint8_t * buf,
	uint32_t len,
	uint32_t x_dp,
	uint32_t y_dp
)
{
	uint32_t width, height;
	uint8_t *p;
	uint32_t old_prompt_width = 0, old_prompt_height = 0;
	uint32_t screenWidth = getScreenWidth();
	uint32_t screenHeight = getScreenHeight();
	uint32_t softkeyHeight = PINPAD_SOFTKEY_HEIGHT;
	uint32_t bottomBarHeight = PINPAD_BOTTOM_BAR_HEIGHT;

	if (type >= RES_END) {
		STORE_TA_ERROR("%s invalid loadable resource type: %d", LOG_TAG, type);
		return TIMA_ERROR_INVALID_ARGUMENT;
	}
	// free old resource
	if (g_loadable_img[type].len > 0) {
		DBG_LOG("%s free old resource", LOG_TAG);
		if (type == RES_PROMPT_ABOVE_PINBOX
			|| type == RES_PROMPT_BELOW_PINBOX) {
			old_prompt_width = g_loadable_img[type].width;
			old_prompt_height = g_loadable_img[type].height;
		}

		TZ_free(g_loadable_img[type].pointer);
		memset(&g_loadable_img[type], 0, sizeof(loadable_img_t));
	}
	// allocate for new resource
	DBG_LOG("%s allocate buffer %d", LOG_TAG, len);
	p = (uint8_t *)TZ_malloc(len);
	if (p == NULL) {
		STORE_TA_ERROR("%s Cannot allocate buffer (%d) for loadable images!",
			LOG_TAG, len);
		return TIMA_ERROR_OUT_OF_MEMORY;
	}

	DBG_LOG("%s allocated pointer %p", LOG_TAG, p);

	memcpy(p, buf, len);

	if (validatePng(p, len, &width, &height)) {
		STORE_TA_ERROR("%s resource (%d) is not a valid png image!", LOG_TAG,
			type);
		TZ_free(p);
		return TIMA_ERROR_TUI_IMG_BAD_FORMAT;
	}

	if (screenWidth < width || screenHeight < height) {
		STORE_TA_ERROR("%s Prompt width/height is greater than screen width/height!",
			LOG_TAG);
		TZ_free(p);
		return TIMA_ERROR_TUI_IMG_BAD_FORMAT;
	}

	if (type == RES_PROMPT_ABOVE_PINBOX || type == RES_PROMPT_BELOW_PINBOX) {
		if (g_pinbox_y == 0) {
			STORE_TA_ERROR("%s Must set PIN box first!", LOG_TAG);
			TZ_free(p);
			return SPAY_TPP_ERROR_INVALID_NUMBER_OF_PIN;
		}

		DBG_LOG("%s screen width!, %d, Prompt width  %d", LOG_TAG, screenWidth, width);
#if defined(SUPPORT_DUAL_LCD_MAIN)
		// x_dp = 0, y_dp = dis_to_pinbox_dp
		g_loadable_img[type].y = (screenHeight - height) >> 1;

		if (type == RES_PROMPT_ABOVE_PINBOX) {
			g_loadable_img[type].x = screenWidth -
				(g_pinbox_y - (y_dp * (screenHeight - softkeyHeight) / (STANDARD_SCREEN_HEIGHT_DP - STANDARD_SOFTKEY_HEIGHT_DP)) - width) - width;
		}
		else {
			g_loadable_img[type].x = screenWidth -
				(g_pinbox_y + (y_dp * (screenHeight - softkeyHeight) / (STANDARD_SCREEN_HEIGHT_DP - STANDARD_SOFTKEY_HEIGHT_DP)) + g_pinbox_height) - width;
		}
#else
		// x_dp = 0, y_dp = dis_to_pinbox_dp
		g_loadable_img[type].x = (screenWidth - width) >> 1;

		if (type == RES_PROMPT_ABOVE_PINBOX) {
#if defined(SUPPORT_DISPLAY_HIDE_NOTCH)
			g_loadable_img[type].y = g_pinbox_y -
				y_dp * (screenHeight - bottomBarHeight - softkeyHeight) / (STANDARD_SCREEN_HEIGHT_DP - STANDARD_BOTTOM_BAR_HEIGHT_DP - STANDARD_SOFTKEY_HEIGHT_DP) - height;
#else
			g_loadable_img[type].y = g_pinbox_y -
				y_dp * (screenHeight - softkeyHeight) / (STANDARD_SCREEN_HEIGHT_DP - STANDARD_SOFTKEY_HEIGHT_DP) - height;
#endif
		}
		else {
#if defined(SUPPORT_DISPLAY_HIDE_NOTCH)
			g_loadable_img[type].y = g_pinbox_y + g_pinbox_height +
				y_dp * (screenHeight - bottomBarHeight - softkeyHeight) / (STANDARD_SCREEN_HEIGHT_DP - STANDARD_BOTTOM_BAR_HEIGHT_DP - STANDARD_SOFTKEY_HEIGHT_DP);
#else
			g_loadable_img[type].y = g_pinbox_y + g_pinbox_height +
				y_dp * (screenHeight - softkeyHeight) / (STANDARD_SCREEN_HEIGHT_DP - STANDARD_SOFTKEY_HEIGHT_DP);
#endif
		}
#endif
		DBG_LOG("%s prompt: width=%d, height=%d, old_w=%d, old_h=%d", LOG_TAG, width, height, old_prompt_width, old_prompt_height);

		if (width >= old_prompt_width && height >= old_prompt_height) {
			g_loadable_img[type].new_prompt_covers_old_prompt = true;
		}

	}
	else if (type == RES_ACTION_BAR_TEXT) {
#if defined(SUPPORT_DUAL_LCD_MAIN)
		uint32_t x = 0;
		uint32_t y = y_dp * screenHeight / STANDARD_SCREEN_HEIGHT_DP;
		if (g_preference.isRTL) {
			if (screenHeight - height < y) {
				return TIMA_ERROR_TUI_IMG_BAD_FORMAT;
			}
			g_loadable_img[type].y = screenHeight - (x_dp * 3) - height; //screenWidth - (x_dp * 3) - width; // Check DP : Tedd
		}
		else {
			g_loadable_img[type].y = x_dp * 3; // Check DP : Tedd
		}

		g_loadable_img[type].x = screenWidth - PINPAD_ACTION_BAR_TOP - PINPAD_ACTION_BAR_HEIGHT + ((PINPAD_ACTION_BAR_HEIGHT - width) / 2) - 4;
#else
		uint32_t x = x_dp * screenWidth / STANDARD_SCREEN_WIDTH_DP;
		if (g_preference.isRTL) {
			if (screenWidth - width < x) {
				return TIMA_ERROR_TUI_IMG_BAD_FORMAT;
			}
			g_loadable_img[type].x = screenWidth - x - width;
		}
		else {
			g_loadable_img[type].x = x;
		}

		g_loadable_img[type].y = PINPAD_ACTION_BAR_TOP + (PINPAD_ACTION_BAR_HEIGHT - height) / 2;
#endif
#if defined(SUPPORT_DUAL_LCD_MAIN)
	}
	else if (type == RES_SECURE_MODE_TEXT) {
		g_loadable_img[type].x = screenWidth - (y_dp * (screenHeight - softkeyHeight) / (STANDARD_SCREEN_HEIGHT_DP - STANDARD_SOFTKEY_HEIGHT_DP));
		g_loadable_img[type].y = x_dp * screenWidth / STANDARD_SCREEN_WIDTH_DP;
#endif
	}
	else {
		g_loadable_img[type].x =
			x_dp * screenWidth / STANDARD_SCREEN_WIDTH_DP;
#if defined(SUPPORT_DISPLAY_HIDE_NOTCH)
		g_loadable_img[type].y =
			y_dp * (screenHeight - bottomBarHeight - softkeyHeight) / (STANDARD_SCREEN_HEIGHT_DP - STANDARD_BOTTOM_BAR_HEIGHT_DP - STANDARD_SOFTKEY_HEIGHT_DP);
#elif defined(SUPPORT_DUAL_LCD_MAIN)
		g_loadable_img[type].x =
			screenWidth - (y_dp * screenHeight / STANDARD_SCREEN_HEIGHT_DP);
		g_loadable_img[type].y =
			x_dp * (screenWidth - softkeyHeight) / (STANDARD_SCREEN_WIDTH_DP - STANDARD_SOFTKEY_HEIGHT_DP);
#else
		g_loadable_img[type].x =
			x_dp * screenWidth / STANDARD_SCREEN_WIDTH_DP;
		g_loadable_img[type].y =
			y_dp * (screenHeight - softkeyHeight) / (STANDARD_SCREEN_HEIGHT_DP - STANDARD_SOFTKEY_HEIGHT_DP);
#endif
	}

	// Out of buffer check
	int chk_ret = checkImageBounds(type, g_loadable_img[type].x,
		g_loadable_img[type].y, width, height);
	if (chk_ret != 0) {
		TZ_free(p);
		return chk_ret;
	}

	g_loadable_img[type].pointer = p;
	g_loadable_img[type].len = len;
	g_loadable_img[type].width = width;
	g_loadable_img[type].height = height;
	g_loadable_img[type].to_display = true;

	DBG_LOG("%s loadable image: len=%d, w=%d, h=%d, x=%d, y=%d", LOG_TAG,
		len, width, height, g_loadable_img[type].x,
		g_loadable_img[type].y);

	return TIMA_SUCCESS;
}

uint32_t drawPinpadImage(
	uint32_t id,
	uint32_t x,
	uint32_t y
)
{
	uint8_t *png_buffer;
	uint32_t png_buffer_len;

	if (id < (sizeof(resource) / sizeof(resource[0]))) {
		png_buffer = resource[id];
		png_buffer_len = sizes[id];
	}
	else {
		STORE_TA_ERROR("%s no image resource for %d", LOG_TAG, id);
		return TIMA_ERROR_TUI_NO_RESOURCE;
	}

	DBG_LOG("show image id = %d", id);

	if (id == IDX_CANCEL && g_loadable_img[RES_CANCEL_BUTTON].len > 0) {
		png_buffer = g_loadable_img[RES_CANCEL_BUTTON].pointer;
		png_buffer_len = g_loadable_img[RES_CANCEL_BUTTON].len;
	}
	else if (id == IDX_CANCEL_PRESSED
		&& g_loadable_img[RES_CANCEL_BUTTON_PRESSED].len > 0) {
		png_buffer = g_loadable_img[RES_CANCEL_BUTTON_PRESSED].pointer;
		png_buffer_len = g_loadable_img[RES_CANCEL_BUTTON_PRESSED].len;
	}
	//TTY_LOG("%s show_image %d at (%d, %d)", LOG_TAG, id, x, y);

	return drawImage(x, y, png_buffer, png_buffer_len);
}

/** add_pin() - Display PIN dot at index
 *
 * @param keynum    Digit that was entered
 *
 * @return  TLAPI_OK upon success or specific error
 */
uint32_t addPin(uint8_t keynum) {
	uint32_t x, y;
	uint32_t ret;
	uint32_t screenWidth = getScreenWidth();
	uint32_t screenHeight = getScreenHeight();

#if defined(SUPPORT_DUAL_LCD_MAIN)
	uint32_t len = (screenHeight - g_min_pin_len * g_pinbox_width - (g_min_pin_len - 1) * g_pinbox_space) >> 1;

	y = len;	// the first PIN box
	y = y + g_pin_length * (g_pinbox_width + g_pinbox_space) + ((g_pinbox_width - PINPAD_STAR_SIZE) >> 1);	// where the pin is
	x = screenWidth - (g_pinbox_y + ((g_pinbox_height - PINPAD_STAR_SIZE) >> 1)) - PINPAD_PIN_BOX_IMG_HEIGHT + g_pinbox_height - PINPAD_STAR_SIZE;
#else
	uint32_t len = (screenWidth - g_min_pin_len * g_pinbox_width - (g_min_pin_len - 1) * g_pinbox_space) >> 1;

	x = len;	// the first PIN box
	x = x + g_pin_length * (g_pinbox_width + g_pinbox_space) + ((g_pinbox_width - PINPAD_STAR_SIZE) >> 1);	// where the pin is
	y = g_pinbox_y + ((g_pinbox_height - PINPAD_STAR_SIZE) >> 1);
#endif
	pin_coordinate[g_pin_length].x = x;
	pin_coordinate[g_pin_length].y = y;

	++g_pin_length;

	if (!g_display_normal_pinbox) {
		// display error pin dot if the png is available
		ret = drawPinpadImage(IDX_PINPAD_STAR_ERROR, x, y);
		if (ret) {
			return drawPinpadImage(IDX_PINPAD_STAR, x, y);
		} else {
			return 0;
		}
	} else {
		return drawPinpadImage(IDX_PINPAD_STAR, x, y);
	}
}

/** remove_pin() - Display blank image at index
 *
 * @return  TIMA_SUCCESS upon success or specific error
 */
uint32_t removePin() {
	--g_pin_length;
	return drawPinpadImage(IDX_PINPAD_BLANK, pin_coordinate[g_pin_length].x,
		pin_coordinate[g_pin_length].y);
}

/**
 */
uint32_t removeAllPin() {
	uint32_t ret = 0;
	while (g_pin_length > 0) {
		ret = removePin();
		if (ret)
			break;
	}
	return ret;
}

/** setButtonImage() - set Image of one pinpad button
 *
 * @param touched_key    Button that was touched
 * @param pressed        Pressed or released
 *
 * Prepares the tlApiTuiSetImage() call to show the negative picture of the button.
 *
 * @return  TLAPI_OK upon success or specific error
 */
uint32_t setButtonImage(sPinPadKey_t key, bool pressed) {
	uint8_t provIdx;

	if (key.val == PAD_SOFTKEY_BACK_VAL) {
		if (g_preference.isRTL) {
			provIdx = pressed ? IDX_SOFTKEY_BACK_PRESSED_RTL : IDX_SOFTKEY_BACK_RTL;
		} else {
			provIdx = pressed ? IDX_SOFTKEY_BACK_PRESSED : IDX_SOFTKEY_BACK;
		}
	} else {
		/* Calculate the provisionning index with the button value */
		provIdx = key.val + IDX_PINPAD_0;
		if (pressed) {
			provIdx += IDX_DELTA_PRESSED;
		}
	}
#if defined(SUPPORT_DUAL_LCD_MAIN)
	if (key.val == PAD_SOFTKEY_BACK_VAL)
		return drawPinpadImage(provIdx, getScreenWidth() - key.yTop - PINPAD_SOFTKEY_HEIGHT, key.xLeft);
	else
		return drawPinpadImage(provIdx, getScreenWidth() - key.yTop - PINPAD_KEY_HEIGHT, key.xLeft);
#else
	return drawPinpadImage(provIdx, key.xLeft, key.yTop);
#endif
}

/** setReleasedButtonImage() - set Image of one pinpad button
 *
 * @param value    Value of the button to display
 *
 * Prepares the tlApiTuiSetImage() call to show the picture of the released button.
 *
 * @return  TLAPI_OK upon success or specific error
 */
uint32_t setReleasedButtonImage(uint8_t value) {
	const sPinPadKey_t *key;
	uint32_t ret = TIMA_SUCCESS;
	sLayout_t *layout = (sLayout_t *)& g_pinpad_layout;
#if defined(SUPPORT_SOFTKEY) || defined(SUPPORT_SOFTKEY_PUNCHCUT) || defined(SUPPORT_SOFTKEY_PUNCHHOLE) || defined(SUPPORT_DISPLAY_HIDE_NOTCH) || defined(SUPPORT_DUAL_LCD_MAIN) || defined(SUPPORT_DUAL_LCD_SUB)
	// lookup softkey first:
	for (int i = 0; i < SOFTKEY_SIZE; i++) {
		key = g_preference.isBHR ? &g_softkey_bhr[i] : &g_softkey[i];
		DBG_LOG("key->val:%d value=%d", key->val, value);
		if (key->val == value) {
			ret = setButtonImage(*key, false);
			return ret;
		}
	}
#endif
	for (int i = 1; i <= PINPAD_SIZE; i++) {
		key = &layout->buttons_array[i];
		if (key->val == value) {
			DBG_LOG("button val:%d value=%d", key->val, value);
			ret = setButtonImage(*key, false);
			break;
		}
	}
	return ret;
}

uint32_t processKeyEvent(uint32_t x, uint32_t y, bool pressed) {
	uint32_t ret = TIMA_SUCCESS;
	sPinPadKey_t touched_key;
	uint32_t ret_st = getPinpadState();
	DBG_LOG("%s processKeyEvent start: getPinpadState() = 0x%x", LOG_TAG, getPinpadState());
	getTouchedKey(x, y, &touched_key);

	DBG_LOG("%s touched_key.type = %d, touched_key.val = %d, pressed = %d",
		LOG_TAG, touched_key.type, touched_key.val, pressed);

#ifndef PIN_ENTER_BUTTON_ENABLED
	if (touched_key.type == PAD_VALIDATE) {
		// ignore the enter button. no state change
		return ret_st;
	}
#endif

	if (touched_key.type == PAD_CANCEL) {
		return SPAY_TUI_ST_CANCELLED;
	}

	if (touched_key.type == PAD_VALIDATE && g_pin_length < g_min_pin_len) {
		return ret_st;
	}

	if (pressed) {
		/* Set the pressed button image. But do not set it continuously during long press */
		if (touched_key.val != g_current_button
			&& g_current_button != PAD_KEY_OUT_VAL) {
			if (g_current_button != PAD_NOKEY_VAL) {
				/* Reset the picture of the previous touched button */
				DBG_LOG("TUI: release %d", g_current_button);
				ret = setReleasedButtonImage(g_current_button);
				g_current_button = PAD_KEY_OUT_VAL;
			} else if (touched_key.type != NOKEY) {
				DBG_LOG("TUI: set %d", touched_key.val);
				ret = setButtonImage(touched_key, pressed);
				g_current_button = touched_key.val;
				if (touched_key.val == PAD_CORRECT_VAL) {
					backspace_press_start = getUptime();
				}
			}
			showFrameBuffer();
		} else if (g_current_button == PAD_CORRECT_VAL &&
			backspace_press_start > 0) {
			if (getUptime() - backspace_press_start >=
				BACKSPACE_LONG_PRESS) {
				DBG_LOG
				("TUI: backspace is pressed over 2 seconds");
				backspace_press_start = 0;
				removeAllPin();
				showFrameBuffer();
			}
		}

		/* Return: don't process data on pressing event */
		return (ret == 0 ? getPinpadState() : SPAY_TUI_ST_CANCELLED);
	} else {
		/* Reset the picture of the previous touched button */
		if (g_current_button < PAD_KEY_OUT_VAL) {
			ret = setReleasedButtonImage(g_current_button);
			DBG_LOG("TUI: l=[%d] release=[%d]", __LINE__, g_current_button);
			if (ret != TIMA_SUCCESS) {
				return SPAY_TUI_ST_CANCELLED;
			}
		} else {
#define USE_MOBICORE_XX
#ifdef USE_MOBICORE_XX
			//STORE_TA_ERROR("%s temporary solution for tbase, set touched button to released button", LOG_TAG);
			if (g_current_button != PAD_KEY_OUT_VAL) {
				// skip the case when dragged out of the pressed key and then released
				g_current_button = touched_key.val;
				setButtonImage(touched_key, true);
				setReleasedButtonImage(g_current_button);
			}
#else
			//STORE_TA_ERROR("%s Release but no button to reset. Do nothing.", LOG_TAG);
			g_current_button = PAD_NOKEY_VAL;
			return getPinpadState();
#endif

		}

		// if the released button is not the pressed button, do nothing
		if (touched_key.val != g_current_button) {
			g_current_button = PAD_NOKEY_VAL;
			DBG_LOG("TUI: showFrameBuffer() call forcely");
			showFrameBuffer();  //PLM P170327-03217 issue fixed.
			return getPinpadState();
		}
		g_current_button = PAD_NOKEY_VAL;
	}

	switch (touched_key.type) {
	case PAD_NUM:
		if (g_pin_length < g_min_pin_len) {
			g_pin[g_pin_length] = touched_key.val;
			ret = addPin(touched_key.val);
			if (ret != TIMA_SUCCESS) {
				ret_st = SPAY_TUI_ST_CANCELLED;
				break;
			}
#ifndef PIN_ENTER_BUTTON_ENABLED
			if (g_pin_length == g_min_pin_len) {
				ret_st = ((getPinpadState() & _SPAY_TUI_ST_REMOVE_START) | _SPAY_TUI_ST_ENTER);	// switch from start to enter
			}
#endif
		} else {
			////STORE_TA_ERROR("%s Ignoring entered key.", LOG_TAG);
		}
		break;
	case PAD_CORRECT:
		if (g_pin_length > 0) {
			ret = removePin();
			if (ret != TIMA_SUCCESS) {
				ret_st = SPAY_TUI_ST_CANCELLED;
			}
		}
		break;
	case PAD_CANCEL:
		// Ignore cancel button
		//STORE_TA_ERROR("%s CANCEL", LOG_TAG);
		//ret_st = SPAY_TUI_ST_CANCELLED;
		break;

	case PAD_VALIDATE:
		//STORE_TA_ERROR("%s PIN entered", LOG_TAG);
		ret_st = ((getPinpadState() & _SPAY_TUI_ST_REMOVE_START) | _SPAY_TUI_ST_ENTER);
		break;
	case PAD_SOFTKEY_BACK:
		setPinpadState(SPAY_TUI_ST_CANCELLED);
		ret_st = getPinpadState();
		DBG_LOG("%s PAD_SOFTKEY_BACK", LOG_TAG);
	default:
		break;
	}			/* switch(key) */
	showFrameBuffer();

	return ret_st;
}

// Display all PIN buttons
uint32_t displayPinButtons() {
	uint32_t ret;
	sPinPadKey_t *key;
	sLayout_t *layout = (sLayout_t *)& g_pinpad_layout;
	for (int i = 1; i <= PINPAD_SIZE; i++) {
		key = &layout->buttons_array[i];
#if defined(SUPPORT_DUAL_LCD_MAIN)
		ret = drawPinpadImage(key->val + IDX_PINPAD_0, getScreenWidth() - key->yTop - PINPAD_KEY_HEIGHT, key->xLeft);
#else
		ret = drawPinpadImage(key->val + IDX_PINPAD_0, key->xLeft, key->yTop);
#endif
		if (ret) {
			break;
		}
	}
	return ret;
}

// display PIN boxes
uint32_t displayPinBox(enum pin_box_type type) {
	uint32_t screenWidth = getScreenWidth();
	uint32_t screenHeight = getScreenHeight();
#if defined(SUPPORT_DUAL_LCD_MAIN)
	int i;
	uint32_t ret = 0;
	int y = 0;
	uint32_t len = 0;

	loadable_img_t *img = &(g_loadable_img[RES_NORMAL_PINBOX + type]);

	if (img->len == 0 || img->width == 0 || img->height == 0) {

		len = (screenHeight - g_min_pin_len * g_pinbox_width - (g_min_pin_len - 1) * g_pinbox_space) >> 1;
		if (len > (screenWidth >> 1)) {
			STORE_TA_ERROR("%s: invalid value! g_min_pin_len=%d g_pinbox_width=%d g_pinbox_space=%d",
				__func__, g_min_pin_len, g_pinbox_width, g_pinbox_space);
			return TIMA_ERROR_TUI_DISPLAY_ERROR;
		}

		DBG_LOG("%s: g_min_pin_len=%d g_pinbox_y=%d, g_pinbox_width=%d g_pinbox_height=%d g_pinbox_space=%d",
			__func__, g_min_pin_len, g_pinbox_y, g_pinbox_width, g_pinbox_height, g_pinbox_space);

		if (CHECK_INT_OVERFLOW(g_pinbox_y, g_pinbox_height)
			|| g_pinbox_y + g_pinbox_height < PINPAD_PIN_BOX_IMG_HEIGHT
			|| g_pinbox_y < PINPAD_ACTION_BAR_TOP + PINPAD_ACTION_BAR_HEIGHT
			|| g_pinbox_y + g_pinbox_height > PINPAD_SECURE_MODE_TEXT_TOP * SCREEN_PIX_PER_DP) {
			STORE_TA_ERROR("%s: invalid value! g_pinbox_y=%d g_pinbox_height=%d",
				__func__, g_pinbox_y, g_pinbox_height);
			return TIMA_ERROR_TUI_DISPLAY_ERROR;
		}
		DBG_LOG("%s display_pin_box len %d!", LOG_TAG, y);

		// display internal pin box
		for (i = 0; i < g_min_pin_len; i++) {
			y = len;	// the first PIN box
			drawPinpadImage(IDX_NORMAL_PINBOX + type,
				screenWidth - (g_pinbox_y + g_pinbox_height - PINPAD_PIN_BOX_IMG_HEIGHT) - g_pinbox_height,
				y + i * (g_pinbox_width + g_pinbox_space));
			/*
						drawPinpadImage(IDX_NORMAL_PINBOX + type,
							x + i * (g_pinbox_width + g_pinbox_space),
							g_pinbox_y + g_pinbox_height - PINPAD_PIN_BOX_IMG_HEIGHT);
			*/
			if (ret) {
				STORE_TA_ERROR("%s unable to display internal PIN box!", LOG_TAG);
				break;
			} else {
				DBG_LOG("%s displayed internal PIN box at (%d, %d)!", LOG_TAG,
					y + i * (g_pinbox_width + g_pinbox_space), g_pinbox_y + g_pinbox_height - PINPAD_PIN_BOX_IMG_HEIGHT);

				DBG_LOG("screenHeight=%d, g_min_pin_len=%d, g_pinbox_width=%d, g_pinbox_space=%d, g_pinbox_width=%d. g_pinbox_y=%d, g_pinbox_height=%d",
					screenHeight, g_min_pin_len,
					g_pinbox_width, g_pinbox_space,
					g_pinbox_width, g_pinbox_y,
					g_pinbox_height);

			}

		}
	} else {

		DBG_LOG("%s display loadable pinbox: %p, %d", LOG_TAG, img->pointer, img->len);
		y = (screenWidth - g_min_pin_len * img->width - (g_min_pin_len - 1) * g_pinbox_space) >> 1;
		for (i = 0; i < g_min_pin_len; i++) {
			ret = drawImage(screenWidth - (img->y) - g_pinbox_height, y + i * (img->width + g_pinbox_space), img->pointer, img->len);
			if (ret) {
				STORE_TA_ERROR("%s unable to display loadable PIN box!", LOG_TAG);
				break;
			} else {
				DBG_LOG("%s displayed PIN box!", LOG_TAG);
			}
		}
	}
	return ret;
#else
	int i;
	uint32_t ret = 0;
	int x = 0;
	uint32_t len = 0;

	loadable_img_t *img = &(g_loadable_img[RES_NORMAL_PINBOX + type]);

	if (img->len == 0 || img->width == 0 || img->height == 0) {

		len = (screenWidth - g_min_pin_len * g_pinbox_width - (g_min_pin_len - 1) * g_pinbox_space) >> 1;
		if (len > (screenWidth >> 1)) {
			STORE_TA_ERROR("%s: invalid value! g_min_pin_len=%d g_pinbox_width=%d g_pinbox_space=%d",
				__func__, g_min_pin_len, g_pinbox_width, g_pinbox_space);
			return TIMA_ERROR_TUI_DISPLAY_ERROR;
		}
		if (CHECK_INT_OVERFLOW(g_pinbox_y, g_pinbox_height)
			|| g_pinbox_y + g_pinbox_height < PINPAD_PIN_BOX_IMG_HEIGHT
			|| g_pinbox_y < PINPAD_ACTION_BAR_TOP + PINPAD_ACTION_BAR_HEIGHT
			|| g_pinbox_y + g_pinbox_height > PINPAD_SECURE_MODE_TEXT_TOP * SCREEN_PIX_PER_DP) {
			STORE_TA_ERROR("%s: invalid value! g_pinbox_y=%d g_pinbox_height=%d",
				__func__, g_pinbox_y, g_pinbox_height);
			return TIMA_ERROR_TUI_DISPLAY_ERROR;
		}
		DBG_LOG("%s display_pin_box len %d!", LOG_TAG, x);

		// display internal pin box
		for (i = 0; i < g_min_pin_len; i++) {
			x = len;	// the first PIN box
			drawPinpadImage(IDX_NORMAL_PINBOX + type,
				x + i * (g_pinbox_width + g_pinbox_space),
				g_pinbox_y + g_pinbox_height - PINPAD_PIN_BOX_IMG_HEIGHT);

			if (ret) {
				STORE_TA_ERROR("%s unable to display internal PIN box!", LOG_TAG);
				break;
			} else {
				DBG_LOG("%s displayed internal PIN box at (%d, %d)!", LOG_TAG,
					x + i * (g_pinbox_width + g_pinbox_space), g_pinbox_y + g_pinbox_height - PINPAD_PIN_BOX_IMG_HEIGHT);

				DBG_LOG
				("screenWidth=%d, g_min_pin_len=%d, g_pinbox_width=%d, g_pinbox_space=%d, g_pinbox_width=%d. g_pinbox_y=%d, g_pinbox_height=%d",
					screenWidth, g_min_pin_len,
					g_pinbox_width, g_pinbox_space,
					g_pinbox_width, g_pinbox_y,
					g_pinbox_height);

			}

		}
	} else {

		DBG_LOG("%s display loadable pinbox: %p, %d", LOG_TAG,
			img->pointer, img->len);
		x = (screenWidth - g_min_pin_len * img->width -
			(g_min_pin_len - 1) * g_pinbox_space) >> 1;
		for (i = 0; i < g_min_pin_len; i++) {
			ret = drawImage(x + i * (img->width + g_pinbox_space), img->y, img->pointer, img->len);
			if (ret) {
				STORE_TA_ERROR
				("%s unable to display loadable PIN box!",
					LOG_TAG);
				break;
			} else {
				//STORE_TA_ERROR("%s displayed PIN box!", LOG_TAG);
			}
		}
	}
	return ret;
#endif
}

// Display loadable images except PIN boxes
uint32_t displayLoadableResource() {
	uint32_t ret = 0;
	uint32_t screenWidth = getScreenWidth();
	uint32_t screenHeight = getScreenHeight();
	// display loadable background, prompts and cancel button
	for (uint32_t i = RES_BACKGROUND; i <= RES_CANCEL_BUTTON; i++) {
		if (g_loadable_img[i].width > 0 &&
			g_loadable_img[i].height > 0 &&
			g_loadable_img[i].to_display) {

			if (i == RES_SECURE_MODE_TEXT) {
				// special case
#if defined(SUPPORT_DUAL_LCD_MAIN) // NEED to fix about hardcorded coordinate after UX guide.
				uint32_t len = ((PINPAD_SECURE_ICON_WIDTH + PINPAD_SECURE_ICON_TEXT_DISTANCE) * SCREEN_PIX_PER_DP) + g_loadable_img[i].height;
				uint32_t y = g_preference.isRTL ?
					screenHeight - (screenHeight - len) / 2 - PINPAD_SECURE_ICON_WIDTH * SCREEN_PIX_PER_DP :
					((screenHeight - len) / 2); // (screenWidth - len) / 2;  // Tedd

				drawPinpadImage(IDX_SECURE_ICON, screenWidth - ((PINPAD_SECURE_ICON_TOP + PINPAD_SECURE_ICON_WIDTH) * SCREEN_PIX_PER_DP), y);

				ret = drawImage(screenWidth - ((PINPAD_SECURE_ICON_TOP + PINPAD_SECURE_ICON_WIDTH - 7) * SCREEN_PIX_PER_DP),
					g_preference.isRTL ?
					y - PINPAD_SECURE_ICON_TEXT_DISTANCE * SCREEN_PIX_PER_DP - g_loadable_img[i].height :
					y + (PINPAD_SECURE_ICON_WIDTH + PINPAD_SECURE_ICON_TEXT_DISTANCE) * SCREEN_PIX_PER_DP,
					g_loadable_img[i].pointer,
					g_loadable_img[i].len);
#else
				uint32_t len =
					(PINPAD_SECURE_ICON_WIDTH +
						PINPAD_SECURE_ICON_TEXT_DISTANCE) * SCREEN_PIX_PER_DP +
					g_loadable_img[i].width;
				uint32_t x = g_preference.isRTL ?
					screenWidth - (screenWidth - len) / 2 - PINPAD_SECURE_ICON_WIDTH * SCREEN_PIX_PER_DP :
					(screenWidth - len) / 2;
				drawPinpadImage(IDX_SECURE_ICON, x,
					PINPAD_SECURE_ICON_TOP * SCREEN_PIX_PER_DP);

				ret = drawImage(g_preference.isRTL ?
					x - PINPAD_SECURE_ICON_TEXT_DISTANCE * SCREEN_PIX_PER_DP - g_loadable_img[i].width :
					x + (PINPAD_SECURE_ICON_WIDTH + PINPAD_SECURE_ICON_TEXT_DISTANCE) * SCREEN_PIX_PER_DP,
					g_loadable_img[i].y,
					g_loadable_img[i].pointer,
					g_loadable_img[i].len);
#endif
			} else {
				ret = drawImage(g_loadable_img[i].x,
					g_loadable_img[i].y,
					g_loadable_img[i].pointer,
					g_loadable_img[i].len);
			}

			g_loadable_img[i].to_display = false;

			if (ret) {
				STORE_TA_ERROR
				("%s failed to display loadable img %d: len %d, x %d, y %d!",
					LOG_TAG, i, g_loadable_img[i].len,
					g_loadable_img[i].x, g_loadable_img[i].y);
				// return ret;
			} else {
#if defined(SUPPORT_DUAL_LCD_MAIN)
				DBG_LOG("%s display loadable img %d: len %d, x %d, y %d!",
					LOG_TAG, i, g_loadable_img[i].len,
					g_loadable_img[i].x, g_loadable_img[i].y);
#else
				DBG_LOG("%s display loadable img %d!",
					LOG_TAG, i);
#endif
			}
		} else {	/*
				//STORE_TA_ERROR("%s no loadable img (%d) to display: len=%d, w=%d, h=%d, x=%d, y=%d",
				LOG_TAG,
				i,
				g_loadable_img[i].len,
				g_loadable_img[i].width,
				g_loadable_img[i].height,
				g_loadable_img[i].x,
				g_loadable_img[i].y);
			  */
		}
	}
	return ret;
}

uint32_t launchPinpad(
	bool start_tui_session,
	enum pin_box_type pinbox_type
)
{
	uint32_t ret;
	g_cancel_button_enabled = false;

	if (start_tui_session) {
		if (g_preference.isBHR) {
			ret = startTuiSession(resource[IDX_PINPAD_PINPAD_BHR + g_preference.isRTL], sizes[IDX_PINPAD_PINPAD_BHR + g_preference.isRTL]);
		} else {
			ret = startTuiSession(resource[IDX_PINPAD_PINPAD + g_preference.isRTL], sizes[IDX_PINPAD_PINPAD + g_preference.isRTL]);
		}
		if (ret) {
			return ret;
		}

		if (isStartTuiWithBackground() == false) {
			// display PIN Pad
#if defined(SUPPORT_SOFTKEY) || defined(SUPPORT_SOFTKEY_PUNCHCUT) || defined(SUPPORT_SOFTKEY_PUNCHHOLE) || defined(SUPPORT_DISPLAY_HIDE_NOTCH) || defined(SUPPORT_DUAL_LCD_MAIN) || defined(SUPPORT_DUAL_LCD_SUB)
			if (g_preference.isBHR) {
				ret = drawPinpadImage(IDX_PINPAD_PINPAD_BHR + g_preference.isRTL, 0, 0);
			} else
#endif
			ret = drawPinpadImage(IDX_PINPAD_PINPAD + g_preference.isRTL, 0, 0);
			if (ret) {
				STORE_TA_ERROR("%s cannot display PIN background!. ret=0x%x", LOG_TAG, ret);
				return ret;
			}
		}

		DBG_LOG("%s open session done", LOG_TAG);

		ret = displayLoadableResource();
		if (ret) {
			STORE_TA_ERROR("%s Unable to display loadable image! ret=0x%x",
				LOG_TAG, ret);
			return ret;
		}

		ret = displayPinBox(pinbox_type);
		if (ret) {
			STORE_TA_ERROR("%s Unable to display pin box. ret=0x%x", LOG_TAG, ret);
		}
		DBG_LOG("%s display images done", LOG_TAG);
	} else {
		ret = updatePinpadScreen(pinbox_type);
	}

	showFrameBuffer();
	return ret;
}

uint32_t updatePinpadScreen(enum pin_box_type pinbox_type) {
	uint32_t ret;

	// update background and action bar text if changed
	for (uint32_t i = RES_BACKGROUND; i <= RES_ACTION_BAR_TEXT; i++) {
		if (g_loadable_img[i].width > 0 &&
			g_loadable_img[i].height > 0 &&
			g_loadable_img[i].to_display) {

			ret = drawImage(g_loadable_img[i].x,
				g_loadable_img[i].y,
				g_loadable_img[i].pointer,
				g_loadable_img[i].len);

			g_loadable_img[i].to_display = false;
		} else {

			DBG_LOG("%s No need to display resource %d", LOG_TAG,
				i);
		}

	}

	// TUI session is already started, check whether we need to clean all prompts first or not
	if ((g_loadable_img[RES_PROMPT_ABOVE_PINBOX].to_display &&
		g_loadable_img[RES_PROMPT_ABOVE_PINBOX].width > 0 &&
		g_loadable_img[RES_PROMPT_ABOVE_PINBOX].height > 0 &&
		!g_loadable_img
		[RES_PROMPT_ABOVE_PINBOX].new_prompt_covers_old_prompt)
		|| (g_loadable_img[RES_PROMPT_BELOW_PINBOX].to_display
			&& g_loadable_img[RES_PROMPT_BELOW_PINBOX].width > 0
			&& g_loadable_img[RES_PROMPT_BELOW_PINBOX].height > 0
			&&
			!g_loadable_img
			[RES_PROMPT_BELOW_PINBOX].new_prompt_covers_old_prompt)) {
		DBG_LOG
		("%s New prompt cannot fully cover the old prompt! above=%d, below=%d",
			LOG_TAG,
			g_loadable_img
			[RES_PROMPT_ABOVE_PINBOX].new_prompt_covers_old_prompt,
			g_loadable_img
			[RES_PROMPT_BELOW_PINBOX].new_prompt_covers_old_prompt);

		// remove prompts and pin boxes
		ret = drawPinpadImage(IDX_CLEAR_TEXT, 0, PINPAD_PROMPT_AREA_TOP);
		if (ret) {
			STORE_TA_ERROR("%s display error!", LOG_TAG);
			return ret;
		}
		// display prompts
		ret = displayLoadableResource();
		if (ret) {
			STORE_TA_ERROR("%s Unable to display loadable image!",
				LOG_TAG);
			return ret;
		}
		// display pin boxes
		ret = displayPinBox(pinbox_type);
		if (ret) {
			STORE_TA_ERROR("%s Unable to display pin box", LOG_TAG);
		}
	}
	else {
		DBG_LOG
		("%s New prompt can fully cover the old prompt! above=%d, below=%d",
			LOG_TAG,
			g_loadable_img
			[RES_PROMPT_ABOVE_PINBOX].new_prompt_covers_old_prompt,
			g_loadable_img
			[RES_PROMPT_BELOW_PINBOX].new_prompt_covers_old_prompt);

		// Only need to display prompts

		if (g_loadable_img[RES_PROMPT_ABOVE_PINBOX].to_display &&
			g_loadable_img[RES_PROMPT_ABOVE_PINBOX].width > 0 &&
			g_loadable_img[RES_PROMPT_ABOVE_PINBOX].height > 0) {
			ret =
				drawImage(g_loadable_img[RES_PROMPT_ABOVE_PINBOX].x,
					g_loadable_img[RES_PROMPT_ABOVE_PINBOX].y,
					g_loadable_img[RES_PROMPT_ABOVE_PINBOX].pointer,
					g_loadable_img[RES_PROMPT_ABOVE_PINBOX].len);
			g_loadable_img[RES_PROMPT_ABOVE_PINBOX].to_display =
				false;
		}

		if (g_loadable_img[RES_PROMPT_BELOW_PINBOX].to_display &&
			g_loadable_img[RES_PROMPT_BELOW_PINBOX].width > 0 &&
			g_loadable_img[RES_PROMPT_BELOW_PINBOX].height > 0) {
			ret = drawImage(g_loadable_img[RES_PROMPT_BELOW_PINBOX].x,
				g_loadable_img[RES_PROMPT_BELOW_PINBOX].y,
				g_loadable_img[RES_PROMPT_BELOW_PINBOX].pointer,
				g_loadable_img[RES_PROMPT_BELOW_PINBOX].len);
			g_loadable_img[RES_PROMPT_BELOW_PINBOX].to_display =
				false;
		}

		ret = displayPinBox(pinbox_type);
		if (ret) {
			STORE_TA_ERROR("%s Unable to display pin box", LOG_TAG);
		}

	}

	ret = showFrameBuffer();
	if (ret) {
		STORE_TA_ERROR("%s showFrameBuffer - TIMA_ERROR_TUI_DISPLAY_ERROR", LOG_TAG);
	}

	return ret;
}

/*
  Clean PIN and PIN dots
*/
void clearPinData() {
	// clear input PIN buffer
	memset(g_pin, 0, PIN_SIZE);
	g_pin_length = 0;
	g_current_button = PAD_NOKEY_VAL;
}

void clearLoadableResource() {
	int type;
	for (type = 0; type < RES_END - RES_BACKGROUND; type++) {
		if (g_loadable_img[type].pointer != 0) {
			DBG_LOG("clear loadable resource: %d", type);
			TZ_free(g_loadable_img[type].pointer);
			memset(&g_loadable_img[type], 0, sizeof(loadable_img_t));
		}
	}
}

uint32_t setPinpadTimer() {
	uint32_t ret = TZ_get_secure_timestamp(&tui_verify_timestamp);
	if (ret != TZ_API_OK) {
		TTY_LOG("%s Error fetching secure timestamp, Error: %d",
			LOG_TAG, ret);
		tui_verify_timestamp = 0;
	}
	DBG_LOG("%s TUI timer starts at: %lld"
		, LOG_TAG, tui_verify_timestamp);
	return ret;
}

bool isPinpadTimerExpired() {
	uint64_t current_timestamp = 0;
	uint32_t timer_val = 0;
	uint32_t ret = TZ_get_secure_timestamp(&current_timestamp);
	if (ret != TZ_API_OK) {
		TTY_LOG("%s Error fetching secure timestamp, Error: %d",
			LOG_TAG, ret);
		current_timestamp = tui_verify_timestamp = 0;
		return true;
	}

	if (tui_verify_timestamp == 0) {
		TTY_LOG("%s timer is not set, please set the timer", LOG_TAG);
		return true;
	}

	DBG_LOG("%s : Current timestamp = %lld", LOG_TAG, current_timestamp);
	timer_val = (current_timestamp - tui_verify_timestamp) / (TS_FORMAT);
	DBG_LOG("%s : Current timer val : %d", LOG_TAG, timer_val);
	if (timer_val >= SPAY_TUI_MAX_TIMER_VAL_SECS) {
		DBG_LOG("%s, *** Timer expired ***", LOG_TAG);
		tui_verify_timestamp = 0;
		return true;
	}
	DBG_LOG("%s : You have %d more sec(s)", LOG_TAG,
		(SPAY_TUI_MAX_TIMER_VAL_SECS - timer_val));
	return false;
}
