public ITargetDevice CreateDevice(string InRef, string InParam)
        {
            AndroidDeviceData DeviceData = null;

            if (!String.IsNullOrEmpty(InParam))
            {
                DeviceData = fastJSON.JSON.Instance.ToObject <AndroidDeviceData>(InParam);
            }

            return(new TargetDeviceAndroid(InRef, DeviceData));
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="InReferenceName"></param>
        /// <param name="InRemoveOnDestruction"></param>
        public TargetDeviceAndroid(string InDeviceName = "", AndroidDeviceData DeviceData = null)
        {
            DeviceName = InDeviceName;

            AdbCredentialCache.AddInstance(DeviceData);

            // If no device name or its 'default' then use the first default device
            if (string.IsNullOrEmpty(DeviceName) || DeviceName.Equals("default", StringComparison.OrdinalIgnoreCase))
            {
                var DefaultDevices = GetAllAvailableDevices();

                if (DefaultDevices.Count() == 0)
                {
                    if (GetAllConnectedDevices().Count > 0)
                    {
                        throw new AutomationException("No default device available. One or more devices are connected but unauthorized. See 'adb devices'");
                    }
                    else
                    {
                        throw new AutomationException("No default device available. See 'adb devices'");
                    }
                }

                DeviceName = DefaultDevices.First();
            }

            if (Log.IsVerbose)
            {
                RunOptions = CommandUtils.ERunOptions.NoWaitForExit;
            }
            else
            {
                RunOptions = CommandUtils.ERunOptions.NoWaitForExit | CommandUtils.ERunOptions.NoLoggingOfRunCommand;
            }

            // if this is not a connected device then remove when done
            var ConnectedDevices = GetAllConnectedDevices();

            IsExistingDevice = ConnectedDevices.Keys.Contains(DeviceName);

            if (!IsExistingDevice)
            {
                // adb uses 5555 by default
                if (DeviceName.Contains(":") == false)
                {
                    DeviceName = DeviceName + ":5555";
                }

                lock (Globals.MainLock)
                {
                    using (var PauseEC = new ScopedSuspendECErrorParsing())
                    {
                        IProcessResult AdbResult = RunAdbGlobalCommand(string.Format("connect {0}", DeviceName));

                        if (AdbResult.ExitCode != 0)
                        {
                            throw new AutomationException("adb failed to connect to {0}. {1}", DeviceName, AdbResult.Output);
                        }
                    }

                    Log.Info("Connected to {0}", DeviceName);

                    // Need to sleep for adb service process to register, otherwise get an unauthorized (especially on parallel device use)
                    Thread.Sleep(5000);
                }
            }

            LocalDirectoryMappings = new Dictionary <EIntendedBaseCopyDirectory, string>();

            // for IP devices need to sanitize this
            Name = DeviceName.Replace(":", "_");

            LocalCachePath = Path.Combine(Path.GetTempPath(), "AndroidDevice_" + Name);

            ConnectedDevices = GetAllConnectedDevices();

            SetUpDirectoryMappings();

            // sanity check that it was now dound
            if (ConnectedDevices.Keys.Contains(DeviceName) == false)
            {
                throw new AutomationException("Failed to find new device {0} in connection list", DeviceName);
            }

            if (ConnectedDevices[DeviceName] == false)
            {
                Dispose();
                throw new AutomationException("Device {0} is connected but this PC is not authorized.", DeviceName);
            }
        }
        public static void AddInstance(AndroidDeviceData DeviceData = null)
        {
            lock (Globals.MainLock)
            {
                string KeyPath = Globals.Params.ParseValue("adbkeys", null);

                // setup key store from device data
                if (String.IsNullOrEmpty(KeyPath) && DeviceData != null)
                {
                    // checked that cached keys are the same
                    if (!String.IsNullOrEmpty(PrivateKey))
                    {
                        if (PrivateKey != DeviceData.privateKey)
                        {
                            throw new AutomationException("ADB device private keys must match");
                        }
                    }

                    if (!String.IsNullOrEmpty(PublicKey))
                    {
                        if (PublicKey != DeviceData.publicKey)
                        {
                            throw new AutomationException("ADB device public keys must match");
                        }
                    }

                    PrivateKey = DeviceData.privateKey;
                    PublicKey  = DeviceData.publicKey;

                    if (String.IsNullOrEmpty(PublicKey) || String.IsNullOrEmpty(PrivateKey))
                    {
                        throw new AutomationException("Invalid key in device data");
                    }

                    KeyPath = Path.Combine(Globals.TempDir, "AndroidADBKeys");

                    if (!Directory.Exists(KeyPath))
                    {
                        Directory.CreateDirectory(KeyPath);
                    }

                    if (InstanceCount == 0)
                    {
                        byte[] data = Convert.FromBase64String(PrivateKey);
                        File.WriteAllText(KeyPath + "/adbkey", Encoding.UTF8.GetString(data));

                        data = Convert.FromBase64String(PublicKey);
                        File.WriteAllText(KeyPath + "/adbkey.pub", Encoding.UTF8.GetString(data));
                    }
                }

                if (InstanceCount == 0 && !String.IsNullOrEmpty(KeyPath))
                {
                    Log.Info("Using adb keys at {0}", KeyPath);

                    string LocalKeyPath = Path.Combine(Environment.GetEnvironmentVariable("USERPROFILE"), ".android");

                    string RemoteKeyFile    = Path.Combine(KeyPath, "adbkey");
                    string RemotePubKeyFile = Path.Combine(KeyPath, "adbkey.pub");
                    string LocalKeyFile     = Path.Combine(LocalKeyPath, "adbkey");
                    string LocalPubKeyFile  = Path.Combine(LocalKeyPath, "adbkey.pub");
                    string BackupSentry     = Path.Combine(LocalKeyPath, "gauntlet.inuse");

                    if (File.Exists(RemoteKeyFile) == false)
                    {
                        throw new AutomationException("adbkey at {0} does not exist", KeyPath);
                    }

                    if (File.Exists(RemotePubKeyFile) == false)
                    {
                        throw new AutomationException("adbkey.pub at {0} does not exist", KeyPath);
                    }

                    if (File.Exists(BackupSentry) == false)
                    {
                        if (File.Exists(LocalKeyFile))
                        {
                            File.Copy(LocalKeyFile, LocalKeyFile + KeyBackupExt, true);
                        }

                        if (File.Exists(LocalPubKeyFile))
                        {
                            File.Copy(LocalPubKeyFile, LocalPubKeyFile + KeyBackupExt, true);
                        }
                        File.WriteAllText(BackupSentry, "placeholder");
                    }

                    File.Copy(RemoteKeyFile, LocalKeyFile, true);
                    File.Copy(RemotePubKeyFile, LocalPubKeyFile, true);

                    bUsingCustomKeys = true;

                    Log.Info("Running adb kill-server to refresh credentials");
                    TargetDeviceAndroid.RunAdbGlobalCommand("kill-server");

                    Thread.Sleep(5000);
                }

                InstanceCount++;
            }
        }