Android Pattern Generator

To assist with the regular tasks that happen on most examinations in my role, I planned out and started to create multiple small utilities to assist my team and I. I decided to create a toolkit which could be expanded easily to act as a launchpad for all of these projects. The first tool that I developed to be launched from this toolkit is an Android Pattern Lock picture generator.

As part of our report that we produce after examining mobile devices, we include passcodes that are given to us and the actual passcode of the device. For pattern locked devices, it can difficult to accurately show what the pattern is, as both of our main tools, and the applicant of the submission all display them differently.

In order to simplify this for our end users, I designed a small tool that allows us to enter the pattern in either of the 2 ways presented in the pieces of software, and it will create a picture of the pattern that we include on our report, so that there is no uncertainty of what the device’s actual security unlock pattern is.


The application has several elements:

  1. A textbox for entering the numbers that make up the pattern
  2. A checkbox for toggling invalid patterns
  3. A checkbox for including / removing an offset of 1
  4. A save / Export button

When you enter digits into the textbox, it will automatically check to see if it’s a valid combination as it goes along, and will draw arrows below on the canvas to visually show this. By default, it will only allow valid patterns – this means you can’t go directly from corner to corner, e.g. 0 > 8 / 1 > 9, as it would go through the centre number and technically would be 0 > 4 > 8 / 1 > 5 > 9.

By checking the Invalid patterns option you’ll be able to enter a combination that would normally be invalid. This has been implemented as sometimes the patterns we are provided are invalid, as it’s what’s been given to them by the owner of the device. This option allows us to record their provided pattern accurately, and also allows them to show it to the owner and explain to them that it’s invalid and ask them to provide a different pattern.

Due to way our examination tools decode data and display it, sometimes the pattern is displayed as numbers between 0 & 8, and other times it’s displayed as numbers between 1 & 9. The patterns that we’re given by the submission applicant are usually in the format of 1-9, or drawn as a picture.

The offset button allows us to record their provided pattern in all possible formats, as being given a code of “1 > 2 > 3 > 4 > 7”, for example, could be interpreted as 2 very different patterns depending on if they mean it to be 0-8 (how it’s stored in the device, and how we usually reference it), or 1-9 like a dial pad of a phone.


Once you’ve entered the provided pattern, you can press the “Save / Export” button to create a picture of the pattern, so that it can be included in our reports.

Input:

Output:

private void DrawPattern()
{
	ClearCanvas();
	int OffsetNo = 0;
	if (Offset ==true)
	{
		OffsetNo = 1;
	}
	
	string InputString = PatternString.Text;
	InputString = InputString.Replace(",", "");
	for (int CurrentIndex = 0; CurrentIndex < InputString.Length -1; CurrentIndex++)
	{
		Line DrawLine = new Line();
		DrawLine.Uid = "Line" + CurrentIndex;
		DrawLine.Stroke = Brushes.Lime;
		DrawLine.StrokeThickness = 3;
		// X/Y Start point - taken from first int in string                
		DrawLine.X1 = CoordsLookup[Int32.Parse(InputString[CurrentIndex].ToString()) - OffsetNo].X;
		DrawLine.Y1 = CoordsLookup[Int32.Parse(InputString[CurrentIndex].ToString()) - OffsetNo].Y;
		// X/Y End point - taken from next int in string
		int NextIndex = CurrentIndex + 1;
		DrawLine.X2 = CoordsLookup[Int32.Parse(InputString[NextIndex].ToString()) - OffsetNo].X;
		DrawLine.Y2 = CoordsLookup[Int32.Parse(InputString[NextIndex].ToString()) - OffsetNo].Y;
		
		PatternCanvas.Children.Add(DrawLine);
		Canvas.SetZIndex(DrawLine, 99);
		// Draw Arrow halfway along line
		Polygon DrawArrow = new Polygon();
		DrawArrow.Uid = "LineArrow" + CurrentIndex;
		DrawArrow.Fill = Brushes.Lime;
		DrawArrow.Points.Add(new Point((DrawLine.X2 - ((DrawLine.X2 - DrawLine.X1)/2)) -5 , DrawLine.Y2 - ((DrawLine.Y2 - DrawLine.Y1)/2) - 10));
		DrawArrow.Points.Add(new Point((DrawLine.X2 - ((DrawLine.X2 - DrawLine.X1)/2)) + 10 , DrawLine.Y2 - ((DrawLine.Y2 - DrawLine.Y1)/2) ));
		DrawArrow.Points.Add(new Point((DrawLine.X2 - ((DrawLine.X2 - DrawLine.X1)/2)) - 5 , DrawLine.Y2 - ((DrawLine.Y2 - DrawLine.Y1)/2) + 10));
		
		RotateTransform SpinArrow = new RotateTransform(-(Math.Atan2(DrawLine.Y1 - DrawLine.Y2, DrawLine.X2 - DrawLine.X1) * (180 / Math.PI)));
		SpinArrow.CenterX = DrawLine.X2 - ((DrawLine.X2 - DrawLine.X1)/2);
		SpinArrow.CenterY = DrawLine.Y2 - ((DrawLine.Y2 - DrawLine.Y1)/2);
		DrawArrow.RenderTransform = SpinArrow;
		if (CurrentIndex == InputString.Length -2)
		{
			DrawArrow.Fill = Brushes.Orange;
		}
		PatternCanvas.Children.Add(DrawArrow);
		Canvas.SetZIndex(DrawArrow, 99);
		
	}
}