Move reloading of theme outside of the action thread

Reloading the GUI while the GUI is running and rendering is very
dangerous as we may be deleting GUI resources before or while we
are trying to render those same items. This change will allow us
to safely load new resources and delete the old ones.

Fixed a double free situation that was causing a crash on every
other theme reload.

Clear parsed xml documents when we are done loading the theme
instead of keeping them in memory for the life of the theme to
help save a little memory.

Store starting page so that if we request a reload, we can enter
the theme at the same starting point, which may come in handy if
we allow for language selection on alternate starting pages such
as the decrypt prompt or the system read only prompt.

Change-Id: I45a7e3fb3daeefac56d70f8d4936938eb1244b99
diff --git a/gui/pages.cpp b/gui/pages.cpp
index 0a1de96..0511b1a 100644
--- a/gui/pages.cpp
+++ b/gui/pages.cpp
@@ -55,6 +55,8 @@
 PageSet* PageManager::mBaseSet = NULL;
 MouseCursor *PageManager::mMouseCursor = NULL;
 HardwareKeyboard *PageManager::mHardwareKeyboard = NULL;
+bool PageManager::mReloadTheme = false;
+std::string PageManager::mStartPage = "main";
 
 int tw_x_offset = 0;
 int tw_y_offset = 0;
@@ -650,15 +652,12 @@
 	return 0;
 }
 
-PageSet::PageSet(char* xmlFile)
+PageSet::PageSet(const char* xmlFile)
 {
 	mResources = new ResourceManager;
 	mCurrentPage = NULL;
 
-	mXmlFile = xmlFile;
-	if (xmlFile)
-		mDoc.parse<0>(mXmlFile);
-	else
+	if (!xmlFile)
 		mCurrentPage = new Page(NULL, NULL);
 }
 
@@ -669,23 +668,17 @@
 		delete *itr;
 
 	delete mResources;
-	free(mXmlFile);
-
-	mDoc.clear();
-
-	for (std::vector<xml_document<>*>::iterator itr = mIncludedDocs.begin(); itr != mIncludedDocs.end(); ++itr) {
-		(*itr)->clear();
-		delete *itr;
-	}
 }
 
-int PageSet::Load(ZipArchive* package)
+int PageSet::Load(ZipArchive* package, char* xmlFile)
 {
+	xml_document<> mDoc;
 	xml_node<>* parent;
 	xml_node<>* child;
 	xml_node<>* xmltemplate;
 	xml_node<>* xmlstyle;
 
+	mDoc.parse<0>(xmlFile);
 	parent = mDoc.first_node("recovery");
 	if (!parent)
 		parent = mDoc.first_node("install");
@@ -772,11 +765,15 @@
 	if (child) {
 		if (LoadPages(child)) {
 			LOGERR("PageSet::Load returning -1\n");
+			mDoc.clear();
 			return -1;
 		}
 	}
 
-	return CheckInclude(package, &mDoc);
+	int ret = CheckInclude(package, &mDoc);
+	mDoc.clear();
+	templates.clear();
+	return ret;
 }
 
 int PageSet::CheckInclude(ZipArchive* package, xml_document<> *parentDoc)
@@ -867,17 +864,19 @@
 			return -1;
 		}
 
-		mIncludedDocs.push_back(doc);
-
 		if (CheckInclude(package, doc)) {
+			doc->clear();
+			delete doc;
 			free(xmlFile);
 			return -1;
 		}
+		doc->clear();
+		delete doc;
+		free(xmlFile);
 
 		chld = chld->next_sibling("xmlfile");
 	}
-	if (xmlFile)
-		free(xmlFile);
+
 	return 0;
 }
 
@@ -1192,6 +1191,9 @@
 	int ret;
 	MemMapping map;
 
+	mReloadTheme = false;
+	mStartPage = startpage;
+
 	// Open the XML file
 	LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
 	if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
@@ -1229,7 +1231,7 @@
 	pageSet = mCurrentSet;
 	mCurrentSet = new PageSet(xmlFile);
 
-	ret = mCurrentSet->Load(pZip);
+	ret = mCurrentSet->Load(pZip, xmlFile);
 	if (ret == 0)
 	{
 		mCurrentSet->SetPage(startpage);
@@ -1297,6 +1299,8 @@
 {
 	std::map<std::string, PageSet*>::iterator iter;
 
+	mReloadTheme = false;
+
 	iter = mPageSets.find(name);
 	if (iter == mPageSets.end())
 		return -1;
@@ -1307,7 +1311,7 @@
 	PageSet* set = (*iter).second;
 	mPageSets.erase(iter);
 
-	if (LoadPackage(name, package, "main") != 0)
+	if (LoadPackage(name, package, mStartPage) != 0)
 	{
 		LOGERR("Failed to load package '%s'.\n", package.c_str());
 		mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
@@ -1335,6 +1339,38 @@
 	return;
 }
 
+int PageManager::RunReload() {
+	int ret_val = 0;
+	std::string theme_path;
+
+	if (!mReloadTheme)
+		return 0;
+
+	mReloadTheme = false;
+	theme_path = DataManager::GetSettingsStoragePath();
+	if (PartitionManager.Mount_By_Path(theme_path.c_str(), 1) < 0) {
+		LOGERR("Unable to mount %s during gui_reload_theme function.\n", theme_path.c_str());
+		ret_val = 1;
+	}
+
+	theme_path += "/TWRP/theme/ui.zip";
+	if (ret_val != 0 || ReloadPackage("TWRP", theme_path) != 0)
+	{
+		// Loading the custom theme failed - try loading the stock theme
+		LOGINFO("Attempting to reload stock theme...\n");
+		if (ReloadPackage("TWRP", TWRES "ui.xml"))
+		{
+			LOGERR("Failed to load base packages.\n");
+			ret_val = 1;
+		}
+	}
+	return ret_val;
+}
+
+void PageManager::RequestReload() {
+	mReloadTheme = true;
+}
+
 int PageManager::ChangePage(std::string name)
 {
 	DataManager::SetValue("tw_operation_state", 0);
@@ -1383,6 +1419,9 @@
 
 int PageManager::Render(void)
 {
+	if(blankTimer.isScreenOff())
+		return 0;
+
 	int res = (mCurrentSet ? mCurrentSet->Render() : -1);
 	if(mMouseCursor)
 		mMouseCursor->Render();
@@ -1433,6 +1472,9 @@
 	if(blankTimer.isScreenOff())
 		return 0;
 
+	if (RunReload())
+		return -2;
+
 	int res = (mCurrentSet ? mCurrentSet->Update() : -1);
 
 	if(mMouseCursor)