In Focus

Xamarin.Android - Build Real Life Applications Using TCP/IP - Part Three

This is the third and final part of my article series of Xamarin.Android where we learned how to build real-life applications using TCP/IP”.

Introduction 

Last time, we performed the workstation's sleep functionality on the basis of the client app SLP2 command. In this third and final part of my article series, we will complete the functionality of both of our applications, client and server. First, we will talk about how the screenshot functionality will perform because the client will only send the TSC1 command and the server will receive this. Then, on the basis of this command, the TakeScreenshot function will perform, that we will write inside the server app.
 
After capturing the screenshot of the current activity of the workstation, we will send it to the client. The size of the picture could be large and we cannot send the large data to the client. Therefore, to achieve this target, we will convert the screenshot data into bytes type packets and then send it to the client. When the client will receive the bytes type packets, it will have to convert into its original form. We will also perform the shutdown functionality. If a client sends SHTD3 command to the server application, the server will execute the shutdown function. Finally, if the admin wants to log out from the client application, then we will give this opportunity too to the admin. We will put the "logout" button at the end of the control page. If the admin clicks the "logout" button, the application will navigate to the login page.
Server Application
 
Let's go back to the server application and write the functionality of screenshot and shutdown workstation. Open the program.cs file and write the following code inside the while loop, that we had implemented in the last episode. In the while loop, we put the try-catch block and inside, we wrote the condition of If-Else. After if sleep check, you will write the following code.
  1.                     else if (data.ToUpper().Contains("SHTD3"))  
  2.                     {  
  3.                         Console.WriteLine("Pc is going to Shutdown!" + " \n");  
  4.   
  5.                         Shutdown();  
  6.                     }  
  7.                     else if (data.ToUpper().Contains("TSC1"))  
  8.                     {  
  9.                         Console.WriteLine("Take Screenshot!" + " \n");  
  10.   
  11.                         var bitmap = SaveScreenshot();  
  12.                         var stream = new MemoryStream();  
  13.                         bitmap.Save(stream, ImageFormat.Bmp);  
  14.                         sendData(stream.ToArray(), client.GetStream());  
  15.                     }  
Shutdown and TakeScreenshot Functions
 
Add the following namespaces to the server application. Otherwise, Visual Studio will not recognize the graphics keyword of the screenshot function.
  1. using System.Drawing;  
  2. using System.Drawing.Imaging;  
Go back to program.cs and put these functions inside the main class. 
  1. //Workstation Shutdown function  
  2.   
  3. void Shutdown()  
  4.             {  
  5.                 System.Diagnostics.Process.Start("Shutdown""-s -t 10");  
  6.             }  
  7.   
  8. //Save Screenshot function  
  9.   
  10.             Bitmap SaveScreenshot()  
  11.             {  
  12.                 var bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width,  
  13.                                                Screen.PrimaryScreen.Bounds.Height,  
  14.                                                PixelFormat.Format32bppArgb);  
  15.   
  16.                 // Create a graphics object from the bitmap.  
  17.   
  18.                 var gfxScreenshot = Graphics.FromImage(bmpScreenshot);  
  19.   
  20.                 // Take the screenshot from the upper left corner to the right   
  21.   
  22. bottom corner.  
  23.                 gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,  
  24.                                             Screen.PrimaryScreen.Bounds.Y,  
  25.                                             0,  
  26.                                             0,  
  27.                                             Screen.PrimaryScreen.Bounds.Size,  
  28.                                             CopyPixelOperation.SourceCopy);  
  29.                 return bmpScreenshot;  
  30.             }  
  31.   
  32. //Convert Image to byte type data.  
  33.   
  34.             void sendData(byte[] data, NetworkStream stream)  
  35.             {  
  36.                 int bufferSize = 1024;  
  37.   
  38.                 byte[] dataLength = BitConverter.GetBytes(data.Length);  
  39.   
  40.                 stream.Write(dataLength, 0, 4);  
  41.   
  42.                 int bytesSent = 0;  
  43.                 int bytesLeft = data.Length;  
  44.   
  45.                 while (bytesLeft > 0)  
  46.                 {  
  47.                     int curDataSize = Math.Min(bufferSize, bytesLeft);  
  48.   
  49.                     stream.Write(data, bytesSent, curDataSize);  
  50.   
  51.                     bytesSent += curDataSize;  
  52.                     bytesLeft -= curDataSize;  
  53.                 }  
  54.             }  

We have finished our server application and its all functionality. Let's start to code our client application.

Client Application
 
Go back to the client application and open the control.axml file. Inside a linear layout, add the following code to create more buttons and picture holders.
 
(Folder Name: Layout , File Name: Control.axml) 
  1.     <Button  
  2.         android:text="Take Screenshot"  
  3.         android:layout_width="match_parent"  
  4.         android:layout_height="wrap_content"  
  5.         android:layout_marginTop="15dp"  
  6.         android:id="@+id/btnTakeScreen" />  
  7.     <Button  
  8.         android:text="Shutdown"  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="wrap_content"  
  11.         android:id="@+id/btnShutdown" />  
  12.     <ImageView  
  13.         android:id="@+id/imageView"  
  14.         android:layout_width="match_parent"  
  15.         android:layout_height="0dp"  
  16.         android:layout_weight="1" />  
  17.     <Button  
  18.         android:text="Logout"  
  19.         android:layout_width="match_parent"  
  20.         android:layout_height="wrap_content"  
  21.         android:layout_marginBottom="15dp"  
  22.         android:id="@+id/btnLogout" />  
Control Activity
 
Open the control.cs file that we had created in the last episode and replace the following code with appropriate namespaces.
  1.     [Activity]  
  2.     public class Control : Activity  
  3.     {  
  4. //Instances   
  5.         private Button btnTakeScreen, btnSleep, btnShutdown ,btnLogout;  
  6.         private ImageView imageView;  
  7.         NetworkStream stream;  

  8.         protected override void OnCreate(Bundle savedInstanceState)  
  9.         {  
  10.             base.OnCreate(savedInstanceState);  
  11.             var client = Connection.Instance.client;  
  12.             // Create your application here  
  13.             SetContentView(Resource.Layout.Control);  
  14.             btnTakeScreen = FindViewById<Button>(Resource.Id.btnTakeScreen);  
  15.             btnSleep = FindViewById<Button>(Resource.Id.btnSleep);  
  16.             btnShutdown = FindViewById<Button>(Resource.Id.btnShutdown);  
  17.             btnLogout = FindViewById<Button>(Resource.Id.btnLogout);  
  18.             imageView = FindViewById<ImageView>(Resource.Id.imageView);  
  19.   
  20. //Sleep command button  
  21.   
  22.             btnSleep.Click += delegate   
  23.             {  
  24.                 stream = client.GetStream();  
  25.                 String s = "SLP2";  
  26.                 byte[] message = Encoding.ASCII.GetBytes(s);  
  27.                 stream.Write(message, 0, message.Length);  
  28.             };  
  29.   
  30. //Shutdown command button  
  31.   
  32.             btnShutdown.Click += delegate   
  33.             {  
  34.                 stream = client.GetStream();  
  35.                 String s = "SHTD3";  
  36.                 byte[] message = Encoding.ASCII.GetBytes(s);  
  37.                 stream.Write(message, 0, message.Length);  
  38.             };  
  39.   
  40. //Take Screenshot command button  
  41.   
  42.             btnTakeScreen.Click += delegate   
  43.             {  
  44.                 stream = client.GetStream();  
  45.                 String s = "TSC1";  
  46.                 byte[] message = Encoding.ASCII.GetBytes(s);  
  47.                 stream.Write(message, 0, message.Length);  
  48.                 var data = getData(client);  
  49.                 var image = BitmapFactory.DecodeByteArray(data, 0, data.Length);  
  50.                 imageView.SetImageBitmap(image);  
  51.             };  
  52.   
  53. //Logout button  
  54.   
  55.             btnLogout.Click += delegate   
  56.             {  
  57.                 StartActivity(typeof(MainActivity));  
  58.                 client.Close();  
  59.             };  
  60.         }  
  61.   
  62. //Convert byte to Image  
  63.   
  64.         public byte[] getData(TcpClient client)  
  65.         {  
  66.             NetworkStream stream = client.GetStream();  
  67.             byte[] fileSizeBytes = new byte[4];  
  68.             int bytes = stream.Read(fileSizeBytes,0,fileSizeBytes.Length);  
  69.             int dataLength = BitConverter.ToInt32(fileSizeBytes,0);  
  70.   
  71.             int bytesLeft = dataLength;  
  72.             byte[] data = new byte[dataLength];  
  73.   
  74.             int buffersize = 1024;  
  75.             int bytesRead = 0;  
  76.   
  77.             while(bytesLeft > 0)  
  78.             {  
  79.                 int curDataSize = Math.Min(buffersize, bytesLeft);  
  80.                 if (client.Available < curDataSize)  
  81.                     curDataSize = client.Available;//This save me  
  82.   
  83.                 bytes = stream.Read(data, bytesRead, curDataSize);  
  84.                 bytesRead += curDataSize;  
  85.                 bytesLeft -= curDataSize;  
  86.             }  
  87.             return data;  
  88.         }  
  89.     }  

Take Screenshot

Run both projects - server and client. Log into the client application as admin if you are already registered. Else, register as admin. Put the workstation IP address and port that you can see on the server application output screen into the client application and hit "Connect".
After connecting with the server, now you can perform your task. Click on the "Take Screenshot" button; after a few seconds, you will see the screenshot of workstation inside the client application.
 
Xamarin.Android - Build Real Life Application Using TCP/IP - Part Three 
 
Shutdown
 
After login and building the connection with the server, hit the "Shutdown" button. You will see a notification that your PC will be shut down in 30 seconds.
 
Xamarin.Android - Build Real Life Application Using TCP/IP - Part Three