Files
android_bootable_recovery/gui/console.cpp
gordon1337 1035509376 Console Render Bug caused by touch drag event
With starting the console the touch drag event is active without even touching the display.
This causes to render the console at any time it is displayed, which consumes alot of battery and heats up the device.
What the patch does is resetting the touch drag state to ensure it is only re-rendering the console when it it really needed.
2013-06-08 14:15:32 +02:00

403 lines
10 KiB
C++

// console.cpp - GUIConsole object
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/reboot.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <string>
extern "C" {
#include "../twcommon.h"
#include "../minuitwrp/minui.h"
}
#include "rapidxml.hpp"
#include "objects.hpp"
static std::vector<std::string> gConsole;
extern "C" void gui_print(const char *fmt, ...)
{
char buf[512]; // We're going to limit a single request to 512 bytes
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, 512, fmt, ap);
va_end(ap);
fputs(buf, stdout);
char *start, *next;
if (buf[0] == '\n' && strlen(buf) < 2) {
// This prevents the double lines bug seen in the console during zip installs
return;
}
for (start = next = buf; *next != '\0'; next++)
{
if (*next == '\n')
{
*next = '\0';
next++;
std::string line = start;
gConsole.push_back(line);
start = next;
// Handle the normal \n\0 case
if (*next == '\0')
return;
}
}
std::string line = start;
gConsole.push_back(line);
return;
}
extern "C" void gui_print_overwrite(const char *fmt, ...)
{
char buf[512]; // We're going to limit a single request to 512 bytes
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, 512, fmt, ap);
va_end(ap);
fputs(buf, stdout);
// Pop the last line, and we can continue
if (!gConsole.empty()) gConsole.pop_back();
char *start, *next;
for (start = next = buf; *next != '\0'; next++)
{
if (*next == '\n')
{
*next = '\0';
next++;
std::string line = start;
gConsole.push_back(line);
start = next;
// Handle the normal \n\0 case
if (*next == '\0')
return;
}
}
std::string line = start;
gConsole.push_back(line);
return;
}
GUIConsole::GUIConsole(xml_node<>* node)
{
xml_attribute<>* attr;
xml_node<>* child;
mFont = NULL;
mCurrentLine = -1;
memset(&mForegroundColor, 255, sizeof(COLOR));
memset(&mBackgroundColor, 0, sizeof(COLOR));
mBackgroundColor.alpha = 255;
memset(&mScrollColor, 0x08, sizeof(COLOR));
mScrollColor.alpha = 255;
mLastCount = 0;
mSlideout = 0;
mSlideoutState = hidden;
mRenderX = 0; mRenderY = 0; mRenderW = gr_fb_width(); mRenderH = gr_fb_height();
if (!node)
{
mSlideoutX = 0; mSlideoutY = 0; mSlideoutW = 0; mSlideoutH = 0;
mConsoleX = 0; mConsoleY = 0; mConsoleW = gr_fb_width(); mConsoleH = gr_fb_height();
}
else
{
child = node->first_node("font");
if (child)
{
attr = child->first_attribute("resource");
if (attr)
mFont = PageManager::FindResource(attr->value());
}
child = node->first_node("color");
if (child)
{
attr = child->first_attribute("foreground");
if (attr)
{
std::string color = attr->value();
ConvertStrToColor(color, &mForegroundColor);
}
attr = child->first_attribute("background");
if (attr)
{
std::string color = attr->value();
ConvertStrToColor(color, &mBackgroundColor);
}
attr = child->first_attribute("scroll");
if (attr)
{
std::string color = attr->value();
ConvertStrToColor(color, &mScrollColor);
}
}
// Load the placement
LoadPlacement(node->first_node("placement"), &mConsoleX, &mConsoleY, &mConsoleW, &mConsoleH);
child = node->first_node("slideout");
if (child)
{
mSlideout = 1;
LoadPlacement(child, &mSlideoutX, &mSlideoutY);
attr = child->first_attribute("resource");
if (attr) mSlideoutImage = PageManager::FindResource(attr->value());
if (mSlideoutImage && mSlideoutImage->GetResource())
{
mSlideoutW = gr_get_width(mSlideoutImage->GetResource());
mSlideoutH = gr_get_height(mSlideoutImage->GetResource());
}
}
}
gr_getFontDetails(mFont, &mFontHeight, NULL);
SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
SetRenderPos(mConsoleX, mConsoleY);
return;
}
int GUIConsole::RenderSlideout(void)
{
if (!mSlideoutImage || !mSlideoutImage->GetResource()) return -1;
gr_blit(mSlideoutImage->GetResource(), 0, 0, mSlideoutW, mSlideoutH, mSlideoutX, mSlideoutY);
return 0;
}
int GUIConsole::RenderConsole(void)
{
void* fontResource = NULL;
if (mFont) fontResource = mFont->GetResource();
// We fill the background
gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
gr_fill(mConsoleX, mConsoleY, mConsoleW, mConsoleH);
gr_color(mScrollColor.red, mScrollColor.green, mScrollColor.blue, mScrollColor.alpha);
gr_fill(mConsoleX + (mConsoleW * 9 / 10), mConsoleY, (mConsoleW / 10), mConsoleH);
// Render the lines
gr_color(mForegroundColor.red, mForegroundColor.green, mForegroundColor.blue, mForegroundColor.alpha);
// Don't try to continue to render without data
mLastCount = gConsole.size();
if (mLastCount == 0) return (mSlideout ? RenderSlideout() : 0);
// Find the start point
int start;
int curLine = mCurrentLine; // Thread-safing (Another thread updates this value)
if (curLine == -1)
{
start = mLastCount - mMaxRows;
}
else
{
if (curLine > (int) mLastCount) curLine = (int) mLastCount;
if ((int) mMaxRows > curLine) curLine = (int) mMaxRows;
start = curLine - mMaxRows;
}
unsigned int line;
for (line = 0; line < mMaxRows; line++)
{
if ((start + (int) line) >= 0 && (start + (int) line) < (int) mLastCount)
{
gr_textExW(mConsoleX, mStartY + (line * mFontHeight), gConsole[start + line].c_str(), fontResource, mConsoleW + mConsoleX);
}
}
return (mSlideout ? RenderSlideout() : 0);
}
int GUIConsole::Render(void)
{
if (mSlideout && mSlideoutState == hidden)
{
return RenderSlideout();
}
return RenderConsole();
}
int GUIConsole::Update(void)
{
if (mSlideout && mSlideoutState != visible)
{
if (mSlideoutState == hidden)
return 0;
if (mSlideoutState == request_hide)
mSlideoutState = hidden;
if (mSlideoutState == request_show)
mSlideoutState = visible;
// Any time we activate the slider, we reset the position
mCurrentLine = -1;
return 2;
}
if (mCurrentLine == -1 && mLastCount != gConsole.size())
{
// We can use Render, and return for just a flip
Render();
return 2;
}
else if (mLastTouchY >= 0)
{
// They're still touching, so re-render
Render();
mLastTouchY = -1;
return 2;
}
return 0;
}
int GUIConsole::SetRenderPos(int x, int y, int w, int h)
{
// Adjust the stub position accordingly
mSlideoutX += (x - mConsoleX);
mSlideoutY += (y - mConsoleY);
mConsoleX = x;
mConsoleY = y;
if (w || h)
{
mConsoleW = w;
mConsoleH = h;
}
// Calculate the max rows
mMaxRows = mConsoleH / mFontHeight;
// Adjust so we always fit to bottom
mStartY = mConsoleY + (mConsoleH % mFontHeight);
return 0;
}
// IsInRegion - Checks if the request is handled by this object
// Return 0 if this object handles the request, 1 if not
int GUIConsole::IsInRegion(int x, int y)
{
if (mSlideout)
{
// Check if they tapped the slideout button
if (x >= mSlideoutX && x <= mSlideoutX + mSlideoutW && y >= mSlideoutY && y < mSlideoutY + mSlideoutH)
return 1;
// If we're only rendering the slideout, bail now
if (mSlideoutState == hidden)
return 0;
}
return (x < mConsoleX || x > mConsoleX + mConsoleW || y < mConsoleY || y > mConsoleY + mConsoleH) ? 0 : 1;
}
// NotifyTouch - Notify of a touch event
// Return 0 on success, >0 to ignore remainder of touch, and <0 on error
int GUIConsole::NotifyTouch(TOUCH_STATE state, int x, int y)
{
if (mSlideout && mSlideoutState == hidden)
{
if (state == TOUCH_START)
{
mSlideoutState = request_show;
return 1;
}
}
else if (mSlideout && mSlideoutState == visible)
{
// Are we sliding it back in?
if (state == TOUCH_START && x > mSlideoutX && x < (mSlideoutX + mSlideoutW) && y > mSlideoutY && y < (mSlideoutY + mSlideoutH))
{
mSlideoutState = request_hide;
return 1;
}
}
// If we don't have enough lines to scroll, throw this away.
if (mLastCount < mMaxRows) return 1;
// We are scrolling!!!
switch (state)
{
case TOUCH_START:
mLastTouchX = x;
mLastTouchY = y;
if ((x - mConsoleX) > ((9 * mConsoleW) / 10))
mSlideMultiplier = 10;
else
mSlideMultiplier = 1;
break;
case TOUCH_DRAG:
// This handles tapping
if (x == mLastTouchX && y == mLastTouchY) break;
mLastTouchX = -1;
if (y > mLastTouchY + 5)
{
mLastTouchY = y;
if (mCurrentLine == -1)
mCurrentLine = mLastCount - 1;
else if (mCurrentLine > mSlideMultiplier)
mCurrentLine -= mSlideMultiplier;
else
mCurrentLine = mMaxRows;
if (mCurrentLine < (int) mMaxRows)
mCurrentLine = mMaxRows;
}
else if (y < mLastTouchY - 5)
{
mLastTouchY = y;
if (mCurrentLine >= 0)
{
mCurrentLine += mSlideMultiplier;
if (mCurrentLine >= (int) mLastCount)
mCurrentLine = -1;
}
}
break;
case TOUCH_RELEASE:
// On a tap, we jump to the tail
if (mLastTouchX >= 0)
mCurrentLine = -1;
mLastTouchY = -1;
case TOUCH_REPEAT:
case TOUCH_HOLD:
break;
}
return 0;
}