gui: PatternPassword: allow any N*N grid

Rather than only supporting a 3x3 grid, allow for multiple grid sizes
(using the CyanogenMod method of generating passphrases for non-3x3
grids). Also fix the detection of touches, as the old code was far too
sensitive for larger grids (and also didn't make much sense).

Change-Id: I343ef654e6d29ce0cb790a28281be7c7c9b171d9
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
diff --git a/gui/devices/1080x1920/res/ui.xml b/gui/devices/1080x1920/res/ui.xml
index 0ac3e43..d491577 100644
--- a/gui/devices/1080x1920/res/ui.xml
+++ b/gui/devices/1080x1920/res/ui.xml
@@ -200,14 +200,19 @@
 		<variable name="slidervalue_padding" value="30" />
 		<variable name="slidervalue_sliderw" value="15" />
 		<variable name="slidervalue_sliderh" value="90" />
-		<variable name="pattern_x" value="216" />
+		<variable name="pattern_button3_x" value="275" />
+		<variable name="pattern_button4_x" value="409" />
+		<variable name="pattern_button5_x" value="543" />
+		<variable name="pattern_button6_x" value="677" />
+		<variable name="pattern_x" value="92" />
 		<variable name="pattern_y" value="508" />
-		<variable name="pattern_width" value="648" />
+		<variable name="pattern_width" value="896" />
 		<variable name="pattern_dot_color" value="#33B5E5" />
 		<variable name="pattern_dot_color_active" value="#FFFFFF" />
 		<variable name="pattern_dot_radius" value="23" />
 		<variable name="pattern_line_color" value="#33B5E5" />
 		<variable name="pattern_line_width" value="18" />
+		<variable name="pattern_cancel_y" value="1440" />
 	</variables>
 
 	<mousecursor>
@@ -318,6 +323,40 @@
 			</object>
 		</template>
 
+		<template name="pattern_options">
+			<object type="button">
+				<placement x="%pattern_button3_x%" y="%row2_text_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>3x3</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=3</action>
+			</object>
+
+			<object type="button">
+				<placement x="%pattern_button4_x%" y="%row2_text_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>4x4</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=4</action>
+			</object>
+
+			<object type="button">
+				<placement x="%pattern_button5_x%" y="%row2_text_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>5x5</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=5</action>
+			</object>
+
+			<object type="button">
+				<placement x="%pattern_button6_x%" y="%row2_text_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>6x6</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=6</action>
+			</object>
+		</template>
+
 		<template name="sort_options">
 			<object type="text" color="%text_color%">
 				<font resource="font" />
diff --git a/gui/devices/1920x1200/res/ui.xml b/gui/devices/1920x1200/res/ui.xml
index 8171cf5..160ddf6 100644
--- a/gui/devices/1920x1200/res/ui.xml
+++ b/gui/devices/1920x1200/res/ui.xml
@@ -221,6 +221,7 @@
 		<variable name="pattern_dot_radius" value="23" />
 		<variable name="pattern_line_color" value="#33B5E5" />
 		<variable name="pattern_line_width" value="18" />
+		<variable name="pattern_button_y" value="190" />
 	</variables>
 
 	<mousecursor>
@@ -329,6 +330,40 @@
 			</object>
 		</template>
 
+		<template name="pattern_options">
+			<object type="button">
+				<placement x="%col1_medium_x%" y="%pattern_button_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>3x3</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=3</action>
+			</object>
+
+			<object type="button">
+				<placement x="%col2_medium_x%" y="%pattern_button_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>4x4</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=4</action>
+			</object>
+
+			<object type="button">
+				<placement x="%col3_medium_x%" y="%pattern_button_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>5x5</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=5</action>
+			</object>
+
+			<object type="button">
+				<placement x="%col4_medium_x%" y="%pattern_button_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>6x6</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=6</action>
+			</object>
+		</template>
+
 		<template name="sort_options">
 			<object type="text" color="%text_color%">
 				<font resource="font" />
diff --git a/gui/devices/320x320/res/ui.xml b/gui/devices/320x320/res/ui.xml
index afe2509..345a81c 100644
--- a/gui/devices/320x320/res/ui.xml
+++ b/gui/devices/320x320/res/ui.xml
@@ -211,6 +211,7 @@
 		<variable name="pattern_dot_radius" value="7" />
 		<variable name="pattern_line_color" value="#33B5E5" />
 		<variable name="pattern_line_width" value="4" />
+		<variable name="pattern_button_y" value="33" />
 	</variables>
 
 	<templates>
@@ -323,6 +324,40 @@
 			</object>
 		</template>
 
+		<template name="pattern_options">
+			<object type="button">
+				<placement x="%col1_medium_x%" y="%pattern_button_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>3x3</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=3</action>
+			</object>
+
+			<object type="button">
+				<placement x="%col2_medium_x%" y="%pattern_button_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>4x4</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=4</action>
+			</object>
+
+			<object type="button">
+				<placement x="%col3_medium_x%" y="%pattern_button_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>5x5</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=5</action>
+			</object>
+
+			<object type="button">
+				<placement x="%col4_medium_x%" y="%pattern_button_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>6x6</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=6</action>
+			</object>
+		</template>
+
 		<template name="sort_options">
 			<object type="text" color="%text_color%">
 				<font resource="mediumfont" />
diff --git a/gui/devices/480x800/res/ui.xml b/gui/devices/480x800/res/ui.xml
index c406e66..ec9df7e 100644
--- a/gui/devices/480x800/res/ui.xml
+++ b/gui/devices/480x800/res/ui.xml
@@ -195,14 +195,19 @@
 		<variable name="slidervalue_padding" value="13" />
 		<variable name="slidervalue_sliderw" value="7" />
 		<variable name="slidervalue_sliderh" value="40" />
-		<variable name="pattern_x" value="90" />
+		<variable name="pattern_button3_x" value="117" />
+		<variable name="pattern_button4_x" value="180" />
+		<variable name="pattern_button5_x" value="243" />
+		<variable name="pattern_button6_x" value="306" />
+		<variable name="pattern_x" value="41" />
 		<variable name="pattern_y" value="250" />
-		<variable name="pattern_width" value="300" />
+		<variable name="pattern_width" value="398" />
 		<variable name="pattern_dot_color" value="#33B5E5" />
 		<variable name="pattern_dot_color_active" value="#FFFFFF" />
 		<variable name="pattern_dot_radius" value="12" />
 		<variable name="pattern_line_color" value="#33B5E5" />
 		<variable name="pattern_line_width" value="9" />
+		<variable name="pattern_cancel_y" value="672" />
 	</variables>
 
 	<mousecursor>
@@ -319,6 +324,40 @@
 			</object>
 		</template>
 
+		<template name="pattern_options">
+			<object type="button">
+				<placement x="%pattern_button3_x%" y="%row2_text_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>3x3</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=3</action>
+			</object>
+
+			<object type="button">
+				<placement x="%pattern_button4_x%" y="%row2_text_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>4x4</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=4</action>
+			</object>
+
+			<object type="button">
+				<placement x="%pattern_button5_x%" y="%row2_text_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>5x5</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=5</action>
+			</object>
+
+			<object type="button">
+				<placement x="%pattern_button6_x%" y="%row2_text_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>6x6</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=6</action>
+			</object>
+		</template>
+
 		<template name="sort_options">
 			<object type="text" color="%text_color%">
 				<font resource="font" />
diff --git a/gui/devices/800x480/res/ui.xml b/gui/devices/800x480/res/ui.xml
index a9bf904..a561a3c 100644
--- a/gui/devices/800x480/res/ui.xml
+++ b/gui/devices/800x480/res/ui.xml
@@ -222,6 +222,7 @@
 		<variable name="pattern_dot_radius" value="10" />
 		<variable name="pattern_line_color" value="#33B5E5" />
 		<variable name="pattern_line_width" value="7" />
+		<variable name="pattern_button_y" value="94" />
 	</variables>
 
 	<mousecursor>
@@ -332,6 +333,40 @@
 			</object>
 		</template>
 
+		<template name="pattern_options">
+			<object type="button">
+				<placement x="%col1_medium_x%" y="%pattern_button_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>3x3</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=3</action>
+			</object>
+
+			<object type="button">
+				<placement x="%col2_medium_x%" y="%pattern_button_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>4x4</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=4</action>
+			</object>
+
+			<object type="button">
+				<placement x="%col3_medium_x%" y="%pattern_button_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>5x5</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=5</action>
+			</object>
+
+			<object type="button">
+				<placement x="%col4_medium_x%" y="%pattern_button_y%" />
+				<font resource="font" color="%button_text_color%" />
+				<text>6x6</text>
+				<image resource="sort_button" />
+				<action function="set">tw_gui_pattern_grid_size=6</action>
+			</object>
+		</template>
+
 		<template name="sort_options">
 			<object type="text" color="%text_color%">
 				<font resource="font" />
diff --git a/gui/devices/landscape/res/landscape.xml b/gui/devices/landscape/res/landscape.xml
index ec6f88e..b0f6b16 100644
--- a/gui/devices/landscape/res/landscape.xml
+++ b/gui/devices/landscape/res/landscape.xml
@@ -63,6 +63,10 @@
 			<sort name="tw_gui_sort_order" />
 		</style>
 
+		<style name="patternpassword">
+			<size name="tw_gui_pattern_grid_size" default="3" />
+		</style>
+
 		<style name="partitionlist">
 			<style name="scrolllist" />
 			<icon selected="checkbox_true" unselected="checkbox_false" />
@@ -3359,6 +3363,8 @@
 				<text>Pattern Failed, Please Try Again</text>
 			</object>
 
+			<object type="template" name="pattern_options" />
+
 			<object type="patternpassword">
 				<placement x="%pattern_x%" y="%pattern_y%" w="%pattern_width%" h="%pattern_width%" />
 				<dot color="%pattern_dot_color%" activecolor="%pattern_dot_color_active%" radius="%pattern_dot_radius%" />
diff --git a/gui/devices/portrait/res/portrait.xml b/gui/devices/portrait/res/portrait.xml
index 9c23067..b7e79e9 100644
--- a/gui/devices/portrait/res/portrait.xml
+++ b/gui/devices/portrait/res/portrait.xml
@@ -58,6 +58,10 @@
 			<sort name="tw_gui_sort_order" />
 		</style>
 
+		<style name="patternpassword">
+			<size name="tw_gui_pattern_grid_size" default="3" />
+		</style>
+
 		<style name="partitionlist">
 			<style name="scrolllist" />
 			<icon selected="checkbox_true" unselected="checkbox_false" />
@@ -3382,10 +3386,12 @@
 			<object type="text">
 				<condition var1="tw_password_fail" var2="1" />
 				<font resource="font" color="%text_fail_color%"/>
-				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<placement x="%center_x%" y="%row1_text_y%" placement="5" />
 				<text>Pattern Failed, Please Try Again</text>
 			</object>
 
+			<object type="template" name="pattern_options" />
+
 			<object type="patternpassword">
 				<placement x="%pattern_x%" y="%pattern_y%" w="%pattern_width%" h="%pattern_width%" />
 				<dot color="%pattern_dot_color%" activecolor="%pattern_dot_color_active%" radius="%pattern_dot_radius%" />
@@ -3395,7 +3401,7 @@
 			</object>
 
 			<object type="button">
-				<placement x="%col_center_x%" y="%row4_y%" />
+				<placement x="%col_center_x%" y="%pattern_cancel_y%" />
 				<text>Cancel</text>
 				<actions>
 					<action function="set">tw_page_done=1</action>
diff --git a/gui/devices/watch/res/watch.xml b/gui/devices/watch/res/watch.xml
index 3adf164..2dc2912 100644
--- a/gui/devices/watch/res/watch.xml
+++ b/gui/devices/watch/res/watch.xml
@@ -58,6 +58,10 @@
 			<sort name="tw_gui_sort_order" />
 		</style>
 
+		<style name="patternpassword">
+			<size name="tw_gui_pattern_grid_size" default="3" />
+		</style>
+
 		<style name="partitionlist">
 			<style name="scrolllist" />
 			<icon selected="checkbox_true" unselected="checkbox_false" />
@@ -3379,6 +3383,8 @@
 				<text>Pattern Failed, Please Try Again</text>
 			</object>
 
+			<object type="template" name="pattern_options" />
+
 			<object type="patternpassword">
 				<placement x="%pattern_x%" y="%pattern_y%" w="%pattern_width%" h="%pattern_width%" />
 				<dot color="%pattern_dot_color%" activecolor="%pattern_dot_color_active%" radius="%pattern_dot_radius%" />
diff --git a/gui/objects.hpp b/gui/objects.hpp
index ebf08a8..4e7ea29 100644
--- a/gui/objects.hpp
+++ b/gui/objects.hpp
@@ -1134,6 +1134,7 @@
 	virtual int Render(void);
 	virtual int Update(void);
 	virtual int NotifyTouch(TOUCH_STATE state, int x, int y);
+	virtual int NotifyVarChange(const std::string& varName, const std::string& value);
 	virtual int SetRenderPos(int x, int y, int w = 0, int h = 0);
 
 protected:
@@ -1141,9 +1142,10 @@
 	void ResetActiveDots();
 	void ConnectDot(int dot_idx);
 	void ConnectIntermediateDots(int dot_idx);
+	void Resize(size_t size);
 	int InDot(int x, int y);
 	bool DotUsed(int dot_idx);
-	static bool IsInRect(int x, int y, int rx, int ry, int rw, int rh);
+	std::string GeneratePassphrase();
 	void PatternDrawn();
 
 	struct Dot {
@@ -1152,8 +1154,11 @@
 		bool active;
 	};
 
-	Dot mDots[9];
-	int mConnectedDots[9];
+	std::string mSizeVar;
+	size_t mGridSize;
+
+	Dot* mDots;
+	int* mConnectedDots;
 	size_t mConnectedDotsLen;
 	int mCurLineX;
 	int mCurLineY;
diff --git a/gui/patternpassword.cpp b/gui/patternpassword.cpp
index ed15285..a6ab831 100644
--- a/gui/patternpassword.cpp
+++ b/gui/patternpassword.cpp
@@ -9,6 +9,7 @@
 #include <stdlib.h>
 
 #include <string>
+#include <sstream>
 
 extern "C" {
 #include "../twcommon.h"
@@ -24,6 +25,11 @@
 	xml_attribute<>* attr;
 	xml_node<>* child;
 
+	// 3x3 is the default.
+	mGridSize = 3;
+	mDots = new Dot[mGridSize * mGridSize];
+	mConnectedDots = new int[mGridSize * mGridSize];
+
 	ResetActiveDots();
 	mTrackingTouch = false;
 	mNeedRender = true;
@@ -69,6 +75,14 @@
 	if(child)
 		mPassVar = LoadAttrString(child, "name", "");
 
+	child = FindNode(node, "size");
+	if(child) {
+		mSizeVar = LoadAttrString(child, "name", "");
+
+		// Use the configured default, if set.
+		size_t size = LoadAttrInt(child, "default", mGridSize);
+		Resize(size);
+	}
 
 	if(!mDotImage || !mDotImage->GetResource() || !mActiveDotImage || !mActiveDotImage->GetResource())
 	{
@@ -87,6 +101,9 @@
 	delete mActiveDotImage;
 	delete mAction;
 
+	delete[] mDots;
+	delete[] mConnectedDots;
+
 	if(mDotCircle)
 		gr_free_surface(mDotCircle);
 
@@ -98,7 +115,7 @@
 {
 	mConnectedDotsLen = 0;
 	mCurLineX = mCurLineY = -1;
-	for(int i = 0; i < 9; ++i)
+	for(size_t i = 0; i < mGridSize * mGridSize; ++i)
 		mDots[i].active = false;
 }
 
@@ -122,17 +139,28 @@
 
 void GUIPatternPassword::CalculateDotPositions(void)
 {
-	const int step_x = (mRenderW - mDotRadius*2) / 2;
-	const int step_y = (mRenderH - mDotRadius*2) / 2;
+	const int num_gaps = mGridSize - 1;
+	const int step_x = (mRenderW - mDotRadius*2) / num_gaps;
+	const int step_y = (mRenderH - mDotRadius*2) / num_gaps;
 	int x = mRenderX;
 	int y = mRenderY;
 
-	for(int r = 0; r < 3; ++r)
+	/* Order is important for keyphrase generation:
+	 *
+	 *   0    1    2    3 ...  n-1
+	 *   n  n+1  n+2  n+3 ... 2n-1
+	 *  2n 2n+1 2n+2 2n+3 ... 3n-1
+	 *  3n 3n+1 3n+2 3n+3 ... 4n-1
+	 *   :  :    :    :
+	 *                       n*n-1
+	 */
+
+	for(size_t r = 0; r < mGridSize; ++r)
 	{
-		for(int c = 0; c < 3; ++c)
+		for(size_t c = 0; c < mGridSize; ++c)
 		{
-			mDots[3*r+c].x = x;
-			mDots[3*r+c].y = y;
+			mDots[mGridSize*r + c].x = x;
+			mDots[mGridSize*r + c].y = y;
 			x += step_x;
 		}
 		x = mRenderX;
@@ -157,7 +185,7 @@
 		gr_line(dc.x + mDotRadius, dc.y + mDotRadius, mCurLineX, mCurLineY, mLineWidth);
 	}
 
-	for(int i = 0; i < 9; ++i) {
+	for(size_t i = 0; i < mGridSize * mGridSize; ++i) {
 		if(mDotCircle) {
 			gr_blit(mDotCircle, 0, 0, gr_get_width(mDotCircle), gr_get_height(mDotCircle), mDots[i].x, mDots[i].y);
 			if(mDots[i].active) {
@@ -185,15 +213,39 @@
 	return res;
 }
 
-bool GUIPatternPassword::IsInRect(int x, int y, int rx, int ry, int rw, int rh)
+void GUIPatternPassword::Resize(size_t n) {
+	if(mGridSize == n)
+		return;
+
+	delete[] mDots;
+	delete[] mConnectedDots;
+
+	mGridSize = n;
+	mDots = new Dot[n*n];
+	mConnectedDots = new int[n*n];
+
+	ResetActiveDots();
+	CalculateDotPositions();
+	mTrackingTouch = false;
+	mNeedRender = true;
+}
+
+static int pow(int x, int i)
 {
-	return x >= rx && y >= ry && x <= rx+rw && y <= ry+rh;
+	while(i-- > 1)
+		x *= x;
+	return x;
+}
+
+static bool IsInCircle(int x, int y, int ox, int oy, int r)
+{
+	return pow(x - ox, 2) + pow(y - oy, 2) <= pow(r, 2);
 }
 
 int GUIPatternPassword::InDot(int x, int y)
 {
-	for(int i = 0; i < 9; ++i) {
-		if(IsInRect(x, y, mDots[i].x - mDotRadius*1.5, mDots[i].y - mDotRadius*1.5, mDotRadius*6, mDotRadius*6))
+	for(size_t i = 0; i < mGridSize * mGridSize; ++i) {
+		if(IsInCircle(x, y, mDots[i].x + mDotRadius, mDots[i].y + mDotRadius, mDotRadius*3))
 			return i;
 	}
 	return -1;
@@ -210,7 +262,7 @@
 
 void GUIPatternPassword::ConnectDot(int dot_idx)
 {
-	if(mConnectedDotsLen >= 9)
+	if(mConnectedDotsLen >= mGridSize * mGridSize)
 	{
 		LOGERR("mConnectedDots in GUIPatternPassword has overflown!\n");
 		return;
@@ -220,30 +272,66 @@
 	mDots[dot_idx].active = true;
 }
 
-void GUIPatternPassword::ConnectIntermediateDots(int dot_idx)
+void GUIPatternPassword::ConnectIntermediateDots(int next_dot_idx)
 {
 	if(mConnectedDotsLen == 0)
 		return;
 
-	const int last_dot = mConnectedDots[mConnectedDotsLen-1];
-	int mid = -1;
+	const int prev_dot_idx = mConnectedDots[mConnectedDotsLen-1];
 
-	// The line is vertical and has crossed a point in the middle
-	if(dot_idx%3 == last_dot%3 && abs(dot_idx - last_dot) > 3) {
-		mid = 3 + dot_idx%3;
-	// the line is horizontal and has crossed a point in the middle
-	} else if(dot_idx/3 == last_dot/3 && abs(dot_idx - last_dot) > 1) {
-		mid = (dot_idx/3)*3 + 1;
-	// the line is diagonal and has crossed the middle point
-	} else if((dot_idx == 0 && last_dot == 8) || (dot_idx == 8 && last_dot == 0) ||
-			(dot_idx == 2 && last_dot == 6) || (dot_idx == 6 && last_dot == 2)) {
-		mid = 4;
-	} else {
+	int px = prev_dot_idx % mGridSize;
+	int py = prev_dot_idx / mGridSize;
+
+	int nx = next_dot_idx % mGridSize;
+	int ny = next_dot_idx / mGridSize;
+
+	/*
+	 * We connect all dots that are in a straight line between the previous dot
+	 * and the next one. This is simple for 3x3, but is more complicated for
+	 * larger grids.
+	 *
+	 * Weirdly, Android doesn't do the logical thing when it comes to connecting
+	 * dots between two points. Rather than simply adding all points that lie
+	 * on the line between the start and end points, it instead only connects
+	 * dots that are adjacent in only three directions -- horizontal, vertical
+	 * and diagonal (45°).
+	 *
+	 * So we can just iterate over the correct axes, taking care to ensure that
+	 * the order in which the intermediate points are added to the pattern is
+	 * correct.
+	 */
+
+	int x = px;
+	int y = py;
+
+	int Dx = (nx > px) ? 1 : -1;
+	int Dy = (ny > py) ? 1 : -1;
+
+	// Vertical lines.
+	if(px == nx)
+		Dx = 0;
+
+	// Horizontal lines.
+	else if(py == ny)
+		Dy = 0;
+
+	// Diagonal lines (|∆x| = |∆y|).
+	else if(abs(px - nx) == abs(py - ny))
+		;
+
+	// No valid intermediate dots.
+	else
 		return;
-	}
 
-	if(!DotUsed(mid))
-		ConnectDot(mid);
+	// Iterate along axis, adding dots in the correct order.
+	while((Dy == 0 || y != ny - Dy) && (Dx == 0 || x != nx - Dx)) {
+		x += Dx;
+		y += Dy;
+
+		int idx = mGridSize * y + x;
+		if(!DotUsed(idx))
+			ConnectDot(idx);
+	}
 }
 
 int GUIPatternPassword::NotifyTouch(TOUCH_STATE state, int x, int y)
@@ -303,15 +391,65 @@
 	return 0;
 }
 
+int GUIPatternPassword::NotifyVarChange(const std::string& varName, const std::string& value)
+{
+	if(!isConditionTrue())
+		return 0;
+
+	if(varName == mSizeVar) {
+		Resize(atoi(value.c_str()));
+		mUpdate = true;
+	}
+	return 0;
+}
+
+std::string GUIPatternPassword::GeneratePassphrase()
+{
+	char pattern[mConnectedDotsLen];
+	for(size_t i = 0; i < mConnectedDotsLen; i++) {
+		 pattern[i] = (char) mConnectedDots[i];
+	}
+
+	std::stringstream pass;
+
+	for(size_t i = 0; i < mConnectedDotsLen; i++) {
+		int digit = pattern[i] & 0xff;
+
+		/*
+		 * Okay, rant time.
+		 * It turns out that Android and CyanogenMod have *two* separate methods
+		 * for generating passphrases from patterns. This is a legacy issue, as
+		 * Android only supports 3x3 grids, and so we need to support both.
+		 * Luckily, CyanogenMod is in the same boat as us and needs to support
+		 * Android's 3x3 encryption style.
+		 *
+		 * In order to generate a 3x3 passphrase, add 1 to each dot index
+		 * and concatenate the string representation of the integers. No
+		 * padding should be added.
+		 *
+		 * For *all* other NxN passphrases (until a 16x16 grid comes along),
+		 * they are generated by taking "%.2x" for each dot index and
+		 * concatenating the results (without adding 1).
+		 */
+
+		if(mGridSize == 3)
+			// Android (legacy) 3x3 grids.
+			pass << digit + 1;
+		else {
+			// Other NxN grids.
+			char buffer[3];
+			snprintf(buffer, 3, "%.2x", digit);
+			pass << std::string(buffer);
+		}
+	}
+
+	return pass.str();
+}
+
 void GUIPatternPassword::PatternDrawn()
 {
 	if(!mPassVar.empty() && mConnectedDotsLen > 0)
-	{
-		std::string pass;
-		for(size_t i = 0; i < mConnectedDotsLen; ++i)
-			pass += '1' + mConnectedDots[i];
-		DataManager::SetValue(mPassVar, pass);
-	}
+		DataManager::SetValue(mPassVar, GeneratePassphrase());
 
 	if(mAction)
 		mAction->doActions();
diff --git a/gui/theme/common/landscape.xml b/gui/theme/common/landscape.xml
index 938c854..35986dd 100755
--- a/gui/theme/common/landscape.xml
+++ b/gui/theme/common/landscape.xml
@@ -176,6 +176,10 @@
 			<colors line="%fileselector_linecolor%"/>
 			<dimensions lineh="%slidervalue_lineh%" linepadding="%slidervalue_padding%" sliderw="%slidervalue_sliderw%" sliderh="%slidervalue_sliderh%"/>
 		</style>
+
+		<style name="patternpassword">
+			<size name="tw_gui_pattern_grid_size" default="3"/>
+		</style>
 	</styles>
 
 	<pages>
@@ -3911,19 +3915,48 @@
 			</text>
 
 			<text style="text_m_accent">
-				<placement x="%center_x%" y="%row2_y%" placement="5"/>
+				<placement x="%col2_x_left%" y="%row2_y%" placement="5"/>
 				<text>{@decrypt_data_enter_pattern=Enter Pattern.}</text>
 			</text>
 
+			<text style="text_m_fail">
+				<condition var1="tw_password_fail" var2="1"/>
+				<placement x="%col2_x_left%" y="%row3_y%" placement="5"/>
+				<text>{@decryt_data_failed_pattern=Pattern failed, please try again!}</text>
+			</text>
+
 			<patternpassword>
-				<placement x="%pattern_x%" y="%row4_y%" w="%pattern_size%" h="%pattern_size%"/>
-				<size name="tw_pattern_grid_size" default="3"/>
+				<placement x="%pattern_x%" y="%row4a_y%" w="%pattern_size%" h="%pattern_size%"/>
 				<dot color="%fileselector_linecolor%" activecolor="%accent_color%" radius="%pattern_dot_dia%"/>
 				<line color="%fileselector_linecolor%" width="%pattern_line_w%"/>
 				<data name="tw_crypto_password"/>
 				<action function="page">trydecrypt</action>
 			</patternpassword>
 
+			<button style="main_button_half_width_low">
+				<placement x="%col_button_right%" y="%row1a_y%"/>
+				<text>3x3</text>
+				<action function="set">tw_gui_pattern_grid_size=3</action>
+			</button>
+
+			<button style="main_button_half_width_low">
+				<placement x="%col_button_right%" y="%row4a_y%"/>
+				<text>4x4</text>
+				<action function="set">tw_gui_pattern_grid_size=4</action>
+			</button>
+
+			<button style="main_button_half_width_low">
+				<placement x="%col_button_right%" y="%row7a_y%"/>
+				<text>5x5</text>
+				<action function="set">tw_gui_pattern_grid_size=5</action>
+			</button>
+
+			<button style="main_button_half_width_low">
+				<placement x="%col_button_right%" y="%row10a_y%"/>
+				<text>6x6</text>
+				<action function="set">tw_gui_pattern_grid_size=6</action>
+			</button>
+
 			<button style="main_button_half_width">
 				<placement x="%col2_x_right%" y="%row15a_y%"/>
 				<text>{@cancel_btn=Cancel}</text>
diff --git a/gui/theme/common/languages/en.xml b/gui/theme/common/languages/en.xml
index 2847d22..e417ace 100755
--- a/gui/theme/common/languages/en.xml
+++ b/gui/theme/common/languages/en.xml
@@ -435,6 +435,7 @@
 		<string name="decrypt_data_hdr">Decrypt Data</string>
 		<string name="decrypt_data_enter_pass"></string>
 		<string name="decryt_data_failed">Password failed, please try again!</string>
+		<string name="decryt_data_failed_pattern">Pattern failed, please try again!</string>
 		<string name="decrypt_data_enter_pattern">Enter Pattern.</string>
 		<string name="decrypt_data_trying">Trying Decryption</string>
 		<string name="term_hdr">Terminal Command</string>
diff --git a/gui/theme/common/portrait.xml b/gui/theme/common/portrait.xml
index 2cd49e4..2d399ba 100755
--- a/gui/theme/common/portrait.xml
+++ b/gui/theme/common/portrait.xml
@@ -141,6 +141,10 @@
 			<colors line="%fileselector_linecolor%"/>
 			<dimensions lineh="%slidervalue_lineh%" linepadding="%slidervalue_padding%" sliderw="%slidervalue_sliderw%" sliderh="%slidervalue_sliderh%"/>
 		</style>
+
+		<style name="patternpassword">
+			<size name="tw_gui_pattern_grid_size" default="3"/>
+		</style>
 	</styles>
 
 	<pages>
@@ -3986,15 +3990,44 @@
 				<text>{@decrypt_data_enter_pattern=Enter Pattern.}</text>
 			</text>
 
+			<text style="text_m_fail">
+				<condition var1="tw_password_fail" var2="1"/>
+				<placement x="%center_x%" y="%row3_y%" placement="5"/>
+				<text>{@decryt_data_failed_pattern=Pattern failed, please try again!}</text>
+			</text>
+
 			<patternpassword>
-				<placement x="%pattern_x%" y="%row6_y%" w="%pattern_size%" h="%pattern_size%"/>
-				<size name="tw_pattern_grid_size" default="3"/>
+				<placement x="%pattern_x%" y="%row5_y%" w="%pattern_size%" h="%pattern_size%"/>
 				<dot color="%fileselector_linecolor%" activecolor="%accent_color%" radius="%pattern_dot_dia%"/>
 				<line color="%fileselector_linecolor%" width="%pattern_line_w%"/>
 				<data name="tw_crypto_password"/>
 				<action function="page">trydecrypt</action>
 			</patternpassword>
 
+			<button style="button_quarter_width">
+				<placement x="%indent%" y="%row19a_y%"/>
+				<text>3x3</text>
+				<action function="set">tw_gui_pattern_grid_size=3</action>
+			</button>
+
+			<button style="button_quarter_width">
+				<placement x="%btn4_col2_x%" y="%row19a_y%"/>
+				<text>4x4</text>
+				<action function="set">tw_gui_pattern_grid_size=4</action>
+			</button>
+
+			<button style="button_quarter_width">
+				<placement x="%btn4_col3_x%" y="%row19a_y%"/>
+				<text>5x5</text>
+				<action function="set">tw_gui_pattern_grid_size=5</action>
+			</button>
+
+			<button style="button_quarter_width">
+				<placement x="%btn4_col4_x%" y="%row19a_y%"/>
+				<text>6x6</text>
+				<action function="set">tw_gui_pattern_grid_size=6</action>
+			</button>
+
 			<button style="main_button_half_height">
 				<placement x="%indent%" y="%row21a_y%"/>
 				<text>{@cancel_btn=Cancel}</text>
diff --git a/gui/theme/common/watch.xml b/gui/theme/common/watch.xml
index 2ed266a..382b2e1 100755
--- a/gui/theme/common/watch.xml
+++ b/gui/theme/common/watch.xml
@@ -68,6 +68,10 @@
 			<image resource="tab_3"/>
 		</style>
 
+		<style name="button_navbar">
+			<font resource="font_m" color="%text_button_color%"/>
+		</style>
+
 		<style name="console">
 			<color foreground="%text_color%" background="%background_color%" scroll="%background_color%"/>
 			<font resource="fixed"/>
@@ -167,6 +171,10 @@
 			<colors line="%fileselector_linecolor%"/>
 			<dimensions lineh="%slidervalue_lineh%" linepadding="%slidervalue_padding%" sliderw="%slidervalue_sliderw%" sliderh="%slidervalue_sliderh%"/>
 		</style>
+
+		<style name="patternpassword">
+			<size name="tw_gui_pattern_grid_size" default="3"/>
+		</style>
 	</styles>
 
 	<pages>
@@ -4780,16 +4788,27 @@
 
 			<template name="statusbar"/>
 
+			<action>
+				<action function="set">tw_gui_pattern_grid_size=3</action>
+			</action>
+
 			<text style="text_m">
 				<placement x="%col1_x_left%" y="%row1_header_y%"/>
 				<text>{@mount_hdr=Mount} &gt; {@decrypt_data_hdr=Decrypt Data}</text>
 			</text>
 
 			<text style="text_m_accent">
+				<condition var1="tw_password_fail" op="!=" var2="1"/>
 				<placement x="%center_x%" y="%row5_y%" placement="5"/>
 				<text>{@decrypt_data_enter_pattern=Enter Pattern.}</text>
 			</text>
 
+			<text style="text_m_fail">
+				<condition var1="tw_password_fail" var2="1"/>
+				<placement x="%center_x%" y="%row5_y%" placement="5"/>
+				<text>{@decryt_data_failed_pattern=Pattern failed, please try again!}</text>
+			</text>
+
 			<text style="text_m">
 				<placement x="%center_x%" y="%row10_y%" placement="5"/>
 				<text>{@back_cancel=Press back to cancel.}</text>
@@ -4797,7 +4816,6 @@
 
 			<patternpassword>
 				<placement x="%pattern_x%" y="%row2_y%" w="%pattern_size%" h="%pattern_size%"/>
-				<size name="tw_pattern_grid_size" default="3"/>
 				<dot color="%fileselector_linecolor%" activecolor="%accent_color%" radius="%pattern_dot_dia%"/>
 				<line color="%fileselector_linecolor%" width="%pattern_line_w%"/>
 				<data name="tw_crypto_password"/>
@@ -4817,6 +4835,62 @@
 					<action function="page">main</action>
 				</actions>
 			</button>
+
+			<button>
+				<condition var1="tw_gui_pattern_grid_size" var2="3"/>
+				<placement x="%center_x%" y="%navbar_btn_y%" placement="4"/>
+				<image resource="grid_less"/>
+				<action function="set">tw_gui_pattern_grid_size=3</action>
+			</button>
+
+			<button>
+				<condition var1="tw_gui_pattern_grid_size" var2="4"/>
+				<placement x="%center_x%" y="%navbar_btn_y%" placement="4"/>
+				<image resource="grid_less"/>
+				<action function="set">tw_gui_pattern_grid_size=3</action>
+			</button>
+
+			<button>
+				<condition var1="tw_gui_pattern_grid_size" var2="5"/>
+				<placement x="%center_x%" y="%navbar_btn_y%" placement="4"/>
+				<image resource="grid_less"/>
+				<action function="set">tw_gui_pattern_grid_size=4</action>
+			</button>
+
+			<button>
+				<condition var1="tw_gui_pattern_grid_size" var2="6"/>
+				<placement x="%center_x%" y="%navbar_btn_y%" placement="4"/>
+				<image resource="grid_less"/>
+				<action function="set">tw_gui_pattern_grid_size=5</action>
+			</button>
+
+			<button>
+				<condition var1="tw_gui_pattern_grid_size" var2="3"/>
+				<placement x="%console_button_x%" y="%navbar_btn_y%" placement="4"/>
+				<image resource="grid_more"/>
+				<action function="set">tw_gui_pattern_grid_size=4</action>
+			</button>
+
+			<button>
+				<condition var1="tw_gui_pattern_grid_size" var2="4"/>
+				<placement x="%console_button_x%" y="%navbar_btn_y%" placement="4"/>
+				<image resource="grid_more"/>
+				<action function="set">tw_gui_pattern_grid_size=5</action>
+			</button>
+
+			<button>
+				<condition var1="tw_gui_pattern_grid_size" var2="5"/>
+				<placement x="%console_button_x%" y="%navbar_btn_y%" placement="4"/>
+				<image resource="grid_more"/>
+				<action function="set">tw_gui_pattern_grid_size=6</action>
+			</button>
+
+			<button>
+				<condition var1="tw_gui_pattern_grid_size" var2="6"/>
+				<placement x="%console_button_x%" y="%navbar_btn_y%" placement="4"/>
+				<image resource="grid_more"/>
+				<action function="set">tw_gui_pattern_grid_size=6</action>
+			</button>
 		</page>
 
 		<page name="trydecrypt">
diff --git a/gui/theme/landscape_hdpi/ui.xml b/gui/theme/landscape_hdpi/ui.xml
index 8241641..e6a6b68 100644
--- a/gui/theme/landscape_hdpi/ui.xml
+++ b/gui/theme/landscape_hdpi/ui.xml
@@ -206,7 +206,7 @@
 		<variable name="progress_x" value="552" />
 		<variable name="progress_text_x" value="96" />
 		<variable name="progress_text_y" value="900" />
-		<variable name="pattern_x" value="636" />
+		<variable name="pattern_x" value="180" />
 		<variable name="pattern_dot_dia" value="32" />
 		<variable name="pattern_line_w" value="12" />
 		<variable name="pattern_size" value="648" />
diff --git a/gui/theme/landscape_mdpi/ui.xml b/gui/theme/landscape_mdpi/ui.xml
index 818c23d..f4b34a7 100644
--- a/gui/theme/landscape_mdpi/ui.xml
+++ b/gui/theme/landscape_mdpi/ui.xml
@@ -206,10 +206,10 @@
 		<variable name="progress_x" value="230" />

 		<variable name="progress_text_x" value="40" />

 		<variable name="progress_text_y" value="348" />

-		<variable name="pattern_x" value="300" />

+		<variable name="pattern_x" value="84" />

 		<variable name="pattern_dot_dia" value="12" />

 		<variable name="pattern_line_w" value="4" />

-		<variable name="pattern_size" value="200" />

+		<variable name="pattern_size" value="252" />

 	</variables>

 

 	<mousecursor>

diff --git a/gui/theme/portrait_hdpi/ui.xml b/gui/theme/portrait_hdpi/ui.xml
index 7708f92..1693735 100644
--- a/gui/theme/portrait_hdpi/ui.xml
+++ b/gui/theme/portrait_hdpi/ui.xml
@@ -198,10 +198,10 @@
 		<variable name="console_height" value="960" />
 		<variable name="console_terminal_height" value="576" />
 		<variable name="dialog_button_x" value="696" />
-		<variable name="pattern_x" value="216" />
+		<variable name="pattern_x" value="126" />
 		<variable name="pattern_dot_dia" value="32" />
 		<variable name="pattern_line_w" value="12" />
-		<variable name="pattern_size" value="648" />
+		<variable name="pattern_size" value="828" />
 	</variables>
 
 	<mousecursor>
diff --git a/gui/theme/portrait_mdpi/ui.xml b/gui/theme/portrait_mdpi/ui.xml
index 68fd324..946132d 100644
--- a/gui/theme/portrait_mdpi/ui.xml
+++ b/gui/theme/portrait_mdpi/ui.xml
@@ -198,10 +198,10 @@
 		<variable name="console_height" value="390" />
 		<variable name="console_terminal_height" value="234" />
 		<variable name="dialog_button_x" value="310" />
-		<variable name="pattern_x" value="88" />
+		<variable name="pattern_x" value="60" />
 		<variable name="pattern_dot_dia" value="12" />
 		<variable name="pattern_line_w" value="4" />
-		<variable name="pattern_size" value="392" />
+		<variable name="pattern_size" value="360" />
 	</variables>
 
 	<mousecursor>
diff --git a/gui/theme/watch_mdpi/images/grid_less.png b/gui/theme/watch_mdpi/images/grid_less.png
new file mode 100644
index 0000000..7366c8e
--- /dev/null
+++ b/gui/theme/watch_mdpi/images/grid_less.png
Binary files differ
diff --git a/gui/theme/watch_mdpi/images/grid_more.png b/gui/theme/watch_mdpi/images/grid_more.png
new file mode 100644
index 0000000..cd51f7e
--- /dev/null
+++ b/gui/theme/watch_mdpi/images/grid_more.png
Binary files differ
diff --git a/gui/theme/watch_mdpi/ui.xml b/gui/theme/watch_mdpi/ui.xml
index 7c7715a..850a32f 100644
--- a/gui/theme/watch_mdpi/ui.xml
+++ b/gui/theme/watch_mdpi/ui.xml
@@ -46,6 +46,8 @@
 		<resource name="home" type="image" filename="home" retainaspect="1" />
 		<resource name="back" type="image" filename="back" retainaspect="1" />
 		<resource name="console" type="image" filename="console" retainaspect="1" />
+		<resource name="grid_less" type="image" filename="grid_less" retainaspect="1" />
+		<resource name="grid_more" type="image" filename="grid_more" retainaspect="1" />
 		<resource name="checkbox_false" type="image" filename="checkbox_false" retainaspect="1" />
 		<resource name="checkbox_false_small" type="image" filename="checkbox_false_small" retainaspect="1" />
 		<resource name="checkbox_true" type="image" filename="checkbox_true" retainaspect="1" />
@@ -167,8 +169,8 @@
 		<variable name="console_terminal_height" value="64" />
 		<variable name="close_btn_x" value="280" />
 		<variable name="pattern_x" value="60" />
-		<variable name="pattern_dot_dia" value="20" />
-		<variable name="pattern_line_w" value="8" />
+		<variable name="pattern_dot_dia" value="12" />
+		<variable name="pattern_line_w" value="4" />
 		<variable name="pattern_size" value="200" />
 	</variables>