public async void Can_Install_Apk()
        {
            var logger = new ConsoleLogger();
            Guid emuId = Guid.NewGuid();

            // Start an emulator.
            var adbFactory = new AndroidDebugBridgeFactory(TestConfig.PathToAdbExe);
            int consolePort = 5554;
            var emuFactory = new AndroidSdkEmulatorFactory(logger, TestConfig.PathToAndroidEmulatorExe, adbFactory, TestConfig.AvdName, consolePort, true, false, emuId);

            using (IEmulator droidEmulator = emuFactory.GetEmulator())
            {
                await droidEmulator.Start(TestConfig.EmulatorStartupTimeout).ContinueWith((t) =>
                {
                    // sut
                    var adb = adbFactory.GetAndroidDebugBridge();
                    var currentDir = Environment.CurrentDirectory;

                    var apkPath = System.IO.Path.Combine(currentDir, "..\\..\\..\\", TestConfig.PathToAndroidTestsApk);

                    adb.Install(droidEmulator.Device, apkPath, AdbInstallFlags.ReplaceExistingApplication);


                });


            }


        }
        public void Can_Create_Android_Emulator()
        {
            var logger = new ConsoleLogger();
            Guid emuId = Guid.NewGuid();

            var adbFactory = new AndroidDebugBridgeFactory(TestConfig.PathToAdbExe);
            int consolePort = 5554;
            var emuFactory = new AndroidSdkEmulatorFactory(logger, TestConfig.PathToAndroidEmulatorExe, adbFactory, TestConfig.AvdName, consolePort, true, false, emuId);

            IEmulator droidEmulator = emuFactory.GetEmulator();
        }
        public async void Can_Start_And_Stop_Android_Emulator_With_No_Window()
        {
            var logger = new ConsoleLogger();
            Guid emuId = Guid.NewGuid();

            var adbFactory = new AndroidDebugBridgeFactory(TestConfig.PathToAdbExe);
            int consolePort = 5554;
            var emuFactory = new AndroidSdkEmulatorFactory(logger, TestConfig.PathToAndroidEmulatorExe, adbFactory, TestConfig.AvdName, consolePort, true, true, emuId);

            IEmulator droidEmulator = emuFactory.GetEmulator();
            await droidEmulator.Start(TestConfig.EmulatorStartupTimeout).ContinueWith((t) =>
            {
                droidEmulator.Stop();
            });

        }
        public async void Can_Run_Tests()
        {
            var logger = new ConsoleLogger();
            Guid emuId = Guid.NewGuid();

            // Start an emulator.
            var adbFactory = new AndroidDebugBridgeFactory(TestConfig.PathToAdbExe);
            int consolePort = 5554;
            var emuFactory = new AndroidSdkEmulatorFactory(logger, TestConfig.PathToAndroidEmulatorExe, adbFactory, TestConfig.AvdName, consolePort, true, false, emuId);

            using (IEmulator droidEmulator = emuFactory.GetEmulator())
            {
                await droidEmulator.Start(TestConfig.EmulatorStartupTimeout).ContinueWith((t) =>
                {

                    if (t.IsFaulted)
                    {
                        throw t.Exception;
                    }

                    var adb = adbFactory.GetAndroidDebugBridge();

                    // install tests apk
                    var currentDir = Environment.CurrentDirectory;
                    var apkPath = System.IO.Path.Combine(currentDir, "..\\..\\..\\", TestConfig.PathToAndroidTestsApk);
                    adb.Install(droidEmulator.Device, apkPath, AdbInstallFlags.ReplaceExistingApplication);

                    // sut
                    var testRunner = new AndroidTestRunner(logger, adbFactory, droidEmulator.Device, TestConfig.AndroidTestsPackageName, TestConfig.AndroidTestsInstrumentationClassPath);
                    var testResults = testRunner.RunTests();

                    Assert.That(testResults, Is.Not.Null);
                    var tests = testResults.GetTests().ToList();
                    var failedTests = tests.Where(a => a.Kind == TestResultKind.Failure);

                    foreach (var a in failedTests)
                    {
                        logger.LogMessage(string.Format("{0} - ", a.Name, a.StackTrace));
                    }

                });

            }

        }
        public async void Can_Report_Tests_To_Default_Reporter()
        {
            var logger = new ConsoleLogger();
            Guid emuId = Guid.NewGuid();

            // Start an emulator.
            var adbFactory = new AndroidDebugBridgeFactory(TestConfig.PathToAdbExe);
            int consolePort = 5554;
            var emuFactory = new AndroidSdkEmulatorFactory(logger, TestConfig.PathToAndroidEmulatorExe, adbFactory, TestConfig.AvdName, consolePort, true, false, emuId);

            using (IEmulator droidEmulator = emuFactory.GetEmulator())
            {
                await droidEmulator.Start(TestConfig.EmulatorStartupTimeout).ContinueWith((t) =>
                {

                    if (t.IsFaulted)
                    {
                        throw t.Exception;
                    }

                    var adb = adbFactory.GetAndroidDebugBridge();

                    // install tests apk
                    var currentDir = Environment.CurrentDirectory;
                    var apkPath = System.IO.Path.Combine(currentDir, "..\\..\\..\\", TestConfig.PathToAndroidTestsApk);
                    adb.Install(droidEmulator.Device, apkPath, AdbInstallFlags.ReplaceExistingApplication);

                    // sut
                    IProgressReporter progressReporter = new DefaultProgressReporter(Console.WriteLine);
                    progressReporter.ReportTestsStarted(TestConfig.AndroidTestsPackageName);
                    var testRunner = new AndroidTestRunner(logger, adbFactory, droidEmulator.Device, TestConfig.AndroidTestsPackageName, TestConfig.AndroidTestsInstrumentationClassPath);
                    var testResults = testRunner.RunTests();
                    Assert.That(testResults, Is.Not.Null);

                    progressReporter.ReportTests(testResults);
                    progressReporter.ReportTestsFinished(TestConfig.AndroidTestsPackageName);
                    return testResults;

                });

            }

        }
        public async void Cannot_Start_Emulator_If_Existing_Device_Using_Port_And_Single_Instance_Mode_Abort_Specified()
        {
            var logger = new ConsoleLogger();
            Guid emuId = Guid.NewGuid();

            var adbFactory = new AndroidDebugBridgeFactory(TestConfig.PathToAdbExe);
            int consolePort = 5554;
            var emuFactory = new AndroidSdkEmulatorFactory(logger, TestConfig.PathToAndroidEmulatorExe, adbFactory, TestConfig.AvdName, consolePort, true, true, emuId, SingleInstanceMode.Abort);

            IEmulator droidEmulator = emuFactory.GetEmulator();
            Exception e = null;
                        
            var handles = new AutoResetEvent[] { new AutoResetEvent(false), new AutoResetEvent(false) };
            
            await droidEmulator.Start(TestConfig.EmulatorStartupTimeout).ContinueWith(async (t) =>
            {
                // now try and start another one on same port.
                IEmulator secondEmulator = emuFactory.GetEmulator();
                await secondEmulator.Start(TestConfig.EmulatorStartupTimeout).ContinueWith((a) =>
                {
                    if (a.IsFaulted)
                    {
                        e = a.Exception.InnerExceptions[0];
                    }
                  
                    secondEmulator.Stop();
                    handles[0].Set();

                });
                droidEmulator.Stop();
                handles[1].Set();
            });

            WaitHandle.WaitAll(handles, new TimeSpan(0, 2, 0));          
            if (e != null)
            {
                var rootEx = e.GetBaseException();
                throw rootEx;
            }

        }
        public async void Can_Get_Devices()
        {
            var logger = new ConsoleLogger();
            Guid emuId = Guid.NewGuid();

            // Start an emulator.
            var adbFactory = new AndroidDebugBridgeFactory(TestConfig.PathToAdbExe);
            int consolePort = 5554;
            var emuFactory = new AndroidSdkEmulatorFactory(logger, TestConfig.PathToAndroidEmulatorExe, adbFactory, TestConfig.AvdName, consolePort, true, false, emuId);

            using (IEmulator droidEmulator = emuFactory.GetEmulator())
            {
                await droidEmulator.Start(TestConfig.EmulatorStartupTimeout).ContinueWith((t) =>
                {
                    // sut
                    var adb = adbFactory.GetAndroidDebugBridge();
                    var devices = adb.GetDevices();

                    Assert.That(devices, Is.Not.Null);
                    Assert.That(devices.Length, Is.GreaterThanOrEqualTo(1));

                    var deviceFound = devices.Where(a => a.Port == consolePort).FirstOrDefault();
                    Assert.That(deviceFound, Is.Not.Null);

                    foreach (var item in devices)
                    {
                        Console.WriteLine("Device Name: {0}, Status: {1}", item.Name, item.Status);
                    }

                });


            }


        }
        public async void Can_Start_Emulator_If_Existing_Device_Using_Port_Then_It_Is_Reused_And_Killed_Afterwards_When_Single_Instance_Mode_ReuseExistingThenKill_Specified()
        {
            var logger = new ConsoleLogger();
            Guid emuId = Guid.NewGuid();

            var adbFactory = new AndroidDebugBridgeFactory(TestConfig.PathToAdbExe);
            int consolePort = 5554;
            var emuFactory = new AndroidSdkEmulatorFactory(logger, TestConfig.PathToAndroidEmulatorExe, adbFactory, TestConfig.AvdName, consolePort, true, true, emuId, SingleInstanceMode.ReuseExistingThenKill);

            IEmulator droidEmulator = emuFactory.GetEmulator();
            await droidEmulator.Start(TestConfig.EmulatorStartupTimeout).ContinueWith((t) =>
            {

                var firstDevice = (AndroidDevice)droidEmulator.Device;

                // now try and start another one on same port.
                Guid secondEmuId = Guid.NewGuid();
                var secondEmuFactory = new AndroidSdkEmulatorFactory(logger, TestConfig.PathToAndroidEmulatorExe, adbFactory, TestConfig.AvdName, consolePort, true, true, secondEmuId, SingleInstanceMode.ReuseExistingThenKill);

                IEmulator secondEmulator = secondEmuFactory.GetEmulator();
                secondEmulator.Start(TestConfig.EmulatorStartupTimeout).Wait();

                // now try and start another one on same port.
                AndroidDevice device = (AndroidDevice)secondEmulator.Device;

                Assert.That(device.FullName() == firstDevice.FullName());

                var adb = adbFactory.GetAndroidDebugBridge();

                // this should result in the device being killed.
                secondEmulator.Stop();

                Thread.Sleep(new TimeSpan(0, 0, 3)); // give time for device to be killed.

                // device should no longer be listed.
                var devices = adb.GetDevices();
                foreach (var d in devices)
                {
                    Assert.That(d.FullName() != firstDevice.FullName(), "device was still listed in adb devices after it was killed");
                }

                droidEmulator.Stop();
            });

        }
        public async void Can_Start_Emulator_If_Existing_Device_Using_Port_Then_It_Is_Reused_When_Single_Instance_Mode_ReuseExisting_Specified()
        {
            var logger = new ConsoleLogger();
            Guid emuId = Guid.NewGuid();

            var adbFactory = new AndroidDebugBridgeFactory(TestConfig.PathToAdbExe);
            int consolePort = 5554;
            var emuFactory = new AndroidSdkEmulatorFactory(logger, TestConfig.PathToAndroidEmulatorExe, adbFactory, TestConfig.AvdName, consolePort, true, true, emuId, SingleInstanceMode.ReuseExisting);

            IEmulator droidEmulator = emuFactory.GetEmulator();
            await droidEmulator.Start(TestConfig.EmulatorStartupTimeout).ContinueWith((t) =>
            {
                // now try and start another one on same port.
                Guid secondEmuId = Guid.NewGuid();
                var secondEmuFactory = new AndroidSdkEmulatorFactory(logger, TestConfig.PathToAndroidEmulatorExe, adbFactory, TestConfig.AvdName, consolePort, true, true, secondEmuId, SingleInstanceMode.ReuseExisting);

                IEmulator secondEmulator = secondEmuFactory.GetEmulator();
                secondEmulator.Start(TestConfig.EmulatorStartupTimeout).Wait();

                // now try and start another one on same port.
                AndroidDevice device = (AndroidDevice)secondEmulator.Device;
                var adb = adbFactory.GetAndroidDebugBridge();

                // this second device should actually re-use the first device so should have device 1 emu id, not device 2.
                var secondId = device.QueryId(adb);
                Assert.That(Guid.Parse(secondId) != secondEmuId);

                secondEmulator.Stop();
                droidEmulator.Stop();
            });

        }
        public async void Can_Start_Emulator_If_Existing_Device_Using_Port_Then_It_Is_Killed_When_Single_Instance_Mode_KillExisting_Specified()
        {
            var logger = new ConsoleLogger();
            Guid emuId = Guid.NewGuid();

            var adbFactory = new AndroidDebugBridgeFactory(TestConfig.PathToAdbExe);
            int consolePort = 5554;
            var emuFactory = new AndroidSdkEmulatorFactory(logger, TestConfig.PathToAndroidEmulatorExe, adbFactory, TestConfig.AvdName, consolePort, true, true, emuId, SingleInstanceMode.KillExisting);

            IEmulator droidEmulator = emuFactory.GetEmulator();
            await droidEmulator.Start(TestConfig.EmulatorStartupTimeout).ContinueWith((t) =>
            {
                // now try and start another one on same port.
                IEmulator secondEmulator = emuFactory.GetEmulator();
                secondEmulator.Start(TestConfig.EmulatorStartupTimeout).ContinueWith((a) =>
                {
                    // now try and start another one on same port.
                    secondEmulator.Stop();
                });

                droidEmulator.Stop();
            });

        }
        public void Can_Restart()
        {                     
            var adbFactory = new AndroidDebugBridgeFactory(TestConfig.PathToAdbExe);
            var adb = adbFactory.GetAndroidDebugBridge();
            adb.RestartServer();

        }
        public async void Cannot_Proceed_Past_Timeout()
        {
            var logger = new ConsoleLogger();
            Guid emuId = Guid.NewGuid();

            // Start an emulator.
            var adbFactory = new AndroidDebugBridgeFactory(TestConfig.PathToAdbExe);
            int consolePort = 5554;
            var emuFactory = new AndroidSdkEmulatorFactory(logger, TestConfig.PathToAndroidEmulatorExe, adbFactory, TestConfig.AvdName, consolePort, true, false, emuId);

            try
            {
                using (IEmulator droidEmulator = emuFactory.GetEmulator())
                {
                    TaskContinuationOptions y = new TaskContinuationOptions();

                    await droidEmulator.Start(TimeSpan.FromSeconds(5)).ContinueWith((t) =>
                    {
                        if (!t.IsFaulted)
                        {
                            Assert.Fail();
                        }

                        var exception = t.Exception.InnerExceptions[0];
                        throw exception;

                    });

                }
            }
            catch (AggregateException e)
            {
                var ex = e.InnerExceptions[0];
                throw ex;
            }



        }