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

Playing with a .NET types definition

In the last few days I spent some time trying to unify structure of one of the project I`m currently working on. Most of the changes were about changing variable types because it`s were not used right way. That is why in this post I want to share my observations and practices with you. First of all we need to understand what ' variable definition ' is and how it`s different from ' variable initialization '. This part should be pretty straightforward:   variable definition  consist of data type and variable name only <data_type> <variable_name> ; for example int i ; . It`s important to understand how variable definition affects your code because it behaves differently depends weather you work with value or reference types. In the case of value types after defining variable it always has default value and it`s never null value. However after defined reference type variable without initializing it has null value by default. variable initialization  is

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; ///   <

Using Hortonworks Hive in .NET

A few months ago I decided to learn a big data. This sounds very complex and of course it is. All these strange names which actually tells nothing to person who is new in these area combined with different way of looking at data storage makes entire topic even more complex. However after reading N blogs and watching many, many tutorials today I finally had a chance to try to write some code. As in last week I managed to setup a Hortonworks distribution of Hadoop today I decided to connect to it from my .NET based application and this is what I will describe in this post. First things first I didn`t setup entire Hortonworks ecosystem from scratch - I`d love to but for now it`s far beyond my knowledge thus I decided to use a sandbox environment provided by Hortonworks. There are multiple different VMs available to download but in my case I`ve choose a Hyper-V. More about setting this environment up you can read here . Picture 1. Up and running sandbox environment. Now whe