Implement "take a screenshot" feature

* Like in android - press power+volume down, screenshots are saved
  in /sdcard/Pictures/Screenshots (if /sdcard is mounted) or /tmp

Change-Id: Iaefa15b11a1d5fdfac57d77388db1621f378a8d4
Signed-off-by: Vojtech Bocek <vbocek@gmail.com>
diff --git a/gui/action.cpp b/gui/action.cpp
index 3c5584d..b77e7e7 100644
--- a/gui/action.cpp
+++ b/gui/action.cpp
@@ -32,6 +32,7 @@
 #include <stdlib.h>
 #include <sys/wait.h>
 #include <dirent.h>
+#include <pwd.h>
 
 #include <string>
 #include <sstream>
@@ -775,6 +776,54 @@
 		return 0;
 	}
 
+	if (function == "screenshot")
+	{
+		time_t tm;
+		char path[256];
+		int path_len;
+		uid_t uid = -1;
+		gid_t gid = -1;
+
+		struct passwd *pwd = getpwnam("media_rw");
+		if(pwd) {
+			uid = pwd->pw_uid;
+			gid = pwd->pw_gid;
+		}
+
+		const std::string storage = DataManager::GetCurrentStoragePath();
+		if(PartitionManager.Is_Mounted_By_Path(storage)) {
+			snprintf(path, sizeof(path), "%s/Pictures/Screenshots/", storage.c_str());
+		} else {
+			strcpy(path, "/tmp/");
+		}
+
+		if(!TWFunc::Create_Dir_Recursive(path, 0666, uid, gid))
+			return 0;
+
+		tm = time(NULL);
+		path_len = strlen(path);
+
+		// Screenshot_2014-01-01-18-21-38.png
+		strftime(path+path_len, sizeof(path)-path_len, "Screenshot_%Y-%m-%d-%H-%M-%S.png", localtime(&tm));
+
+		int res = gr_save_screenshot(path);
+		if(res == 0) {
+			chmod(path, 0666);
+			chown(path, uid, gid);
+
+			gui_print("Screenshot was saved to %s\n", path);
+
+			// blink to notify that the screenshow was taken
+			gr_color(255, 255, 255, 255);
+			gr_fill(0, 0, gr_fb_width(), gr_fb_height());
+			gr_flip();
+			gui_forceRender();
+		} else {
+			LOGERR("Failed to take a screenshot!\n");
+		}
+		return 0;
+	}
+
 	if (isThreaded)
 	{
 		if (function == "fileexists")
diff --git a/gui/devices/1024x600/res/ui.xml b/gui/devices/1024x600/res/ui.xml
old mode 100755
new mode 100644
index 4795ce0..5c9c63b
--- a/gui/devices/1024x600/res/ui.xml
+++ b/gui/devices/1024x600/res/ui.xml
@@ -277,6 +277,11 @@
 				<touch key="power" />
 				<action function="overlay">lock</action>
 			</object>
+
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
 		</template>
 
 		<template name="progress_bar">
@@ -4159,6 +4164,11 @@
 				<action function="overlay">lock</action>
 			</object>
 
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
+
 			<object type="template" name="keyboardtemplate" />
 
 			<object type="action">
diff --git a/gui/devices/1024x768/res/ui.xml b/gui/devices/1024x768/res/ui.xml
index d041c50..f3e0a8e 100644
--- a/gui/devices/1024x768/res/ui.xml
+++ b/gui/devices/1024x768/res/ui.xml
@@ -277,6 +277,11 @@
 				<touch key="power" />
 				<action function="overlay">lock</action>
 			</object>
+
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
 		</template>
 
 		<template name="progress_bar">
@@ -4159,6 +4164,11 @@
 				<action function="overlay">lock</action>
 			</object>
 
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
+
 			<object type="template" name="keyboardtemplate" />
 
 			<object type="action">
diff --git a/gui/devices/1080x1920/res/ui.xml b/gui/devices/1080x1920/res/ui.xml
index f95ae09..5801f20 100644
--- a/gui/devices/1080x1920/res/ui.xml
+++ b/gui/devices/1080x1920/res/ui.xml
@@ -266,6 +266,11 @@
 				<touch key="power" />
 				<action function="overlay">lock</action>
 			</object>
+
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
 		</template>
 
 		<template name="progress_bar">
diff --git a/gui/devices/1200x1920/res/ui.xml b/gui/devices/1200x1920/res/ui.xml
index 0630e10..d0c8b4e 100644
--- a/gui/devices/1200x1920/res/ui.xml
+++ b/gui/devices/1200x1920/res/ui.xml
@@ -269,6 +269,11 @@
 				<touch key="power" />
 				<action function="overlay">lock</action>
 			</object>
+
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
 		</template>
 
 		<template name="progress_bar">
diff --git a/gui/devices/1280x800/res/ui.xml b/gui/devices/1280x800/res/ui.xml
index fdd2059..b76060a 100644
--- a/gui/devices/1280x800/res/ui.xml
+++ b/gui/devices/1280x800/res/ui.xml
@@ -277,6 +277,11 @@
 				<touch key="power" />
 				<action function="overlay">lock</action>
 			</object>
+
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
 		</template>
 
 		<template name="progress_bar">
@@ -4159,6 +4164,11 @@
 				<action function="overlay">lock</action>
 			</object>
 
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
+
 			<object type="template" name="keyboardtemplate" />
 
 			<object type="action">
diff --git a/gui/devices/1920x1200/res/ui.xml b/gui/devices/1920x1200/res/ui.xml
index 2622a88..0841c96 100644
--- a/gui/devices/1920x1200/res/ui.xml
+++ b/gui/devices/1920x1200/res/ui.xml
@@ -277,6 +277,11 @@
 				<touch key="power" />
 				<action function="overlay">lock</action>
 			</object>
+
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
 		</template>
 
 		<template name="progress_bar">
@@ -4159,6 +4164,11 @@
 				<action function="overlay">lock</action>
 			</object>
 
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
+
 			<object type="template" name="keyboardtemplate" />
 
 			<object type="action">
diff --git a/gui/devices/240x240/res/ui.xml b/gui/devices/240x240/res/ui.xml
index ac98dba..da73a99 100644
--- a/gui/devices/240x240/res/ui.xml
+++ b/gui/devices/240x240/res/ui.xml
@@ -253,6 +253,11 @@
 				<touch key="power" />
 				<action function="overlay">lock</action>
 			</object>
+
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
 		</template>
 
 		<template name="progress_bar">
diff --git a/gui/devices/2560x1600/res/ui.xml b/gui/devices/2560x1600/res/ui.xml
index 06880b2..28a9b81 100644
--- a/gui/devices/2560x1600/res/ui.xml
+++ b/gui/devices/2560x1600/res/ui.xml
@@ -277,6 +277,11 @@
 				<touch key="power" />
 				<action function="overlay">lock</action>
 			</object>
+
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
 		</template>
 
 		<template name="progress_bar">
@@ -4159,6 +4164,11 @@
 				<action function="overlay">lock</action>
 			</object>
 
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
+
 			<object type="template" name="keyboardtemplate" />
 
 			<object type="action">
diff --git a/gui/devices/320x480/res/ui.xml b/gui/devices/320x480/res/ui.xml
index fff8533..82273ce 100644
--- a/gui/devices/320x480/res/ui.xml
+++ b/gui/devices/320x480/res/ui.xml
@@ -259,6 +259,11 @@
 				<touch key="power" />
 				<action function="overlay">lock</action>
 			</object>
+
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
 		</template>
 
 		<template name="progress_bar">
diff --git a/gui/devices/480x800/res/ui.xml b/gui/devices/480x800/res/ui.xml
index 6baa702..53d630f 100644
--- a/gui/devices/480x800/res/ui.xml
+++ b/gui/devices/480x800/res/ui.xml
@@ -259,6 +259,11 @@
 				<touch key="power" />
 				<action function="overlay">lock</action>
 			</object>
+
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
 		</template>
 
 		<template name="progress_bar">
diff --git a/gui/devices/480x854/res/ui.xml b/gui/devices/480x854/res/ui.xml
index 4f5a7c9..ce79ebf 100644
--- a/gui/devices/480x854/res/ui.xml
+++ b/gui/devices/480x854/res/ui.xml
@@ -258,6 +258,11 @@
 				<touch key="power" />
 				<action function="overlay">lock</action>
 			</object>
+
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
 		</template>
 
 		<template name="progress_bar">
diff --git a/gui/devices/540x960/res/ui.xml b/gui/devices/540x960/res/ui.xml
index 11c9490..5e2807f 100644
--- a/gui/devices/540x960/res/ui.xml
+++ b/gui/devices/540x960/res/ui.xml
@@ -259,6 +259,11 @@
 				<touch key="power" />
 				<action function="overlay">lock</action>
 			</object>
+
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
 		</template>
 
 		<template name="progress_bar">
diff --git a/gui/devices/720x1280/res/ui.xml b/gui/devices/720x1280/res/ui.xml
index 1575485..4db6e22 100644
--- a/gui/devices/720x1280/res/ui.xml
+++ b/gui/devices/720x1280/res/ui.xml
@@ -266,6 +266,11 @@
 				<touch key="power" />
 				<action function="overlay">lock</action>
 			</object>
+
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
 		</template>
 
 		<template name="progress_bar">
diff --git a/gui/devices/800x1280/res/ui.xml b/gui/devices/800x1280/res/ui.xml
old mode 100755
new mode 100644
index abd62de..718074e
--- a/gui/devices/800x1280/res/ui.xml
+++ b/gui/devices/800x1280/res/ui.xml
@@ -260,6 +260,11 @@
 				<touch key="power" />
 				<action function="overlay">lock</action>
 			</object>
+
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
 		</template>
 
 		<template name="progress_bar">
diff --git a/gui/devices/800x480/res/ui.xml b/gui/devices/800x480/res/ui.xml
old mode 100755
new mode 100644
index 6a2c08f..9c56ca3
--- a/gui/devices/800x480/res/ui.xml
+++ b/gui/devices/800x480/res/ui.xml
@@ -279,6 +279,11 @@
 				<touch key="power" />
 				<action function="overlay">lock</action>
 			</object>
+
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
 		</template>
 
 		<template name="progress_bar">
@@ -4167,6 +4172,11 @@
 				<action function="overlay">lock</action>
 			</object>
 
+			<object type="action">
+				<touch key="power+voldown" />
+				<action function="screenshot" />
+			</object>
+
 			<object type="template" name="keyboardtemplate" />
 
 			<object type="action">
diff --git a/minuitwrp/Android.mk b/minuitwrp/Android.mk
index 2797a00..3c148ea 100644
--- a/minuitwrp/Android.mk
+++ b/minuitwrp/Android.mk
@@ -2,7 +2,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := events.c resources.c graphics_overlay.c
+LOCAL_SRC_FILES := events.c resources.c graphics_overlay.c graphics_utils.c
 
 ifneq ($(TW_BOARD_CUSTOM_GRAPHICS),)
     LOCAL_SRC_FILES += $(TW_BOARD_CUSTOM_GRAPHICS)
diff --git a/minuitwrp/graphics.c b/minuitwrp/graphics.c
index 594592d..e71693a 100644
--- a/minuitwrp/graphics.c
+++ b/minuitwrp/graphics.c
@@ -68,7 +68,7 @@
 static GGLContext *gr_context = 0;
 static GGLSurface gr_font_texture;
 static GGLSurface gr_framebuffer[NUM_BUFFERS];
-static GGLSurface gr_mem_surface;
+GGLSurface gr_mem_surface;
 static unsigned gr_active_fb = 0;
 static unsigned double_buffering = 0;
 static int gr_is_curr_clr_opaque = 0;
@@ -76,7 +76,7 @@
 static int gr_fb_fd = -1;
 static int gr_vt_fd = -1;
 
-static struct fb_var_screeninfo vi;
+struct fb_var_screeninfo vi;
 static struct fb_fix_screeninfo fi;
 
 static bool has_overlay = false;
diff --git a/minuitwrp/graphics_utils.c b/minuitwrp/graphics_utils.c
new file mode 100644
index 0000000..96f6449
--- /dev/null
+++ b/minuitwrp/graphics_utils.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <png.h>
+#include <pixelflinger/pixelflinger.h>
+#include <linux/fb.h>
+
+#include "minui.h"
+
+struct fb_var_screeninfo vi;
+GGLSurface gr_mem_surface;
+
+int gr_save_screenshot(const char *dest)
+{
+    uint32_t y, stride_bytes;
+    int res = -1;
+    GGLContext *gl = NULL;
+    GGLSurface surface;
+    uint8_t * volatile img_data = NULL;
+    uint8_t *ptr;
+    FILE *fp = NULL;
+    png_structp png_ptr = NULL;
+    png_infop info_ptr = NULL;
+
+    fp = fopen(dest, "wb");
+    if(!fp)
+        goto exit;
+
+    img_data = malloc(vi.xres * vi.yres * 3);
+    surface.version = sizeof(surface);
+    surface.width = gr_mem_surface.width;
+    surface.height = gr_mem_surface.height;
+    surface.stride = gr_mem_surface.width;
+    surface.data = img_data;
+    surface.format = GGL_PIXEL_FORMAT_RGB_888;
+
+    gglInit(&gl);
+    gl->colorBuffer(gl, &surface);
+    gl->activeTexture(gl, 0);
+
+    gl->bindTexture(gl, &gr_mem_surface);
+    gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
+    gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
+    gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
+    gl->enable(gl, GGL_TEXTURE_2D);
+    gl->texCoord2i(gl, 0, 0);
+    gl->recti(gl, 0, 0, gr_mem_surface.width, gr_mem_surface.height);
+
+    gglUninit(gl);
+    gl = NULL;
+
+    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!png_ptr)
+        goto exit;
+
+    info_ptr = png_create_info_struct(png_ptr);
+    if (info_ptr == NULL)
+        goto exit;
+
+    if (setjmp(png_jmpbuf(png_ptr)))
+        goto exit;
+
+    png_init_io(png_ptr, fp);
+    png_set_IHDR(png_ptr, info_ptr, surface.width, surface.height,
+         8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
+         PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+    png_write_info(png_ptr, info_ptr);
+
+    ptr = img_data;
+    stride_bytes = surface.width*3;
+    for(y = 0; y < surface.height; ++y)
+    {
+        png_write_row(png_ptr, ptr);
+        ptr += stride_bytes;
+    }
+
+    png_write_end(png_ptr, NULL);
+
+    res = 0;
+exit:
+    if(info_ptr)
+        png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
+    if(png_ptr)
+        png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+    if(gl)
+        gglUninit(gl);
+    if(img_data)
+        free(img_data);
+    if(fp)
+        fclose(fp);
+    return res;
+}
diff --git a/minuitwrp/minui.h b/minuitwrp/minui.h
index cf90532..f04f518 100644
--- a/minuitwrp/minui.h
+++ b/minuitwrp/minui.h
@@ -52,6 +52,8 @@
 int gr_get_surface(gr_surface* surface);
 int gr_free_surface(gr_surface surface);
 
+int gr_save_screenshot(const char *dest);
+
 // input event structure, include <linux/input.h> for the definition.
 // see http://www.mjmwired.net/kernel/Documentation/input/ for info.
 struct input_event;
diff --git a/twrp-functions.cpp b/twrp-functions.cpp
index 4306c45..1788c7e 100644
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -1176,4 +1176,22 @@
 	return res;
 }
 
+bool TWFunc::Create_Dir_Recursive(const std::string& path, mode_t mode, uid_t uid, gid_t gid)
+{
+	std::vector<std::string> parts = Split_String(path, "/");
+	std::string cur_path;
+	struct stat info;
+	for(size_t i = 0; i < parts.size(); ++i)
+	{
+		cur_path += "/" + parts[i];
+		if(stat(cur_path.c_str(), &info) < 0 || !S_ISDIR(info.st_mode))
+		{
+			if(mkdir(cur_path.c_str(), mode) < 0)
+				return false;
+			chown(cur_path.c_str(), uid, gid);
+		}
+	}
+	return true;
+}
+
 #endif // ndef BUILD_TWRPTAR_MAIN
diff --git a/twrp-functions.hpp b/twrp-functions.hpp
index 284a297..a0c7151 100644
--- a/twrp-functions.hpp
+++ b/twrp-functions.hpp
@@ -82,6 +82,7 @@
 	static void Auto_Generate_Backup_Name();                            // Populates TW_BACKUP_NAME with a backup name based on current date and ro.build.display.id from /system/build.prop
 	static void Fixup_Time_On_Boot(); // Fixes time on devices which need it
 	static std::vector<std::string> Split_String(const std::string& str, const std::string& delimiter, bool removeEmpty = true); // Splits string by delimiter
+	static bool Create_Dir_Recursive(const std::string& path, mode_t mode = 0755, uid_t uid = -1, gid_t gid = -1);  // Create directory and it's parents, if they don't exist. mode, uid and gid are set to all _newly_ created folders. If whole path exists, do nothing.
 
 private:
 	static void Copy_Log(string Source, string Destination);