public IAppInstance Run(IAppInstall App)
        {
            AndroidAppInstall DroidAppInstall = App as AndroidAppInstall;

            if (DroidAppInstall == null)
            {
                throw new Exception("AppInstance is of incorrect type!");
            }

            // wake the device - we can install while its asleep but not run
            PowerOn();

            // kill any currently running instance:
            KillRunningProcess(DroidAppInstall.AndroidPackageName);

            string LaunchActivity = AndroidPlatform.GetLaunchableActivityName();

            Log.Info("Launching {0} on '{1}' ", DroidAppInstall.AndroidPackageName + "/" + LaunchActivity, ToString());
            Log.Verbose("\t{0}", DroidAppInstall.CommandLine);

            // Clear the device's logcat in preparation for the test..
            RunAdbDeviceCommand("logcat --clear");

            // start the app on device!
            string         CommandLine = "shell am start -W -S -n " + DroidAppInstall.AndroidPackageName + "/" + LaunchActivity;
            IProcessResult Process     = RunAdbDeviceCommand(CommandLine, false, true);

            return(new AndroidAppInstance(this, DroidAppInstall, Process));
        }
        public IAppInstall InstallApplication(UnrealAppConfig AppConfig)
        {
            // todo - pass this through
            AndroidBuild Build = AppConfig.Build as AndroidBuild;

            // Ensure APK exists
            if (Build == null)
            {
                throw new AutomationException("Invalid build for Android!");
            }

            // kill any currently running instance:
            KillRunningProcess(Build.AndroidPackageName);

            bool SkipDeploy = Globals.Params.ParseParam("SkipDeploy");

            if (SkipDeploy == false)
            {
                // Establish remote directory locations
                string         DeviceStorageQueryCommand = AndroidPlatform.GetStorageQueryCommand();
                IProcessResult StorageQueryResult        = RunAdbDeviceCommand(DeviceStorageQueryCommand);
                string         StorageLocation           = StorageQueryResult.Output.Trim(); // "/mnt/sdcard";

                // remote dir used to save things
                string RemoteDir = StorageLocation + "/UE4Game/" + AppConfig.ProjectName;

                // if not a bulk/dev build, remote dir will be under /{StorageLocation}/Android/data/{PackageName}
                if ((Build.Flags & (BuildFlags.Bulk | BuildFlags.CanReplaceExecutable)) == 0)
                {
                    RemoteDir = StorageLocation + "/Android/data/" + Build.AndroidPackageName + "/files/UE4Game/" + AppConfig.ProjectName;
                }

                string DependencyDir = RemoteDir + "/deps";

                // device artifact path, always clear between runs
                DeviceArtifactPath = string.Format("{0}/{1}/Saved", RemoteDir, AppConfig.ProjectName);
                RunAdbDeviceCommand(string.Format("shell rm -r {0}", DeviceArtifactPath));

                // path for OBB files
                string OBBRemoteDestination = string.Format("{0}/obb/{1}", StorageLocation, Build.AndroidPackageName);

                if (Globals.Params.ParseParam("cleandevice"))
                {
                    Log.Info("Cleaning previous builds due to presence of -cleandevice");

                    // we need to ununstall then install the apk - don't care if it fails, may have been deleted
                    Log.Info("Uninstalling {0}", Build.AndroidPackageName);
                    RunAdbDeviceCommand(string.Format("uninstall {0}", Build.AndroidPackageName));

                    Log.Info("Removing {0}", RemoteDir);
                    RunAdbDeviceCommand(string.Format("shell rm -r {0}", RemoteDir));

                    Log.Info("Removing {0}", OBBRemoteDestination);
                    RunAdbDeviceCommand(string.Format("shell rm -r {0}", OBBRemoteDestination));
                }

                // remote dir on the device, create it if it doesn't exist
                RunAdbDeviceCommand(string.Format("shell mkdir -p {0}/", RemoteDir));

                IProcessResult AdbResult;
                string         AdbCommand;

                // path to the APK to install.
                string ApkPath = Build.SourceApkPath;

                // check for a local newer executable
                if (Globals.Params.ParseParam("dev"))
                {
                    //string ApkFileName = Path.GetFileName(ApkPath);

                    string ApkFileName2 = UnrealHelpers.GetExecutableName(AppConfig.ProjectName, UnrealTargetPlatform.Android, AppConfig.Configuration, AppConfig.ProcessType, "apk");

                    string LocalAPK = Path.Combine(Environment.CurrentDirectory, AppConfig.ProjectName, "Binaries/Android", ApkFileName2);

                    bool LocalFileExists = File.Exists(LocalAPK);
                    bool LocalFileNewer  = LocalFileExists && File.GetLastWriteTime(LocalAPK) > File.GetLastWriteTime(ApkPath);

                    Log.Verbose("Checking for newer binary at {0}", LocalAPK);
                    Log.Verbose("LocalFile exists: {0}. Newer: {1}", LocalFileExists, LocalFileNewer);

                    if (LocalFileExists && LocalFileNewer)
                    {
                        ApkPath = LocalAPK;
                    }
                }

                // first install the APK
                CopyFileToDevice(Build.AndroidPackageName, ApkPath, "");

                // obb files need to be named based on APK version (grrr), so find that out. This should return something like
                // versionCode=2 minSdk=21 targetSdk=21
                string PackageInfo = RunAdbDeviceCommand(string.Format("shell dumpsys package {0} | grep versionCode", Build.AndroidPackageName)).Output;
                var    Match       = Regex.Match(PackageInfo, @"versionCode=([\d\.]+)\s");
                if (Match.Success == false)
                {
                    throw new AutomationException("Failed to find version info for APK!");
                }
                string PackageVersion = Match.Groups[1].ToString();

                // Convert the files from the source to final destination names
                Dictionary <string, string> FilesToInstall = new Dictionary <string, string>();

                Console.WriteLine("trying to copy files over.");
                if (AppConfig.FilesToCopy != null)
                {
                    if (LocalDirectoryMappings.Count == 0)
                    {
                        Console.WriteLine("Populating Directory");
                        PopulateDirectoryMappings(DeviceArtifactPath);
                    }
                    Console.WriteLine("trying to copy files over.");
                    foreach (UnrealFileToCopy FileToCopy in AppConfig.FilesToCopy)
                    {
                        string PathToCopyTo = Path.Combine(LocalDirectoryMappings[FileToCopy.TargetBaseDirectory], FileToCopy.TargetRelativeLocation);
                        if (File.Exists(FileToCopy.SourceFileLocation))
                        {
                            FileInfo SrcInfo = new FileInfo(FileToCopy.SourceFileLocation);
                            SrcInfo.IsReadOnly = false;
                            FilesToInstall.Add(FileToCopy.SourceFileLocation, PathToCopyTo.Replace("\\", "/"));
                            Console.WriteLine("Copying {0} to {1}", FileToCopy.SourceFileLocation, PathToCopyTo);
                        }

                        else
                        {
                            Log.Warning("File to copy {0} not found", FileToCopy);
                        }
                    }
                }

                Build.FilesToInstall.Keys.ToList().ForEach(K =>
                {
                    string SrcPath  = K;
                    string DestPath = Build.FilesToInstall[K];

                    string DestFile = Path.GetFileName(DestPath);

                    // If we installed a new APK we need to change the package version
                    Match OBBMatch = Regex.Match(DestFile, @"main\.(\d+)\.com.*\.obb");
                    if (OBBMatch.Success)
                    {
                        string NewFileName = DestFile.Replace(OBBMatch.Groups[1].ToString(), PackageVersion);
                        DestPath           = DestPath.Replace(DestFile, NewFileName);
                    }

                    DestPath = Regex.Replace(DestPath, "%STORAGE%", StorageLocation, RegexOptions.IgnoreCase);

                    FilesToInstall.Add(SrcPath, DestPath);
                });



                // get a list of files in the destination OBB directory
                AdbResult = RunAdbDeviceCommand(string.Format("shell ls {0}", OBBRemoteDestination));

                // if != 0 then no folder exists
                if (AdbResult.ExitCode == 0)
                {
                    IEnumerable <string> CurrentRemoteFileList = AdbResult.Output.Replace("\r\n", "\n").Split('\n');
                    IEnumerable <string> NewRemoteFileList     = FilesToInstall.Values.Select(F => Path.GetFileName(F));

                    // delete any files that should not be there
                    foreach (string FileName in CurrentRemoteFileList)
                    {
                        if (FileName.StartsWith(".") || FileName.Length == 0)
                        {
                            continue;
                        }

                        if (NewRemoteFileList.Contains(FileName) == false)
                        {
                            RunAdbDeviceCommand(string.Format("shell rm {0}/{1}", OBBRemoteDestination, FileName));
                        }
                    }
                }

                foreach (var KV in FilesToInstall)
                {
                    string LocalFile  = KV.Key;
                    string RemoteFile = KV.Value;

                    CopyFileToDevice(Build.AndroidPackageName, LocalFile, RemoteFile);
                }

                // create a tempfile, insert the command line, and push it over
                string TmpFile = Path.GetTempFileName();

                CommandLineFilePath = string.Format("{0}/UE4CommandLine.txt", RemoteDir);

                // I've seen a weird thing where adb push truncates by a byte, so add some padding...
                File.WriteAllText(TmpFile, AppConfig.CommandLine + "    ");
                AdbCommand = string.Format("push {0} {1}", TmpFile, CommandLineFilePath);
                RunAdbDeviceCommand(AdbCommand);


                File.Delete(TmpFile);
            }
            else
            {
                Log.Info("Skipping install of {0} (-skipdeploy)", Build.AndroidPackageName);
            }

            AndroidAppInstall AppInstall = new AndroidAppInstall(this, AppConfig.ProjectName, Build.AndroidPackageName, AppConfig.CommandLine);

            return(AppInstall);
        }
 public AndroidAppInstance(TargetDeviceAndroid InDevice, AndroidAppInstall InInstall, IProcessResult InProcess)
 {
     AndroidDevice = InDevice;
     Install       = InInstall;
     LaunchProcess = InProcess;
 }