Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Android Style Screen Pattern for Login

0.00/5 (No votes)
12 Jul 2013 1  
Draw pattern instead of password for login screen.

Image 1

Introduction

This article explains creating a smart phone style password screen. The authentication is done based on user name and screen code drawn on the screen.

Background

The basic idea came from Android based smart phones which provide a screen lock/unlock feature based on a pattern drawn on the screen.

Using the code  

Login process

In the login screen, there will be two authentication processes. The user name will be authenticated and the pattern canvas will be displayed. Draw the pattern and on completion, the user will be authenticated. The username authentication is done to retrieve the screen pattern information for the entered user.

Screen requirement

Display screen pattern canvas on username authentication. The pattern can be drawn in a visible / invisible mode by selecting the Stealth mode. On invalid entry, the screen code will be displayed in red color for a second and will erase automatically. On success, the authenticated message will be displayed and screen code will be erased. Allow editing of screen code after authentication success. The screen code can be saved and an internally drawn image will be sent to the user via mail and the drawn pattern will be available in the image area for user reference.

How to achieve above requirements

Part 1:

  1. Create a LockView usercontrol.
  2. Create pattern Canvas.
  3. Create 3x3 matrix of ellipse with tag values set (1,2..9).
  4. Register ellipse Mouse Down event.
  5. Register ellipse Mouse Move event.
  6. Register Canvas Mouse up event.
  7. Create stealth mode check box.
  8. Register Save and Clear button events.

Part 2:

  1. Create delegate for validation with screen data and validation flag as parameters.
  2. Create delegate for save with screen data as parameter.
  3. Create screen data with validation delegate object, save delegate object, screen code, target screen code, drawn image source.

Part 3:

  1. Create lock base class with screen data and screen mode as dependency properties and methods to draw pattern, insert pattern data, validate pattern, save pattern, capture screen pattern as image source.
  2. Encrypt the screen pattern using MD5Hash and set the screen code value.

How to draw a pattern

Image 2 Image 3

Create a polyline shape on ellipse mouse down and keep on adding points as the mouse moves on valid ellipses. Add lines with arrow heads to show the flow of the pattern. The arrow lines are created based on the current and previous points from the polyline point collection. Apply theta for calculating the arrow angle.

C#
NewLine = new Polyline();
NewLine.Name = CodeLine;
NewLine.Stroke = color;
NewLine.StrokeThickness = 10.0;  
  
/// <summary>
/// Draw arrow lines for the selected points
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="arrowName"></param>
/// <returns></returns>
protected static Shape DrawLinkArrow(Point p1, Point p2, string arrowName)
{
    GeometryGroup lineGroup = new GeometryGroup();
    double theta = Math.Atan2((p2.Y - p1.Y), (p2.X - p1.X)) * 180 / Math.PI;

    PathGeometry pathGeometry = new PathGeometry();
    PathFigure pathFigure = new PathFigure();
    Point p = new Point(p1.X + ((p2.X - p1.X) / 1.35), p1.Y + ((p2.Y - p1.Y) / 1.35));
    pathFigure.StartPoint = p;

    Point lpoint = new Point(p.X + 6, p.Y + 15);
    Point rpoint = new Point(p.X - 6, p.Y + 15);
    LineSegment seg1 = new LineSegment();
    seg1.Point = lpoint;
    pathFigure.Segments.Add(seg1);

    LineSegment seg2 = new LineSegment();
    seg2.Point = rpoint;
    pathFigure.Segments.Add(seg2);

    LineSegment seg3 = new LineSegment();
    seg3.Point = p;
    pathFigure.Segments.Add(seg3);

    pathGeometry.Figures.Add(pathFigure);
    RotateTransform transform = new RotateTransform();
    transform.Angle = theta + 90;
    transform.CenterX = p.X;
    transform.CenterY = p.Y;
    pathGeometry.Transform = transform;
    lineGroup.Children.Add(pathGeometry);

    LineGeometry connectorGeometry = new LineGeometry();
    connectorGeometry.StartPoint = p1;
    connectorGeometry.EndPoint = p2;
    lineGroup.Children.Add(connectorGeometry);
    System.Windows.Shapes.Path path = new System.Windows.Shapes.Path();
    path.Data = lineGroup;
    path.StrokeThickness = 2;
    path.Stroke = path.Fill = Brushes.Black;
    path.Name = string.Format("ArrowLine{0}", arrowName);
    return path;
}

Check for duplicate entries and insert each ellipse’s tag value in a stack. On mouse up, validate the pattern with the target screen code by encrypting it into an MD5hash string. Invoke the onvalidate delegate with validation flag and screen data as parameters. Start a timer with an elapse time of 1 second to clear all code and patterns on the screen. If the screen pattern is invalid, redraw the pattern with a red color and start the timer again to clear the screen.

Create a 3x3 matrix of ellipses with Tag values starting from (1,2,3...9) in a canvas

Image 4

XAML code

XML
<Canvas x:Name="LockCanvas" MouseUp="Canvas_MouseUp" Margin="110,20,80,10"
                    HorizontalAlignment="Center"  Height="180" Width="200" 
                    Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">
    <Ellipse   x:Name="Code1" Tag="1" Margin="5" Canvas.Left="0"
      Canvas.Top="0" Fill="Silver" Height="35"
      Width="35"
      StrokeThickness="5"
      Stroke="Black"  MouseMove="Canvas_MouseMove"  
      MouseDown="Canvas_MouseDown"/>
        :
    :
</Canvas>

C# code:

C#
//Draw pattern on mouse down
 CodeSequence = new Stack<int>();
 ClearAll();
 CreatePolyLine(Brushes.Green);
 FillCodeSequence(sender as Ellipse);
 if (!chkStealthMode.IsChecked.Value)
 {
   FillCodeColor(sender as Ellipse, Brushes.Green);
   LockCanvas.Children.Add(NewLine);
 }


//start drawing the screen code on mouse move checking duplicity and starting and end points
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
    if (e.LeftButton == MouseButtonState.Pressed)
    {
        Point currentPoint = e.GetPosition(LockCanvas);
        var ellipse = sender as Ellipse;
        bool firstEntry = IsItFirstEntry(ellipse);
        Point point = GetPointFromCodeEllipse(ellipse);
        if (!CheckSequenceExists(ellipse))
        {
            Shape arrow = null;
            if (NewLine.Points.Count - 1 > 0)
            {
                arrow = DrawLinkArrow(NewLine.Points[NewLine.Points.Count - 1], point,
                        Convert.ToString(ellipse.Tag));
            }
            NewLine.Points.Add(point);
            if (!chkStealthMode.IsChecked.Value)
            {
                FillCodeColor(sender as Ellipse, Brushes.Green);
                if (arrow != null)
                {
                    LockCanvas.Children.Add(arrow);
                }
            }
            FillCodeSequence(ellipse);
        }
        if (firstEntry)
        {
            NewLine.Points.Add(point);
        }
    }
}

Create/Edit Screen pattern

On Save, the pattern is saved as an MD5Hash encrypted code which will be saved in the database.  After the pattern is saved, the captured screen pattern will be emailed to the user for reference.

Image 5

C#

C#
private static BitmapSource CaptureScreen(Visual target, double dpiX, double dpiY)
{
    if (target == null)
    {
        return null;
    }
    Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
    RenderTargetBitmap rtb = new RenderTargetBitmap((int)(bounds.Width * dpiX / 96.0),
                                                    (int)(bounds.Height * dpiY / 96.0),
                                                    dpiX,
                                                    dpiY,
                                                    PixelFormats.Pbgra32);
    DrawingVisual dv = new DrawingVisual();
    using (DrawingContext ctx = dv.RenderOpen())
    {
        VisualBrush vb = new VisualBrush(target);
        ctx.DrawRectangle(vb, null, new Rect(new Point(), bounds.Size));
    }
    rtb.Render(dv);
    return rtb;
}

/// <summary>
/// Encrypt passcode and raise the event to continue using the encrypted passcode
/// </summary>
protected virtual void SavePassCode()
{
    if (ScreenLockData != null && ScreenLockData.OnSave != null)
    {
        var encryptedCode = Encryptor.MD5Hash(CodeSequence.ToStackString());
        ScreenLockData.ScreenCode = encryptedCode;
        ScreenLockData.TargetScreenCode = encryptedCode;
        ScreenLockData.SreenCodeImage = CaptureScreen(LockCanvas, 100, 100);
        ScreenLockData.OnSave(ScreenLockData);
        timer.Start();
    }
}

Login window

As we have the lock screen user control ready for use, let’s use it in a login page.

Bind ScreenLockdata with a viewmodel of type IScreenLockViewModel. Register the viewmodel delegates with the handler methods.

XAML:

XML
<lock:LockView ScreenLockMode="{Binding ScreenLockMode,Mode=TwoWay,
    UpdateSourceTrigger=PropertyChanged}" 
    HorizontalAlignment="Stretch" 
    Visibility="{Binding ScreenVisibility,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" 
    ScreenLockData="{Binding ScreenLockViewModel, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
</lock:LockView>
C#
/// <summary>
/// Screen lock data
/// </summary>
public IScreenLockViewModel ScreenLockViewModel
{
    get { return screenViewModel; }
    set
    {
        screenViewModel = value;
        RaisePropertyChanged("ScreenLockViewModel ");
    }
}

ScreenLockViewModel = new ScreenLockViewModel();
ScreenLockViewModel.OnScreenCodeValidated = OnScreenCodeValidation;
ScreenLockViewModel.OnSave = OnSave;
ScreenLockViewModel.TargetScreenCode = GetUserCode(user);// get from database;
ScreenLockMode = Extensions.ScreenLockMode.Login;
this.DataContext = this;

/// <summary>
/// Authenticate the user and proceed
/// </summary>
/// <param name="obj"></param>
/// <param name="isValidated"></param>
private void OnScreenCodeValidation(IScreenLockViewModel obj, bool isValidated)
{
    if (isValidated)
        MessageBox.Show(string.Format("Authenticated Password : {0}", obj.ScreenCode));
}

/// <summary>
/// Create or edit an existing password and save the target screen code 
/// </summary>
/// <param name="obj"></param>
private void OnSave(IScreenLockViewModel obj)
{
    MessageBox.Show("Saved Successfully!");
    ScreenLockViewModel.TargetScreenCode = obj.ScreenCode;
    ScreenLockMode = Extensions.ScreenLockMode.Login;
    SavedImage = obj.SreenCodeImage;
  //Send an email with screen code attachment
}

Points of Interest

  1. Dependency property for binding the screen data.
  2. Drawing shapes such as polyline and line segment.
  3. Using geometry group for lines with arrow heads.
  4. Delegates.
  5. Encryption using MD5Hash.
  6. Pattern control can be used for locking the screen or for an initial authentication process.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here