Skip to main content

Managing Android emulator in .NET

Automated coded UI testing become very popular in the past few years. Its allow developers to create tests which are executed directly on UI level and simulate user actions. At the same time HTML5 become a standard for creating universal modern applications which can be hosts in a native browser controls.

New model of creating applications brings a new challenges in the testing fields that's why in this post I want to present my solution (it takes me almost two days to get this working!) which is first step in the process of creation an end-to-end test automation for mobile applications. My solution is prototype of a .NET console application which can be use to control Android emulator and simulate user standard operation like installing app, typing and rotating. This prototype can be use as 'emulator manager' which controls device emulator on which tests are performed - for example by using  Selenium.

As initial requirements to run the project:
1) Install the latest Java build :(  (sorry .NET geeks but it`s required)
2) Install Android SDK

Now we have all environment in place so we can create our emulator device. To do that we need to use Android Virtual Devices Manager tool which is located in the '..\\sdk\tools\' path inside Android SDK folder. To run this tool we need start cmd, navigate to the SDK tools folder and type 'android avd'. Now we can create a new emulator by specifying all setting we need - in the picture below I presented settings for my AVD called 'nexus'. To make sure that all configuration if correct we should run out AVD by calling emulator.exe  from  '..\\sdk\tools\'  for example 'emulator -avd nexus' - this cause our emulator start running and first run might take some time so be patient.

Picture 1. Configuration of a new  device emulator.
Now its time to back to the C# code a present solution which can manage Android emulator through .NET code. Basically solution based on the simple console application which is calling externals console applications:

  • emulator.exe - console application which allow to start device emulator by device name with specific parameters.
  • adb.exe - console application which allow communication with device emulator; allow to run shell mode directly on the emulator.
Picture 2. Application architecture.

There is two very important parts inside this solution. First one is the IEmulator interface which expose all functions which are currently supported by the program. The idea is that this solution can be extended to all main three mobile platforms (iOS, Android, Windows) and the IEmulator interface will remain common an contract for all of them so just implementation of each emulator will be different (now only AndroidEmulator class is implemented). IEmulator interface implementation is as follow:

Code Snippet
  1. /// <summary>
  2. /// Expose all emulator tasks.
  3. /// </summary>
  4. public interface IEmulator
  5. {
  6.     /// <summary>
  7.     /// Starts the emulator.
  8.     /// </summary>
  9.     /// <returns>Value which determines emulator is ready for use.</returns>
  10.     bool Initialize();
  11.  
  12.     /// <summary>
  13.     /// Enable shell mode on the emulator.
  14.     /// </summary>
  15.     void StartShell();
  16.  
  17.     /// <summary>
  18.     /// Checks the emulator is running.
  19.     /// </summary>
  20.     bool IsRunning();
  21.  
  22.     /// <summary>
  23.     /// Install app on the emulator.
  24.     /// </summary>
  25.     /// <param name="packagePath">Path to the apk package to intsall.</param>
  26.     /// <returns>True if application installed correctly.</returns>
  27.     bool InstallApp(string packagePath = null);
  28.  
  29.     /// <summary>
  30.     /// Uninstall specyfic package from emulator.
  31.     /// </summary>
  32.     /// <param name="packageName">Specyfic package name to uninstall.</param>
  33.     void UninstallApp(string packageName = null);
  34.  
  35.     /// <summary>
  36.     /// Run monkey on package.
  37.     /// </summary>
  38.     /// <param name="activitiesCount">Action count.</param>
  39.     void RunMonkey(int activitiesCount = 500);
  40.  
  41.     /// <summary>
  42.     /// Simulating keypress events on emulator.
  43.     /// </summary>
  44.     /// <param name="codes">Hardware codes array.</param>
  45.     void TypeAsHardwareInput(int[] codes);
  46.  
  47.     /// <summary>
  48.     /// Change orientation of the emulator.
  49.     /// </summary>
  50.     void ChangeOrientation();
  51. }

As you can see here, not all options are implemented but the most important functions are on place so let`s have a quick look on its:
  • Initialize: function which starts device emulator by calling emulator.exe as separate process and pass AVD name from the configuration file.
  • StartShell:  using 'adb shell' command from adb.exe tool in separated process to start shell mode on the currently running AVD. Process which hosts shell will remain active until application close.
  • IsRunning: function which call  'adb devices'  command  in separated process from adb.exe tool to check if AVD  is currently running.
  • InstallApp: install APK file from specific path in local PC by calling 'adb wait-for-device install <apk full-path>' command from adb.exe as separated process. Additional wait-for-device command ensure that emulator is ready to install app. 
  • UninstalApp: uninstall app from shell level by using package name (ex. com.android.tools.sdkcontroller stored in AndroidInstalledAppName App.config)
  • RunMonkey: from shell mode run monkey random actions on the installed package by executing N (activitiesCount) random activities.
  • TypeAsHardwareInput: allow to use simulate hardware keys to input any supported input. Under the hood its calling shell command 'input keyevent <key_code>' with key code specified for the platform. Key-codes list is available here.
Last function I want to describe in not supported by the Android SDK and from testing point of view it`s crucial -I mean here changing emulator orientation during the run-time. I spent a lot of time reading and investigating any potential possibility of changing emulator orientation by no of solutions I`ve found  was working for me. There is only one official way to switch emulator orientation - by pressing CTRL+F11, and I`m implemented it. Source code for this using  an external library called InuputSimulator (thank you Michael) to simulate keystroke. Additionally I used emulator process  name to find exact process and get focus on their main window before simulate keystroke.   

Code Snippet
  1. [DllImport("user32.dll")]
  2.         static extern bool SetForegroundWindow(IntPtr hWnd);
  3.  
  4.         /// <summary>
  5.         /// Change orientation of the emulator.
  6.         /// </summary>
  7.         public void ChangeOrientation()
  8.         {
  9.             var emulatorProcess = Process.GetProcessesByName("emulator-arm");
  10.             if (emulatorProcess.Count() == 0)
  11.             {
  12.                 throw new InvalidOperationException("Unable to find emulator process.");
  13.             }
  14.  
  15.             BringToFront(emulatorProcess[0]);
  16.             WindowsInput.InputSimulator.SimulateModifiedKeyStroke(WindowsInput.VirtualKeyCode.CONTROL, WindowsInput.VirtualKeyCode.F11);
  17.         }
  18.         
  19.         /// <summary>
  20.         /// Set focus on the process.
  21.         /// </summary>
  22.         /// <param name="pTemp">Process to be focused.</param>
  23.         private void BringToFront(Process pTemp)
  24.         {
  25.             SetForegroundWindow(pTemp.MainWindowHandle);
  26.         }

Now when all functions are on place we can call them in logical order.

Code Snippet
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         var emulator = EmulatorFactory.GetEmulator(EmulatorType.Android);
  6.  
  7.         emulator.Initialize();
  8.  
  9.         emulator.InstallApp();
  10.  
  11.         emulator.StartShell();
  12.  
  13.         emulator.ChangeOrientation();
  14.         emulator.ChangeOrientation();
  15.  
  16.         emulator.RunMonkey();
  17.         emulator.UnistallApp();
  18.     }
  19. }

I can`t guarantee but I hope that soon I will add next emulator - keep your fingers crossed!

Whole source code of the project is available here.

Thank you

More info:

Popular posts from this blog

Using Newtonsoft serializer in CosmosDB client

Problem In some scenarios engineers might want to use a custom JSON serializer for documents stored in CosmosDB.  Solution In CosmosDBV3 .NET Core API, when creating an instance of  CosmosClient one of optional setting in  CosmosClientOptions is to specify an instance of a Serializer . This serializer must be JSON based and be of  CosmosSerializer type. This means that if a custom serializer is needed this should inherit from CosmosSerializer abstract class and override its two methods for serializing and deserializing of an object. The challenge is that both methods from  CosmosSerializer are stream based and therefore might be not as easy to implement as engineers used to assume - still not super complex.  For demonstration purpose as or my custom serializer I'm going to use Netwonsoft.JSON library. Firstly a new type is needed and this must inherit from  CosmosSerializer.  using  Microsoft.Azure.Cosmos; using  Newtonsoft.Json; using  System.IO; using  System.Text; ///   <

Full-Text Search with PDF in Microsoft SQL Server

Last week I get interesting task to develop. The task was to search input text in PDF file stored in database as FileStream. The task implementation took me some time so I decided to share it with other developers. Here we are going to use SQL Server 2008 R2 (x64 Developers Edition), external driver from Adobe, Full-Text Search technology and FileStream technology.Because this sems a little bit comlicated let`s make this topic clear and do it step by step. 1) Enable FileStream - this part is pretty easy, just check wheter You already have enabled filestream on Your SQL Server instance - if no simply enable it as in the picture below. Picture 1. Enable filestream in SQL Server instance. 2) Create SQL table to store files  - mainly ther will be PDF file stored but some others is also be allright. Out table DocumentFile will be created in dbo schema and contain one column primary key with default value as sequential GUID. Important this is out table contains FileStream

Autocomplete control with ASP.NET MVC 4 and jQuery

Almost in each modern website project one of the feature is suggesting user possible items to select when he start typing one of them. Such functionality is done by using control named autocomplete . Under the hood  it consists of at least three elements: UI control which allow user to type some text - mainly this in HTML input of text type Server-side function which serves data to be auto-completed Client-side logic (written in JavaScript) which , by using AJAX, send request to the server asynchronously and then process the results. When we think about creating autocomplete control in ASP.NET MVC 4 we definitely should take a look at  jQueryUI framework. One of the feature of this framework is autocomplete control which enables users to quickly find and select from a pre-populated list of values as they type, leveraging searching and filtering. That sounds very good and is excellently what we are looking for. First step in autocomplete control  creation is creating a